@wrongstack/mcp 1.0.24 → 1.0.26

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,24 @@
1
+ export interface MCPOAuthCallbackServerOptions {
2
+ /** Fixed port when the authorization server requires a preregistered URI. */
3
+ port?: number | undefined;
4
+ path?: string | undefined;
5
+ timeoutMs?: number | undefined;
6
+ signal?: AbortSignal | undefined;
7
+ }
8
+ export interface MCPOAuthCallbackServer {
9
+ /** Exact redirect URI to pass to the authorization request. */
10
+ redirectUri: string;
11
+ /** Resolves with the full callback URL the browser was redirected to. */
12
+ waitForCallback(): Promise<string>;
13
+ close(): void;
14
+ }
15
+ /**
16
+ * Loopback redirect receiver for the manual OAuth flow.
17
+ *
18
+ * Without this the user had to copy the callback URL out of the browser address
19
+ * bar and paste it back into a second command. The listener binds 127.0.0.1
20
+ * only — never a routable interface — and answers exactly one path, so nothing
21
+ * else on the machine can reach it or enumerate its responses.
22
+ */
23
+ export declare function startMcpOAuthCallbackServer(options?: MCPOAuthCallbackServerOptions): Promise<MCPOAuthCallbackServer>;
24
+ //# sourceMappingURL=authorization-callback-server.d.ts.map
@@ -0,0 +1,96 @@
1
+ export interface MCPAuthorizationChallenge {
2
+ status: 401;
3
+ resource: string;
4
+ resourceMetadataUrl?: string | undefined;
5
+ scopes: string[];
6
+ rawScheme: 'Bearer';
7
+ }
8
+ export interface MCPProtectedResourceMetadata {
9
+ resource: string;
10
+ authorizationServers: string[];
11
+ scopesSupported: string[];
12
+ }
13
+ export interface MCPAuthorizationServerMetadata {
14
+ issuer: string;
15
+ authorizationEndpoint: string;
16
+ tokenEndpoint: string;
17
+ registrationEndpoint?: string | undefined;
18
+ authorizationResponseIssuerParameterSupported?: boolean | undefined;
19
+ scopesSupported: string[];
20
+ }
21
+ export interface MCPAuthorizationDiscoveryResult {
22
+ resourceMetadataUrl: string;
23
+ authorizationServerMetadataUrl: string;
24
+ protectedResource: MCPProtectedResourceMetadata;
25
+ authorizationServer: MCPAuthorizationServerMetadata;
26
+ }
27
+ export type MCPAuthorizationJsonFetcher = (url: string, signal?: AbortSignal | undefined) => Promise<unknown | undefined>;
28
+ export interface MCPAuthorizationDiscoveryOptions {
29
+ challengeHeader?: string | null | undefined;
30
+ signal?: AbortSignal | undefined;
31
+ timeoutMs?: number | undefined;
32
+ maxResponseBytes?: number | undefined;
33
+ lookup?: BrowserCompatibleDnsLookup | undefined;
34
+ /** Test/host override. Production callers should use the pinned default. */
35
+ fetchJson?: MCPAuthorizationJsonFetcher | undefined;
36
+ }
37
+ export type BrowserCompatibleDnsLookup = (hostname: string) => Promise<readonly {
38
+ address: string;
39
+ family: number;
40
+ }[]>;
41
+ /** Non-2xx answer from an OAuth endpoint, carrying the HTTP status. */
42
+ export declare class MCPOAuthHttpError extends Error {
43
+ readonly status: number;
44
+ readonly name = "MCPOAuthHttpError";
45
+ constructor(message: string, status: number);
46
+ }
47
+ export declare function canonicalMcpResource(rawUrl: string): string;
48
+ export declare function parseMcpBearerChallenge(header: string | null, resource: string): MCPAuthorizationChallenge;
49
+ /** RFC 9728 fallback order for an MCP endpoint when no challenge URL exists. */
50
+ export declare function protectedResourceMetadataUrls(resource: string): string[];
51
+ /** RFC 8414 + OIDC discovery order required by the MCP authorization spec. */
52
+ export declare function authorizationServerMetadataUrls(issuer: string): string[];
53
+ export declare function parseProtectedResourceMetadata(value: unknown, expectedResource: string): MCPProtectedResourceMetadata;
54
+ export declare function parseAuthorizationServerMetadata(value: unknown, expectedIssuer: string): MCPAuthorizationServerMetadata;
55
+ /**
56
+ * Discover and validate MCP OAuth metadata without following redirects. The
57
+ * default fetcher resolves once and opens the socket to that exact IP, making
58
+ * discovery resistant to DNS rebinding.
59
+ */
60
+ export declare function discoverMcpAuthorization(resource: string, options?: MCPAuthorizationDiscoveryOptions): Promise<MCPAuthorizationDiscoveryResult>;
61
+ export declare function challengeParameter(parameters: string, name: string): string | undefined;
62
+ export declare function validateMetadataUrl(value: string): string | undefined;
63
+ export declare function record(value: unknown, label: string): Record<string, unknown>;
64
+ export declare function requiredString(value: unknown, field: string): string;
65
+ export declare function optionalString(value: unknown, field: string): string | undefined;
66
+ export declare function optionalBoolean(value: unknown, field: string): boolean | undefined;
67
+ export declare function boundedStringArray(value: unknown, field: string, maxItems: number): string[];
68
+ export declare function optionalStringArray(value: unknown, field: string, maxItems: number): string[];
69
+ export declare function secureOAuthUrl(value: string, label: string): URL;
70
+ export declare function discoverFirst<T>(candidates: readonly string[], fetchJson: MCPAuthorizationJsonFetcher, signal: AbortSignal | undefined, parse: (value: unknown) => T, label: string): Promise<{
71
+ url: string;
72
+ value: T;
73
+ }>;
74
+ export declare function requestPinnedJson(rawUrl: string, options: {
75
+ method?: 'GET' | 'POST' | undefined;
76
+ body?: string | undefined;
77
+ headers?: Record<string, string> | undefined;
78
+ signal?: AbortSignal | undefined;
79
+ timeoutMs?: number | undefined;
80
+ maxResponseBytes?: number | undefined;
81
+ lookup?: BrowserCompatibleDnsLookup | undefined;
82
+ allowedLoopbackHostname?: string | undefined;
83
+ /** Names the endpoint in errors — token calls were reported as "discovery". */
84
+ label?: string | undefined;
85
+ }): Promise<unknown | undefined>;
86
+ export declare function resolvePinnedAddress(url: URL, options: {
87
+ lookup?: BrowserCompatibleDnsLookup | undefined;
88
+ allowedLoopbackHostname?: string | undefined;
89
+ }): Promise<{
90
+ address: string;
91
+ family: 4 | 6;
92
+ }>;
93
+ export declare function assertDiscoveryAddressAllowed(address: string, family: 4 | 6, hostname: string, allowedLoopbackHostname: string | undefined): void;
94
+ export declare function unbracket(hostname: string): string;
95
+ export declare function isLoopbackHttp(url: URL): boolean;
96
+ //# sourceMappingURL=authorization-discovery.d.ts.map
@@ -1,24 +1,50 @@
1
1
  import { type MCPAuthorizationDiscoveryOptions, type MCPAuthorizationDiscoveryResult, type MCPTokenExchangeOptions, type MCPTokenSet } from './authorization.js';
