@wrongstack/mcp 1.0.33 → 1.0.35

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.
@@ -98,4 +98,45 @@ export declare function parseGetPromptResult(value: unknown): MCPGetPromptResult
98
98
  * a notification has no reply, so a bad one is ignored, not answered.
99
99
  */
100
100
  export declare function resourceUpdatedUri(params: unknown): string | undefined;
101
+ /** Parsed `notifications/progress` payload (2024-11-05 progress utility). */
102
+ export interface MCPProgressNotification {
103
+ /** Echo of the `params._meta.progressToken` the originating request sent. */
104
+ progressToken: string | number;
105
+ /** Monotonically increasing progress value for the token's request. */
106
+ progress: number;
107
+ /** Expected final `progress` value, when the server sent one. */
108
+ total?: number | undefined;
109
+ /** Human-readable progress text (a later revision's optional field). */
110
+ message?: string | undefined;
111
+ }
112
+ /** Log levels `notifications/message` may carry (MCP `LoggingLevel`, RFC 5424 severities). */
113
+ export type MCPLogLevel = 'debug' | 'info' | 'notice' | 'warning' | 'error' | 'critical' | 'alert' | 'emergency';
114
+ /** Parsed `notifications/message` (logging) payload. */
115
+ export interface MCPLogMessageNotification {
116
+ level: MCPLogLevel;
117
+ /** Name of the emitting subsystem, when the server sent one. */
118
+ logger?: string | undefined;
119
+ /** Log content serialized to bounded, control-free text. */
120
+ data?: string | undefined;
121
+ }
122
+ /**
123
+ * Parse a `notifications/progress` payload (2024-11-05 progress utility).
124
+ *
125
+ * A server sends progress only while a request whose `params._meta` carried
126
+ * a `progressToken` is in flight, so the token in the result is the only
127
+ * correlation between a notification and the call that asked for it. Returns
128
+ * `undefined` for a malformed payload rather than throwing — a notification
129
+ * has no reply, so a bad one is ignored, not answered (same contract as
130
+ * {@link resourceUpdatedUri}). Optional fields (`total`, `message`) are
131
+ * dropped when invalid instead of failing the whole notification.
132
+ */
133
+ export declare function progressNotification(params: unknown): MCPProgressNotification | undefined;
134
+ /**
135
+ * Parse a `notifications/message` (logging) payload (2024-11-05 logging
136
+ * utility). The log `data` is serialized to text and clamped — it is
137
+ * attacker-controllable server output — and an out-of-enum `level` makes the
138
+ * notification malformed. Returns `undefined` rather than throwing; a
139
+ * notification has no reply.
140
+ */
141
+ export declare function logMessageNotification(params: unknown): MCPLogMessageNotification | undefined;
101
142
  //# sourceMappingURL=protocol.d.ts.map
@@ -1,15 +1,17 @@
1
1
  import type { MCPServerConfig } from '@wrongstack/core/types';
2
2
  import type { MCPAuthorizationLoginHandle, MCPAuthorizationLoginInput, MCPAuthorizationManager, MCPAuthorizationStartResult, MCPAuthorizationStatus } from './authorization-manager.js';
3
3
  import type { ServerSlot } from './registry-slots.js';
4
- export declare function requireAuthorizationManager(manager: MCPAuthorizationManager | undefined): MCPAuthorizationManager;
5
- export declare function requireHttpServerConfig(servers: Map<string, ServerSlot>, disabledServers: Map<string, MCPServerConfig>, name: string): MCPServerConfig;
6
- export declare function loginRegistryAuthorization(manager: MCPAuthorizationManager | undefined, cfg: MCPServerConfig, name: string, input: Omit<MCPAuthorizationLoginInput, 'serverName' | 'resource'>): Promise<MCPAuthorizationLoginHandle>;
7
- export declare function beginRegistryAuthorization(manager: MCPAuthorizationManager | undefined, cfg: MCPServerConfig, name: string, input: {
4
+ /** Caller-supplied part of `MCPRegistry.beginAuthorization()`; the registry adds server + resource. */
5
+ export interface MCPRegistryAuthorizationBeginInput {
8
6
  clientId?: string | undefined;
9
7
  redirectUri: string;
10
8
  scopes?: readonly string[] | undefined;
11
9
  challengeHeader?: string | null | undefined;
12
10
  signal?: AbortSignal | undefined;
13
- }): Promise<MCPAuthorizationStartResult>;
11
+ }
12
+ export declare function requireAuthorizationManager(manager: MCPAuthorizationManager | undefined): MCPAuthorizationManager;
13
+ export declare function requireHttpServerConfig(servers: Map<string, ServerSlot>, disabledServers: Map<string, MCPServerConfig>, name: string): MCPServerConfig;
14
+ export declare function loginRegistryAuthorization(manager: MCPAuthorizationManager | undefined, cfg: MCPServerConfig, name: string, input: Omit<MCPAuthorizationLoginInput, 'serverName' | 'resource'>): Promise<MCPAuthorizationLoginHandle>;
15
+ export declare function beginRegistryAuthorization(manager: MCPAuthorizationManager | undefined, cfg: MCPServerConfig, name: string, input: MCPRegistryAuthorizationBeginInput): Promise<MCPAuthorizationStartResult>;
14
16
  export declare function completeRegistryAuthorization(manager: MCPAuthorizationManager | undefined, cfg: MCPServerConfig, name: string, callbackUrl: string, signal?: AbortSignal | undefined): Promise<MCPAuthorizationStatus>;
