@mcp-ts/sdk 2.4.2 → 2.4.3
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.
- package/dist/adapters/agui-adapter.d.mts +1 -1
- package/dist/adapters/agui-adapter.d.ts +1 -1
- package/dist/adapters/agui-middleware.d.mts +1 -1
- package/dist/adapters/agui-middleware.d.ts +1 -1
- package/dist/adapters/ai-adapter.d.mts +1 -1
- package/dist/adapters/ai-adapter.d.ts +1 -1
- package/dist/adapters/langchain-adapter.d.mts +1 -1
- package/dist/adapters/langchain-adapter.d.ts +1 -1
- package/dist/adapters/mastra-adapter.d.mts +1 -1
- package/dist/adapters/mastra-adapter.d.ts +1 -1
- package/dist/bin/mcp-ts.js +5 -5
- package/dist/bin/mcp-ts.js.map +1 -1
- package/dist/bin/mcp-ts.mjs +5 -5
- package/dist/bin/mcp-ts.mjs.map +1 -1
- package/dist/index.d.mts +1 -1
- package/dist/index.d.ts +1 -1
- package/dist/index.js +71 -15
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +71 -15
- package/dist/index.mjs.map +1 -1
- package/dist/{multi-session-client-CWs-AE78.d.mts → multi-session-client-B6hsYO8V.d.mts} +17 -0
- package/dist/{multi-session-client-BluyCPo9.d.ts → multi-session-client-DOBvtaQV.d.ts} +17 -0
- package/dist/server/index.d.mts +2 -2
- package/dist/server/index.d.ts +2 -2
- package/dist/server/index.js +71 -15
- package/dist/server/index.js.map +1 -1
- package/dist/server/index.mjs +71 -15
- package/dist/server/index.mjs.map +1 -1
- package/package.json +1 -1
- package/src/bin/mcp-ts.ts +5 -5
- package/src/server/mcp/multi-session-client.ts +13 -0
- package/src/server/mcp/oauth-client.ts +49 -7
- package/src/server/storage/index.ts +8 -8
package/package.json
CHANGED
package/src/bin/mcp-ts.ts
CHANGED
|
@@ -82,13 +82,13 @@ async function initSupabase() {
|
|
|
82
82
|
console.log(' npx supabase db push');
|
|
83
83
|
console.log('\n3. Add your Supabase credentials to .env:');
|
|
84
84
|
console.log(' SUPABASE_URL=https://<your-project-id>.supabase.co');
|
|
85
|
-
console.log('
|
|
86
|
-
console.log('\n⚠️ Important: Use the
|
|
87
|
-
console.log(' The
|
|
88
|
-
console.log(' Find it in: Supabase Dashboard -> Project Settings -> API ->
|
|
85
|
+
console.log(' SUPABASE_SECRET_KEY=<your-secret-key>');
|
|
86
|
+
console.log('\n⚠️ Important: Use the secret key (not the anon key) for server-side storage.');
|
|
87
|
+
console.log(' The secret key bypasses RLS policies and is required for mcp-ts to work correctly.');
|
|
88
|
+
console.log(' Find it in: Supabase Dashboard -> Project Settings -> API -> Secret key');
|
|
89
89
|
} else if (files.length > 0) {
|
|
90
90
|
console.log('\n👍 All migration files are already present in your project.');
|
|
91
|
-
console.log(' Ensure
|
|
91
|
+
console.log(' Ensure SUPABASE_SECRET_KEY (not SUPABASE_ANON_KEY) is set in your .env');
|
|
92
92
|
} else {
|
|
93
93
|
console.log('⚠️ No migration files found to copy.');
|
|
94
94
|
}
|
|
@@ -152,6 +152,19 @@ export class MultiSessionClient implements ToolClientProvider {
|
|
|
152
152
|
return this.clients;
|
|
153
153
|
}
|
|
154
154
|
|
|
155
|
+
/**
|
|
156
|
+
* Removes and disconnects a single session by ID.
|
|
157
|
+
*
|
|
158
|
+
* @returns `true` if the session was found and removed, `false` if not found.
|
|
159
|
+
*/
|
|
160
|
+
async removeSession(sessionId: string): Promise<boolean> {
|
|
161
|
+
const idx = this.clients.findIndex(c => c.getSessionId() === sessionId);
|
|
162
|
+
if (idx === -1) return false;
|
|
163
|
+
const [client] = this.clients.splice(idx, 1);
|
|
164
|
+
await client.disconnect();
|
|
165
|
+
return true;
|
|
166
|
+
}
|
|
167
|
+
|
|
155
168
|
/**
|
|
156
169
|
* Gracefully disconnects all active MCP clients and clears the internal list.
|
|
157
170
|
*
|
|
@@ -257,7 +257,6 @@ export class MCPClient {
|
|
|
257
257
|
const hasSessionHeader = init?.headers && new Headers(init.headers as HeadersInit).has('mcp-session-id');
|
|
258
258
|
|
|
259
259
|
if (response.status === 404 && hasSessionHeader) {
|
|
260
|
-
this.client = null;
|
|
261
260
|
throw new Error("MCP_SESSION_EXPIRED: Downstream session was not found on the server.");
|
|
262
261
|
}
|
|
263
262
|
|
|
@@ -791,7 +790,9 @@ export class MCPClient {
|
|
|
791
790
|
params: {},
|
|
792
791
|
};
|
|
793
792
|
|
|
794
|
-
const result = await this.
|
|
793
|
+
const result = await this.withRetry(() =>
|
|
794
|
+
this.client!.request(request, ListToolsResultSchema)
|
|
795
|
+
);
|
|
795
796
|
|
|
796
797
|
if (this.serverId) {
|
|
797
798
|
this._onConnectionEvent.fire({
|
|
@@ -837,7 +838,9 @@ export class MCPClient {
|
|
|
837
838
|
};
|
|
838
839
|
|
|
839
840
|
try {
|
|
840
|
-
const result = await this.
|
|
841
|
+
const result = await this.withRetry(() =>
|
|
842
|
+
this.client!.request(request, CallToolResultSchema)
|
|
843
|
+
);
|
|
841
844
|
|
|
842
845
|
this._onObservabilityEvent.fire({
|
|
843
846
|
type: 'mcp:client:tool_call',
|
|
@@ -897,7 +900,9 @@ export class MCPClient {
|
|
|
897
900
|
params: {},
|
|
898
901
|
};
|
|
899
902
|
|
|
900
|
-
const result = await this.
|
|
903
|
+
const result = await this.withRetry(() =>
|
|
904
|
+
this.client!.request(request, ListPromptsResultSchema)
|
|
905
|
+
);
|
|
901
906
|
|
|
902
907
|
this.emitStateChange('READY');
|
|
903
908
|
this.emitProgress(`Discovered ${result.prompts.length} prompts`);
|
|
@@ -931,7 +936,9 @@ export class MCPClient {
|
|
|
931
936
|
},
|
|
932
937
|
};
|
|
933
938
|
|
|
934
|
-
return await this.
|
|
939
|
+
return await this.withRetry(() =>
|
|
940
|
+
this.client!.request(request, GetPromptResultSchema)
|
|
941
|
+
);
|
|
935
942
|
}
|
|
936
943
|
|
|
937
944
|
/**
|
|
@@ -952,7 +959,9 @@ export class MCPClient {
|
|
|
952
959
|
params: {},
|
|
953
960
|
};
|
|
954
961
|
|
|
955
|
-
const result = await this.
|
|
962
|
+
const result = await this.withRetry(() =>
|
|
963
|
+
this.client!.request(request, ListResourcesResultSchema)
|
|
964
|
+
);
|
|
956
965
|
|
|
957
966
|
this.emitStateChange('READY');
|
|
958
967
|
this.emitProgress(`Discovered ${result.resources.length} resources`);
|
|
@@ -984,7 +993,34 @@ export class MCPClient {
|
|
|
984
993
|
},
|
|
985
994
|
};
|
|
986
995
|
|
|
987
|
-
return await this.
|
|
996
|
+
return await this.withRetry(() =>
|
|
997
|
+
this.client!.request(request, ReadResourceResultSchema)
|
|
998
|
+
);
|
|
999
|
+
}
|
|
1000
|
+
|
|
1001
|
+
/**
|
|
1002
|
+
* Wraps an MCP request with automatic transport-session recovery.
|
|
1003
|
+
*
|
|
1004
|
+
* When the downstream MCP server rejects the request with a 404 indicating
|
|
1005
|
+
* the transport session has expired, this method tears down the stale SDK
|
|
1006
|
+
* client and transport, calls {@link reconnect} to negotiate a fresh session,
|
|
1007
|
+
* and retries the request once.
|
|
1008
|
+
*
|
|
1009
|
+
* Non-transient errors (network failures, auth errors, etc.) propagate as-is.
|
|
1010
|
+
*/
|
|
1011
|
+
private async withRetry<T>(fn: () => Promise<T>): Promise<T> {
|
|
1012
|
+
try {
|
|
1013
|
+
return await fn();
|
|
1014
|
+
} catch (error) {
|
|
1015
|
+
if (!(error instanceof Error && error.message.includes('MCP_SESSION_EXPIRED'))) throw error;
|
|
1016
|
+
if (this.client) {
|
|
1017
|
+
try { await this.client.close(); } catch {}
|
|
1018
|
+
this.transport = null;
|
|
1019
|
+
this.client = null;
|
|
1020
|
+
}
|
|
1021
|
+
await this.reconnect();
|
|
1022
|
+
return await fn();
|
|
1023
|
+
}
|
|
988
1024
|
}
|
|
989
1025
|
|
|
990
1026
|
/**
|
|
@@ -1000,6 +1036,12 @@ export class MCPClient {
|
|
|
1000
1036
|
throw new Error('OAuth provider not initialized');
|
|
1001
1037
|
}
|
|
1002
1038
|
|
|
1039
|
+
// Close the client initialize() may have created — we need a fresh
|
|
1040
|
+
// client that will negotiate a new transport session.
|
|
1041
|
+
if (this.client) {
|
|
1042
|
+
try { await this.client.close(); } catch {}
|
|
1043
|
+
}
|
|
1044
|
+
|
|
1003
1045
|
this.client = new Client(
|
|
1004
1046
|
{
|
|
1005
1047
|
name: MCP_CLIENT_NAME,
|
|
@@ -141,13 +141,13 @@ async function createStorage(): Promise<SessionStore> {
|
|
|
141
141
|
|
|
142
142
|
if (type === 'supabase') {
|
|
143
143
|
const url = process.env.SUPABASE_URL;
|
|
144
|
-
const key = process.env.
|
|
144
|
+
const key = process.env.SUPABASE_SECRET_KEY || process.env.SUPABASE_ANON_KEY;
|
|
145
145
|
|
|
146
146
|
if (!url || !key) {
|
|
147
|
-
console.warn('[mcp-ts][Storage] Explicit selection "supabase" requires SUPABASE_URL and
|
|
147
|
+
console.warn('[mcp-ts][Storage] Explicit selection "supabase" requires SUPABASE_URL and SUPABASE_SECRET_KEY.');
|
|
148
148
|
} else {
|
|
149
|
-
if (!process.env.
|
|
150
|
-
console.warn('[mcp-ts][Storage] ⚠️ Warning: Using "SUPABASE_ANON_KEY" for server-side storage. You may encounter RLS policy violations. "
|
|
149
|
+
if (!process.env.SUPABASE_SECRET_KEY) {
|
|
150
|
+
console.warn('[mcp-ts][Storage] ⚠️ Warning: Using "SUPABASE_ANON_KEY" for server-side storage. You may encounter RLS policy violations. "SUPABASE_SECRET_KEY" is recommended.');
|
|
151
151
|
}
|
|
152
152
|
try {
|
|
153
153
|
const { createClient } = await import('@supabase/supabase-js');
|
|
@@ -210,14 +210,14 @@ async function createStorage(): Promise<SessionStore> {
|
|
|
210
210
|
return await initializeStorage(new SqliteStorage({ path: process.env.MCP_TS_STORAGE_SQLITE_PATH }));
|
|
211
211
|
}
|
|
212
212
|
|
|
213
|
-
if (process.env.SUPABASE_URL && (process.env.
|
|
213
|
+
if (process.env.SUPABASE_URL && (process.env.SUPABASE_SECRET_KEY || process.env.SUPABASE_ANON_KEY)) {
|
|
214
214
|
try {
|
|
215
215
|
const { createClient } = await import('@supabase/supabase-js');
|
|
216
216
|
const url = process.env.SUPABASE_URL;
|
|
217
|
-
const key = process.env.
|
|
217
|
+
const key = process.env.SUPABASE_SECRET_KEY || process.env.SUPABASE_ANON_KEY!;
|
|
218
218
|
|
|
219
|
-
if (!process.env.
|
|
220
|
-
console.warn('[mcp-ts][Storage] ⚠️ Warning: Using "SUPABASE_ANON_KEY" for server-side storage. You may encounter RLS policy violations. "
|
|
219
|
+
if (!process.env.SUPABASE_SECRET_KEY) {
|
|
220
|
+
console.warn('[mcp-ts][Storage] ⚠️ Warning: Using "SUPABASE_ANON_KEY" for server-side storage. You may encounter RLS policy violations. "SUPABASE_SECRET_KEY" is recommended.');
|
|
221
221
|
}
|
|
222
222
|
|
|
223
223
|
const client = createClient(url, key);
|