2
+ import { type MCPClientRegistration, type MCPClientRegistrationOptions } from './authorization-registration.js';
2
3
  import type { MCPAuthorizationStateEvent, MCPVaultTokenStore } from './token-store.js';
3
4
  type DiscoverAuthorization = (resource: string, options?: MCPAuthorizationDiscoveryOptions) => Promise<MCPAuthorizationDiscoveryResult>;
4
5
  type ExchangeAuthorizationCode = (options: MCPTokenExchangeOptions) => Promise<MCPTokenSet>;
6
+ type RegisterClient = (options: MCPClientRegistrationOptions) => Promise<MCPClientRegistration>;
5
7
  export interface MCPAuthorizationManagerOptions {
6
8
  store: MCPVaultTokenStore;
7
9
  pendingTtlMs?: number | undefined;
8
10
  discover?: DiscoverAuthorization | undefined;
9
11
  exchange?: ExchangeAuthorizationCode | undefined;
12
+ register?: RegisterClient | undefined;
13
+ /** `client_name` sent during dynamic registration. */
14
+ clientName?: string | undefined;
10
15
  now?: (() => number) | undefined;
11
16
  onStateChange?: ((event: MCPAuthorizationStateEvent) => void) | undefined;
12
17
  }
13
18
  export interface MCPAuthorizationStartInput {
14
19
  serverName: string;
15
20
  resource: string;
16
- clientId: string;
21
+ /** Omit to reuse a stored identity or dynamically register one (RFC 7591). */
22
+ clientId?: string | undefined;
17
23
  redirectUri: string;
18
24
  scopes?: readonly string[] | undefined;
19
25
  challengeHeader?: string | null | undefined;
20
26
  signal?: AbortSignal | undefined;
21
27
  }
