@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
|
@@ -80,6 +80,39 @@ interface ToolSummary {
|
|
|
80
80
|
/** Estimated token cost of the full inputSchema */
|
|
81
81
|
estimatedTokens: number;
|
|
82
82
|
}
|
|
83
|
+
/** Server-level summary derived from indexed tools. */
|
|
84
|
+
interface ToolServerSummary {
|
|
85
|
+
/** Human-readable server name */
|
|
86
|
+
serverName: string;
|
|
87
|
+
/** Stable server identifier */
|
|
88
|
+
serverId: string;
|
|
89
|
+
/** Session the server belongs to */
|
|
90
|
+
sessionId: string;
|
|
91
|
+
/** Number of indexed tools for this server */
|
|
92
|
+
toolCount: number;
|
|
93
|
+
}
|
|
94
|
+
/** Optional filters for search and listing. */
|
|
95
|
+
interface ToolSearchOptions {
|
|
96
|
+
/** Restrict results to this server ID. */
|
|
97
|
+
serverId?: string;
|
|
98
|
+
/** Restrict results to servers whose name or ID matches this value. */
|
|
99
|
+
serverName?: string;
|
|
100
|
+
}
|
|
101
|
+
/** Paginated tool listing result. */
|
|
102
|
+
interface ToolListResult {
|
|
103
|
+
tools: ToolSummary[];
|
|
104
|
+
totalCount: number;
|
|
105
|
+
returnedCount: number;
|
|
106
|
+
nextCursor?: string;
|
|
107
|
+
servers: ToolServerSummary[];
|
|
108
|
+
}
|
|
109
|
+
interface ToolLookupOptions {
|
|
110
|
+
/**
|
|
111
|
+
* Allow namespace to match a fragment of serverName after exact
|
|
112
|
+
* sessionId/serverId matching fails.
|
|
113
|
+
*/
|
|
114
|
+
allowServerNameFragment?: boolean;
|
|
115
|
+
}
|
|
83
116
|
/** A tool with routing metadata attached during indexing. */
|
|
84
117
|
interface IndexedTool extends Tool {
|
|
85
118
|
sessionId: string;
|
|
@@ -147,7 +180,7 @@ declare class ToolIndex {
|
|
|
147
180
|
*
|
|
148
181
|
* `score = keywordWeight × keyword_score + (1 - keywordWeight) × cosine_score`
|
|
149
182
|
*/
|
|
150
|
-
search(query: string, topK?: number): Promise<ToolSummary[]>;
|
|
183
|
+
search(query: string, topK?: number, options?: ToolSearchOptions): Promise<ToolSummary[]>;
|
|
151
184
|
/**
|
|
152
185
|
* Search tools using a regex pattern.
|
|
153
186
|
* Matches against name, description, and parameter metadata.
|
|
@@ -155,11 +188,19 @@ declare class ToolIndex {
|
|
|
155
188
|
searchRegex(pattern: string, topK?: number): ToolSummary[];
|
|
156
189
|
/**
|
|
157
190
|
* Get tool definition(s) by name.
|
|
158
|
-
* If namespace is provided,
|
|
191
|
+
* If namespace is provided, exact sessionId/serverId matches take precedence.
|
|
192
|
+
* Falls back to serverName fragment matching only when explicitly allowed.
|
|
159
193
|
*/
|
|
160
|
-
getTool(name: string, namespace?: string): IndexedTool[];
|
|
194
|
+
getTool(name: string, namespace?: string, options?: ToolLookupOptions): IndexedTool[];
|
|
161
195
|
/** All indexed tool names. */
|
|
162
196
|
getToolNames(): string[];
|
|
197
|
+
/** List indexed servers with tool counts. */
|
|
198
|
+
listServers(options?: ToolSearchOptions): ToolServerSummary[];
|
|
199
|
+
/** List tools deterministically, optionally scoped to a server. */
|
|
200
|
+
listTools(options?: ToolSearchOptions & {
|
|
201
|
+
limit?: number;
|
|
202
|
+
cursor?: string;
|
|
203
|
+
}): ToolListResult;
|
|
163
204
|
/** Number of indexed tools (including duplicates). */
|
|
164
205
|
get size(): number;
|
|
165
206
|
/** Total estimated token cost of all indexed tool schemas. */
|
|
@@ -174,6 +215,7 @@ declare class ToolIndex {
|
|
|
174
215
|
/** Build a single searchable string from tool metadata. */
|
|
175
216
|
private buildSearchableText;
|
|
176
217
|
private getDocumentKey;
|
|
218
|
+
private matchesServer;
|
|
177
219
|
/** Simple whitespace + camelCase + snake_case tokenizer. */
|
|
178
220
|
private tokenize;
|
|
179
221
|
/** Cosine similarity between two vectors. */
|
|
@@ -262,7 +304,7 @@ declare class ToolRouter {
|
|
|
262
304
|
* This is the main method adapters should call.
|
|
263
305
|
*
|
|
264
306
|
* - `all` → returns all tools (unchanged behavior)
|
|
265
|
-
* - `search` → returns only meta-tools (
|
|
307
|
+
* - `search` → returns only meta-tools (mcp_search_tools, mcp_get_tool_schema, mcp_execute_tool)
|
|
266
308
|
* - `groups` → returns tools from active groups only
|
|
267
309
|
*/
|
|
268
310
|
getFilteredTools(): Promise<Tool[]>;
|
|
@@ -270,17 +312,24 @@ declare class ToolRouter {
|
|
|
270
312
|
* Search tools by natural-language query.
|
|
271
313
|
* Works regardless of strategy.
|
|
272
314
|
*/
|
|
273
|
-
searchTools(query: string, topK?: number): Promise<ToolSummary[]>;
|
|
315
|
+
searchTools(query: string, topK?: number, options?: ToolSearchOptions): Promise<ToolSummary[]>;
|
|
274
316
|
/**
|
|
275
317
|
* Search tools by regex pattern.
|
|
276
318
|
* Matches against name, description, and parameter metadata.
|
|
277
319
|
*/
|
|
278
320
|
searchToolsRegex(pattern: string, topK?: number): Promise<ToolSummary[]>;
|
|
321
|
+
/** List connected MCP servers with indexed tool counts. */
|
|
322
|
+
listServers(options?: ToolSearchOptions): Promise<ToolServerSummary[]>;
|
|
323
|
+
/** List tools deterministically, optionally scoped to a server. */
|
|
324
|
+
listTools(options?: ToolSearchOptions & {
|
|
325
|
+
limit?: number;
|
|
326
|
+
cursor?: string;
|
|
327
|
+
}): Promise<ToolListResult>;
|
|
279
328
|
/**
|
|
280
329
|
* Get the full tool definition by name.
|
|
281
330
|
* If tool name is ambiguous, use namespace to specify the server.
|
|
282
331
|
*/
|
|
283
|
-
getToolSchema(toolName: string, namespace?: string): IndexedTool | undefined;
|
|
332
|
+
getToolSchema(toolName: string, namespace?: string, options?: ToolLookupOptions): IndexedTool | undefined;
|
|
284
333
|
/**
|
|
285
334
|
* Get compact (schema-less) summaries for all tools.
|
|
286
335
|
*/
|
|
@@ -325,4 +374,4 @@ declare class ToolRouter {
|
|
|
325
374
|
private getMetaToolDefinitions;
|
|
326
375
|
}
|
|
327
376
|
|
|
328
|
-
export { type CompactTool as C, type EmbedFn as E, type IndexedTool as I, SchemaCompressor as S, type ToolGroupInfo as T, type CompressionStats as a, ToolIndex as b, type ToolIndexOptions as c,
|
|
377
|
+
export { type CompactTool as C, type EmbedFn as E, type IndexedTool as I, SchemaCompressor as S, type ToolGroupInfo as T, type CompressionStats as a, ToolIndex as b, type ToolIndexOptions as c, type ToolListResult as d, ToolRouter as e, type ToolRouterClientInput as f, type ToolRouterOptions as g, type ToolRouterStrategy as h, type ToolSearchOptions as i, type ToolServerSummary as j, type ToolSummary as k };
|
|
@@ -80,6 +80,39 @@ interface ToolSummary {
|
|
|
80
80
|
/** Estimated token cost of the full inputSchema */
|
|
81
81
|
estimatedTokens: number;
|
|
82
82
|
}
|
|
83
|
+
/** Server-level summary derived from indexed tools. */
|
|
84
|
+
interface ToolServerSummary {
|
|
85
|
+
/** Human-readable server name */
|
|
86
|
+
serverName: string;
|
|
87
|
+
/** Stable server identifier */
|
|
88
|
+
serverId: string;
|
|
89
|
+
/** Session the server belongs to */
|
|
90
|
+
sessionId: string;
|
|
91
|
+
/** Number of indexed tools for this server */
|
|
92
|
+
toolCount: number;
|
|
93
|
+
}
|
|
94
|
+
/** Optional filters for search and listing. */
|
|
95
|
+
interface ToolSearchOptions {
|
|
96
|
+
/** Restrict results to this server ID. */
|
|
97
|
+
serverId?: string;
|
|
98
|
+
/** Restrict results to servers whose name or ID matches this value. */
|
|
99
|
+
serverName?: string;
|
|
100
|
+
}
|
|
101
|
+
/** Paginated tool listing result. */
|
|
102
|
+
interface ToolListResult {
|
|
103
|
+
tools: ToolSummary[];
|
|
104
|
+
totalCount: number;
|
|
105
|
+
returnedCount: number;
|
|
106
|
+
nextCursor?: string;
|
|
107
|
+
servers: ToolServerSummary[];
|
|
108
|
+
}
|
|
109
|
+
interface ToolLookupOptions {
|
|
110
|
+
/**
|
|
111
|
+
* Allow namespace to match a fragment of serverName after exact
|
|
112
|
+
* sessionId/serverId matching fails.
|
|
113
|
+
*/
|
|
114
|
+
allowServerNameFragment?: boolean;
|
|
115
|
+
}
|
|
83
116
|
/** A tool with routing metadata attached during indexing. */
|
|
84
117
|
interface IndexedTool extends Tool {
|
|
85
118
|
sessionId: string;
|
|
@@ -147,7 +180,7 @@ declare class ToolIndex {
|
|
|
147
180
|
*
|
|
148
181
|
* `score = keywordWeight × keyword_score + (1 - keywordWeight) × cosine_score`
|
|
149
182
|
*/
|
|
150
|
-
search(query: string, topK?: number): Promise<ToolSummary[]>;
|
|
183
|
+
search(query: string, topK?: number, options?: ToolSearchOptions): Promise<ToolSummary[]>;
|
|
151
184
|
/**
|
|
152
185
|
* Search tools using a regex pattern.
|
|
153
186
|
* Matches against name, description, and parameter metadata.
|
|
@@ -155,11 +188,19 @@ declare class ToolIndex {
|
|
|
155
188
|
searchRegex(pattern: string, topK?: number): ToolSummary[];
|
|
156
189
|
/**
|
|
157
190
|
* Get tool definition(s) by name.
|
|
158
|
-
* If namespace is provided,
|
|
191
|
+
* If namespace is provided, exact sessionId/serverId matches take precedence.
|
|
192
|
+
* Falls back to serverName fragment matching only when explicitly allowed.
|
|
159
193
|
*/
|
|
160
|
-
getTool(name: string, namespace?: string): IndexedTool[];
|
|
194
|
+
getTool(name: string, namespace?: string, options?: ToolLookupOptions): IndexedTool[];
|
|
161
195
|
/** All indexed tool names. */
|
|
162
196
|
getToolNames(): string[];
|
|
197
|
+
/** List indexed servers with tool counts. */
|
|
198
|
+
listServers(options?: ToolSearchOptions): ToolServerSummary[];
|
|
199
|
+
/** List tools deterministically, optionally scoped to a server. */
|
|
200
|
+
listTools(options?: ToolSearchOptions & {
|
|
201
|
+
limit?: number;
|
|
202
|
+
cursor?: string;
|
|
203
|
+
}): ToolListResult;
|
|
163
204
|
/** Number of indexed tools (including duplicates). */
|
|
164
205
|
get size(): number;
|
|
165
206
|
/** Total estimated token cost of all indexed tool schemas. */
|
|
@@ -174,6 +215,7 @@ declare class ToolIndex {
|
|
|
174
215
|
/** Build a single searchable string from tool metadata. */
|
|
175
216
|
private buildSearchableText;
|
|
176
217
|
private getDocumentKey;
|
|
218
|
+
private matchesServer;
|
|
177
219
|
/** Simple whitespace + camelCase + snake_case tokenizer. */
|
|
178
220
|
private tokenize;
|
|
179
221
|
/** Cosine similarity between two vectors. */
|
|
@@ -262,7 +304,7 @@ declare class ToolRouter {
|
|
|
262
304
|
* This is the main method adapters should call.
|
|
263
305
|
*
|
|
264
306
|
* - `all` → returns all tools (unchanged behavior)
|
|
265
|
-
* - `search` → returns only meta-tools (
|
|
307
|
+
* - `search` → returns only meta-tools (mcp_search_tools, mcp_get_tool_schema, mcp_execute_tool)
|
|
266
308
|
* - `groups` → returns tools from active groups only
|
|
267
309
|
*/
|
|
268
310
|
getFilteredTools(): Promise<Tool[]>;
|
|
@@ -270,17 +312,24 @@ declare class ToolRouter {
|
|
|
270
312
|
* Search tools by natural-language query.
|
|
271
313
|
* Works regardless of strategy.
|
|
272
314
|
*/
|
|
273
|
-
searchTools(query: string, topK?: number): Promise<ToolSummary[]>;
|
|
315
|
+
searchTools(query: string, topK?: number, options?: ToolSearchOptions): Promise<ToolSummary[]>;
|
|
274
316
|
/**
|
|
275
317
|
* Search tools by regex pattern.
|
|
276
318
|
* Matches against name, description, and parameter metadata.
|
|
277
319
|
*/
|
|
278
320
|
searchToolsRegex(pattern: string, topK?: number): Promise<ToolSummary[]>;
|
|
321
|
+
/** List connected MCP servers with indexed tool counts. */
|
|
322
|
+
listServers(options?: ToolSearchOptions): Promise<ToolServerSummary[]>;
|
|
323
|
+
/** List tools deterministically, optionally scoped to a server. */
|
|
324
|
+
listTools(options?: ToolSearchOptions & {
|
|
325
|
+
limit?: number;
|
|
326
|
+
cursor?: string;
|
|
327
|
+
}): Promise<ToolListResult>;
|
|
279
328
|
/**
|
|
280
329
|
* Get the full tool definition by name.
|
|
281
330
|
* If tool name is ambiguous, use namespace to specify the server.
|
|
282
331
|
*/
|
|
283
|
-
getToolSchema(toolName: string, namespace?: string): IndexedTool | undefined;
|
|
332
|
+
getToolSchema(toolName: string, namespace?: string, options?: ToolLookupOptions): IndexedTool | undefined;
|
|
284
333
|
/**
|
|
285
334
|
* Get compact (schema-less) summaries for all tools.
|
|
286
335
|
*/
|
|
@@ -325,4 +374,4 @@ declare class ToolRouter {
|
|
|
325
374
|
private getMetaToolDefinitions;
|
|
326
375
|
}
|
|
327
376
|
|
|
328
|
-
export { type CompactTool as C, type EmbedFn as E, type IndexedTool as I, SchemaCompressor as S, type ToolGroupInfo as T, type CompressionStats as a, ToolIndex as b, type ToolIndexOptions as c,
|
|
377
|
+
export { type CompactTool as C, type EmbedFn as E, type IndexedTool as I, SchemaCompressor as S, type ToolGroupInfo as T, type CompressionStats as a, ToolIndex as b, type ToolIndexOptions as c, type ToolListResult as d, ToolRouter as e, type ToolRouterClientInput as f, type ToolRouterOptions as g, type ToolRouterStrategy as h, type ToolSearchOptions as i, type ToolServerSummary as j, type ToolSummary as k };
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@mcp-ts/sdk",
|
|
3
|
-
"version": "1.
|
|
3
|
+
"version": "1.6.0",
|
|
4
4
|
"publishConfig": {
|
|
5
5
|
"access": "public"
|
|
6
6
|
},
|
|
@@ -84,6 +84,8 @@
|
|
|
84
84
|
"test": "npx playwright test",
|
|
85
85
|
"test:ui": "npx playwright test --ui",
|
|
86
86
|
"test:debug": "npx playwright test --debug",
|
|
87
|
+
"benchmark:toolrouter": "npm run build && node benchmarks/toolrouter-efficiency.mjs",
|
|
88
|
+
"benchmark:toolrouter:live": "npm run build && node benchmarks/toolrouter-live.mjs",
|
|
87
89
|
"supabase:push": "supabase db push",
|
|
88
90
|
"supabase:reset": "supabase db reset",
|
|
89
91
|
"supabase:status": "supabase status",
|
|
@@ -1126,9 +1126,10 @@ export class MCPClient {
|
|
|
1126
1126
|
* @returns Server name or undefined
|
|
1127
1127
|
*/
|
|
1128
1128
|
getServerName(): string | undefined {
|
|
1129
|
-
|
|
1130
|
-
|
|
1131
|
-
return info?.title ?? info?.name ?? this.serverName;
|
|
1129
|
+
// Temporarily avoid deriving serverName from serverVersion metadata.
|
|
1130
|
+
// const info = (this.client as any)?.getServerVersion();
|
|
1131
|
+
// return info?.title ?? info?.name ?? this.serverName;
|
|
1132
|
+
return this.serverName;
|
|
1132
1133
|
}
|
|
1133
1134
|
|
|
1134
1135
|
/**
|
|
@@ -1228,4 +1229,3 @@ export class MCPClient {
|
|
|
1228
1229
|
}
|
|
1229
1230
|
|
|
1230
1231
|
}
|
|
1231
|
-
|
package/src/shared/index.ts
CHANGED
|
@@ -87,6 +87,9 @@ export {
|
|
|
87
87
|
export {
|
|
88
88
|
ToolIndex,
|
|
89
89
|
type ToolSummary,
|
|
90
|
+
type ToolServerSummary,
|
|
91
|
+
type ToolSearchOptions,
|
|
92
|
+
type ToolListResult,
|
|
90
93
|
type IndexedTool,
|
|
91
94
|
type ToolIndexOptions,
|
|
92
95
|
type EmbedFn,
|
|
@@ -100,6 +103,7 @@ export {
|
|
|
100
103
|
|
|
101
104
|
export {
|
|
102
105
|
createSearchToolDefinition,
|
|
106
|
+
createListServersToolDefinition,
|
|
103
107
|
createRegexSearchToolDefinition,
|
|
104
108
|
createGetSchemaToolDefinition,
|
|
105
109
|
createExecuteToolDefinition,
|
package/src/shared/meta-tools.ts
CHANGED
|
@@ -7,7 +7,7 @@
|
|
|
7
7
|
* only the tools it actually needs.
|
|
8
8
|
*
|
|
9
9
|
* Meta-tools:
|
|
10
|
-
* • `
|
|
10
|
+
* • `mcp_search_tools` — Search/list available tools
|
|
11
11
|
* • `mcp_search_tool_regex` — Regex pattern search
|
|
12
12
|
* • `mcp_get_tool_schema` — Get full inputSchema for a discovered tool
|
|
13
13
|
* • `mcp_execute_tool` — Execute a discovered tool
|
|
@@ -17,14 +17,14 @@
|
|
|
17
17
|
|
|
18
18
|
import type { Tool, CallToolResult } from '@modelcontextprotocol/sdk/types.js';
|
|
19
19
|
import type { ToolRouter } from './tool-router.js';
|
|
20
|
-
import type { IndexedTool } from './tool-index.js';
|
|
20
|
+
import type { IndexedTool, ToolLookupOptions } from './tool-index.js';
|
|
21
21
|
|
|
22
22
|
// ---------------------------------------------------------------------------
|
|
23
23
|
// Tool Definitions
|
|
24
24
|
// ---------------------------------------------------------------------------
|
|
25
25
|
|
|
26
26
|
/**
|
|
27
|
-
* Creates the `
|
|
27
|
+
* Creates the `mcp_search_tools` tool definition.
|
|
28
28
|
*
|
|
29
29
|
* This tool lets the LLM search the full catalog of available MCP tools
|
|
30
30
|
* using a BM25 natural-language query. Returns tool names and descriptions
|
|
@@ -32,7 +32,7 @@ import type { IndexedTool } from './tool-index.js';
|
|
|
32
32
|
*/
|
|
33
33
|
export function createSearchToolDefinition(): Tool {
|
|
34
34
|
return {
|
|
35
|
-
name: '
|
|
35
|
+
name: 'mcp_search_tools',
|
|
36
36
|
description:
|
|
37
37
|
'Search the catalog of available tools. Returns tool names, descriptions, and server info. ' +
|
|
38
38
|
'Use this FIRST to find relevant tools before calling them.\n\n' +
|
|
@@ -47,9 +47,28 @@ export function createSearchToolDefinition(): Tool {
|
|
|
47
47
|
type: 'string',
|
|
48
48
|
description: 'Query to find tools. Use "select:<tool_name>" for direct selection, or keywords to search. Prefix keywords with + to require them.',
|
|
49
49
|
},
|
|
50
|
+
operation: {
|
|
51
|
+
type: 'string',
|
|
52
|
+
enum: ['search', 'list'],
|
|
53
|
+
description:
|
|
54
|
+
'Operation to perform. Use "search" to find relevant tools by capability. Use "list" with serverId or serverName when the user asks for every tool from a connected MCP server.',
|
|
55
|
+
},
|
|
56
|
+
serverId: {
|
|
57
|
+
type: 'string',
|
|
58
|
+
description: 'Optional server ID to restrict search/list results to one MCP server.',
|
|
59
|
+
},
|
|
60
|
+
serverName: {
|
|
61
|
+
type: 'string',
|
|
62
|
+
description:
|
|
63
|
+
'Optional server name fragment to restrict search/list results to matching MCP servers, e.g. "supabase".',
|
|
64
|
+
},
|
|
50
65
|
limit: {
|
|
51
66
|
type: 'number',
|
|
52
|
-
description: 'Maximum number of results to return (default: 5, max: 20).',
|
|
67
|
+
description: 'Maximum number of results to return (default: 5 for search, 20 for list; max: 20 for search, 100 for list).',
|
|
68
|
+
},
|
|
69
|
+
cursor: {
|
|
70
|
+
type: 'string',
|
|
71
|
+
description: 'Optional pagination cursor returned by operation "list".',
|
|
53
72
|
},
|
|
54
73
|
},
|
|
55
74
|
required: ['query'],
|
|
@@ -57,6 +76,31 @@ export function createSearchToolDefinition(): Tool {
|
|
|
57
76
|
};
|
|
58
77
|
}
|
|
59
78
|
|
|
79
|
+
/**
|
|
80
|
+
* Creates the `mcp_list_servers` tool definition.
|
|
81
|
+
*
|
|
82
|
+
* This tool lets the LLM inspect connected MCP servers before doing
|
|
83
|
+
* server-scoped tool discovery.
|
|
84
|
+
*/
|
|
85
|
+
export function createListServersToolDefinition(): Tool {
|
|
86
|
+
return {
|
|
87
|
+
name: 'mcp_list_servers',
|
|
88
|
+
description:
|
|
89
|
+
'List connected MCP servers and their tool counts. ' +
|
|
90
|
+
'Use this when mcp_search_tools returns no matches, then retry mcp_search_tools with serverId or serverName.',
|
|
91
|
+
inputSchema: {
|
|
92
|
+
type: 'object' as const,
|
|
93
|
+
properties: {
|
|
94
|
+
query: {
|
|
95
|
+
type: 'string',
|
|
96
|
+
description:
|
|
97
|
+
'Optional server filter text. Matches server name or serverId, e.g. "web" or "supabase".',
|
|
98
|
+
},
|
|
99
|
+
},
|
|
100
|
+
},
|
|
101
|
+
};
|
|
102
|
+
}
|
|
103
|
+
|
|
60
104
|
/**
|
|
61
105
|
* Creates the `mcp_search_tool_regex` tool definition.
|
|
62
106
|
*
|
|
@@ -89,7 +133,7 @@ export function createRegexSearchToolDefinition(): Tool {
|
|
|
89
133
|
/**
|
|
90
134
|
* Creates the `mcp_get_tool_schema` tool definition.
|
|
91
135
|
*
|
|
92
|
-
* After discovering tools via `
|
|
136
|
+
* After discovering tools via `mcp_search_tools` or
|
|
93
137
|
* `mcp_search_tool_regex`, the LLM calls this to load the full
|
|
94
138
|
* inputSchema for a specific tool so it can construct the correct
|
|
95
139
|
* arguments.
|
|
@@ -99,7 +143,7 @@ export function createGetSchemaToolDefinition(): Tool {
|
|
|
99
143
|
name: 'mcp_get_tool_schema',
|
|
100
144
|
description:
|
|
101
145
|
'Get the full input schema (parameters) for a specific tool. ' +
|
|
102
|
-
'Call this after
|
|
146
|
+
'Call this after mcp_search_tools to get the parameter details ' +
|
|
103
147
|
'needed to call a tool correctly. ' +
|
|
104
148
|
'Do NOT call the discovered tool directly; after reading the schema, call mcp_execute_tool.',
|
|
105
149
|
inputSchema: {
|
|
@@ -107,12 +151,12 @@ export function createGetSchemaToolDefinition(): Tool {
|
|
|
107
151
|
properties: {
|
|
108
152
|
toolName: {
|
|
109
153
|
type: 'string',
|
|
110
|
-
description: 'The exact tool name returned by
|
|
154
|
+
description: 'The exact tool name returned by mcp_search_tools.',
|
|
111
155
|
},
|
|
112
156
|
serverId: {
|
|
113
157
|
type: 'string',
|
|
114
158
|
description:
|
|
115
|
-
'Optional: The server ID provided in
|
|
159
|
+
'Optional: The server ID provided in mcp_search_tools. Required if multiple tools have the same name.',
|
|
116
160
|
},
|
|
117
161
|
},
|
|
118
162
|
required: ['toolName'],
|
|
@@ -124,7 +168,7 @@ export function createGetSchemaToolDefinition(): Tool {
|
|
|
124
168
|
* Creates the `mcp_execute_tool` tool definition.
|
|
125
169
|
*
|
|
126
170
|
* This is the execution meta-tool — the LLM calls this to execute any
|
|
127
|
-
* tool discovered via `
|
|
171
|
+
* tool discovered via `mcp_search_tools` or `mcp_search_tool_regex`.
|
|
128
172
|
* The LLM should first call `mcp_get_tool_schema` to know the correct
|
|
129
173
|
* arguments.
|
|
130
174
|
*
|
|
@@ -135,7 +179,7 @@ export function createExecuteToolDefinition(): Tool {
|
|
|
135
179
|
return {
|
|
136
180
|
name: 'mcp_execute_tool',
|
|
137
181
|
description:
|
|
138
|
-
'Execute a tool that was discovered via
|
|
182
|
+
'Execute a tool that was discovered via mcp_search_tools. ' +
|
|
139
183
|
'You MUST call mcp_get_tool_schema first to know the correct parameters. ' +
|
|
140
184
|
'Pass the exact tool name and its arguments.',
|
|
141
185
|
inputSchema: {
|
|
@@ -143,12 +187,12 @@ export function createExecuteToolDefinition(): Tool {
|
|
|
143
187
|
properties: {
|
|
144
188
|
toolName: {
|
|
145
189
|
type: 'string',
|
|
146
|
-
description: 'The exact tool name from
|
|
190
|
+
description: 'The exact tool name from mcp_search_tools results.',
|
|
147
191
|
},
|
|
148
192
|
serverId: {
|
|
149
193
|
type: 'string',
|
|
150
194
|
description:
|
|
151
|
-
'Optional: The server ID provided in
|
|
195
|
+
'Optional: The server ID provided in mcp_search_tools. Required if multiple tools have the same name.',
|
|
152
196
|
},
|
|
153
197
|
args: {
|
|
154
198
|
type: 'object',
|
|
@@ -179,7 +223,7 @@ export type CallToolFn = (
|
|
|
179
223
|
/**
|
|
180
224
|
* Execute a meta-tool call and return the result in MCP CallToolResult format.
|
|
181
225
|
*
|
|
182
|
-
* @param toolName - One of the meta-tool names (
|
|
226
|
+
* @param toolName - One of the meta-tool names (mcp_search_tools, mcp_list_servers, mcp_search_tool_regex, etc.)
|
|
183
227
|
* @param args - The arguments from the LLM's tool call
|
|
184
228
|
* @param router - The ToolRouter to query
|
|
185
229
|
* @param callToolFn - Optional callback for executing real tools (required for mcp_execute_tool)
|
|
@@ -191,9 +235,13 @@ export async function executeMetaTool(
|
|
|
191
235
|
router: ToolRouter,
|
|
192
236
|
callToolFn?: CallToolFn
|
|
193
237
|
): Promise<CallToolResult | null> {
|
|
194
|
-
const resolveToolSchema = (
|
|
238
|
+
const resolveToolSchema = (
|
|
239
|
+
name: string,
|
|
240
|
+
namespace?: string,
|
|
241
|
+
options?: ToolLookupOptions
|
|
242
|
+
): { tool?: IndexedTool; error?: CallToolResult } => {
|
|
195
243
|
try {
|
|
196
|
-
return { tool: router.getToolSchema(name, namespace) };
|
|
244
|
+
return { tool: router.getToolSchema(name, namespace, options) };
|
|
197
245
|
} catch (err) {
|
|
198
246
|
const errorMessage = err instanceof Error ? err.message : String(err);
|
|
199
247
|
return {
|
|
@@ -206,13 +254,61 @@ export async function executeMetaTool(
|
|
|
206
254
|
};
|
|
207
255
|
|
|
208
256
|
switch (toolName) {
|
|
209
|
-
case '
|
|
257
|
+
case 'mcp_search_tools': {
|
|
210
258
|
const query = String(args.query ?? '');
|
|
259
|
+
const operation = String(args.operation ?? 'search');
|
|
260
|
+
const serverId = String(args.serverId ?? '') || undefined;
|
|
261
|
+
const serverName = String(args.serverName ?? '') || undefined;
|
|
262
|
+
|
|
263
|
+
if (operation === 'list') {
|
|
264
|
+
const limit = Math.min(Number(args.limit) || 20, 100);
|
|
265
|
+
const cursor = String(args.cursor ?? '') || undefined;
|
|
266
|
+
const result = await router.listTools({
|
|
267
|
+
serverId,
|
|
268
|
+
serverName: serverName ?? (!serverId && query ? query : undefined),
|
|
269
|
+
limit,
|
|
270
|
+
cursor,
|
|
271
|
+
});
|
|
272
|
+
|
|
273
|
+
const serverText = result.servers.length > 0
|
|
274
|
+
? result.servers
|
|
275
|
+
.map((server) => `${server.serverName} (serverId: ${server.serverId}, tools: ${server.toolCount})`)
|
|
276
|
+
.join(', ')
|
|
277
|
+
: 'none';
|
|
278
|
+
|
|
279
|
+
const lines: string[] = [
|
|
280
|
+
'operation: list',
|
|
281
|
+
`servers: ${serverText}`,
|
|
282
|
+
`totalCount: ${result.totalCount}`,
|
|
283
|
+
`returnedCount: ${result.returnedCount}`,
|
|
284
|
+
`nextCursor: ${result.nextCursor ?? 'null'}`,
|
|
285
|
+
'',
|
|
286
|
+
];
|
|
287
|
+
|
|
288
|
+
if (result.tools.length > 0) {
|
|
289
|
+
lines.push(...formatToolSummaries(result.tools));
|
|
290
|
+
} else {
|
|
291
|
+
lines.push(
|
|
292
|
+
serverId || serverName
|
|
293
|
+
? 'No tools found for the requested server scope.'
|
|
294
|
+
: 'No tools found. Try operation "search" or provide serverId/serverName.'
|
|
295
|
+
);
|
|
296
|
+
}
|
|
297
|
+
|
|
298
|
+
return {
|
|
299
|
+
content: [{ type: 'text', text: lines.join('\n') }],
|
|
300
|
+
isError: false,
|
|
301
|
+
};
|
|
302
|
+
}
|
|
303
|
+
|
|
211
304
|
const limit = Math.min(Number(args.limit) || 5, 20);
|
|
305
|
+
const searchOptions = { serverId, serverName };
|
|
212
306
|
|
|
213
307
|
// Fast path: Check for select: prefix
|
|
214
308
|
const selectMatch = query.match(/^select:(.+)$/i);
|
|
215
309
|
if (selectMatch) {
|
|
310
|
+
await router.listTools({ serverId, serverName, limit: 1 });
|
|
311
|
+
|
|
216
312
|
const requested = selectMatch[1]!
|
|
217
313
|
.split(',')
|
|
218
314
|
.map((s) => s.trim())
|
|
@@ -221,15 +317,19 @@ export async function executeMetaTool(
|
|
|
221
317
|
const found: any[] = [];
|
|
222
318
|
const errors: string[] = [];
|
|
223
319
|
|
|
320
|
+
const namespace = serverId ?? serverName;
|
|
321
|
+
|
|
224
322
|
for (const requestedToolName of requested) {
|
|
225
|
-
const { tool, error } = resolveToolSchema(requestedToolName
|
|
323
|
+
const { tool, error } = resolveToolSchema(requestedToolName, namespace, {
|
|
324
|
+
allowServerNameFragment: Boolean(serverName && !serverId),
|
|
325
|
+
});
|
|
226
326
|
if (error) {
|
|
227
327
|
const errorMsg = error.content[0]?.type === 'text' ? error.content[0].text : 'Unknown error';
|
|
228
328
|
errors.push(`- **${requestedToolName}**: ${errorMsg}`);
|
|
229
329
|
} else if (tool) {
|
|
230
330
|
found.push(tool);
|
|
231
331
|
} else {
|
|
232
|
-
errors.push(`- **${requestedToolName}**: Tool not found. Try searching with
|
|
332
|
+
errors.push(`- **${requestedToolName}**: Tool not found. Try searching with mcp_search_tools.`);
|
|
233
333
|
}
|
|
234
334
|
}
|
|
235
335
|
|
|
@@ -257,16 +357,31 @@ export async function executeMetaTool(
|
|
|
257
357
|
};
|
|
258
358
|
}
|
|
259
359
|
|
|
260
|
-
const results = await router.searchTools(query, limit);
|
|
360
|
+
const results = await router.searchTools(query, limit, searchOptions);
|
|
261
361
|
|
|
262
362
|
const text = results.length === 0
|
|
263
|
-
? 'No tools found matching your query.
|
|
264
|
-
: results
|
|
363
|
+
? 'No tools found matching your query. Call mcp_list_servers to inspect connected servers, then retry mcp_search_tools with serverId or serverName.'
|
|
364
|
+
: formatToolSummaries(results).join('\n');
|
|
365
|
+
|
|
366
|
+
return {
|
|
367
|
+
content: [{ type: 'text', text }],
|
|
368
|
+
isError: false,
|
|
369
|
+
};
|
|
370
|
+
}
|
|
371
|
+
|
|
372
|
+
case 'mcp_list_servers': {
|
|
373
|
+
const query = String(args.query ?? '').trim();
|
|
374
|
+
const servers = await router.listServers({
|
|
375
|
+
serverName: query || undefined,
|
|
376
|
+
});
|
|
377
|
+
|
|
378
|
+
const text = servers.length === 0
|
|
379
|
+
? 'No connected servers found.'
|
|
380
|
+
: servers
|
|
265
381
|
.map(
|
|
266
|
-
(
|
|
267
|
-
`${i + 1}. **${
|
|
268
|
-
` ${
|
|
269
|
-
` Estimated tokens: ${t.estimatedTokens}`
|
|
382
|
+
(server, i) =>
|
|
383
|
+
`${i + 1}. **${server.serverName}** (serverId: ${server.serverId}, sessionId: ${server.sessionId})\n` +
|
|
384
|
+
` Tool count: ${server.toolCount}`
|
|
270
385
|
)
|
|
271
386
|
.join('\n');
|
|
272
387
|
|
|
@@ -284,14 +399,7 @@ export async function executeMetaTool(
|
|
|
284
399
|
|
|
285
400
|
const text = results.length === 0
|
|
286
401
|
? 'No tools matched your regex pattern. Try a broader pattern.'
|
|
287
|
-
: results
|
|
288
|
-
.map(
|
|
289
|
-
(t, i) =>
|
|
290
|
-
`${i + 1}. **${t.name}** (server: ${t.serverName}, serverId: ${t.serverId})\n` +
|
|
291
|
-
` ${t.description}\n` +
|
|
292
|
-
` Estimated tokens: ${t.estimatedTokens}`
|
|
293
|
-
)
|
|
294
|
-
.join('\n');
|
|
402
|
+
: formatToolSummaries(results).join('\n');
|
|
295
403
|
|
|
296
404
|
return {
|
|
297
405
|
content: [{ type: 'text', text }],
|
|
@@ -313,7 +421,7 @@ export async function executeMetaTool(
|
|
|
313
421
|
content: [
|
|
314
422
|
{
|
|
315
423
|
type: 'text',
|
|
316
|
-
text: `Tool "${name}" not found. Use
|
|
424
|
+
text: `Tool "${name}" not found. Use mcp_search_tools to find available tools first.`,
|
|
317
425
|
},
|
|
318
426
|
],
|
|
319
427
|
isError: true,
|
|
@@ -362,7 +470,7 @@ export async function executeMetaTool(
|
|
|
362
470
|
content: [
|
|
363
471
|
{
|
|
364
472
|
type: 'text',
|
|
365
|
-
text: `Tool "${targetToolName}" not found. Use
|
|
473
|
+
text: `Tool "${targetToolName}" not found. Use mcp_search_tools to discover available tools first.`,
|
|
366
474
|
},
|
|
367
475
|
],
|
|
368
476
|
isError: true,
|
|
@@ -404,10 +512,28 @@ export async function executeMetaTool(
|
|
|
404
512
|
}
|
|
405
513
|
}
|
|
406
514
|
|
|
515
|
+
function formatToolSummaries(
|
|
516
|
+
tools: Array<{
|
|
517
|
+
name: string;
|
|
518
|
+
description: string;
|
|
519
|
+
serverName: string;
|
|
520
|
+
serverId: string;
|
|
521
|
+
estimatedTokens: number;
|
|
522
|
+
}>
|
|
523
|
+
): string[] {
|
|
524
|
+
return tools.map(
|
|
525
|
+
(t, i) =>
|
|
526
|
+
`${i + 1}. **${t.name}** (server: ${t.serverName}, serverId: ${t.serverId})\n` +
|
|
527
|
+
` ${t.description}\n` +
|
|
528
|
+
` Estimated tokens: ${t.estimatedTokens}`
|
|
529
|
+
);
|
|
530
|
+
}
|
|
531
|
+
|
|
407
532
|
/** Check if a tool name is one of the meta-tools. */
|
|
408
533
|
export function isMetaTool(toolName: string): boolean {
|
|
409
534
|
return (
|
|
410
|
-
toolName === '
|
|
535
|
+
toolName === 'mcp_search_tools' ||
|
|
536
|
+
toolName === 'mcp_list_servers' ||
|
|
411
537
|
toolName === 'mcp_search_tool_regex' ||
|
|
412
538
|
toolName === 'mcp_get_tool_schema' ||
|
|
413
539
|
toolName === 'mcp_execute_tool'
|