15
17
  //# sourceMappingURL=registry-authorization.d.ts.map
@@ -26,4 +26,11 @@ export declare function listPrompts(this: RegistryCatalogOperationsHost, name: s
26
26
  }): Promise<MCPPrompt[]>;
27
27
  export declare function getPrompt(this: RegistryCatalogOperationsHost, serverName: string, promptName: string, args?: Record<string, string> | undefined): Promise<MCPGetPromptResult>;
28
28
  export declare function selectPromptForInsertion(this: RegistryCatalogOperationsHost, serverName: string, promptName: string, args?: Record<string, string> | undefined, policy?: MCPInsertionPolicy | undefined): Promise<MCPPromptInsertion>;
29
+ /**
30
+ * Body of `MCPRegistry.withConnectedClient()`: keep all remote requests awake
31
+ * and reject results from superseded clients.
32
+ */
33
+ export declare function runWithConnectedClient<T>(self: Pick<RegistryCatalogOperationsHost, 'servers' | 'requireSlot'> & {
34
+ ensureConnected(name: string): Promise<import('./client.js').MCPClient>;
35
+ }, name: string, run: (client: import('./client.js').MCPClient, assertCurrent: () => void) => Promise<T>): Promise<T>;
29
36
  //# sourceMappingURL=registry-catalog-operations.d.ts.map
@@ -0,0 +1,11 @@
1
+ import type { RegistryConnectContext } from './registry-connect-loop.js';
2
+ import type { RegistryIdleContext } from './registry-idle.js';
3
+ import type { MCPRegistryInternals } from './registry-internals.js';
4
+ /**
5
+ * The context objects `MCPRegistry` hands to the connect loop and the idle
6
+ * sweep. Every callback dispatches through the registry instance, so a
7
+ * replaced/spied member is honored exactly as when the class built them.
8
+ */
9
+ export declare function buildRegistryConnectContext(self: MCPRegistryInternals): RegistryConnectContext;
10
+ export declare function buildRegistryIdleContext(self: MCPRegistryInternals): RegistryIdleContext;
11
+ //# sourceMappingURL=registry-contexts.d.ts.map
@@ -0,0 +1,39 @@
1
+ import type { MCPServerConfig } from '@wrongstack/core/types';
2
+ import type { ConnectionState, MCPToolAnnotations } from './contracts.js';
3
+ import type { ServerSlot } from './registry-slots.js';
4
+ /** Snapshot shapes `MCPRegistry` reports for its servers (list/describe/health/describeTools). */
5
+ /** One server's tool, as `MCPRegistry.describeTools()` reports it. */
6
+ export interface MCPDescribedTool {
7
+ name: string;
8
+ description?: string | undefined;
9
+ inputSchema: Record<string, unknown>;
10
+ annotations?: MCPToolAnnotations | undefined;
11
+ }
12
+ /**
13
+ * Resolve the live tool names for a slot — the registered names in normal
14
+ * mode, or the cached lazy-tool names when running in lazy mode (where
15
+ * tools are connected but intentionally not registered).
16
+ */
17
+ export declare function toolNamesForSlot(s: ServerSlot): string[];
18
+ /** Body of `MCPRegistry.describeTools()` for a registered slot (honors `allowedTools`). */
19
+ export declare function describeSlotTools(slot: ServerSlot): MCPDescribedTool[];
20
+ export declare function listServers(servers: Map<string, ServerSlot>): {
21
+ name: string;
22
+ state: ConnectionState;
23
+ toolCount: number;
24
+ tools: string[];
25
+ }[];
26
+ /** Body of `MCPRegistry.describe()` — active slots followed by configured-off servers. */
27
+ export declare function describeServers(servers: Map<string, ServerSlot>, disabledServers: Map<string, MCPServerConfig>): {
28
+ name: string;
29
+ state: ConnectionState;
30
+ toolCount: number;
31
+ enabled: boolean;
32
+ tools: string[];
33
+ }[];
34
+ export declare function serverHealth(servers: Map<string, ServerSlot>): {
35
+ name: string;
36
+ alive: boolean;
37
+ latencyMs?: number | undefined;
38
+ }[];
39
+ //# sourceMappingURL=registry-describe.d.ts.map
@@ -0,0 +1,57 @@
1
+ import type { EventBus } from '@wrongstack/core/kernel';
2
+ import type { ToolRegistry } from '@wrongstack/core/registry';
3
+ import type { Logger, MCPServerConfig } from '@wrongstack/core/types';
4
+ import type { MCPClient } from './client.js';
5
+ import type { MCPTool } from './contracts.js';
6
+ import type { MCPFailureKind, MCPOperationKind, MCPOperationListener } from './operations.js';
7
+ import type { MCPLogMessageNotification, MCPProgressNotification } from './protocol.js';
8
+ import type { RegistryCatalogOperationsHost } from './registry-catalog-operations.js';
9
+ import type { RegistryServerLifecycleHost } from './registry-server-lifecycle.js';
10
+ import type { ServerSlot } from './registry-slots.js';
11
+ import type { MCPRegistryOptions } from './registry-types.js';
12
+ /**
13
+ * The private state and private members of `MCPRegistry`, as seen by the
14
+ * free functions its method bodies were extracted into (registry-slot-events,
15
+ * registry-contexts, registry-describe). The class hands itself to those
16
+ * functions through this structural view; consumers still see the members
17
+ * as private.
18
+ */
19
+ export interface MCPRegistryInternals extends RegistryServerLifecycleHost, RegistryCatalogOperationsHost {
20
+ readonly servers: Map<string, ServerSlot>;
21
+ readonly disabledServers: Map<string, MCPServerConfig>;
22
+ readonly toolRegistry: ToolRegistry;
23
+ readonly events: EventBus;
24
+ readonly log: Logger;
25
+ readonly lazyMode: boolean;
26
+ readonly cacheDir: string | undefined;
27
+ readonly cwd: string | undefined;
28
+ readonly idleTimeoutMs: number;
29
+ readonly authorizationProviderFactory: MCPRegistryOptions['authorizationProviderFactory'];
30
+ readonly elicitationHandler: MCPRegistryOptions['elicitationHandler'];
31
+ readonly operationListeners: Set<MCPOperationListener>;
32
+ readonly onToolsChanged: (name: string, _tools: {
33
+ name: string;
34
+ }[]) => void;
35
+ readonly onResourcesChanged: (name: string) => void;
36
+ readonly onResourceUpdated: (name: string, uri: string) => void;
37
+ readonly onProgress: (name: string, progress: MCPProgressNotification) => void;
38
+ readonly onLogMessage: (name: string, log: MCPLogMessageNotification) => void;
39
+ readonly onPromptsChanged: (name: string) => void;
40
+ readonly onChildExit: (name: string, code: number | null, _signal: string | null) => void;
41
+ readonly onTransportDisconnect: (name: string) => void;
42
+ ensureConnected(name: string): Promise<MCPClient>;
43
+ requireSlot(name: string): ServerSlot;
44
+ singleFlightConnect(slot: ServerSlot): Promise<MCPClient | undefined>;
45
+ applyTools(slot: ServerSlot, tools: MCPTool[], client?: MCPClient | undefined): void;
46
+ persistCapabilityManifest(slot: ServerSlot): Promise<void>;
47
+ toolNamesForSlot(s: ServerSlot): string[];
48
+ addCatalogListeners(client: MCPClient): void;
49
+ removeCatalogListeners(client: MCPClient): void;
50
+ ensureIdleSweep(): void;
51
+ scheduleReconnect(slot: ServerSlot): void;
52
+ attemptReconnect(slot: ServerSlot): Promise<void>;
53
+ recordSuccess(slot: ServerSlot, resetFailures?: boolean): void;
54
+ recordFailure(slot: ServerSlot, failureKind: MCPFailureKind, reason: string, durationMs?: number | undefined): void;
55
+ recordOperation(slot: ServerSlot, kind: MCPOperationKind, reason?: string | undefined, failureKind?: MCPFailureKind | undefined, durationMs?: number | undefined, retain?: boolean): void;
56
+ }
57
+ //# sourceMappingURL=registry-internals.d.ts.map
@@ -0,0 +1,101 @@
1
+ import type { EventBus } from '@wrongstack/core/kernel';
2
+ import type { ToolRegistry } from '@wrongstack/core/registry';
3
+ import type { Logger, MCPServerConfig } from '@wrongstack/core/types';
4
+ import type { MCPAuthorizationManager } from './authorization-manager.js';
5
+ import type { MCPClient } from './client.js';
6
+ import type { MCPTool } from './contracts.js';
7
+ import type { MCPFailureKind, MCPOperationKind, MCPOperationListener } from './operations.js';
8
+ import type { MCPLogMessageNotification, MCPProgressNotification } from './protocol.js';
9
+ import { type RegistryIdleContext } from './registry-idle.js';
10
+ import type { MCPRegistryInternals } from './registry-internals.js';
11
+ import type { ServerSlot } from './registry-slots.js';
12
+ import type { MCPRegistryOptions } from './registry-types.js';
13
+ /**
14
+ * State and connection machinery behind `MCPRegistry`: the slot table,
15
+ * single-flight connects, idle sweep, the listeners a connected client
16
+ * notifies (catalog changes, exit/disconnect + reconnect) and operational
17
+ * bookkeeping. `MCPRegistry` (registry.ts) extends this with the public
18
+ * lifecycle, catalog and authorization API. The members it needs from that
19
+ * subclass are declared abstract here.
20
+ */
21
+ export declare abstract class MCPRegistryRuntime {
22
+ protected readonly servers: Map<string, ServerSlot>;
23
+ /** Configured-off servers are tracked without creating a transport/client. */
24
+ protected readonly disabledServers: Map<string, MCPServerConfig>;
25
+ protected readonly toolRegistry: ToolRegistry;
26
+ protected readonly events: EventBus;
27
+ protected readonly log: Logger;
28
+ protected readonly lazyMode: boolean;
29
+ protected readonly cacheDir?: string | undefined;
30
+ protected readonly cwd?: string | undefined;
31
+ protected readonly idleTimeoutMs: number;
32
+ protected readonly authorizationProviderFactory?: MCPRegistryOptions['authorizationProviderFactory'];
33
+ protected readonly authorizationManager?: MCPAuthorizationManager | undefined;
34
+ protected readonly elicitationHandler?: MCPRegistryOptions['elicitationHandler'];
35
+ protected readonly operationListeners: Set<MCPOperationListener>;
36
+ /** Starts still in flight, for {@link whenStarted}. */
37
+ protected readonly startups: Set<Promise<void>>;
38
+ /** Single shared idle sweep timer (started lazily; unref'd; cleared on stopAll). */
39
+ protected idleTimer?: ReturnType<typeof setInterval> | undefined;
40
+ constructor(opts: MCPRegistryOptions);
41
+ protected requireSlot(name: string): ServerSlot;
42
+ /**
43
+ * Boot a lazy server WITHOUT spawning it. If a tool manifest is cached (from a
44
+ * prior connect with matching config), register resolver-backed wrappers and
45
+ * go `dormant` — the process spawns on the first tool call. If there is no
46
+ * cache yet, do a one-time cold discovery connect to learn + cache the tools.
47
+ */
48
+ protected startLazy(slot: ServerSlot): Promise<void>;
49
+ protected singleFlightConnect(slot: ServerSlot): Promise<MCPClient | undefined>;
50
+ /** Keep all remote requests awake and reject results from superseded clients. */
51
+ protected withConnectedClient<T>(name: string, run: (client: MCPClient, assertCurrent: () => void) => Promise<T>): Promise<T>;
52
+ /**
53
+ * Resolve the live tool names for a slot — the registered names in normal
54
+ * mode, or the cached lazy-tool names when running in lazy mode (where
55
+ * tools are connected but intentionally not registered).
56
+ */
57
+ protected toolNamesForSlot(s: ServerSlot): string[];
58
+ /**
59
+ * This registry as the structural view its extracted method bodies take
60
+ * (see registry-internals.ts); the abstract members are supplied by
61
+ * `MCPRegistry`.
62
+ */
63
+ protected internals(): MCPRegistryInternals;
64
+ protected connectContext(): import("./registry-connect-loop.js").RegistryConnectContext;
65
+ protected idleContext(): RegistryIdleContext;
66
+ protected applyTools(slot: ServerSlot, tools: MCPTool[], client?: MCPClient | undefined): void;
67
+ protected persistCapabilityManifest(slot: ServerSlot): Promise<void>;
68
+ /** Start the shared idle sweep timer once (unref'd so it never holds the process). */
69
+ protected ensureIdleSweep(): void;
70
+ protected sweepIdle(): Promise<void>;
71
+ /**
72
+ * L2-C: handle `notifications/tools/list_changed` from the server.
73
+ * Unregister the previous wrapper set, then re-register the fresh
74
+ * tool list. The client has already refreshed its cache before
75
+ * dispatching — we just need to re-wrap and re-register.
76
+ * In lazy mode, only update the internal cache without registering.
77
+ */
78
+ protected readonly onToolsChanged: (name: string, _tools: {
79
+ name: string;
80
+ }[]) => void;
81
+ protected readonly onResourcesChanged: (name: string) => void;
82
+ protected readonly onResourceUpdated: (name: string, uri: string) => void;
83
+ protected readonly onProgress: (name: string, progress: MCPProgressNotification) => void;
84
+ protected readonly onLogMessage: (name: string, log: MCPLogMessageNotification) => void;
85
+ protected readonly onPromptsChanged: (name: string) => void;
86
+ protected addCatalogListeners(client: MCPClient): void;
87
+ protected removeCatalogListeners(client: MCPClient): void;
88
+ protected readonly onChildExit: (name: string, code: number | null, _signal: string | null) => void;
89
+ /** Handles SSE / streamable-http disconnect — same recovery as stdio child exit. */
90
+ protected readonly onTransportDisconnect: (name: string) => void;
91
+ protected scheduleReconnect(slot: ServerSlot): void;
92
+ protected attemptReconnect(slot: ServerSlot): Promise<void>;
93
+ protected recordSuccess(slot: ServerSlot, resetFailures?: boolean): void;
94
+ protected recordFailure(slot: ServerSlot, failureKind: MCPFailureKind, reason: string, durationMs?: number | undefined): void;
95
+ protected recordOperation(slot: ServerSlot, kind: MCPOperationKind, reason?: string | undefined, failureKind?: MCPFailureKind | undefined, durationMs?: number | undefined, retain?: boolean): void;
96
+ protected attemptConnect(slot: ServerSlot): Promise<void>;
97
+ abstract ensureConnected(name: string): Promise<MCPClient>;
98
+ abstract stop(name: string): Promise<void>;
99
+ abstract markDisabled(cfg: MCPServerConfig): void;
100
+ }
101
+ //# sourceMappingURL=registry-runtime.d.ts.map
@@ -0,0 +1,42 @@
1
+ import type { EventBus } from '@wrongstack/core/kernel';
2
+ import type { ToolRegistry } from '@wrongstack/core/registry';
3
+ import type { Logger, MCPServerConfig } from '@wrongstack/core/types';
4
+ import type { MCPClient } from './client.js';
5
+ import type { MCPTool } from './contracts.js';
6
+ import { type MCPFailureKind, type MCPOperationKind } from './operations.js';
7
+ import { type RegistryIdleContext } from './registry-idle.js';
8
+ import type { ServerSlot } from './registry-slots.js';
9
+ export interface RegistryServerLifecycleHost {
10
+ servers: Map<string, ServerSlot>;
11
+ stop(name: string): Promise<void>;
12
+ markDisabled(cfg: MCPServerConfig): void;
13
+ disabledServers: Map<string, MCPServerConfig>;
14
+ cacheDir: string | undefined;
15
+ startLazy(slot: ServerSlot): Promise<void>;
16
+ singleFlightConnect(slot: ServerSlot): Promise<MCPClient | undefined>;
17
+ startups: Set<Promise<void>>;
18
+ applyTools(slot: ServerSlot, tools: MCPTool[], client?: MCPClient | undefined): void;
19
+ ensureIdleSweep(): void;
20
+ log: Logger;
21
+ attemptConnect(slot: ServerSlot): Promise<void>;
22
+ recordOperation(slot: ServerSlot, kind: MCPOperationKind, reason?: string | undefined, failureKind?: MCPFailureKind | undefined, durationMs?: number | undefined, retain?: boolean): void;
23
+ toolRegistry: ToolRegistry;
24
+ onChildExit: (name: string, code: number | null, _signal: string | null) => void;
25
+ onToolsChanged: (name: string, _tools: {
26
+ name: string;
27
+ }[]) => void;
28
+ removeCatalogListeners(client: MCPClient): void;
29
+ events: EventBus;
30
+ requireSlot(name: string): ServerSlot;
31
+ idleContext(): RegistryIdleContext;
32
+ }
33
+ export declare function start(host: RegistryServerLifecycleHost, cfg: MCPServerConfig): Promise<void>;
34
+ export declare function startLazy(host: RegistryServerLifecycleHost, slot: ServerSlot): Promise<void>;
35
+ export declare function singleFlightConnect(host: RegistryServerLifecycleHost, slot: ServerSlot): Promise<MCPClient | undefined>;
36
+ export declare function ensureConnected(host: RegistryServerLifecycleHost, name: string): Promise<MCPClient>;
37
+ export declare function activateServer(host: RegistryServerLifecycleHost, name: string): void;
38
+ export declare function deactivateServer(host: RegistryServerLifecycleHost, name: string): number;
39
+ export declare function stop(host: RegistryServerLifecycleHost, name: string): Promise<void>;
40
+ export declare function sleep(host: RegistryServerLifecycleHost, name: string): Promise<void>;
41
+ export declare function restart(host: RegistryServerLifecycleHost, name: string, nextCfg?: MCPServerConfig | undefined): Promise<void>;
42
+ //# sourceMappingURL=registry-server-lifecycle.d.ts.map
@@ -0,0 +1,32 @@
1
+ import type { MCPClient } from './client.js';
2
+ import type { MCPLogMessageNotification, MCPProgressNotification } from './protocol.js';
3
+ import type { MCPRegistryInternals } from './registry-internals.js';
4
+ import type { ServerSlot } from './registry-slots.js';
5
+ /**
6
+ * Bodies of the `MCPRegistry` listeners a connected client notifies:
7
+ * catalog/list-changed signals, live resource updates, progress/log
8
+ * telemetry, child exit and transport disconnect (plus the reconnect they
9
+ * schedule). The class keeps the stable arrow-function identities it
10
+ * registers and delegates to these.
11
+ */
12
+ /**
13
+ * L2-C: handle `notifications/tools/list_changed` from the server.
14
+ * Unregister the previous wrapper set, then re-register the fresh
15
+ * tool list. The client has already refreshed its cache before
16
+ * dispatching — we just need to re-wrap and re-register.
17
+ * In lazy mode, only update the internal cache without registering.
18
+ */
19
+ export declare function handleToolsChanged(self: MCPRegistryInternals, name: string): void;
20
+ export declare function handleResourcesChanged(self: MCPRegistryInternals, name: string): void;
21
+ export declare function handleResourceUpdated(self: MCPRegistryInternals, name: string, uri: string): void;
22
+ export declare function handleProgress(self: MCPRegistryInternals, name: string, progress: MCPProgressNotification): void;
23
+ export declare function handleLogMessage(self: MCPRegistryInternals, name: string, log: MCPLogMessageNotification): void;
24
+ export declare function handlePromptsChanged(self: MCPRegistryInternals, name: string): void;
25
+ export declare function attachCatalogListeners(self: MCPRegistryInternals, client: MCPClient): void;
26
+ export declare function detachCatalogListeners(self: MCPRegistryInternals, client: MCPClient): void;
27
+ export declare function handleChildExit(self: MCPRegistryInternals, name: string, code: number | null): void;
28
+ /** Handles SSE / streamable-http disconnect — same recovery as stdio child exit. */
29
+ export declare function handleTransportDisconnect(self: MCPRegistryInternals, name: string): void;
30
+ export declare function scheduleSlotReconnect(self: MCPRegistryInternals, slot: ServerSlot): void;
31
+ export declare function attemptSlotReconnect(self: MCPRegistryInternals, slot: ServerSlot): Promise<void>;
32
+ //# sourceMappingURL=registry-slot-events.d.ts.map
@@ -1,5 +1,6 @@
1
1
  import type { MCPServerConfig, Tool } from '@wrongstack/core/types';
2
2
  import type { MCPClient } from './client.js';
3
+ import type { MCPUnsupportedProtocolVersionError } from './constants.js';
3
4
  import type { ConnectionState, MCPTool } from './contracts.js';
4
5
  import type { ElicitationRequester } from './elicitation.js';
5
6
  import type { MCPServerOperationState } from './operations.js';
@@ -31,6 +32,15 @@ export interface ServerSlot {
31
32
  /** Serializes replacements so rapid list-change notifications cannot restore stale data. */
32
33
  manifestWrite?: Promise<void> | undefined;
33
34
  attempts: number;
35
+ /**
36
+ * The protocol-version refusal that ended the last connect attempt, if any.
37
+ *
38
+ * `attemptConnectSlot` swallows connect failures (a bad server must not
39
+ * reject `start()`), so without this the demand-wake path could only report
40
+ * a generic "failed to connect" and the refused revision — the one detail the
41
+ * operator can act on — would be lost. Cleared when an attempt begins.
42
+ */
43
+ protocolVersionRefusal?: MCPUnsupportedProtocolVersionError | undefined;
34
44
  /** Set when a reconnect cycle is already running for this slot. */
35
45
  reconnectPending: boolean;
36
46
  reconnectTimer?: NodeJS.Timeout | undefined;
@@ -1,41 +1,18 @@
1
1
  import type { MCPServerConfig } from '@wrongstack/core/types';
2
- import type { MCPAuthorizationStartResult, MCPAuthorizationStatus } from './authorization-manager.js';
2
+ import type { MCPAuthorizationLoginHandle, MCPAuthorizationLoginInput, MCPAuthorizationStartResult, MCPAuthorizationStatus } from './authorization-manager.js';
3
3
  import type { MCPClient } from './client.js';
4
4
  import type { MCPInsertionPolicy, MCPPromptInsertion, MCPResourceInsertion } from './content-selection.js';
5
- import type { ConnectionState } from './contracts.js';
6
- import { type MCPOperationListener, type MCPServerOperationalHealth } from './operations.js';
5
+ import type { MCPOperationListener, MCPServerOperationalHealth } from './operations.js';
7
6
  import type { MCPGetPromptResult, MCPPrompt, MCPReadResourceResult, MCPResource, MCPResourceTemplate } from './protocol.js';
8
- import type { MCPRegistryCatalog, MCPRegistryOptions } from './registry-types.js';
7
+ import { type MCPRegistryAuthorizationBeginInput } from './registry-authorization.js';
8
+ import { describeServers, listServers, type MCPDescribedTool, serverHealth } from './registry-describe.js';
9
+ import { MCPRegistryRuntime } from './registry-runtime.js';
10
+ import type { MCPRegistryCatalog } from './registry-types.js';
11
+ export type { MCPDescribedTool } from './registry-describe.js';
9
12
  export type { MCPRegistryCatalog, MCPRegistryOptions } from './registry-types.js';
10
- export declare class MCPRegistry {
11
- private readonly servers;
12
- /** Configured-off servers are tracked without creating a transport/client. */
13
- private readonly disabledServers;
14
- private readonly toolRegistry;
15
- private readonly events;
16
- private readonly log;
17
- private readonly lazyMode;
18
- private readonly cacheDir?;
19
- private readonly cwd?;
20
- private readonly idleTimeoutMs;
21
- private readonly authorizationProviderFactory?;
22
- private readonly authorizationManager?;
23
- private readonly elicitationHandler?;
24
- private readonly operationListeners;
25
- /** Starts still in flight, for {@link whenStarted}. */
26
- private readonly startups;
27
- /** Single shared idle sweep timer (started lazily; unref'd; cleared on stopAll). */
28
- private idleTimer?;
29
- constructor(opts: MCPRegistryOptions);
30
- private requireSlot;
31
- loginAuthorization(name: string, input: Omit<import('./authorization-manager.js').MCPAuthorizationLoginInput, 'serverName' | 'resource'>): Promise<import('./authorization-manager.js').MCPAuthorizationLoginHandle>;
32
- beginAuthorization(name: string, input: {
33
- clientId?: string | undefined;
34
- redirectUri: string;
35
- scopes?: readonly string[] | undefined;
36
- challengeHeader?: string | null | undefined;
37
- signal?: AbortSignal | undefined;
38
- }): Promise<MCPAuthorizationStartResult>;
13
+ export declare class MCPRegistry extends MCPRegistryRuntime {
14
+ loginAuthorization(name: string, input: Omit<MCPAuthorizationLoginInput, 'serverName' | 'resource'>): Promise<MCPAuthorizationLoginHandle>;
15
+ beginAuthorization(name: string, input: MCPRegistryAuthorizationBeginInput): Promise<MCPAuthorizationStartResult>;
39
16
  completeAuthorization(name: string, callbackUrl: string, signal?: AbortSignal | undefined): Promise<MCPAuthorizationStatus>;
40
17
  authorizationStatus(name: string): Promise<MCPAuthorizationStatus>;
41
18
  disconnectAuthorization(name: string): Promise<boolean>;
@@ -51,14 +28,6 @@ export declare class MCPRegistry {
51
28
  markDisabled(cfg: MCPServerConfig): void;
52
29
  /** Remove residual operational/configuration state after a management delete. */
53
30
  forget(name: string): void;
54
- /**
55
- * Boot a lazy server WITHOUT spawning it. If a tool manifest is cached (from a
56
- * prior connect with matching config), register resolver-backed wrappers and
57
- * go `dormant` — the process spawns on the first tool call. If there is no
58
- * cache yet, do a one-time cold discovery connect to learn + cache the tools.
59
- */
60
- private startLazy;
61
- private singleFlightConnect;
62
31
  /**
63
32
  * Ensure a lazy server is connected, spawning it on demand. Single-flight:
64
33
  * concurrent first-calls share one connect. Resolver wrappers call this.
@@ -84,11 +53,7 @@ export declare class MCPRegistry {
84
53
  * of guessing and reading the error. Honors `allowedTools`. Returns
85
54
  * `undefined` for an unknown server, `[]` when nothing was discovered yet.
86
55
  */
87
- describeTools(name: string): {
88
- name: string;
89
- description?: string | undefined;
90
- inputSchema: Record<string, unknown>;
91
- }[] | undefined;
56
+ describeTools(name: string): MCPDescribedTool[] | undefined;
92
57
  /**
93
58
  * Check whether a server's tools are currently registered.
94
59
  */
@@ -111,12 +76,7 @@ export declare class MCPRegistry {
111
76
  */
112
77
  sleep(name: string): Promise<void>;
113
78
  restart(name: string, nextCfg?: MCPServerConfig | undefined): Promise<void>;
114
- list(): {
115
- name: string;
116
- state: ConnectionState;
117
- toolCount: number;
118
- tools: string[];
119
- }[];
79
+ list(): ReturnType<typeof listServers>;
120
80
  /**
121
81
  * Subscribe to payload-free operational signals. Callers must still avoid
122
82
  * using `serverName` as an unbounded metric label.
@@ -139,70 +99,19 @@ export declare class MCPRegistry {
139
99
  refresh?: boolean;
140
100
  }): Promise<MCPPrompt[]>;
141
101
  getPrompt(serverName: string, promptName: string, args?: Record<string, string> | undefined): Promise<MCPGetPromptResult>;
142
- /** Keep all remote requests awake and reject results from superseded clients. */
143
- private withConnectedClient;
144
102
  selectPromptForInsertion(serverName: string, promptName: string, args?: Record<string, string> | undefined, policy?: MCPInsertionPolicy | undefined): Promise<MCPPromptInsertion>;
145
- /**
146
- * Resolve the live tool names for a slot — the registered names in normal
147
- * mode, or the cached lazy-tool names when running in lazy mode (where
148
- * tools are connected but intentionally not registered).
149
- */
150
- private toolNamesForSlot;
151
- private connectContext;
152
- private idleContext;
153
- private applyTools;
154
- private persistCapabilityManifest;
155
- /** Start the shared idle sweep timer once (unref'd so it never holds the process). */
156
- private ensureIdleSweep;
157
- private sweepIdle;
158
103
  /**
159
104
  * Catalog of every server ever registered with this registry — includes
160
105
  * servers that are stopped, failed, or not yet started.
161
106
  * Useful for the `mcp_control` tool to show all known servers without
162
107
  * triggering connections.
163
108
  */
164
- describe(): {
165
- name: string;
166
- state: ConnectionState;
167
- toolCount: number;
168
- enabled: boolean;
169
- tools: string[];
170
- }[];
109
+ describe(): ReturnType<typeof describeServers>;
171
110
  stopAll(): Promise<void>;
172
111
  /**
173
112
  * Health check — returns 'ok' for connected servers, the current state otherwise.
174
113
  * For HTTP-based transports this could also ping the server.
175
114
  */
176
- health(): {
177
- name: string;
178
- alive: boolean;
179
- latencyMs?: number | undefined;
180
- }[];
181
- /**
182
- * L2-C: handle `notifications/tools/list_changed` from the server.
183
- * Unregister the previous wrapper set, then re-register the fresh
184
- * tool list. The client has already refreshed its cache before
185
- * dispatching — we just need to re-wrap and re-register.
186
- * In lazy mode, only update the internal cache without registering.
187
- */
188
- private readonly onToolsChanged;
189
- private readonly onResourcesChanged;
190
- private readonly onResourceUpdated;
191
- private readonly onPromptsChanged;
192
- private addCatalogListeners;
193
- private removeCatalogListeners;
194
- private readonly onChildExit;
195
- /** Handles SSE / streamable-http disconnect — same recovery as stdio child exit. */
196
- private readonly onTransportDisconnect;
197
- private static readonly MAX_RECONNECT_CYCLES;
198
- private static readonly BASE_RECONNECT_DELAY_MS;
199
- private static readonly MAX_RECONNECT_DELAY_MS;
200
- private scheduleReconnect;
201
- private attemptReconnect;
202
- private recordSuccess;
203
- private recordFailure;
204
- private recordOperation;
205
- private attemptConnect;
206
- private registryCatalogOperationsHost;
115
+ health(): ReturnType<typeof serverHealth>;
207
116
  }
208
117
  //# sourceMappingURL=registry.d.ts.map
@@ -1,3 +1,4 @@
1
+ import type { MCPToolAnnotations } from './contracts.js';
1
2
  import type { MCPPromptArgument, MCPPromptMessage, MCPResourceContents } from './protocol.js';
2
3
  /**
3
4
  * Server-side MCP. The mirror image of `MCPClient`: instead of consuming a
@@ -15,6 +16,14 @@ export interface MCPServerTool {
15
16
  name: string;
16
17
  description?: string | undefined;
17
18
  inputSchema: Record<string, unknown>;
19
+ /**
20
+ * `ToolAnnotations` (spec 2025-03-26) — this server's own claim about its
21
+ * behaviour, published verbatim by `tools/list`. A client MUST treat it as
22
+ * untrusted, so publishing it never relaxes anything on our side: the
23
+ * permission tier of a proxied tool comes from WrongStack policy, not from a
24
+ * hint in this object.
25
+ */
26
+ annotations?: MCPToolAnnotations | undefined;
18
27
  }
19
28
  /** The result of a `tools/call`, as the host produces it. */
20
29
  export interface MCPServerCallResult {
@@ -133,13 +142,38 @@ export declare class MCPServer {
133
142
  /** Cap on how many schema violations are echoed back in one error message. */
134
143
  export declare const MAX_REPORTED_SCHEMA_ERRORS = 5;
135
144
  /**
136
- * Marks a `tools/call` rejected by {@link MCPServer.assertArgumentsMatchSchema}
137
- * so `handleMessage` can answer with JSON-RPC `-32602 Invalid params` rather
138
- * than the generic internal-error code every other throw maps to.
145
+ * Marks a `tools/call` rejected by {@link MCPServer.assertArgumentsMatchSchema}.
146
+ * SEP-1303: `handleMessage` answers these in-band — `{ content, isError: true }`
147
+ * — so the model sees the refusal and can retry with corrected arguments,
148
+ * instead of a JSON-RPC error that stays inside the transport.
139
149
  */
140
150
  export declare class InvalidToolArgumentsError extends Error {
141
151
  readonly name = "InvalidToolArgumentsError";
142
152
  }
153
+ /**
154
+ * Base for every failure that is the *caller's* request error, mapped to
155
+ * JSON-RPC `-32602 Invalid params`. Current MCP assigns no dedicated code to these:
156
+ * `prompts.md` prescribes `-32602` for an invalid prompt name AND for missing
157
+ * required arguments, and `resources.md` retired the old `-32002` in favour of
158
+ * the same code. Use this (or a subclass) instead of a bare `throw`, which
159
+ * `handleMessage` would otherwise report as `-32603 Internal error` — a code
160
+ * clients legitimately retry.
161
+ */
162
+ export declare class InvalidParamsError extends Error {
163
+ readonly name: string;
164
+ }
165
+ /**
166
+ * Marks a lookup for a resource or prompt that does not exist.
167
+ *
168
+ * JSON-RPC has no "not found" code, and MCP retired its own `-32002` in favour
169
+ * of plain Invalid params, so this maps to `-32602` rather than the
170
+ * `-32603 Internal error` a bare `throw` would produce. A caller asking for one
171
+ * URI out of a known-good catalog made a request error, not a server failure —
172
+ * and callers key retry policy off that difference.
173
+ */
174
+ export declare class InvalidLookupError extends InvalidParamsError {
175
+ readonly name = "InvalidLookupError";
176
+ }
143
177
  export declare const SERVER_PAGE_SIZE = 100;
144
178
  export declare function paginate<T>(items: T[], params: unknown): {
145
179
  items: T[];
package/dist/server.d.ts CHANGED
@@ -1,5 +1,5 @@
1
1
  export type { MCPServerCallResult, MCPServerLogger, MCPServerOptions, MCPServerPrompt, MCPServerResource, MCPServerTool, MCPServerToolHost, } from './server-dispatch.js';
2
- export { InvalidToolArgumentsError, MCPServer, toContentBlocks } from './server-dispatch.js';
2
+ export { InvalidLookupError, InvalidParamsError, InvalidToolArgumentsError, MCPServer, toContentBlocks, } from './server-dispatch.js';
3
3
  export type { ServeHttpHandle, ServeHttpOptions } from './server-http.js';
4
4
  export { handleHttpRequest, serveHttp } from './server-http.js';
5
5
  export type { ServeStdioHandle, ServeStdioOptions } from './server-stdio.js';