28
+ export interface MCPAuthorizationLoginInput {
29
+ serverName: string;
30
+ resource: string;
31
+ clientId?: string | undefined;
32
+ scopes?: readonly string[] | undefined;
33
+ challengeHeader?: string | null | undefined;
34
+ signal?: AbortSignal | undefined;
35
+ /** Fixed loopback port, when the server only accepts a preregistered URI. */
36
+ port?: number | undefined;
37
+ /** How long to wait for the browser redirect. */
38
+ timeoutMs?: number | undefined;
39
+ }
40
+ export interface MCPAuthorizationLoginHandle {
41
+ /** Available immediately: show this to the user. */
42
+ started: MCPAuthorizationStartResult;
43
+ /** Settles when the browser redirect arrives and the code is exchanged. */
44
+ completion: Promise<MCPAuthorizationStatus>;
45
+ /** Abandon the flow and release the loopback port. */
46
+ cancel(): void;
47
+ }
22
48
  export interface MCPAuthorizationStartResult {
23
49
  serverName: string;
24
50
  resource: string;
@@ -26,6 +52,8 @@ export interface MCPAuthorizationStartResult {
26
52
  redirectUri: string;
27
53
  scopes: string[];
28
54
  expiresAt: number;
55
+ /** How the client identity was obtained, for surfacing in status output. */
56
+ clientIdSource: 'explicit' | 'stored' | 'registered';
29
57
  }
30
58
  export interface MCPAuthorizationCompleteInput {
31
59
  serverName: string;
@@ -50,13 +78,30 @@ export declare class MCPAuthorizationManager {
50
78
  private readonly options;
51
79
  private readonly pending;
52
80
  private readonly starting;
81
+ /** Registrations reused across servers that share one authorization server. */
82
+ private readonly registrations;
53
83
  private readonly pendingTtlMs;
54
84
  private readonly discover;
55
85
  private readonly exchange;
86
+ private readonly register;
56
87
  private readonly now;
57
88
  constructor(options: MCPAuthorizationManagerOptions);
58
89
  begin(input: MCPAuthorizationStartInput): Promise<MCPAuthorizationStartResult>;
59
90
  complete(input: MCPAuthorizationCompleteInput): Promise<MCPAuthorizationStatus>;
91
+ /**
92
+ * Bind a loopback receiver and start the flow, returning as soon as the URL
93
+ * exists so a surface can show it without blocking. Completion is awaited
94
+ * separately — a slash command returns its message immediately and reports
95
+ * the outcome through `onStateChange`. The two-step `begin`/`complete` pair
96
+ * stays for surfaces that cannot host a listener.
97
+ */
98
+ beginLogin(input: MCPAuthorizationLoginInput): Promise<MCPAuthorizationLoginHandle>;
99
+ /**
100
+ * Identity precedence: an explicit id, then the one already stored for this
101
+ * server (so re-authorizing does not orphan a registration), then the
102
+ * per-issuer cache, then a fresh dynamic registration.
103
+ */
104
+ private resolveClientIdentity;
60
105
  status(serverName: string, resource: string): Promise<MCPAuthorizationStatus>;
61
106
  disconnect(serverName: string, resource: string): Promise<boolean>;
62
107
  private pruneExpired;
@@ -0,0 +1,39 @@
1
+ import { type BrowserCompatibleDnsLookup, type MCPAuthorizationServerMetadata, requestPinnedJson } from './authorization-discovery.js';
2
+ /**
3
+ * Identity this client presents to an authorization server. `clientSecret` is
4
+ * only present when the server refused the public-client registration we ask
5
+ * for and issued a confidential client anyway; it is a credential and must
6
+ * reach the vault-backed store, never config or logs.
7
+ */
8
+ export interface MCPClientRegistration {
9
+ clientId: string;
10
+ clientSecret?: string | undefined;
11
+ issuer: string;
12
+ registeredAt: string;
13
+ }
14
+ export interface MCPClientRegistrationOptions {
15
+ authorizationServer: MCPAuthorizationServerMetadata;
16
+ redirectUris: readonly string[];
17
+ clientName?: string | undefined;
18
+ clientUri?: string | undefined;
19
+ scopes?: readonly string[] | undefined;
20
+ /** Canonical MCP resource, used only to allow loopback development servers. */
21
+ resource?: string | undefined;
22
+ signal?: AbortSignal | undefined;
23
+ timeoutMs?: number | undefined;
24
+ maxResponseBytes?: number | undefined;
25
+ lookup?: BrowserCompatibleDnsLookup | undefined;
26
+ /** Test/host override. Production callers should use the pinned default. */
27
+ requestJson?: typeof requestPinnedJson | undefined;
28
+ }
29
+ /**
30
+ * RFC 7591 dynamic client registration.
31
+ *
32
+ * Most hosted MCP servers issue no preregistered client IDs at all, so without
33
+ * this the only way to authorize was for the user to find a client ID by hand.
34
+ * We register as a public client (`token_endpoint_auth_method: "none"`) because
35
+ * a CLI cannot keep a secret; a server that overrides that and returns one is
36
+ * still honored, but the secret goes straight to the vault.
37
+ */
38
+ export declare function registerMcpOAuthClient(options: MCPClientRegistrationOptions): Promise<MCPClientRegistration>;
39
+ //# sourceMappingURL=authorization-registration.d.ts.map
@@ -1,3 +1,5 @@
1
+ import { type BrowserCompatibleDnsLookup, type MCPAuthorizationChallenge, type MCPAuthorizationServerMetadata } from './authorization-discovery.js';
2
+ export { authorizationServerMetadataUrls, canonicalMcpResource, discoverMcpAuthorization, type MCPAuthorizationChallenge, type MCPAuthorizationDiscoveryOptions, type MCPAuthorizationDiscoveryResult, type MCPAuthorizationJsonFetcher, type MCPAuthorizationServerMetadata, MCPOAuthHttpError, type MCPProtectedResourceMetadata, parseAuthorizationServerMetadata, parseMcpBearerChallenge, parseProtectedResourceMetadata, protectedResourceMetadataUrls, } from './authorization-discovery.js';
1
3
  export interface MCPAccessToken {
2
4
  accessToken: string;
3
5
  tokenType?: string | undefined;
@@ -11,42 +13,6 @@ export interface MCPAuthorizationContext {
11
13
  resource: string;
12
14
  signal?: AbortSignal | undefined;
13
15
  }
14
- export interface MCPAuthorizationChallenge {
15
- status: 401;
16
- resource: string;
17
- resourceMetadataUrl?: string | undefined;
18
- scopes: string[];
19
- rawScheme: 'Bearer';
20
- }
21
- export interface MCPProtectedResourceMetadata {
22
- resource: string;
23
- authorizationServers: string[];
24
- scopesSupported: string[];
25
- }
26
- export interface MCPAuthorizationServerMetadata {
27
- issuer: string;
28
- authorizationEndpoint: string;
29
- tokenEndpoint: string;
30
- registrationEndpoint?: string | undefined;
31
- authorizationResponseIssuerParameterSupported?: boolean | undefined;
32
- scopesSupported: string[];
33
- }
34
- export interface MCPAuthorizationDiscoveryResult {
35
- resourceMetadataUrl: string;
36
- authorizationServerMetadataUrl: string;
37
- protectedResource: MCPProtectedResourceMetadata;
38
- authorizationServer: MCPAuthorizationServerMetadata;
39
- }
40
- export type MCPAuthorizationJsonFetcher = (url: string, signal?: AbortSignal | undefined) => Promise<unknown | undefined>;
41
- export interface MCPAuthorizationDiscoveryOptions {
42
- challengeHeader?: string | null | undefined;
43
- signal?: AbortSignal | undefined;
44
- timeoutMs?: number | undefined;
45
- maxResponseBytes?: number | undefined;
46
- lookup?: BrowserCompatibleDnsLookup | undefined;
47
- /** Test/host override. Production callers should use the pinned default. */
48
- fetchJson?: MCPAuthorizationJsonFetcher | undefined;
49
- }
50
16
  export interface MCPAuthorizationSession {
51
17
  authorizationUrl: string;
52
18
  state: string;
@@ -70,6 +36,8 @@ export interface MCPAuthorizationRequestOptions {
70
36
  export interface MCPTokenExchangeOptions {
71
37
  authorizationServer: MCPAuthorizationServerMetadata;
72
38
  clientId: string;
39
+ /** Only set when dynamic registration issued a confidential client. */
40
+ clientSecret?: string | undefined;
73
41
  redirectUri: string;
74
42
  resource: string;
75
43
  code: string;
@@ -82,6 +50,8 @@ export interface MCPTokenExchangeOptions {
82
50
  export interface MCPTokenRefreshOptions {
83
51
  authorizationServer: MCPAuthorizationServerMetadata;
84
52
  clientId: string;
53
+ /** Only set when dynamic registration issued a confidential client. */
54
+ clientSecret?: string | undefined;
85
55
  resource: string;
86
56
  refreshToken: string;
87
57
  signal?: AbortSignal | undefined;
@@ -89,10 +59,6 @@ export interface MCPTokenRefreshOptions {
89
59
  maxResponseBytes?: number | undefined;
90
60
  lookup?: BrowserCompatibleDnsLookup | undefined;
91
61
  }
92
- type BrowserCompatibleDnsLookup = (hostname: string) => Promise<readonly {
93
- address: string;
94
- family: number;
95
- }[]>;
96
62
  /**
97
63
  * Host-owned bridge to vault-backed OAuth state. The MCP package never stores
98
64
  * access or refresh tokens itself and never exposes them through config.
@@ -102,36 +68,15 @@ export interface MCPAuthorizationProvider {
102
68
  /** Refresh/discover/reauthorize. Return true to retry the HTTP request once. */
103
69
  handleUnauthorized?(challenge: MCPAuthorizationChallenge, context: MCPAuthorizationContext): Promise<boolean>;
104
70
  }
105
- /** Non-2xx answer from an OAuth endpoint, carrying the HTTP status. */
106
- export declare class MCPOAuthHttpError extends Error {
107
- readonly status: number;
108
- readonly name = "MCPOAuthHttpError";
109
- constructor(message: string, status: number);
110
- }
111
- export declare function canonicalMcpResource(rawUrl: string): string;
112
71
  export declare function authorizationHeaderForToken(token: MCPAccessToken, expectedResource: string, now?: number): string;
113
- export declare function parseMcpBearerChallenge(header: string | null, resource: string): MCPAuthorizationChallenge;
114
- /** RFC 9728 fallback order for an MCP endpoint when no challenge URL exists. */
115
- export declare function protectedResourceMetadataUrls(resource: string): string[];
116
- /** RFC 8414 + OIDC discovery order required by the MCP authorization spec. */
117
- export declare function authorizationServerMetadataUrls(issuer: string): string[];
118
- export declare function parseProtectedResourceMetadata(value: unknown, expectedResource: string): MCPProtectedResourceMetadata;
119
- export declare function parseAuthorizationServerMetadata(value: unknown, expectedIssuer: string): MCPAuthorizationServerMetadata;
120
72
  /**
121
73
  * Re-validate the normalized authorization-server shape before it is accepted
122
74
  * from host-owned persistence. PKCE support is established during discovery;
123
75
  * this guard protects the persisted endpoints and bounded fields themselves.
124
76
  */
125
77
  export declare function validateMcpAuthorizationServerMetadata(value: unknown): MCPAuthorizationServerMetadata;
126
- /**
127
- * Discover and validate MCP OAuth metadata without following redirects. The
128
- * default fetcher resolves once and opens the socket to that exact IP, making
129
- * discovery resistant to DNS rebinding.
130
- */
131
- export declare function discoverMcpAuthorization(resource: string, options?: MCPAuthorizationDiscoveryOptions): Promise<MCPAuthorizationDiscoveryResult>;
132
78
  export declare function createMcpAuthorizationRequest(options: MCPAuthorizationRequestOptions): MCPAuthorizationSession;
133
79
  export declare function parseMcpAuthorizationCallback(callbackUrl: string, session: Pick<MCPAuthorizationSession, 'redirectUri' | 'state' | 'issuer' | 'requireIssuerParameter'>): string;
134
80
  export declare function exchangeMcpAuthorizationCode(options: MCPTokenExchangeOptions): Promise<MCPTokenSet>;
135
81
  export declare function refreshMcpAccessToken(options: MCPTokenRefreshOptions): Promise<MCPTokenSet>;
136
- export {};
137
82
  //# sourceMappingURL=authorization.d.ts.map
@@ -0,0 +1,22 @@
1
+ import type { MCPClientOptions, ToolsChangedListener } from './client-types.js';
2
+ import type { ConnectionState, MCPTool } from './contracts.js';
3
+ import type { ServerRequestResponder } from './elicitation.js';
4
+ import type { MCPServerMetadata } from './protocol.js';
5
+ import { SSETransport, StreamableHTTPTransport } from './transport.js';
6
+ export interface ClientHttpConnectionHost {
7
+ opts: MCPClientOptions;
8
+ state: ConnectionState;
9
+ sseTransport: SSETransport | undefined;
10
+ disconnectListeners: Set<() => void>;
11
+ _tools: MCPTool[];
12
+ _toolsCache: MCPTool[] | undefined;
13
+ toolsChangedListeners: Set<ToolsChangedListener>;
14
+ emitCapabilityChanged: (capability: 'resources' | 'prompts') => void;
15
+ emitResourceUpdated: (uri: string) => void;
16
+ _serverMetadata: MCPServerMetadata | undefined;
17
+ httpTransport: StreamableHTTPTransport | undefined;
18
+ serverRequests: ServerRequestResponder;
19
+ }
20
+ export declare function connectSSE(host: ClientHttpConnectionHost): Promise<void>;
21
+ export declare function connectStreamableHTTP(host: ClientHttpConnectionHost): Promise<void>;
22
+ //# sourceMappingURL=client-http-connection.d.ts.map
@@ -1,5 +1,6 @@
1
1
  import type { MCPAuthorizationProvider } from './authorization.js';
2
2
  import type { MCPTool } from './contracts.js';
3
+ import type { MCPClientElicitationHandler } from './elicitation.js';
3
4
  export type Transport = 'stdio' | 'sse' | 'streamable-http';
4
5
  export interface MCPClientOptions {
5
6
  name: string;
@@ -37,6 +38,11 @@ export interface MCPClientOptions {
37
38
  * flag opts this server in. See MCPServerConfig.allowPrivateNetworks.
38
39
  */
39
40
  allowPrivateNetworks?: boolean | undefined;
41
+ /**
42
+ * Answers `elicitation/create`. The capability is declared only when this is
43
+ * set, so a host that can never ask a user should leave it unset.
44
+ */
45
+ elicitation?: MCPClientElicitationHandler | undefined;
40
46
  }
41
47
  export interface MCPRequestOptions {
42
48
  signal?: AbortSignal | undefined;
@@ -59,4 +65,6 @@ export type JsonRpcServerRequest = {
59
65
  export type ExitListener = (name: string, code: number | null, signal: string | null) => void;
60
66
  export type ToolsChangedListener = (name: string, tools: MCPTool[]) => void;
61
67
  export type MCPListChangedListener = (name: string) => void;
68
+ /** `notifications/resources/updated` — the payload of a live subscription. */
69
+ export type MCPResourceUpdatedListener = (name: string, uri: string) => void;
62
70
  //# sourceMappingURL=client-types.d.ts.map
package/dist/client.d.ts CHANGED
@@ -1,5 +1,6 @@
1
- import type { ExitListener, MCPClientOptions, MCPListChangedListener, MCPPageOptions, MCPRequestOptions, ToolsChangedListener } from './client-types.js';
1
+ import type { ExitListener, MCPClientOptions, MCPListChangedListener, MCPPageOptions, MCPRequestOptions, MCPResourceUpdatedListener, ToolsChangedListener } from './client-types.js';
2
2
  import type { ConnectionState, JsonRpcResponse, MCPTool, ToolCallResult } from './contracts.js';
3
+ import { ServerRequestResponder, type UrlElicitation } from './elicitation.js';
3
4
  import { type MCPGetPromptResult, type MCPListPromptsResult, type MCPListResourcesResult, type MCPListResourceTemplatesResult, type MCPReadResourceResult, type MCPServerMetadata } from './protocol.js';
4
5
  export { forceKillTree } from './client-process.js';
5
6
  export { quoteWindowsArg } from './client-protocol-helpers.js';
@@ -52,8 +53,11 @@ export declare class MCPClient {
52
53
  private readonly toolsChangedListeners;
53
54
  private readonly resourcesChangedListeners;
54
55
  private readonly promptsChangedListeners;
56
+ private readonly resourceUpdatedListeners;
55
57
  /** Notified when an HTTP transport (SSE or streamable-http) disconnects. */
56
58
  private readonly disconnectListeners;
59
+ /** Answers server→client requests (ping, elicitation) on every transport. */
60
+ private readonly serverRequests;
57
61
  constructor(opts: MCPClientOptions);
58
62
  getState(): ConnectionState;
59
63
  getServerMetadata(): MCPServerMetadata | undefined;
@@ -80,6 +84,11 @@ export declare class MCPClient {
80
84
  callTool(name: string, input: unknown, opts?: {
81
85
  signal?: AbortSignal | undefined;
82
86
  }): Promise<ToolCallResult>;
87
+ /**
88
+ * Put the pages of a `-32042` tool-call error to the user (consent first,
89
+ * nothing opened without it), on the run whose call got the error.
90
+ */
91
+ presentUrlElicitations(elicitations: readonly UrlElicitation[], signal: AbortSignal): ReturnType<ServerRequestResponder['presentUrl']>;
83
92
  listResources(opts?: MCPPageOptions): Promise<MCPListResourcesResult>;
84
93
  listResourceTemplates(opts?: MCPPageOptions): Promise<MCPListResourceTemplatesResult>;
85
94
  readResource(uri: string, opts?: MCPRequestOptions): Promise<MCPReadResourceResult>;
@@ -113,9 +122,13 @@ export declare class MCPClient {
113
122
  removeToolsChangedListener(listener: ToolsChangedListener): void;
114
123
  addResourcesChangedListener(listener: MCPListChangedListener): void;
115
124
  removeResourcesChangedListener(listener: MCPListChangedListener): void;
125
+ addResourceUpdatedListener(listener: MCPResourceUpdatedListener): void;
126
+ removeResourceUpdatedListener(listener: MCPResourceUpdatedListener): void;
116
127
  addPromptsChangedListener(listener: MCPListChangedListener): void;
117
128
  removePromptsChangedListener(listener: MCPListChangedListener): void;
129
+ private emitResourceUpdated;
118
130
  private emitCapabilityChanged;
131
+ private clientHttpConnectionHost;
119
132
  }
120
- export type { MCPClientOptions, MCPListChangedListener, MCPPageOptions, MCPRequestOptions, Transport, } from './client-types.js';
133
+ export type { MCPClientOptions, MCPListChangedListener, MCPPageOptions, MCPRequestOptions, MCPResourceUpdatedListener, Transport, } from './client-types.js';
121
134
  //# sourceMappingURL=client.d.ts.map
@@ -0,0 +1,18 @@
1
+ import type { MCPServerConfig } from '@wrongstack/core/types';
2
+ interface ExpandableFields {
3
+ command?: string | undefined;
4
+ args?: string[] | undefined;
5
+ env?: Record<string, string> | undefined;
6
+ url?: string | undefined;
7
+ headers?: Record<string, string> | undefined;
8
+ }
9
+ /** Every environment variable a server entry reads through placeholders, sorted. */
10
+ export declare function mcpEnvPlaceholders(cfg: Partial<ExpandableFields>): string[];
11
+ /**
12
+ * The expandable fields with every placeholder resolved from `env`. A variable
13
+ * that is unset (or empty) with no default is an error naming it: sending the
14
+ * literal `${TOKEN}` would only fail later, as an opaque 401.
15
+ */
16
+ export declare function expandMcpEnvPlaceholders(cfg: Readonly<MCPServerConfig>, env?: NodeJS.ProcessEnv): ExpandableFields;
17
+ export {};
18
+ //# sourceMappingURL=config-env.d.ts.map
@@ -11,11 +11,32 @@
11
11
  *
12
12
  * Deliberately conservative: a revision belongs here only once its wire
13
13
  * requirements are met, because the version we send in `initialize` is a
14
- * promise about what the peer may then use. WrongStack speaks the 2024-11-05
15
- * shape — tools, resources, prompts, sampling — and does not implement the
16
- * additions of later revisions (elicitation, structured tool output, resource
17
- * links), so listing one of those would advertise capabilities that are not
18
- * there.
14
+ * promise about what the peer may then use.
15
+ *
16
+ * WrongStack speaks the 2024-11-05 shape: tools, resources, prompts,
17
+ * pagination, list_changed, resource subscriptions and cancellation. It does
18
+ * NOT implement sampling (deliberately denied — see below), nor most additions
19
+ * of later revisions: resource links, `completion/complete`, or progress
20
+ * notifications. Listing a newer revision here would advertise capabilities
21
+ * that are not there.
22
+ *
23
+ * Known drift, accepted: the HTTP layer already implements Streamable HTTP
24
+ * (added 2025-03-26), the `MCP-Protocol-Version` header and OAuth resource
25
+ * indicators (2025-06-18), and the client answers form- and URL-mode
26
+ * elicitation (2025-06-18 / 2025-11-25) and reads structured tool output
27
+ * (2025-06-18), even though we negotiate 2024-11-05. Those ride on the
28
+ * transport, the 401 challenge and the declared client capability rather than
29
+ * on the negotiated revision, so servers accept them; the declaration is
30
+ * narrower than the behavior.
31
+ *
32
+ * Not gaps, by the spec's own reckoning: Roots, Sampling and Logging were all
33
+ * Deprecated in revision 2026-07-28 (SEP-2577), with new implementations told
34
+ * not to adopt them. Not having them is alignment, not lag.
35
+ *
36
+ * The current revision (2026-07-28) also replaced the `initialize` handshake
37
+ * with per-request version negotiation plus a mandatory `server/discover` RPC.
38
+ * Reaching it is an architectural change, not another entry in this list; the
39
+ * spec keeps a backward-compatibility path for handshake-based clients.
19
40
  *
20
41
  * Adding a revision: implement its additions, then put it at the FRONT.
21
42
  * `PROTOCOL_VERSION` follows automatically, and the negotiation below starts
@@ -18,11 +18,32 @@ export interface MCPTool {
18
18
  name: string;
19
19
  description?: string | undefined;
20
20
  inputSchema: Record<string, unknown>;
21
+ /** JSON Schema of the tool's `structuredContent` (spec 2025-06-18). */
22
+ outputSchema?: Record<string, unknown> | undefined;
23
+ }
24
+ /**
25
+ * URL-mode elicitation (spec 2025-11-25): the server asks the user to open a
26
+ * web page for something that must not pass through the client — a
27
+ * third-party sign-in, an API key, a payment. Only the user's consent crosses
28
+ * the protocol; what happens on the page stays between the user and the server.
29
+ */
30
+ export interface UrlElicitation {
31
+ mode: 'url';
32
+ message: string;
33
+ url: string;
34
+ elicitationId: string;
21
35
  }
22
36
  /** Result envelope returned by an MCP `tools/call`. */
23
37
  export interface ToolCallResult {
24
38
  content: unknown;
25
39
  isError: boolean;
40
+ /** The typed result object, when the tool returns one (spec 2025-06-18). */
41
+ structuredContent?: Record<string, unknown> | undefined;
42
+ /**
43
+ * Pages the user must open before the call can succeed: the server answered
44
+ * with a URL-elicitation-required error (`-32042`, spec 2025-11-25).
45
+ */
46
+ urlElicitations?: UrlElicitation[] | undefined;
26
47
  }
27
48
  /** JSON-RPC 2.0 response shape (success or error). */
28
49
  export interface JsonRpcResponse {
@@ -0,0 +1,26 @@
1
+ import { type ElicitationRequester, type MCPElicitationRequest, type MCPElicitationResult } from './elicitation.js';
2
+ /** Opens a page in the user's browser; given by a host that can. */
3
+ export type OpenUrl = (url: string) => void;
4
+ export interface ElicitViaUserInputOptions {
5
+ /**
6
+ * Opens a URL-mode page once the user agrees. Without it the user is only
7
+ * shown the URL to open themselves (the right thing when the browser is on
8
+ * another machine than this process).
9
+ */
10
+ openUrl?: OpenUrl | undefined;
11
+ }
12
+ /**
13
+ * Put a server's elicitation in front of the user as a `clarify`-style form on
14
+ * the run that made the call (or `fallback` when the server asks outside a
15
+ * call), and turn the answers back into schema-checked content.
16
+ *
17
+ * No surface to show it on answers `cancel`; the user dismissing the form is an
18
+ * explicit `decline`. An answer the schema rejects is asked again with the
19
+ * reason, a few times, before giving up.
20
+ *
21
+ * A URL-mode request asks for consent to open a page instead. Nothing is
22
+ * fetched or opened before the user agrees, and `accept` then only means they
23
+ * agreed: the page's outcome reaches the server, not this client.
24
+ */
25
+ export declare function elicitViaUserInput(request: MCPElicitationRequest, fallback?: ElicitationRequester | undefined, options?: ElicitViaUserInputOptions): Promise<MCPElicitationResult>;
26
+ //# sourceMappingURL=elicitation-form.d.ts.map