@mcp-ts/sdk 2.2.0 → 2.3.1
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-adapter.js +9 -5
- package/dist/adapters/agui-adapter.js.map +1 -1
- package/dist/adapters/agui-adapter.mjs +9 -5
- package/dist/adapters/agui-adapter.mjs.map +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/ai-adapter.js +9 -5
- package/dist/adapters/ai-adapter.js.map +1 -1
- package/dist/adapters/ai-adapter.mjs +9 -5
- package/dist/adapters/ai-adapter.mjs.map +1 -1
- package/dist/adapters/langchain-adapter.d.mts +1 -1
- package/dist/adapters/langchain-adapter.d.ts +1 -1
- package/dist/adapters/langchain-adapter.js +9 -5
- package/dist/adapters/langchain-adapter.js.map +1 -1
- package/dist/adapters/langchain-adapter.mjs +9 -5
- package/dist/adapters/langchain-adapter.mjs.map +1 -1
- package/dist/client/react.js.map +1 -1
- package/dist/client/react.mjs.map +1 -1
- package/dist/index.d.mts +2 -2
- package/dist/index.d.ts +2 -2
- package/dist/index.js +83 -6
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +83 -7
- package/dist/index.mjs.map +1 -1
- package/dist/server/index.d.mts +13 -1
- package/dist/server/index.d.ts +13 -1
- package/dist/server/index.js +66 -1
- package/dist/server/index.js.map +1 -1
- package/dist/server/index.mjs +66 -2
- package/dist/server/index.mjs.map +1 -1
- package/dist/shared/index.d.mts +2 -2
- package/dist/shared/index.d.ts +2 -2
- package/dist/shared/index.js +17 -5
- package/dist/shared/index.js.map +1 -1
- package/dist/shared/index.mjs +17 -5
- package/dist/shared/index.mjs.map +1 -1
- package/dist/{tool-router-C8hIA-tg.d.mts → tool-router-BfE_9tay.d.mts} +5 -0
- package/dist/{tool-router-CdX8e9bk.d.ts → tool-router-CP7qLk1J.d.ts} +5 -0
- package/package.json +1 -1
- package/src/server/index.ts +8 -1
- package/src/server/storage/index.ts +77 -2
- package/src/server/storage/types.ts +14 -0
- package/src/shared/meta-tools.ts +16 -7
- package/src/shared/tool-router.ts +13 -0
|
@@ -355,6 +355,11 @@ declare class ToolRouter {
|
|
|
355
355
|
* If tool name is ambiguous, use namespace to specify the server.
|
|
356
356
|
*/
|
|
357
357
|
getToolSchema(toolName: string, namespace?: string, options?: ToolLookupOptions): IndexedTool | undefined;
|
|
358
|
+
/**
|
|
359
|
+
* Resolve the full tool definition by name, ensuring the router index has
|
|
360
|
+
* been initialized first.
|
|
361
|
+
*/
|
|
362
|
+
resolveToolSchema(toolName: string, namespace?: string, options?: ToolLookupOptions): Promise<IndexedTool | undefined>;
|
|
358
363
|
/**
|
|
359
364
|
* Get compact (schema-less) summaries for all tools.
|
|
360
365
|
*/
|
|
@@ -355,6 +355,11 @@ declare class ToolRouter {
|
|
|
355
355
|
* If tool name is ambiguous, use namespace to specify the server.
|
|
356
356
|
*/
|
|
357
357
|
getToolSchema(toolName: string, namespace?: string, options?: ToolLookupOptions): IndexedTool | undefined;
|
|
358
|
+
/**
|
|
359
|
+
* Resolve the full tool definition by name, ensuring the router index has
|
|
360
|
+
* been initialized first.
|
|
361
|
+
*/
|
|
362
|
+
resolveToolSchema(toolName: string, namespace?: string, options?: ToolLookupOptions): Promise<IndexedTool | undefined>;
|
|
358
363
|
/**
|
|
359
364
|
* Get compact (schema-less) summaries for all tools.
|
|
360
365
|
*/
|
package/package.json
CHANGED
package/src/server/index.ts
CHANGED
|
@@ -6,7 +6,7 @@
|
|
|
6
6
|
/** Core MCP client and session management */
|
|
7
7
|
export { MCPClient } from './mcp/oauth-client.js';
|
|
8
8
|
export { UnauthorizedError } from '../shared/errors.js';
|
|
9
|
-
export { sessions, type SessionStore } from './storage/index.js';
|
|
9
|
+
export { sessions, onSessionMutation, type SessionStore } from './storage/index.js';
|
|
10
10
|
export { StorageOAuthClientProvider } from './mcp/storage-oauth-provider.js';
|
|
11
11
|
export { MultiSessionClient } from './mcp/multi-session-client.js';
|
|
12
12
|
|
|
@@ -44,6 +44,13 @@ export type {
|
|
|
44
44
|
CallToolResponse,
|
|
45
45
|
} from '../shared/types';
|
|
46
46
|
|
|
47
|
+
export type {
|
|
48
|
+
Session,
|
|
49
|
+
SessionMutationEvent,
|
|
50
|
+
SessionMutationListener,
|
|
51
|
+
SessionMutationType,
|
|
52
|
+
} from './storage/types.js';
|
|
53
|
+
|
|
47
54
|
/** Re-export MCP SDK types for convenience */
|
|
48
55
|
export type {
|
|
49
56
|
OAuthClientMetadata,
|
|
@@ -5,7 +5,7 @@ import { FileStorageBackend } from './file-backend';
|
|
|
5
5
|
import { SqliteStorage } from './sqlite-backend.js';
|
|
6
6
|
import { SupabaseStorageBackend } from './supabase-backend.js';
|
|
7
7
|
import { NeonStorageBackend, type NeonStorageOptions } from './neon-backend.js';
|
|
8
|
-
import type { SessionStore } from './types.js';
|
|
8
|
+
import type { SessionStore, Session, SessionMutationEvent, SessionMutationListener } from './types.js';
|
|
9
9
|
|
|
10
10
|
// Re-export types
|
|
11
11
|
export * from './types.js';
|
|
@@ -42,6 +42,65 @@ function warnIfNeonConnectionStringIsInsecure(connectionString: string): void {
|
|
|
42
42
|
|
|
43
43
|
let storageInstance: SessionStore | null = null;
|
|
44
44
|
let storagePromise: Promise<SessionStore> | null = null;
|
|
45
|
+
const sessionMutationListeners = new Set<SessionMutationListener>();
|
|
46
|
+
|
|
47
|
+
function emitSessionMutation(event: SessionMutationEvent): void {
|
|
48
|
+
for (const listener of sessionMutationListeners) {
|
|
49
|
+
try {
|
|
50
|
+
const result = listener(event);
|
|
51
|
+
if (result && typeof (result as Promise<void>).catch === 'function') {
|
|
52
|
+
void (result as Promise<void>).catch((error) => {
|
|
53
|
+
console.error('[mcp-ts][Storage] Session mutation listener failed:', error);
|
|
54
|
+
});
|
|
55
|
+
}
|
|
56
|
+
} catch (error) {
|
|
57
|
+
console.error('[mcp-ts][Storage] Session mutation listener failed:', error);
|
|
58
|
+
}
|
|
59
|
+
}
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
function createSessionMutationEvent(prop: PropertyKey, args: any[]): SessionMutationEvent | null {
|
|
63
|
+
const timestamp = Date.now();
|
|
64
|
+
|
|
65
|
+
if (prop === 'create') {
|
|
66
|
+
const [session, ttl] = args as [Session, number | undefined];
|
|
67
|
+
if (!session?.userId || !session?.sessionId) return null;
|
|
68
|
+
return {
|
|
69
|
+
type: 'create',
|
|
70
|
+
userId: session.userId,
|
|
71
|
+
sessionId: session.sessionId,
|
|
72
|
+
session,
|
|
73
|
+
ttl,
|
|
74
|
+
timestamp,
|
|
75
|
+
};
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
if (prop === 'update') {
|
|
79
|
+
const [userId, sessionId, patch, ttl] = args as [string, string, Partial<Session>, number | undefined];
|
|
80
|
+
if (!userId || !sessionId) return null;
|
|
81
|
+
return {
|
|
82
|
+
type: 'update',
|
|
83
|
+
userId,
|
|
84
|
+
sessionId,
|
|
85
|
+
patch,
|
|
86
|
+
ttl,
|
|
87
|
+
timestamp,
|
|
88
|
+
};
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
if (prop === 'delete') {
|
|
92
|
+
const [userId, sessionId] = args as [string, string];
|
|
93
|
+
if (!userId || !sessionId) return null;
|
|
94
|
+
return {
|
|
95
|
+
type: 'delete',
|
|
96
|
+
userId,
|
|
97
|
+
sessionId,
|
|
98
|
+
timestamp,
|
|
99
|
+
};
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
return null;
|
|
103
|
+
}
|
|
45
104
|
|
|
46
105
|
async function initializeStorage<T extends SessionStore>(store: T): Promise<T> {
|
|
47
106
|
if (typeof store.init === 'function') {
|
|
@@ -215,6 +274,17 @@ export function _setStorageInstanceForTesting(instance: SessionStore | null): vo
|
|
|
215
274
|
}
|
|
216
275
|
}
|
|
217
276
|
|
|
277
|
+
export function onSessionMutation(listener: SessionMutationListener): () => void {
|
|
278
|
+
sessionMutationListeners.add(listener);
|
|
279
|
+
return () => {
|
|
280
|
+
sessionMutationListeners.delete(listener);
|
|
281
|
+
};
|
|
282
|
+
}
|
|
283
|
+
|
|
284
|
+
export function _resetSessionMutationListenersForTesting(): void {
|
|
285
|
+
sessionMutationListeners.clear();
|
|
286
|
+
}
|
|
287
|
+
|
|
218
288
|
/**
|
|
219
289
|
* Global session store instance
|
|
220
290
|
* Uses lazy initialization with a Proxy to handle async setup transparently
|
|
@@ -225,7 +295,12 @@ export const sessions: SessionStore = new Proxy({} as SessionStore, {
|
|
|
225
295
|
const instance = await getStorage();
|
|
226
296
|
const value = (instance as any)[prop];
|
|
227
297
|
if (typeof value === 'function') {
|
|
228
|
-
|
|
298
|
+
const result = await value.apply(instance, args);
|
|
299
|
+
const event = createSessionMutationEvent(prop, args);
|
|
300
|
+
if (event) {
|
|
301
|
+
emitSessionMutation(event);
|
|
302
|
+
}
|
|
303
|
+
return result;
|
|
229
304
|
}
|
|
230
305
|
return value;
|
|
231
306
|
};
|
|
@@ -29,6 +29,20 @@ export interface Session {
|
|
|
29
29
|
clientId?: string;
|
|
30
30
|
}
|
|
31
31
|
|
|
32
|
+
export type SessionMutationType = 'create' | 'update' | 'delete';
|
|
33
|
+
|
|
34
|
+
export interface SessionMutationEvent {
|
|
35
|
+
type: SessionMutationType;
|
|
36
|
+
userId: string;
|
|
37
|
+
sessionId: string;
|
|
38
|
+
timestamp: number;
|
|
39
|
+
session?: Session;
|
|
40
|
+
patch?: Partial<Session>;
|
|
41
|
+
ttl?: number;
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
export type SessionMutationListener = (event: SessionMutationEvent) => void | Promise<void>;
|
|
45
|
+
|
|
32
46
|
export interface SetClientOptions {
|
|
33
47
|
sessionId: string;
|
|
34
48
|
serverId?: string; // Database server ID
|
package/src/shared/meta-tools.ts
CHANGED
|
@@ -235,12 +235,23 @@ export async function executeMetaTool(
|
|
|
235
235
|
router: ToolRouter,
|
|
236
236
|
callToolFn?: CallToolFn
|
|
237
237
|
): Promise<CallToolResult | null> {
|
|
238
|
-
const resolveToolSchema = (
|
|
238
|
+
const resolveToolSchema = async (
|
|
239
239
|
name: string,
|
|
240
240
|
namespace?: string,
|
|
241
241
|
options?: ToolLookupOptions
|
|
242
|
-
): { tool?: IndexedTool; error?: CallToolResult } => {
|
|
242
|
+
): Promise<{ tool?: IndexedTool; error?: CallToolResult }> => {
|
|
243
243
|
try {
|
|
244
|
+
if (typeof (router as ToolRouter & { resolveToolSchema?: unknown }).resolveToolSchema === 'function') {
|
|
245
|
+
return {
|
|
246
|
+
tool: await (router as ToolRouter & {
|
|
247
|
+
resolveToolSchema: (
|
|
248
|
+
toolName: string,
|
|
249
|
+
namespace?: string,
|
|
250
|
+
options?: ToolLookupOptions
|
|
251
|
+
) => Promise<IndexedTool | undefined>;
|
|
252
|
+
}).resolveToolSchema(name, namespace, options),
|
|
253
|
+
};
|
|
254
|
+
}
|
|
244
255
|
return { tool: router.getToolSchema(name, namespace, options) };
|
|
245
256
|
} catch (err) {
|
|
246
257
|
const errorMessage = err instanceof Error ? err.message : String(err);
|
|
@@ -307,8 +318,6 @@ export async function executeMetaTool(
|
|
|
307
318
|
// Fast path: Check for select: prefix
|
|
308
319
|
const selectMatch = query.match(/^select:(.+)$/i);
|
|
309
320
|
if (selectMatch) {
|
|
310
|
-
await router.listTools({ serverId, serverName, limit: 1 });
|
|
311
|
-
|
|
312
321
|
const requested = selectMatch[1]!
|
|
313
322
|
.split(',')
|
|
314
323
|
.map((s) => s.trim())
|
|
@@ -320,7 +329,7 @@ export async function executeMetaTool(
|
|
|
320
329
|
const namespace = serverId ?? serverName;
|
|
321
330
|
|
|
322
331
|
for (const requestedToolName of requested) {
|
|
323
|
-
const { tool, error } = resolveToolSchema(requestedToolName, namespace, {
|
|
332
|
+
const { tool, error } = await resolveToolSchema(requestedToolName, namespace, {
|
|
324
333
|
allowServerNameFragment: Boolean(serverName && !serverId),
|
|
325
334
|
});
|
|
326
335
|
if (error) {
|
|
@@ -410,7 +419,7 @@ export async function executeMetaTool(
|
|
|
410
419
|
case 'mcp_get_tool_schema': {
|
|
411
420
|
const name = String(args.toolName ?? '');
|
|
412
421
|
const namespace = String(args.serverId ?? '') || undefined;
|
|
413
|
-
const { tool, error } = resolveToolSchema(name, namespace);
|
|
422
|
+
const { tool, error } = await resolveToolSchema(name, namespace);
|
|
414
423
|
|
|
415
424
|
if (error) {
|
|
416
425
|
return error;
|
|
@@ -461,7 +470,7 @@ export async function executeMetaTool(
|
|
|
461
470
|
}
|
|
462
471
|
|
|
463
472
|
// Verify the tool exists in our index
|
|
464
|
-
const { tool, error } = resolveToolSchema(targetToolName, namespace);
|
|
473
|
+
const { tool, error } = await resolveToolSchema(targetToolName, namespace);
|
|
465
474
|
if (error) {
|
|
466
475
|
return error;
|
|
467
476
|
}
|
|
@@ -289,6 +289,19 @@ export class ToolRouter {
|
|
|
289
289
|
return matches[0];
|
|
290
290
|
}
|
|
291
291
|
|
|
292
|
+
/**
|
|
293
|
+
* Resolve the full tool definition by name, ensuring the router index has
|
|
294
|
+
* been initialized first.
|
|
295
|
+
*/
|
|
296
|
+
async resolveToolSchema(
|
|
297
|
+
toolName: string,
|
|
298
|
+
namespace?: string,
|
|
299
|
+
options: ToolLookupOptions = {}
|
|
300
|
+
): Promise<IndexedTool | undefined> {
|
|
301
|
+
await this.ensureInitialized();
|
|
302
|
+
return this.getToolSchema(toolName, namespace, options);
|
|
303
|
+
}
|
|
304
|
+
|
|
292
305
|
/**
|
|
293
306
|
* Get compact (schema-less) summaries for all tools.
|
|
294
307
|
*/
|