Skip to content

Expose Runtime.connect's options shape as a public type #199

@feniix

Description

@feniix

Summary

Runtime.connect accepts an options object at runtime, but the type signature in dist/runtime.d.ts only exposes the bare positional signature:

connect(server: string): Promise<ClientContext>;

Consumers that need to wrap or override connect — e.g. a long-running daemon forcing disableOAuth: true on every internal call from callTool / listTools — have no public type for the options shape. The existing workaround is Record<string, any> on the parameter, which throws away type safety on a small but load-bearing surface (cache control + OAuth suppression).

Why this matters

connect's options object is already the public-facing primitive for cross-cutting concerns: cache identity (skipCache), OAuth posture (maxOAuthAttempts, disableOAuth once #198 lands, allowCachedAuth), and OAuth session forwarding (oauthSessionOptions). Consumers that need to enforce one of these choices end up writing a connect wrapper — and that wrapper has to know the shape.

Concrete in-the-wild example. evie-platform's daemon wraps Runtime so every internal connect call ends up daemon-safe (source):

// Today: TypeScript loses type safety on the options shape.
proto.connect = async (server: string, options: Record<string, any> = {}) => {
  return originalConnect(server, {
    ...options,
    maxOAuthAttempts: 0,
    allowCachedAuth: true,
    disableOAuth: true,                              // introduced by #198
  });
};

Every consumer that builds something similar (any headless / daemon / CI / scripted caller per the same niche #197 + #198 address) ends up either widening to Record<string, any> like this or copying mcporter's internal option fields locally and drifting from upstream.

Proposed API

Export the options shape under a stable name:

export interface ConnectOptions {
  /** Bypass the connection cache for this single call. */
  skipCache?: boolean;
  /** Maximum OAuth re-establishment attempts. 0 = never. */
  maxOAuthAttempts?: number;
  /** Use cached access tokens when available. */
  allowCachedAuth?: boolean;
  /**
   * Suppress OAuth entirely. Introduced by #198. Stronger than
   * `maxOAuthAttempts: 0` because it also short-circuits
   * `maybePromoteHttpDefinition` on the unauthorized-fallback path.
   * Note: `disableOAuth: false` is normalized to the same cache identity
   * as omitting the option (per #198).
   */
  disableOAuth?: boolean;
  /** Forwarded to `createClientContext`. */
  oauthSessionOptions?: OAuthSessionOptions;
}

(OAuthSessionOptions would likely need to be a named public export too if it isn't already — same rationale as ConnectOptions.)

Tighten Runtime's connect signature:

export interface Runtime {
  connect(server: string, options?: ConnectOptions): Promise<ClientContext>;
  // ...
}

Scope

This issue is scoped to the options shape only. The other casts a consumer like the evie daemon currently uses — the as any to mutate the runtime in place, and the as any to read ClientContext fields off the awaited connect promise — are separate concerns that would need their own changes (e.g. exporting ClientContext publicly, or moving consumers off prototype monkey-patching). Filing those separately keeps each ask easy to accept.

Backward compatibility

Strictly additive. Existing callers passing only the server name keep working (options arg is optional). Existing callers passing arbitrary objects keep working (TypeScript widens structurally). Old code paths using as any can drop the casts at their leisure.

Related

Use-case context

Same daemon shape as #197 — a long-running process polling a hosted MCP server every ~30s, no GUI, needs to ensure no internal mcporter code path can reach openExternal. The daemon wraps Runtime itself today; getting the options shape typed publicly is the difference between three as any casts and zero.

Metadata

Metadata

Assignees

No one assigned

    Labels

    P3Low-risk cleanup, docs, polish, ergonomics, or speculative feature.clawsweeper:fix-shape-clearClawSweeper found a clear likely implementation shape for this issue.clawsweeper:needs-maintainer-reviewClawSweeper marked this issue as needing maintainer review before automation.clawsweeper:needs-product-decisionClawSweeper marked this issue as needing a product or behavior decision.clawsweeper:no-new-fix-prClawSweeper does not recommend queueing a new automated fix PR for this issue.impact:auth-providerThis issue is about auth, provider routing, model choice, or SecretRef resolution.issue-rating: 🌊 off-meta tidepoolIssue quality rating does not apply to this item.

    Type

    No type
    No fields configured for issues without a type.

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions