mcp-compression-proxy 1.0.2 → 1.1.0

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.
@@ -1,13 +1,35 @@
1
1
  import { Client } from '@modelcontextprotocol/sdk/client/index.js';
2
- import type { MCPServerConfig, ServerStatus } from '../types/index.js';
2
+ import type { ConnectionLifecycleDefaults, MCPServerConfig, ServerStatus } from '../types/index.js';
3
3
  import type { Logger } from 'pino';
4
+ import type { ConfigResult } from '../config/loader.js';
5
+ export declare const DEFAULT_SOFT_MAX_CONNECTION_AGE_SECONDS = 3600;
6
+ export declare const DEFAULT_HARD_MAX_CONNECTION_AGE_SECONDS = 28800;
7
+ export interface ManagedClientContext {
8
+ client: Client;
9
+ generation: number;
10
+ /** Record a failed operation without recycling an otherwise healthy backend. */
11
+ markFailure(reason: string): void;
12
+ /**
13
+ * Stop routing new work to this exact generation. Active calls finish before
14
+ * the backend closes, and the next acquisition starts a replacement.
15
+ */
16
+ invalidate(reason: string): void;
17
+ }
4
18
  /**
5
- * Manages connections to multiple MCP servers
19
+ * Manages backend MCP processes as leased connection generations.
20
+ *
21
+ * READY connections may be leased by concurrent callers. Soft-expired
22
+ * connections are replaced on the next acquisition. Hard-expired connections
23
+ * enter DRAINING immediately and close after their final lease is released.
6
24
  */
