@mcp-ts/sdk 1.5.3 → 1.6.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.
- package/dist/adapters/agui-adapter.d.mts +1 -1
- package/dist/adapters/agui-adapter.d.ts +1 -1
- package/dist/adapters/agui-adapter.js +69 -18
- package/dist/adapters/agui-adapter.js.map +1 -1
- package/dist/adapters/agui-adapter.mjs +69 -18
- 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 +69 -18
- package/dist/adapters/ai-adapter.js.map +1 -1
- package/dist/adapters/ai-adapter.mjs +69 -18
- 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 +69 -18
- package/dist/adapters/langchain-adapter.js.map +1 -1
- package/dist/adapters/langchain-adapter.mjs +69 -18
- 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 +200 -42
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +200 -43
- package/dist/index.mjs.map +1 -1
- package/dist/server/index.js +1 -3
- package/dist/server/index.js.map +1 -1
- package/dist/server/index.mjs +1 -3
- package/dist/server/index.mjs.map +1 -1
- package/dist/shared/index.d.mts +15 -8
- package/dist/shared/index.d.ts +15 -8
- package/dist/shared/index.js +199 -39
- package/dist/shared/index.js.map +1 -1
- package/dist/shared/index.mjs +199 -40
- package/dist/shared/index.mjs.map +1 -1
- package/dist/{tool-router-DsKhRmJm.d.ts → tool-router-Bn9R0KWr.d.ts} +56 -7
- package/dist/{tool-router-DK0RJblO.d.mts → tool-router-_O2tIwf7.d.mts} +56 -7
- package/package.json +3 -1
- package/src/server/mcp/oauth-client.ts +4 -4
- package/src/shared/index.ts +4 -0
- package/src/shared/meta-tools.ts +163 -37
- package/src/shared/tool-index.ts +123 -7
- package/src/shared/tool-router.ts +40 -7
package/src/shared/tool-index.ts
CHANGED
|
@@ -32,6 +32,43 @@ export interface ToolSummary {
|
|
|
32
32
|
estimatedTokens: number;
|
|
33
33
|
}
|
|
34
34
|
|
|
35
|
+
/** Server-level summary derived from indexed tools. */
|
|
36
|
+
export interface ToolServerSummary {
|
|
37
|
+
/** Human-readable server name */
|
|
38
|
+
serverName: string;
|
|
39
|
+
/** Stable server identifier */
|
|
40
|
+
serverId: string;
|
|
41
|
+
/** Session the server belongs to */
|
|
42
|
+
sessionId: string;
|
|
43
|
+
/** Number of indexed tools for this server */
|
|
44
|
+
toolCount: number;
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
/** Optional filters for search and listing. */
|
|
48
|
+
export interface ToolSearchOptions {
|
|
49
|
+
/** Restrict results to this server ID. */
|
|
50
|
+
serverId?: string;
|
|
51
|
+
/** Restrict results to servers whose name or ID matches this value. */
|
|
52
|
+
serverName?: string;
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
/** Paginated tool listing result. */
|
|
56
|
+
export interface ToolListResult {
|
|
57
|
+
tools: ToolSummary[];
|
|
58
|
+
totalCount: number;
|
|
59
|
+
returnedCount: number;
|
|
60
|
+
nextCursor?: string;
|
|
61
|
+
servers: ToolServerSummary[];
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
export interface ToolLookupOptions {
|
|
65
|
+
/**
|
|
66
|
+
* Allow namespace to match a fragment of serverName after exact
|
|
67
|
+
* sessionId/serverId matching fails.
|
|
68
|
+
*/
|
|
69
|
+
allowServerNameFragment?: boolean;
|
|
70
|
+
}
|
|
71
|
+
|
|
35
72
|
/** A tool with routing metadata attached during indexing. */
|
|
36
73
|
export interface IndexedTool extends Tool {
|
|
37
74
|
sessionId: string;
|
|
@@ -259,14 +296,14 @@ export class ToolIndex {
|
|
|
259
296
|
*
|
|
260
297
|
* `score = keywordWeight × keyword_score + (1 - keywordWeight) × cosine_score`
|
|
261
298
|
*/
|
|
262
|
-
async search(query: string, topK = 5): Promise<ToolSummary[]> {
|
|
299
|
+
async search(query: string, topK = 5, options: ToolSearchOptions = {}): Promise<ToolSummary[]> {
|
|
263
300
|
if (this.tools.size === 0) return [];
|
|
264
301
|
|
|
265
302
|
const queryLower = query.toLowerCase().trim();
|
|
266
303
|
|
|
267
304
|
// Fast path: Exact tool name match (supports duplicate names across servers)
|
|
268
305
|
const exactMatches = [...this.toolSummaries.values()].filter(
|
|
269
|
-
(summary) => summary.name.toLowerCase() === queryLower
|
|
306
|
+
(summary) => summary.name.toLowerCase() === queryLower && this.matchesServer(summary, options)
|
|
270
307
|
);
|
|
271
308
|
if (exactMatches.length > 0) {
|
|
272
309
|
return exactMatches.slice(0, topK);
|
|
@@ -275,7 +312,7 @@ export class ToolIndex {
|
|
|
275
312
|
// Fast path: MCP prefix match (e.g. "mcp__github")
|
|
276
313
|
if (queryLower.startsWith('mcp__') && queryLower.length > 5) {
|
|
277
314
|
const prefixMatches = [...this.toolSummaries.values()]
|
|
278
|
-
.filter((t) => t.name.toLowerCase().startsWith(queryLower))
|
|
315
|
+
.filter((t) => t.name.toLowerCase().startsWith(queryLower) && this.matchesServer(t, options))
|
|
279
316
|
.slice(0, topK);
|
|
280
317
|
if (prefixMatches.length > 0) return prefixMatches;
|
|
281
318
|
}
|
|
@@ -300,9 +337,11 @@ export class ToolIndex {
|
|
|
300
337
|
// Pre-filter: only keep documents that contain ALL required terms
|
|
301
338
|
const candidateKeys = new Set<string>();
|
|
302
339
|
for (const docKey of this.toolSummaries.keys()) {
|
|
340
|
+
const summary = this.toolSummaries.get(docKey)!;
|
|
341
|
+
if (!this.matchesServer(summary, options)) continue;
|
|
342
|
+
|
|
303
343
|
if (requiredTerms.length > 0) {
|
|
304
344
|
const text = this.searchTexts.get(docKey) || '';
|
|
305
|
-
const summary = this.toolSummaries.get(docKey)!;
|
|
306
345
|
const nameLower = summary.name.toLowerCase();
|
|
307
346
|
const matchesAll = requiredTerms.every(
|
|
308
347
|
(term) => text.includes(term) || nameLower.includes(term)
|
|
@@ -456,13 +495,22 @@ export class ToolIndex {
|
|
|
456
495
|
|
|
457
496
|
/**
|
|
458
497
|
* Get tool definition(s) by name.
|
|
459
|
-
* If namespace is provided,
|
|
498
|
+
* If namespace is provided, exact sessionId/serverId matches take precedence.
|
|
499
|
+
* Falls back to serverName fragment matching only when explicitly allowed.
|
|
460
500
|
*/
|
|
461
|
-
getTool(name: string, namespace?: string): IndexedTool[] {
|
|
501
|
+
getTool(name: string, namespace?: string, options: ToolLookupOptions = {}): IndexedTool[] {
|
|
462
502
|
const list = this.tools.get(name) ?? [];
|
|
463
503
|
if (!namespace) return list;
|
|
464
504
|
|
|
465
|
-
|
|
505
|
+
const exactMatches = list.filter(
|
|
506
|
+
(t) => t.sessionId === namespace || t.serverId === namespace
|
|
507
|
+
);
|
|
508
|
+
if (exactMatches.length > 0) return exactMatches;
|
|
509
|
+
|
|
510
|
+
if (!options.allowServerNameFragment) return [];
|
|
511
|
+
|
|
512
|
+
const namespaceLower = namespace.toLowerCase();
|
|
513
|
+
return list.filter((t) => t.serverName.toLowerCase().includes(namespaceLower));
|
|
466
514
|
}
|
|
467
515
|
|
|
468
516
|
/** All indexed tool names. */
|
|
@@ -470,6 +518,57 @@ export class ToolIndex {
|
|
|
470
518
|
return [...this.tools.keys()];
|
|
471
519
|
}
|
|
472
520
|
|
|
521
|
+
/** List indexed servers with tool counts. */
|
|
522
|
+
listServers(options: ToolSearchOptions = {}): ToolServerSummary[] {
|
|
523
|
+
const servers = new Map<string, ToolServerSummary>();
|
|
524
|
+
|
|
525
|
+
for (const summary of this.toolSummaries.values()) {
|
|
526
|
+
if (!this.matchesServer(summary, options)) continue;
|
|
527
|
+
|
|
528
|
+
const key = `${summary.sessionId}::${summary.serverId}`;
|
|
529
|
+
const existing = servers.get(key);
|
|
530
|
+
if (existing) {
|
|
531
|
+
existing.toolCount += 1;
|
|
532
|
+
} else {
|
|
533
|
+
servers.set(key, {
|
|
534
|
+
serverName: summary.serverName,
|
|
535
|
+
serverId: summary.serverId,
|
|
536
|
+
sessionId: summary.sessionId,
|
|
537
|
+
toolCount: 1,
|
|
538
|
+
});
|
|
539
|
+
}
|
|
540
|
+
}
|
|
541
|
+
|
|
542
|
+
return [...servers.values()].sort((a, b) => {
|
|
543
|
+
const byName = a.serverName.localeCompare(b.serverName);
|
|
544
|
+
return byName !== 0 ? byName : a.serverId.localeCompare(b.serverId);
|
|
545
|
+
});
|
|
546
|
+
}
|
|
547
|
+
|
|
548
|
+
/** List tools deterministically, optionally scoped to a server. */
|
|
549
|
+
listTools(options: ToolSearchOptions & { limit?: number; cursor?: string } = {}): ToolListResult {
|
|
550
|
+
const offset = Math.max(Number(options.cursor) || 0, 0);
|
|
551
|
+
const limit = Math.max(Number(options.limit) || 20, 1);
|
|
552
|
+
const tools = [...this.toolSummaries.values()]
|
|
553
|
+
.filter((summary) => this.matchesServer(summary, options))
|
|
554
|
+
.sort((a, b) => {
|
|
555
|
+
const byServer = a.serverName.localeCompare(b.serverName);
|
|
556
|
+
if (byServer !== 0) return byServer;
|
|
557
|
+
return a.name.localeCompare(b.name);
|
|
558
|
+
});
|
|
559
|
+
|
|
560
|
+
const page = tools.slice(offset, offset + limit);
|
|
561
|
+
const nextOffset = offset + page.length;
|
|
562
|
+
|
|
563
|
+
return {
|
|
564
|
+
tools: page,
|
|
565
|
+
totalCount: tools.length,
|
|
566
|
+
returnedCount: page.length,
|
|
567
|
+
nextCursor: nextOffset < tools.length ? String(nextOffset) : undefined,
|
|
568
|
+
servers: this.listServers(options),
|
|
569
|
+
};
|
|
570
|
+
}
|
|
571
|
+
|
|
473
572
|
/** Number of indexed tools (including duplicates). */
|
|
474
573
|
get size(): number {
|
|
475
574
|
let count = 0;
|
|
@@ -539,6 +638,23 @@ export class ToolIndex {
|
|
|
539
638
|
return `${tool.sessionId}::${tool.serverId}::${tool.name}`;
|
|
540
639
|
}
|
|
541
640
|
|
|
641
|
+
private matchesServer(summary: ToolSummary, options: ToolSearchOptions): boolean {
|
|
642
|
+
if (options.serverId && summary.serverId !== options.serverId) {
|
|
643
|
+
return false;
|
|
644
|
+
}
|
|
645
|
+
|
|
646
|
+
if (options.serverName) {
|
|
647
|
+
const serverNameQuery = options.serverName.toLowerCase();
|
|
648
|
+
const serverName = summary.serverName.toLowerCase();
|
|
649
|
+
const serverId = summary.serverId.toLowerCase();
|
|
650
|
+
if (!serverName.includes(serverNameQuery) && !serverId.includes(serverNameQuery)) {
|
|
651
|
+
return false;
|
|
652
|
+
}
|
|
653
|
+
}
|
|
654
|
+
|
|
655
|
+
return true;
|
|
656
|
+
}
|
|
657
|
+
|
|
542
658
|
/** Simple whitespace + camelCase + snake_case tokenizer. */
|
|
543
659
|
private tokenize(text: string): string[] {
|
|
544
660
|
return text
|
|
@@ -28,10 +28,20 @@
|
|
|
28
28
|
|
|
29
29
|
import type { Tool } from '@modelcontextprotocol/sdk/types.js';
|
|
30
30
|
import type { ToolClient, ToolClientProvider } from './types.js';
|
|
31
|
-
import {
|
|
31
|
+
import {
|
|
32
|
+
ToolIndex,
|
|
33
|
+
type IndexedTool,
|
|
34
|
+
type ToolLookupOptions,
|
|
35
|
+
type ToolListResult,
|
|
36
|
+
type ToolSearchOptions,
|
|
37
|
+
type ToolServerSummary,
|
|
38
|
+
type ToolSummary,
|
|
39
|
+
type EmbedFn,
|
|
40
|
+
} from './tool-index.js';
|
|
32
41
|
import { SchemaCompressor, type CompactTool } from './schema-compressor.js';
|
|
33
42
|
import {
|
|
34
43
|
createSearchToolDefinition,
|
|
44
|
+
createListServersToolDefinition,
|
|
35
45
|
createRegexSearchToolDefinition,
|
|
36
46
|
createGetSchemaToolDefinition,
|
|
37
47
|
createExecuteToolDefinition,
|
|
@@ -159,7 +169,7 @@ export class ToolRouter {
|
|
|
159
169
|
* This is the main method adapters should call.
|
|
160
170
|
*
|
|
161
171
|
* - `all` → returns all tools (unchanged behavior)
|
|
162
|
-
* - `search` → returns only meta-tools (
|
|
172
|
+
* - `search` → returns only meta-tools (mcp_search_tools, mcp_get_tool_schema, mcp_execute_tool)
|
|
163
173
|
* - `groups` → returns tools from active groups only
|
|
164
174
|
*/
|
|
165
175
|
async getFilteredTools(): Promise<Tool[]> {
|
|
@@ -195,9 +205,14 @@ export class ToolRouter {
|
|
|
195
205
|
* Search tools by natural-language query.
|
|
196
206
|
* Works regardless of strategy.
|
|
197
207
|
*/
|
|
198
|
-
async searchTools(
|
|
208
|
+
async searchTools(
|
|
209
|
+
query: string,
|
|
210
|
+
topK?: number,
|
|
211
|
+
options: ToolSearchOptions = {}
|
|
212
|
+
): Promise<ToolSummary[]> {
|
|
199
213
|
await this.ensureInitialized();
|
|
200
|
-
|
|
214
|
+
const limit = topK ?? this.maxTools;
|
|
215
|
+
return this.index.search(query, limit, options);
|
|
201
216
|
}
|
|
202
217
|
|
|
203
218
|
/**
|
|
@@ -209,12 +224,28 @@ export class ToolRouter {
|
|
|
209
224
|
return this.index.searchRegex(pattern, topK ?? this.maxTools);
|
|
210
225
|
}
|
|
211
226
|
|
|
227
|
+
/** List connected MCP servers with indexed tool counts. */
|
|
228
|
+
async listServers(options: ToolSearchOptions = {}): Promise<ToolServerSummary[]> {
|
|
229
|
+
await this.ensureInitialized();
|
|
230
|
+
return this.index.listServers(options);
|
|
231
|
+
}
|
|
232
|
+
|
|
233
|
+
/** List tools deterministically, optionally scoped to a server. */
|
|
234
|
+
async listTools(options: ToolSearchOptions & { limit?: number; cursor?: string } = {}): Promise<ToolListResult> {
|
|
235
|
+
await this.ensureInitialized();
|
|
236
|
+
return this.index.listTools(options);
|
|
237
|
+
}
|
|
238
|
+
|
|
212
239
|
/**
|
|
213
240
|
* Get the full tool definition by name.
|
|
214
241
|
* If tool name is ambiguous, use namespace to specify the server.
|
|
215
242
|
*/
|
|
216
|
-
getToolSchema(
|
|
217
|
-
|
|
243
|
+
getToolSchema(
|
|
244
|
+
toolName: string,
|
|
245
|
+
namespace?: string,
|
|
246
|
+
options: ToolLookupOptions = {}
|
|
247
|
+
): IndexedTool | undefined {
|
|
248
|
+
const matches = this.index.getTool(toolName, namespace, options);
|
|
218
249
|
|
|
219
250
|
if (matches.length === 0) return undefined;
|
|
220
251
|
|
|
@@ -318,7 +349,7 @@ export class ToolRouter {
|
|
|
318
349
|
throw new Error(
|
|
319
350
|
`Tool "${toolName}" not found${
|
|
320
351
|
namespace ? ` on server "${namespace}"` : ''
|
|
321
|
-
}. Use
|
|
352
|
+
}. Use mcp_search_tools or mcp_search_tool_regex to discover available tools.`
|
|
322
353
|
);
|
|
323
354
|
}
|
|
324
355
|
|
|
@@ -462,9 +493,11 @@ export class ToolRouter {
|
|
|
462
493
|
private getMetaToolDefinitions(): Tool[] {
|
|
463
494
|
return [
|
|
464
495
|
createSearchToolDefinition(),
|
|
496
|
+
createListServersToolDefinition(),
|
|
465
497
|
createRegexSearchToolDefinition(),
|
|
466
498
|
createGetSchemaToolDefinition(),
|
|
467
499
|
createExecuteToolDefinition(),
|
|
468
500
|
];
|
|
469
501
|
}
|
|
502
|
+
|
|
470
503
|
}
|