@mcp-ts/sdk 1.5.2 → 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.
Files changed (52) hide show
  1. package/README.md +89 -27
  2. package/dist/adapters/agui-adapter.d.mts +1 -1
  3. package/dist/adapters/agui-adapter.d.ts +1 -1
  4. package/dist/adapters/agui-adapter.js +76 -19
  5. package/dist/adapters/agui-adapter.js.map +1 -1
  6. package/dist/adapters/agui-adapter.mjs +76 -19
  7. package/dist/adapters/agui-adapter.mjs.map +1 -1
  8. package/dist/adapters/agui-middleware.d.mts +5 -1
  9. package/dist/adapters/agui-middleware.d.ts +5 -1
  10. package/dist/adapters/agui-middleware.js +116 -49
  11. package/dist/adapters/agui-middleware.js.map +1 -1
  12. package/dist/adapters/agui-middleware.mjs +117 -50
  13. package/dist/adapters/agui-middleware.mjs.map +1 -1
  14. package/dist/adapters/ai-adapter.d.mts +1 -1
  15. package/dist/adapters/ai-adapter.d.ts +1 -1
  16. package/dist/adapters/ai-adapter.js +76 -19
  17. package/dist/adapters/ai-adapter.js.map +1 -1
  18. package/dist/adapters/ai-adapter.mjs +76 -19
  19. package/dist/adapters/ai-adapter.mjs.map +1 -1
  20. package/dist/adapters/langchain-adapter.d.mts +1 -1
  21. package/dist/adapters/langchain-adapter.d.ts +1 -1
  22. package/dist/adapters/langchain-adapter.js +76 -19
  23. package/dist/adapters/langchain-adapter.js.map +1 -1
  24. package/dist/adapters/langchain-adapter.mjs +76 -19
  25. package/dist/adapters/langchain-adapter.mjs.map +1 -1
  26. package/dist/client/react.js.map +1 -1
  27. package/dist/client/react.mjs.map +1 -1
  28. package/dist/index.d.mts +2 -2
  29. package/dist/index.d.ts +2 -2
  30. package/dist/index.js +207 -43
  31. package/dist/index.js.map +1 -1
  32. package/dist/index.mjs +207 -44
  33. package/dist/index.mjs.map +1 -1
  34. package/dist/server/index.js +1 -3
  35. package/dist/server/index.js.map +1 -1
  36. package/dist/server/index.mjs +1 -3
  37. package/dist/server/index.mjs.map +1 -1
  38. package/dist/shared/index.d.mts +15 -8
  39. package/dist/shared/index.d.ts +15 -8
  40. package/dist/shared/index.js +206 -40
  41. package/dist/shared/index.js.map +1 -1
  42. package/dist/shared/index.mjs +206 -41
  43. package/dist/shared/index.mjs.map +1 -1
  44. package/dist/{tool-router-DsKhRmJm.d.ts → tool-router-Bn9R0KWr.d.ts} +56 -7
  45. package/dist/{tool-router-DK0RJblO.d.mts → tool-router-_O2tIwf7.d.mts} +56 -7
  46. package/package.json +5 -3
  47. package/src/adapters/agui-middleware.ts +163 -59
  48. package/src/server/mcp/oauth-client.ts +4 -4
  49. package/src/shared/index.ts +4 -0
  50. package/src/shared/meta-tools.ts +172 -37
  51. package/src/shared/tool-index.ts +123 -7
  52. package/src/shared/tool-router.ts +40 -7