7
25
  export declare class MCPClientManager {
8
- private connections;
9
- private logger;
26
+ private readonly slots;
27
+ private readonly logger;
10
28
  private readonly DEFAULT_TIMEOUT_MS;
29
+ private readonly RECONNECT_BASE_MS;
30
+ private readonly RECONNECT_MAX_MS;
31
+ private configWatchTimer?;
32
+ private shuttingDown;
11
33
  constructor(logger: Logger);
12
34
  /**
13
35
  * Wraps a promise with a timeout.
@@ -21,45 +43,106 @@ export declare class MCPClientManager {
21
43
  *
22
44
  * The stdio transport only inherits a small allowlist of "safe" variables
23
45
  * (PATH, HOME, ...), so anything else the user exported - API tokens, base
24
- * URLs - never reaches the child unless it is passed explicitly. By default
25
- * we forward the proxy's full environment, matching what users expect from a
26
- * process they launched themselves. `inheritEnv` narrows that when a server
27
- * should not see unrelated secrets.
46
+ * URLs - never reaches the child unless it is passed explicitly.
28
47
  */
29
48
  private buildEnv;
49
+ private resolveConfig;
30
50
  /**
31
- * Initialize and connect to all configured MCP servers
32
- * @param servers - Server configurations to initialize
33
- * @param defaultTimeout - Optional default timeout in seconds (overrides class default)
34
- * @param defaultInheritEnv - Optional default env inheritance policy (overridden per-server)
51
+ * Pick the transport for a server.
52
+ *
53
+ * `url` is the whole discriminator - the config schema makes `command` and
54
+ * `url` mutually exclusive, so there is nothing else to inspect. `buildEnv`
55
+ * falls away on the remote branch because there is no child process to hand
56
+ * an environment to; credentials travel as headers instead.
35
57
  */
36
- initializeServers(servers: MCPServerConfig[], defaultTimeout?: number, defaultInheritEnv?: boolean | string[]): Promise<void>;
58
+ private buildTransport;
37
59
  /**
38
- * Connect to a single MCP server with timeout
60
+ * Initialize all configured slots and eagerly start their first generation.
61
+ * A failed initial connection remains configured and is retried lazily later.
39
62
  */
40
- private connectToServer;
63
+ initializeServers(servers: MCPServerConfig[], defaultTimeout?: number, defaultInheritEnv?: boolean | string[], lifecycleDefaults?: ConnectionLifecycleDefaults): Promise<void>;
64
+ private createConnection;
41
65
  /**
42
- * Get a connected client by server name
66
+ * React to a backend connection going away.
67
+ *
68
+ * `connection` identifies which generation closed: an old transport finishing
69
+ * its teardown after a reconnect already installed a replacement must not
70
+ * mark the live connection down.
43
71
  */
44
- getClient(serverName: string): Client | undefined;
72
+ private handleDrop;
45
73
  /**
46
- * Get all connected clients
74
+ * Queue a reconnect with capped, jittered exponential backoff.
75
+ *
76
+ * Attempts are uncapped on purpose - a backend can be down for hours (a
77
+ * laptop asleep, a container being rebuilt) and should still come back
78
+ * without the operator restarting their whole MCP client. The jitter keeps
79
+ * several backends behind the same dead machine from retrying in lockstep.
47
80
  */
48
- getConnectedClients(): Array<{
49
- name: string;
50
- client: Client;
51
- }>;
81
+ private scheduleReconnect;
82
+ private reconnect;
52
83
  /**
53
- * Get status of all servers
84
+ * Bring the live connections in line with a freshly loaded server list.
85
+ *
86
+ * Servers that vanished or changed are torn down, servers that appeared are
87
+ * connected, and everything untouched keeps its existing connection - an
88
+ * edit to one entry must not interrupt the other backends.
54
89
  */
55
- getServerStatuses(): ServerStatus[];
90
+ reconcile(servers: MCPServerConfig[], defaultTimeout?: number, defaultInheritEnv?: boolean | string[], lifecycleDefaults?: ConnectionLifecycleDefaults): Promise<void>;
56
91
  /**
57
- * Check if at least one server is connected
92
+ * Close a connection the operator has removed or replaced.
93
+ *
94
+ * Order matters: the queued retry dies first and the close is claimed as
95
+ * ours *before* close() runs, so handleDrop() cannot resurrect a server that
96
+ * was deliberately taken out of servers.json.
58
97
  */
59
- hasConnectedServers(): boolean;
98
+ private teardownSlot;
99
+ private lifecycleDefaultsFromConfig;
100
+ private cancelReconnect;
60
101
  /**
61
- * Disconnect from all servers
102
+ * Poll the config for server list changes and apply them live.
103
+ *
104
+ * Polling rather than fs.watch: watchers fire duplicate events and stop
105
+ * working entirely once a file is replaced by write-temp-then-rename, which
106
+ * is how most editors and jq-style tools save. Two stats every few seconds
107
+ * are cheaper than the bug reports that would follow.
108
+ *
109
+ * `loadConfig` is injected rather than imported so this stays testable
110
+ * without fixture files, matching the loader injection in StatsService.
111
+ */
112
+ startConfigWatch(loadConfig: () => ConfigResult, intervalMs?: number, onConfigLoaded?: (config: NonNullable<ConfigResult>) => void): void;
113
+ /**
114
+ * Single-flight connection creation. Concurrent callers share this promise.
115
+ */
116
+ private ensureConnection;
117
+ private scheduleHardExpiry;
118
+ private isSoftExpired;
119
+ private beginDrain;
120
+ private closeConnection;
121
+ private acquireConnection;
122
+ private releaseConnection;
123
+ private recordSuccess;
124
+ private recordFailure;
125
+ /**
126
+ * Execute work under a lease. Invalidating the context drains this exact
127
+ * generation, so concurrent recovery cannot accidentally close a newer one.
128
+ */
129
+ withClient<T>(serverName: string, operation: (context: ManagedClientContext) => Promise<T>): Promise<T>;
130
+ getConfiguredServerNames(): string[];
131
+ getAuthRecoveryPolicy(serverName: string): {
132
+ authErrorPatterns: string[];
133
+ authRetryTools: string[];
134
+ };
135
+ /**
136
+ * Compatibility accessors. Production operations should use withClient so
137
+ * lifecycle age, active leases, and health are tracked.
62
138
  */
139
+ getClient(serverName: string): Client | undefined;
140
+ getConnectedClients(): Array<{
141
+ name: string;
142
+ client: Client;
143
+ }>;
144
+ getServerStatuses(): ServerStatus[];
145
+ hasConnectedServers(): boolean;
63
146
  disconnectAll(): Promise<void>;
64
147
  }
65
148
  //# sourceMappingURL=client-manager.d.ts.map