package/dist/index.d.mts CHANGED
@@ -6,7 +6,7 @@ export { C as CallToolParams, a as CallToolRequest, b as CallToolResponse, c as
6
6
  export { OAuthClientInformation, OAuthClientInformationFull, OAuthClientMetadata, OAuthTokens } from '@modelcontextprotocol/sdk/shared/auth.js';
7
7
  export { CallToolResult, ListToolsResult, Tool } from '@modelcontextprotocol/sdk/types.js';
8
8
  export { A as APP_HOST_DEFAULTS, a as AppHost, D as DEFAULT_MCP_APP_CSP, S as SANDBOX_PROXY_READY_METHOD, b as SANDBOX_RESOURCE_READY_METHOD, c as SSEClient, d as SSEClientOptions } from './index-DcYfpY3H.mjs';
9
- export { CallToolFn, DEFAULT_CLIENT_NAME, DEFAULT_CLIENT_URI, DEFAULT_HEARTBEAT_INTERVAL_MS, DEFAULT_LOGO_URI, DEFAULT_POLICY_URI, MCP_CLIENT_NAME, MCP_CLIENT_VERSION, REDIS_KEY_PREFIX, SESSION_TTL_SECONDS, SOFTWARE_ID, SOFTWARE_VERSION, STATE_EXPIRATION_MS, TOKEN_EXPIRY_BUFFER_MS, ToolUiConfig, createExecuteToolDefinition, createGetSchemaToolDefinition, createRegexSearchToolDefinition, createSearchToolDefinition, executeMetaTool, findToolByName, getToolUiResourceUri, isMetaTool, resolveMetaToolProxy } from './shared/index.mjs';
10
- export { C as CompactTool, a as CompressionStats, E as EmbedFn, I as IndexedTool, S as SchemaCompressor, T as ToolGroupInfo, b as ToolIndex, c as ToolIndexOptions, d as ToolRouter, e as ToolRouterClientInput, f as ToolRouterOptions, g as ToolRouterStrategy, h as ToolSummary } from './tool-router-DK0RJblO.mjs';
9
+ export { CallToolFn, DEFAULT_CLIENT_NAME, DEFAULT_CLIENT_URI, DEFAULT_HEARTBEAT_INTERVAL_MS, DEFAULT_LOGO_URI, DEFAULT_POLICY_URI, MCP_CLIENT_NAME, MCP_CLIENT_VERSION, REDIS_KEY_PREFIX, SESSION_TTL_SECONDS, SOFTWARE_ID, SOFTWARE_VERSION, STATE_EXPIRATION_MS, TOKEN_EXPIRY_BUFFER_MS, ToolUiConfig, createExecuteToolDefinition, createGetSchemaToolDefinition, createListServersToolDefinition, createRegexSearchToolDefinition, createSearchToolDefinition, executeMetaTool, findToolByName, getToolUiResourceUri, isMetaTool, resolveMetaToolProxy } from './shared/index.mjs';
10
+ export { C as CompactTool, a as CompressionStats, E as EmbedFn, I as IndexedTool, S as SchemaCompressor, T as ToolGroupInfo, b as ToolIndex, c as ToolIndexOptions, d as ToolListResult, e as ToolRouter, f as ToolRouterClientInput, g as ToolRouterOptions, h as ToolRouterStrategy, i as ToolSearchOptions, j as ToolServerSummary, k as ToolSummary } from './tool-router-_O2tIwf7.mjs';
11
11
  import '@modelcontextprotocol/sdk/client/auth.js';
12
12
  import '@modelcontextprotocol/ext-apps/app-bridge';
package/dist/index.d.ts CHANGED
@@ -6,7 +6,7 @@ export { C as CallToolParams, a as CallToolRequest, b as CallToolResponse, c as
6
6
  export { OAuthClientInformation, OAuthClientInformationFull, OAuthClientMetadata, OAuthTokens } from '@modelcontextprotocol/sdk/shared/auth.js';
7
7
  export { CallToolResult, ListToolsResult, Tool } from '@modelcontextprotocol/sdk/types.js';
8
8
  export { A as APP_HOST_DEFAULTS, a as AppHost, D as DEFAULT_MCP_APP_CSP, S as SANDBOX_PROXY_READY_METHOD, b as SANDBOX_RESOURCE_READY_METHOD, c as SSEClient, d as SSEClientOptions } from './index-GfC_eNEv.js';
9
- export { CallToolFn, DEFAULT_CLIENT_NAME, DEFAULT_CLIENT_URI, DEFAULT_HEARTBEAT_INTERVAL_MS, DEFAULT_LOGO_URI, DEFAULT_POLICY_URI, MCP_CLIENT_NAME, MCP_CLIENT_VERSION, REDIS_KEY_PREFIX, SESSION_TTL_SECONDS, SOFTWARE_ID, SOFTWARE_VERSION, STATE_EXPIRATION_MS, TOKEN_EXPIRY_BUFFER_MS, ToolUiConfig, createExecuteToolDefinition, createGetSchemaToolDefinition, createRegexSearchToolDefinition, createSearchToolDefinition, executeMetaTool, findToolByName, getToolUiResourceUri, isMetaTool, resolveMetaToolProxy } from './shared/index.js';
10
- export { C as CompactTool, a as CompressionStats, E as EmbedFn, I as IndexedTool, S as SchemaCompressor, T as ToolGroupInfo, b as ToolIndex, c as ToolIndexOptions, d as ToolRouter, e as ToolRouterClientInput, f as ToolRouterOptions, g as ToolRouterStrategy, h as ToolSummary } from './tool-router-DsKhRmJm.js';
9
+ export { CallToolFn, DEFAULT_CLIENT_NAME, DEFAULT_CLIENT_URI, DEFAULT_HEARTBEAT_INTERVAL_MS, DEFAULT_LOGO_URI, DEFAULT_POLICY_URI, MCP_CLIENT_NAME, MCP_CLIENT_VERSION, REDIS_KEY_PREFIX, SESSION_TTL_SECONDS, SOFTWARE_ID, SOFTWARE_VERSION, STATE_EXPIRATION_MS, TOKEN_EXPIRY_BUFFER_MS, ToolUiConfig, createExecuteToolDefinition, createGetSchemaToolDefinition, createListServersToolDefinition, createRegexSearchToolDefinition, createSearchToolDefinition, executeMetaTool, findToolByName, getToolUiResourceUri, isMetaTool, resolveMetaToolProxy } from './shared/index.js';
10
+ export { C as CompactTool, a as CompressionStats, E as EmbedFn, I as IndexedTool, S as SchemaCompressor, T as ToolGroupInfo, b as ToolIndex, c as ToolIndexOptions, d as ToolListResult, e as ToolRouter, f as ToolRouterClientInput, g as ToolRouterOptions, h as ToolRouterStrategy, i as ToolSearchOptions, j as ToolServerSummary, k as ToolSummary } from './tool-router-Bn9R0KWr.js';
11
11
  import '@modelcontextprotocol/sdk/client/auth.js';
12
12
  import '@modelcontextprotocol/ext-apps/app-bridge';
package/dist/index.js CHANGED
@@ -2270,9 +2270,7 @@ var MCPClient = class _MCPClient {
2270
2270
  * @returns Server name or undefined
2271
2271
  */
2272
2272
  getServerName() {
2273
- const info = this.client?.getServerVersion();
2274
- console.log("server info ->", info);
2275
- return info?.title ?? info?.name ?? this.serverName;
2273
+ return this.serverName;
2276
2274
  }
2277
2275
  /**
2278
2276
  * Gets the server ID
@@ -4042,17 +4040,17 @@ var ToolIndex = class _ToolIndex {
4042
4040
  *
4043
4041
  * `score = keywordWeight × keyword_score + (1 - keywordWeight) × cosine_score`
4044
4042
  */
4045
- async search(query, topK = 5) {
4043
+ async search(query, topK = 5, options = {}) {
4046
4044
  if (this.tools.size === 0) return [];
4047
4045
  const queryLower = query.toLowerCase().trim();
4048
4046
  const exactMatches = [...this.toolSummaries.values()].filter(
4049
- (summary) => summary.name.toLowerCase() === queryLower
4047
+ (summary) => summary.name.toLowerCase() === queryLower && this.matchesServer(summary, options)
4050
4048
  );
4051
4049
  if (exactMatches.length > 0) {
4052
4050
  return exactMatches.slice(0, topK);
4053
4051
  }
4054
4052
  if (queryLower.startsWith("mcp__") && queryLower.length > 5) {
4055
- const prefixMatches = [...this.toolSummaries.values()].filter((t) => t.name.toLowerCase().startsWith(queryLower)).slice(0, topK);
4053
+ const prefixMatches = [...this.toolSummaries.values()].filter((t) => t.name.toLowerCase().startsWith(queryLower) && this.matchesServer(t, options)).slice(0, topK);
4056
4054
  if (prefixMatches.length > 0) return prefixMatches;
4057
4055
  }
4058
4056
  const queryTermsRaw = queryLower.split(/\s+/).filter((t) => t.length > 0);
@@ -4070,9 +4068,10 @@ var ToolIndex = class _ToolIndex {
4070
4068
  const queryTokens = this.tokenize(allScoringTerms.join(" "));
4071
4069
  const candidateKeys = /* @__PURE__ */ new Set();
4072
4070
  for (const docKey of this.toolSummaries.keys()) {
4071
+ const summary = this.toolSummaries.get(docKey);
4072
+ if (!this.matchesServer(summary, options)) continue;
4073
4073
  if (requiredTerms.length > 0) {
4074
4074
  const text = this.searchTexts.get(docKey) || "";
4075
- const summary = this.toolSummaries.get(docKey);
4076
4075
  const nameLower = summary.name.toLowerCase();
4077
4076
  const matchesAll = requiredTerms.every(
4078
4077
  (term) => text.includes(term) || nameLower.includes(term)
@@ -4183,17 +4182,66 @@ var ToolIndex = class _ToolIndex {
4183
4182
  // -----------------------------------------------------------------------
4184
4183
  /**
4185
4184
  * Get tool definition(s) by name.
4186
- * If namespace is provided, it tries to match sessionId or serverName.
4185
+ * If namespace is provided, exact sessionId/serverId matches take precedence.
4186
+ * Falls back to serverName fragment matching only when explicitly allowed.
4187
4187
  */
4188
- getTool(name, namespace) {
4188
+ getTool(name, namespace, options = {}) {
4189
4189
  const list = this.tools.get(name) ?? [];
4190
4190
  if (!namespace) return list;
4191
- return list.filter((t) => t.sessionId === namespace || t.serverId === namespace);
4191
+ const exactMatches = list.filter(
4192
+ (t) => t.sessionId === namespace || t.serverId === namespace
4193
+ );
4194
+ if (exactMatches.length > 0) return exactMatches;
4195
+ if (!options.allowServerNameFragment) return [];
4196
+ const namespaceLower = namespace.toLowerCase();
4197
+ return list.filter((t) => t.serverName.toLowerCase().includes(namespaceLower));
4192
4198
  }
4193
4199
  /** All indexed tool names. */
4194
4200
  getToolNames() {
4195
4201
  return [...this.tools.keys()];
4196
4202
  }
4203
+ /** List indexed servers with tool counts. */
4204
+ listServers(options = {}) {
4205
+ const servers = /* @__PURE__ */ new Map();
4206
+ for (const summary of this.toolSummaries.values()) {
4207
+ if (!this.matchesServer(summary, options)) continue;
4208
+ const key = `${summary.sessionId}::${summary.serverId}`;
4209
+ const existing = servers.get(key);
4210
+ if (existing) {
4211
+ existing.toolCount += 1;
4212
+ } else {
4213
+ servers.set(key, {
4214
+ serverName: summary.serverName,
4215
+ serverId: summary.serverId,
4216
+ sessionId: summary.sessionId,
4217
+ toolCount: 1
4218
+ });
4219
+ }
4220
+ }
4221
+ return [...servers.values()].sort((a, b) => {
4222
+ const byName = a.serverName.localeCompare(b.serverName);
4223
+ return byName !== 0 ? byName : a.serverId.localeCompare(b.serverId);
4224
+ });
4225
+ }
4226
+ /** List tools deterministically, optionally scoped to a server. */
4227
+ listTools(options = {}) {
4228
+ const offset = Math.max(Number(options.cursor) || 0, 0);
4229
+ const limit = Math.max(Number(options.limit) || 20, 1);
4230
+ const tools = [...this.toolSummaries.values()].filter((summary) => this.matchesServer(summary, options)).sort((a, b) => {
4231
+ const byServer = a.serverName.localeCompare(b.serverName);
4232
+ if (byServer !== 0) return byServer;
4233
+ return a.name.localeCompare(b.name);
4234
+ });
4235
+ const page = tools.slice(offset, offset + limit);
4236
+ const nextOffset = offset + page.length;
4237
+ return {
4238
+ tools: page,
4239
+ totalCount: tools.length,
4240
+ returnedCount: page.length,
4241
+ nextCursor: nextOffset < tools.length ? String(nextOffset) : void 0,
4242
+ servers: this.listServers(options)
4243
+ };
4244
+ }
4197
4245
  /** Number of indexed tools (including duplicates). */
4198
4246
  get size() {
4199
4247
  let count = 0;
@@ -4250,6 +4298,20 @@ var ToolIndex = class _ToolIndex {
4250
4298
  getDocumentKey(tool) {
4251
4299
  return `${tool.sessionId}::${tool.serverId}::${tool.name}`;
4252
4300
  }
4301
+ matchesServer(summary, options) {
4302
+ if (options.serverId && summary.serverId !== options.serverId) {
4303
+ return false;
4304
+ }
4305
+ if (options.serverName) {
4306
+ const serverNameQuery = options.serverName.toLowerCase();
4307
+ const serverName = summary.serverName.toLowerCase();
4308
+ const serverId = summary.serverId.toLowerCase();
4309
+ if (!serverName.includes(serverNameQuery) && !serverId.includes(serverNameQuery)) {
4310
+ return false;
4311
+ }
4312
+ }
4313
+ return true;
4314
+ }
4253
4315
  /** Simple whitespace + camelCase + snake_case tokenizer. */
4254
4316
  tokenize(text) {
4255
4317
  return text.replace(/([a-z])([A-Z])/g, "$1 $2").replace(/[_-]/g, " ").replace(/[^a-z0-9\s]/g, "").split(/\s+/).filter((t) => t.length > 1);
@@ -4335,7 +4397,7 @@ var SchemaCompressor = class _SchemaCompressor {
4335
4397
  init_cjs_shims();
4336
4398
  function createSearchToolDefinition() {
4337
4399
  return {
4338
- name: "mcp_search_tool_bm25",
4400
+ name: "mcp_search_tools",
4339
4401
  description: 'Search the catalog of available tools. Returns tool names, descriptions, and server info. Use this FIRST to find relevant tools before calling them.\n\nQuery forms:\n- "select:Read,Edit,Grep" \u2014 fetch these exact tools by name\n- "notebook jupyter" \u2014 keyword search, up to limit best matches\n- "+slack send" \u2014 require "slack" in the name, rank by remaining terms',
4340
4402
  inputSchema: {
4341
4403
  type: "object",
@@ -4344,15 +4406,47 @@ function createSearchToolDefinition() {
4344
4406
  type: "string",
4345
4407
  description: 'Query to find tools. Use "select:<tool_name>" for direct selection, or keywords to search. Prefix keywords with + to require them.'
4346
4408
  },
4409
+ operation: {
4410
+ type: "string",
4411
+ enum: ["search", "list"],
4412
+ description: '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.'
4413
+ },
4414
+ serverId: {
4415
+ type: "string",
4416
+ description: "Optional server ID to restrict search/list results to one MCP server."
4417
+ },
4418
+ serverName: {
4419
+ type: "string",
4420
+ description: 'Optional server name fragment to restrict search/list results to matching MCP servers, e.g. "supabase".'
4421
+ },
4347
4422
  limit: {
4348
4423
  type: "number",
4349
- description: "Maximum number of results to return (default: 5, max: 20)."
4424
+ description: "Maximum number of results to return (default: 5 for search, 20 for list; max: 20 for search, 100 for list)."
4425
+ },
4426
+ cursor: {
4427
+ type: "string",
4428
+ description: 'Optional pagination cursor returned by operation "list".'
4350
4429
  }
4351
4430
  },
4352
4431
  required: ["query"]
4353
4432
  }
4354
4433
  };
4355
4434
  }
4435
+ function createListServersToolDefinition() {
4436
+ return {
4437
+ name: "mcp_list_servers",
4438
+ description: "List connected MCP servers and their tool counts. Use this when mcp_search_tools returns no matches, then retry mcp_search_tools with serverId or serverName.",
4439
+ inputSchema: {
4440
+ type: "object",
4441
+ properties: {
4442
+ query: {
4443
+ type: "string",
4444
+ description: 'Optional server filter text. Matches server name or serverId, e.g. "web" or "supabase".'
4445
+ }
4446
+ }
4447
+ }
4448
+ };
4449
+ }
4356
4450
  function createRegexSearchToolDefinition() {
4357
4451
  return {
4358
4452
  name: "mcp_search_tool_regex",
@@ -4376,17 +4470,17 @@ function createRegexSearchToolDefinition() {
4376
4470
  function createGetSchemaToolDefinition() {
4377
4471
  return {
4378
4472
  name: "mcp_get_tool_schema",
4379
- description: "Get the full input schema (parameters) for a specific tool. Call this after mcp_search_tool_bm25 to get the parameter details needed to call a tool correctly.",
4473
+ description: "Get the full input schema (parameters) for a specific tool. Call this after mcp_search_tools to get the parameter details needed to call a tool correctly. Do NOT call the discovered tool directly; after reading the schema, call mcp_execute_tool.",
4380
4474
  inputSchema: {
4381
4475
  type: "object",
4382
4476
  properties: {
4383
4477
  toolName: {
4384
4478
  type: "string",
4385
- description: "The exact tool name returned by mcp_search_tool_bm25."
4479
+ description: "The exact tool name returned by mcp_search_tools."
4386
4480
  },
4387
4481
  serverId: {
4388
4482
  type: "string",
4389
- description: "Optional: The server ID provided in mcp_search_tool_bm25. Required if multiple tools have the same name."
4483
+ description: "Optional: The server ID provided in mcp_search_tools. Required if multiple tools have the same name."
4390
4484
  }
4391
4485
  },
4392
4486
  required: ["toolName"]
@@ -4396,17 +4490,17 @@ function createGetSchemaToolDefinition() {
4396
4490
  function createExecuteToolDefinition() {
4397
4491
  return {
4398
4492
  name: "mcp_execute_tool",
4399
- description: "Execute a tool that was discovered via mcp_search_tool_bm25. You MUST call mcp_get_tool_schema first to know the correct parameters. Pass the exact tool name and its arguments.",
4493
+ description: "Execute a tool that was discovered via mcp_search_tools. You MUST call mcp_get_tool_schema first to know the correct parameters. Pass the exact tool name and its arguments.",
4400
4494
  inputSchema: {
4401
4495
  type: "object",
4402
4496
  properties: {
4403
4497
  toolName: {
4404
4498
  type: "string",
4405
- description: "The exact tool name from mcp_search_tool_bm25 results."
4499
+ description: "The exact tool name from mcp_search_tools results."
4406
4500
  },
4407
4501
  serverId: {
4408
4502
  type: "string",
4409
- description: "Optional: The server ID provided in mcp_search_tool_bm25. Required if multiple tools have the same name."
4503
+ description: "Optional: The server ID provided in mcp_search_tools. Required if multiple tools have the same name."
4410
4504
  },
4411
4505
  args: {
4412
4506
  type: "object",
@@ -4419,9 +4513,9 @@ function createExecuteToolDefinition() {
4419
4513
  };
4420
4514
  }
4421
4515
  async function executeMetaTool(toolName, args, router, callToolFn) {
4422
- const resolveToolSchema = (name, namespace) => {
4516
+ const resolveToolSchema = (name, namespace, options) => {
4423
4517
  try {
4424
- return { tool: router.getToolSchema(name, namespace) };
4518
+ return { tool: router.getToolSchema(name, namespace, options) };
4425
4519
  } catch (err) {
4426
4520
  const errorMessage = err instanceof Error ? err.message : String(err);
4427
4521
  return {
@@ -4433,23 +4527,61 @@ async function executeMetaTool(toolName, args, router, callToolFn) {
4433
4527
  }
4434
4528
  };
4435
4529
  switch (toolName) {
4436
- case "mcp_search_tool_bm25": {
4530
+ case "mcp_search_tools": {
4437
4531
  const query = String(args.query ?? "");
4532
+ const operation = String(args.operation ?? "search");
4533
+ const serverId = String(args.serverId ?? "") || void 0;
4534
+ const serverName = String(args.serverName ?? "") || void 0;
4535
+ if (operation === "list") {
4536
+ const limit2 = Math.min(Number(args.limit) || 20, 100);
4537
+ const cursor = String(args.cursor ?? "") || void 0;
4538
+ const result = await router.listTools({
4539
+ serverId,
4540
+ serverName: serverName ?? (!serverId && query ? query : void 0),
4541
+ limit: limit2,
4542
+ cursor
4543
+ });
4544
+ const serverText = result.servers.length > 0 ? result.servers.map((server) => `${server.serverName} (serverId: ${server.serverId}, tools: ${server.toolCount})`).join(", ") : "none";
4545
+ const lines = [
4546
+ "operation: list",
4547
+ `servers: ${serverText}`,
4548
+ `totalCount: ${result.totalCount}`,
4549
+ `returnedCount: ${result.returnedCount}`,
4550
+ `nextCursor: ${result.nextCursor ?? "null"}`,
4551
+ ""
4552
+ ];
4553
+ if (result.tools.length > 0) {
4554
+ lines.push(...formatToolSummaries(result.tools));
4555
+ } else {
4556
+ lines.push(
4557
+ serverId || serverName ? "No tools found for the requested server scope." : 'No tools found. Try operation "search" or provide serverId/serverName.'
4558
+ );
4559
+ }
4560
+ return {
4561
+ content: [{ type: "text", text: lines.join("\n") }],
4562
+ isError: false
4563
+ };
4564
+ }
4438
4565
  const limit = Math.min(Number(args.limit) || 5, 20);
4566
+ const searchOptions = { serverId, serverName };
4439
4567
  const selectMatch = query.match(/^select:(.+)$/i);
4440
4568
  if (selectMatch) {
4569
+ await router.listTools({ serverId, serverName, limit: 1 });
4441
4570
  const requested = selectMatch[1].split(",").map((s) => s.trim()).filter(Boolean);
4442
4571
  const found = [];
4443
4572
  const errors = [];
4573
+ const namespace = serverId ?? serverName;
4444
4574
  for (const requestedToolName of requested) {
4445
- const { tool, error } = resolveToolSchema(requestedToolName);
4575
+ const { tool, error } = resolveToolSchema(requestedToolName, namespace, {
4576
+ allowServerNameFragment: Boolean(serverName && !serverId)
4577
+ });
4446
4578
  if (error) {
4447
4579
  const errorMsg = error.content[0]?.type === "text" ? error.content[0].text : "Unknown error";
4448
4580
  errors.push(`- **${requestedToolName}**: ${errorMsg}`);
4449
4581
  } else if (tool) {
4450
4582
  found.push(tool);
4451
4583
  } else {
4452
- errors.push(`- **${requestedToolName}**: Tool not found. Try searching with mcp_search_tool_bm25.`);
4584
+ errors.push(`- **${requestedToolName}**: Tool not found. Try searching with mcp_search_tools.`);
4453
4585
  }
4454
4586
  }
4455
4587
  const lines = [];
@@ -4470,11 +4602,21 @@ async function executeMetaTool(toolName, args, router, callToolFn) {
4470
4602
  isError: found.length === 0
4471
4603
  };
4472
4604
  }
4473
- const results = await router.searchTools(query, limit);
4474
- const text = results.length === 0 ? "No tools found matching your query. Try different keywords." : results.map(
4475
- (t, i) => `${i + 1}. **${t.name}** (server: ${t.serverName}, serverId: ${t.serverId})
4476
- ${t.description}
4477
- Estimated tokens: ${t.estimatedTokens}`
4605
+ const results = await router.searchTools(query, limit, searchOptions);
4606
+ const text = results.length === 0 ? "No tools found matching your query. Call mcp_list_servers to inspect connected servers, then retry mcp_search_tools with serverId or serverName." : formatToolSummaries(results).join("\n");
4607
+ return {
4608
+ content: [{ type: "text", text }],
4609
+ isError: false
4610
+ };
4611
+ }
4612
+ case "mcp_list_servers": {
4613
+ const query = String(args.query ?? "").trim();
4614
+ const servers = await router.listServers({
4615
+ serverName: query || void 0
4616
+ });
4617
+ const text = servers.length === 0 ? "No connected servers found." : servers.map(
4618
+ (server, i) => `${i + 1}. **${server.serverName}** (serverId: ${server.serverId}, sessionId: ${server.sessionId})
4619
+ Tool count: ${server.toolCount}`
4478
4620
  ).join("\n");
4479
4621
  return {
4480
4622
  content: [{ type: "text", text }],
@@ -4485,11 +4627,7 @@ async function executeMetaTool(toolName, args, router, callToolFn) {
4485
4627
  const pattern = String(args.query ?? "");
4486
4628
  const limit = Math.min(Number(args.limit) || 5, 20);
4487
4629
  const results = await router.searchToolsRegex(pattern, limit);
4488
- const text = results.length === 0 ? "No tools matched your regex pattern. Try a broader pattern." : results.map(
4489
- (t, i) => `${i + 1}. **${t.name}** (server: ${t.serverName}, serverId: ${t.serverId})
4490
- ${t.description}
4491
- Estimated tokens: ${t.estimatedTokens}`
4492
- ).join("\n");
4630
+ const text = results.length === 0 ? "No tools matched your regex pattern. Try a broader pattern." : formatToolSummaries(results).join("\n");
4493
4631
  return {
4494
4632
  content: [{ type: "text", text }],
4495
4633
  isError: false
@@ -4507,7 +4645,7 @@ async function executeMetaTool(toolName, args, router, callToolFn) {
4507
4645
  content: [
4508
4646
  {
4509
4647
  type: "text",
4510
- text: `Tool "${name}" not found. Use mcp_search_tool_bm25 to find available tools first.`
4648
+ text: `Tool "${name}" not found. Use mcp_search_tools to find available tools first.`
4511
4649
  }
4512
4650
  ],
4513
4651
  isError: true
@@ -4516,7 +4654,13 @@ async function executeMetaTool(toolName, args, router, callToolFn) {
4516
4654
  const schema = {
4517
4655
  name: tool.name,
4518
4656
  description: tool.description,
4519
- inputSchema: tool.inputSchema
4657
+ inputSchema: tool.inputSchema,
4658
+ executionInstructions: {
4659
+ nextTool: "mcp_execute_tool",
4660
+ toolName: tool.name,
4661
+ serverId: tool.serverId,
4662
+ note: "Do not call this discovered tool directly unless it was explicitly registered as a runtime tool. Execute it via mcp_execute_tool and pass these parameters inside args."
4663
+ }
4520
4664
  };
4521
4665
  return {
4522
4666
  content: [{ type: "text", text: JSON.stringify(schema, null, 2) }],
@@ -4542,7 +4686,7 @@ async function executeMetaTool(toolName, args, router, callToolFn) {
4542
4686
  content: [
4543
4687
  {
4544
4688
  type: "text",
4545
- text: `Tool "${targetToolName}" not found. Use mcp_search_tool_bm25 to discover available tools first.`
4689
+ text: `Tool "${targetToolName}" not found. Use mcp_search_tools to discover available tools first.`
4546
4690
  }
4547
4691
  ],
4548
4692
  isError: true
@@ -4576,8 +4720,15 @@ async function executeMetaTool(toolName, args, router, callToolFn) {
4576
4720
  return null;
4577
4721
  }
4578
4722
  }
4723
+ function formatToolSummaries(tools) {
4724
+ return tools.map(
4725
+ (t, i) => `${i + 1}. **${t.name}** (server: ${t.serverName}, serverId: ${t.serverId})
4726
+ ${t.description}
4727
+ Estimated tokens: ${t.estimatedTokens}`
4728
+ );
4729
+ }
4579
4730
  function isMetaTool(toolName) {
4580
- return toolName === "mcp_search_tool_bm25" || toolName === "mcp_search_tool_regex" || toolName === "mcp_get_tool_schema" || toolName === "mcp_execute_tool";
4731
+ return toolName === "mcp_search_tools" || toolName === "mcp_list_servers" || toolName === "mcp_search_tool_regex" || toolName === "mcp_get_tool_schema" || toolName === "mcp_execute_tool";
4581
4732
  }
4582
4733
  function resolveMetaToolProxy(toolName, args) {
4583
4734
  if (toolName === "mcp_execute_tool") {
@@ -4625,7 +4776,7 @@ var ToolRouter = class {
4625
4776
  * This is the main method adapters should call.
4626
4777
  *
4627
4778
  * - `all` → returns all tools (unchanged behavior)
4628
- * - `search` → returns only meta-tools (mcp_search_tool_bm25, mcp_get_tool_schema, mcp_execute_tool)
4779
+ * - `search` → returns only meta-tools (mcp_search_tools, mcp_get_tool_schema, mcp_execute_tool)
4629
4780
  * - `groups` → returns tools from active groups only
4630
4781
  */
4631
4782
  async getFilteredTools() {
@@ -4654,9 +4805,10 @@ var ToolRouter = class {
4654
4805
  * Search tools by natural-language query.
4655
4806
  * Works regardless of strategy.
4656
4807
  */
4657
- async searchTools(query, topK) {
4808
+ async searchTools(query, topK, options = {}) {
4658
4809
  await this.ensureInitialized();
4659
- return this.index.search(query, topK ?? this.maxTools);
4810
+ const limit = topK ?? this.maxTools;
4811
+ return this.index.search(query, limit, options);
4660
4812
  }
4661
4813
  /**
4662
4814
  * Search tools by regex pattern.
@@ -4666,12 +4818,22 @@ var ToolRouter = class {
4666
4818
  await this.ensureInitialized();
4667
4819
  return this.index.searchRegex(pattern, topK ?? this.maxTools);
4668
4820
  }
4821
+ /** List connected MCP servers with indexed tool counts. */
4822
+ async listServers(options = {}) {
4823
+ await this.ensureInitialized();
4824
+ return this.index.listServers(options);
4825
+ }
4826
+ /** List tools deterministically, optionally scoped to a server. */
4827
+ async listTools(options = {}) {
4828
+ await this.ensureInitialized();
4829
+ return this.index.listTools(options);
4830
+ }
4669
4831
  /**
4670
4832
  * Get the full tool definition by name.
4671
4833
  * If tool name is ambiguous, use namespace to specify the server.
4672
4834
  */
4673
- getToolSchema(toolName, namespace) {
4674
- const matches = this.index.getTool(toolName, namespace);
4835
+ getToolSchema(toolName, namespace, options = {}) {
4836
+ const matches = this.index.getTool(toolName, namespace, options);
4675
4837
  if (matches.length === 0) return void 0;
4676
4838
  if (matches.length > 1) {
4677
4839
  const servers = matches.map((m) => m.serverId).join(", ");
@@ -4750,7 +4912,7 @@ var ToolRouter = class {
4750
4912
  const indexedTool = this.getToolSchema(toolName, namespace);
4751
4913
  if (!indexedTool) {
4752
4914
  throw new Error(
4753
- `Tool "${toolName}" not found${namespace ? ` on server "${namespace}"` : ""}. Use mcp_search_tool_bm25 or mcp_search_tool_regex to discover available tools.`
4915
+ `Tool "${toolName}" not found${namespace ? ` on server "${namespace}"` : ""}. Use mcp_search_tools or mcp_search_tool_regex to discover available tools.`
4754
4916
  );
4755
4917
  }
4756
4918
  const clients = this.getClients();
@@ -4862,6 +5024,7 @@ var ToolRouter = class {
4862
5024
  getMetaToolDefinitions() {
4863
5025
  return [
4864
5026
  createSearchToolDefinition(),
5027
+ createListServersToolDefinition(),
4865
5028
  createRegexSearchToolDefinition(),
4866
5029
  createGetSchemaToolDefinition(),
4867
5030
  createExecuteToolDefinition()
@@ -4910,6 +5073,7 @@ exports.ToolRouter = ToolRouter;
4910
5073
  exports.UnauthorizedError = UnauthorizedError;
4911
5074
  exports.createExecuteToolDefinition = createExecuteToolDefinition;
4912
5075
  exports.createGetSchemaToolDefinition = createGetSchemaToolDefinition;
5076
+ exports.createListServersToolDefinition = createListServersToolDefinition;
4913
5077
  exports.createNextMcpHandler = createNextMcpHandler;
4914
5078
  exports.createRegexSearchToolDefinition = createRegexSearchToolDefinition;
4915
5079
  exports.createSSEHandler = createSSEHandler;