@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
@@ -338,17 +338,17 @@ var ToolIndex = class _ToolIndex {
338
338
  *
339
339
  * `score = keywordWeight × keyword_score + (1 - keywordWeight) × cosine_score`
340
340
  */
341
- async search(query, topK = 5) {
341
+ async search(query, topK = 5, options = {}) {
342
342
  if (this.tools.size === 0) return [];
343
343
  const queryLower = query.toLowerCase().trim();
344
344
  const exactMatches = [...this.toolSummaries.values()].filter(
345
- (summary) => summary.name.toLowerCase() === queryLower
345
+ (summary) => summary.name.toLowerCase() === queryLower && this.matchesServer(summary, options)
346
346
  );
347
347
  if (exactMatches.length > 0) {
348
348
  return exactMatches.slice(0, topK);
349
349
  }
350
350
  if (queryLower.startsWith("mcp__") && queryLower.length > 5) {
351
- const prefixMatches = [...this.toolSummaries.values()].filter((t) => t.name.toLowerCase().startsWith(queryLower)).slice(0, topK);
351
+ const prefixMatches = [...this.toolSummaries.values()].filter((t) => t.name.toLowerCase().startsWith(queryLower) && this.matchesServer(t, options)).slice(0, topK);
352
352
  if (prefixMatches.length > 0) return prefixMatches;
353
353
  }
354
354
  const queryTermsRaw = queryLower.split(/\s+/).filter((t) => t.length > 0);
@@ -366,9 +366,10 @@ var ToolIndex = class _ToolIndex {
366
366
  const queryTokens = this.tokenize(allScoringTerms.join(" "));
367
367
  const candidateKeys = /* @__PURE__ */ new Set();
368
368
  for (const docKey of this.toolSummaries.keys()) {
369
+ const summary = this.toolSummaries.get(docKey);
370
+ if (!this.matchesServer(summary, options)) continue;
369
371
  if (requiredTerms.length > 0) {
370
372
  const text = this.searchTexts.get(docKey) || "";
371
- const summary = this.toolSummaries.get(docKey);
372
373
  const nameLower = summary.name.toLowerCase();
373
374
  const matchesAll = requiredTerms.every(
374
375
  (term) => text.includes(term) || nameLower.includes(term)
@@ -479,17 +480,66 @@ var ToolIndex = class _ToolIndex {
479
480
  // -----------------------------------------------------------------------
480
481
  /**
481
482
  * Get tool definition(s) by name.
482
- * If namespace is provided, it tries to match sessionId or serverName.
483
+ * If namespace is provided, exact sessionId/serverId matches take precedence.
484
+ * Falls back to serverName fragment matching only when explicitly allowed.
483
485
  */
484
- getTool(name, namespace) {
486
+ getTool(name, namespace, options = {}) {
485
487
  const list = this.tools.get(name) ?? [];
486
488
  if (!namespace) return list;
487
- return list.filter((t) => t.sessionId === namespace || t.serverId === namespace);
489
+ const exactMatches = list.filter(
490
+ (t) => t.sessionId === namespace || t.serverId === namespace
491
+ );
492
+ if (exactMatches.length > 0) return exactMatches;
493
+ if (!options.allowServerNameFragment) return [];
494
+ const namespaceLower = namespace.toLowerCase();
495
+ return list.filter((t) => t.serverName.toLowerCase().includes(namespaceLower));
488
496
  }
489
497
  /** All indexed tool names. */
490
498
  getToolNames() {
491
499
  return [...this.tools.keys()];
492
500
  }
501
+ /** List indexed servers with tool counts. */
502
+ listServers(options = {}) {
503
+ const servers = /* @__PURE__ */ new Map();
504
+ for (const summary of this.toolSummaries.values()) {
505
+ if (!this.matchesServer(summary, options)) continue;
506
+ const key = `${summary.sessionId}::${summary.serverId}`;
507
+ const existing = servers.get(key);
508
+ if (existing) {
509
+ existing.toolCount += 1;
510
+ } else {
511
+ servers.set(key, {
512
+ serverName: summary.serverName,
513
+ serverId: summary.serverId,
514
+ sessionId: summary.sessionId,
515
+ toolCount: 1
516
+ });
517
+ }
518
+ }
519
+ return [...servers.values()].sort((a, b) => {
520
+ const byName = a.serverName.localeCompare(b.serverName);
521
+ return byName !== 0 ? byName : a.serverId.localeCompare(b.serverId);
522
+ });
523
+ }
524
+ /** List tools deterministically, optionally scoped to a server. */
525
+ listTools(options = {}) {
526
+ const offset = Math.max(Number(options.cursor) || 0, 0);
527
+ const limit = Math.max(Number(options.limit) || 20, 1);
528
+ const tools = [...this.toolSummaries.values()].filter((summary) => this.matchesServer(summary, options)).sort((a, b) => {
529
+ const byServer = a.serverName.localeCompare(b.serverName);
530
+ if (byServer !== 0) return byServer;
531
+ return a.name.localeCompare(b.name);
532
+ });
533
+ const page = tools.slice(offset, offset + limit);
534
+ const nextOffset = offset + page.length;
535
+ return {
536
+ tools: page,
537
+ totalCount: tools.length,
538
+ returnedCount: page.length,
539
+ nextCursor: nextOffset < tools.length ? String(nextOffset) : void 0,
540
+ servers: this.listServers(options)
541
+ };
542
+ }
493
543
  /** Number of indexed tools (including duplicates). */
494
544
  get size() {
495
545
  let count = 0;
@@ -546,6 +596,20 @@ var ToolIndex = class _ToolIndex {
546
596
  getDocumentKey(tool) {
547
597
  return `${tool.sessionId}::${tool.serverId}::${tool.name}`;
548
598
  }
599
+ matchesServer(summary, options) {
600
+ if (options.serverId && summary.serverId !== options.serverId) {
601
+ return false;
602
+ }
603
+ if (options.serverName) {
604
+ const serverNameQuery = options.serverName.toLowerCase();
605
+ const serverName = summary.serverName.toLowerCase();
606
+ const serverId = summary.serverId.toLowerCase();
607
+ if (!serverName.includes(serverNameQuery) && !serverId.includes(serverNameQuery)) {
608
+ return false;
609
+ }
610
+ }
611
+ return true;
612
+ }
549
613
  /** Simple whitespace + camelCase + snake_case tokenizer. */
550
614
  tokenize(text) {
551
615
  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);
@@ -629,7 +693,7 @@ var SchemaCompressor = class _SchemaCompressor {
629
693
  // src/shared/meta-tools.ts
630
694
  function createSearchToolDefinition() {
631
695
  return {
632
- name: "mcp_search_tool_bm25",
696
+ name: "mcp_search_tools",
633
697
  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',
634
698
  inputSchema: {
635
699
  type: "object",
@@ -638,15 +702,47 @@ function createSearchToolDefinition() {
638
702
  type: "string",
639
703
  description: 'Query to find tools. Use "select:<tool_name>" for direct selection, or keywords to search. Prefix keywords with + to require them.'
640
704
  },
705
+ operation: {
706
+ type: "string",
707
+ enum: ["search", "list"],
708
+ 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.'
709
+ },
710
+ serverId: {
711
+ type: "string",
712
+ description: "Optional server ID to restrict search/list results to one MCP server."
713
+ },
714
+ serverName: {
715
+ type: "string",
716
+ description: 'Optional server name fragment to restrict search/list results to matching MCP servers, e.g. "supabase".'
717
+ },
641
718
  limit: {
642
719
  type: "number",
643
- description: "Maximum number of results to return (default: 5, max: 20)."
720
+ description: "Maximum number of results to return (default: 5 for search, 20 for list; max: 20 for search, 100 for list)."
721
+ },
722
+ cursor: {
723
+ type: "string",
724
+ description: 'Optional pagination cursor returned by operation "list".'
644
725
  }
645
726
  },
646
727
  required: ["query"]
647
728
  }
648
729
  };
649
730
  }
731
+ function createListServersToolDefinition() {
732
+ return {
733
+ name: "mcp_list_servers",
734
+ 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.",
735
+ inputSchema: {
736
+ type: "object",
737
+ properties: {
738
+ query: {
739
+ type: "string",
740
+ description: 'Optional server filter text. Matches server name or serverId, e.g. "web" or "supabase".'
741
+ }
742
+ }
743
+ }
744
+ };
745
+ }
650
746
  function createRegexSearchToolDefinition() {
651
747
  return {
652
748
  name: "mcp_search_tool_regex",
@@ -670,17 +766,17 @@ function createRegexSearchToolDefinition() {
670
766
  function createGetSchemaToolDefinition() {
671
767
  return {
672
768
  name: "mcp_get_tool_schema",
673
- 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.",
769
+ 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.",
674
770
  inputSchema: {
675
771
  type: "object",
676
772
  properties: {
677
773
  toolName: {
678
774
  type: "string",
679
- description: "The exact tool name returned by mcp_search_tool_bm25."
775
+ description: "The exact tool name returned by mcp_search_tools."
680
776
  },
681
777
  serverId: {
682
778
  type: "string",
683
- description: "Optional: The server ID provided in mcp_search_tool_bm25. Required if multiple tools have the same name."
779
+ description: "Optional: The server ID provided in mcp_search_tools. Required if multiple tools have the same name."
684
780
  }
685
781
  },
686
782
  required: ["toolName"]
@@ -690,17 +786,17 @@ function createGetSchemaToolDefinition() {
690
786
  function createExecuteToolDefinition() {
691
787
  return {
692
788
  name: "mcp_execute_tool",
693
- 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.",
789
+ 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.",
694
790
  inputSchema: {
695
791
  type: "object",
696
792
  properties: {
697
793
  toolName: {
698
794
  type: "string",
699
- description: "The exact tool name from mcp_search_tool_bm25 results."
795
+ description: "The exact tool name from mcp_search_tools results."
700
796
  },
701
797
  serverId: {
702
798
  type: "string",
703
- description: "Optional: The server ID provided in mcp_search_tool_bm25. Required if multiple tools have the same name."
799
+ description: "Optional: The server ID provided in mcp_search_tools. Required if multiple tools have the same name."
704
800
  },
705
801
  args: {
706
802
  type: "object",
@@ -713,9 +809,9 @@ function createExecuteToolDefinition() {
713
809
  };
714
810
  }
715
811
  async function executeMetaTool(toolName, args, router, callToolFn) {
716
- const resolveToolSchema = (name, namespace) => {
812
+ const resolveToolSchema = (name, namespace, options) => {
717
813
  try {
718
- return { tool: router.getToolSchema(name, namespace) };
814
+ return { tool: router.getToolSchema(name, namespace, options) };
719
815
  } catch (err) {
720
816
  const errorMessage = err instanceof Error ? err.message : String(err);
721
817
  return {
@@ -727,23 +823,61 @@ async function executeMetaTool(toolName, args, router, callToolFn) {
727
823
  }
728
824
  };
729
825
  switch (toolName) {
730
- case "mcp_search_tool_bm25": {
826
+ case "mcp_search_tools": {
731
827
  const query = String(args.query ?? "");
828
+ const operation = String(args.operation ?? "search");
829
+ const serverId = String(args.serverId ?? "") || void 0;
830
+ const serverName = String(args.serverName ?? "") || void 0;
831
+ if (operation === "list") {
832
+ const limit2 = Math.min(Number(args.limit) || 20, 100);
833
+ const cursor = String(args.cursor ?? "") || void 0;
834
+ const result = await router.listTools({
835
+ serverId,
836
+ serverName: serverName ?? (!serverId && query ? query : void 0),
837
+ limit: limit2,
838
+ cursor
839
+ });
840
+ const serverText = result.servers.length > 0 ? result.servers.map((server) => `${server.serverName} (serverId: ${server.serverId}, tools: ${server.toolCount})`).join(", ") : "none";
841
+ const lines = [
842
+ "operation: list",
843
+ `servers: ${serverText}`,
844
+ `totalCount: ${result.totalCount}`,
845
+ `returnedCount: ${result.returnedCount}`,
846
+ `nextCursor: ${result.nextCursor ?? "null"}`,
847
+ ""
848
+ ];
849
+ if (result.tools.length > 0) {
850
+ lines.push(...formatToolSummaries(result.tools));
851
+ } else {
852
+ lines.push(
853
+ serverId || serverName ? "No tools found for the requested server scope." : 'No tools found. Try operation "search" or provide serverId/serverName.'
854
+ );
855
+ }
856
+ return {
857
+ content: [{ type: "text", text: lines.join("\n") }],
858
+ isError: false
859
+ };
860
+ }
732
861
  const limit = Math.min(Number(args.limit) || 5, 20);
862
+ const searchOptions = { serverId, serverName };
733
863
  const selectMatch = query.match(/^select:(.+)$/i);
734
864
  if (selectMatch) {
865
+ await router.listTools({ serverId, serverName, limit: 1 });
735
866
  const requested = selectMatch[1].split(",").map((s) => s.trim()).filter(Boolean);
736
867
  const found = [];
737
868
  const errors = [];
869
+ const namespace = serverId ?? serverName;
738
870
  for (const requestedToolName of requested) {
739
- const { tool, error } = resolveToolSchema(requestedToolName);
871
+ const { tool, error } = resolveToolSchema(requestedToolName, namespace, {
872
+ allowServerNameFragment: Boolean(serverName && !serverId)
873
+ });
740
874
  if (error) {
741
875
  const errorMsg = error.content[0]?.type === "text" ? error.content[0].text : "Unknown error";
742
876
  errors.push(`- **${requestedToolName}**: ${errorMsg}`);
743
877
  } else if (tool) {
744
878
  found.push(tool);
745
879
  } else {
746
- errors.push(`- **${requestedToolName}**: Tool not found. Try searching with mcp_search_tool_bm25.`);
880
+ errors.push(`- **${requestedToolName}**: Tool not found. Try searching with mcp_search_tools.`);
747
881
  }
748
882
  }
749
883
  const lines = [];
@@ -764,11 +898,21 @@ async function executeMetaTool(toolName, args, router, callToolFn) {
764
898
  isError: found.length === 0
765
899
  };
766
900
  }
767
- const results = await router.searchTools(query, limit);
768
- const text = results.length === 0 ? "No tools found matching your query. Try different keywords." : results.map(
769
- (t, i) => `${i + 1}. **${t.name}** (server: ${t.serverName}, serverId: ${t.serverId})
770
- ${t.description}
771
- Estimated tokens: ${t.estimatedTokens}`
901
+ const results = await router.searchTools(query, limit, searchOptions);
902
+ 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");
903
+ return {
904
+ content: [{ type: "text", text }],
905
+ isError: false
906
+ };
907
+ }
908
+ case "mcp_list_servers": {
909
+ const query = String(args.query ?? "").trim();
910
+ const servers = await router.listServers({
911
+ serverName: query || void 0
912
+ });
913
+ const text = servers.length === 0 ? "No connected servers found." : servers.map(
914
+ (server, i) => `${i + 1}. **${server.serverName}** (serverId: ${server.serverId}, sessionId: ${server.sessionId})
915
+ Tool count: ${server.toolCount}`
772
916
  ).join("\n");
773
917
  return {
774
918
  content: [{ type: "text", text }],
@@ -779,11 +923,7 @@ async function executeMetaTool(toolName, args, router, callToolFn) {
779
923
  const pattern = String(args.query ?? "");
780
924
  const limit = Math.min(Number(args.limit) || 5, 20);
781
925
  const results = await router.searchToolsRegex(pattern, limit);
782
- const text = results.length === 0 ? "No tools matched your regex pattern. Try a broader pattern." : results.map(
783
- (t, i) => `${i + 1}. **${t.name}** (server: ${t.serverName}, serverId: ${t.serverId})
784
- ${t.description}
785
- Estimated tokens: ${t.estimatedTokens}`
786
- ).join("\n");
926
+ const text = results.length === 0 ? "No tools matched your regex pattern. Try a broader pattern." : formatToolSummaries(results).join("\n");
787
927
  return {
788
928
  content: [{ type: "text", text }],
789
929
  isError: false
@@ -801,7 +941,7 @@ async function executeMetaTool(toolName, args, router, callToolFn) {
801
941
  content: [
802
942
  {
803
943
  type: "text",
804
- text: `Tool "${name}" not found. Use mcp_search_tool_bm25 to find available tools first.`
944
+ text: `Tool "${name}" not found. Use mcp_search_tools to find available tools first.`
805
945
  }
806
946
  ],
807
947
  isError: true
@@ -810,7 +950,13 @@ async function executeMetaTool(toolName, args, router, callToolFn) {
810
950
  const schema = {
811
951
  name: tool.name,
812
952
  description: tool.description,
813
- inputSchema: tool.inputSchema
953
+ inputSchema: tool.inputSchema,
954
+ executionInstructions: {
955
+ nextTool: "mcp_execute_tool",
956
+ toolName: tool.name,
957
+ serverId: tool.serverId,
958
+ 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."
959
+ }
814
960
  };
815
961
  return {
816
962
  content: [{ type: "text", text: JSON.stringify(schema, null, 2) }],
@@ -836,7 +982,7 @@ async function executeMetaTool(toolName, args, router, callToolFn) {
836
982
  content: [
837
983
  {
838
984
  type: "text",
839
- text: `Tool "${targetToolName}" not found. Use mcp_search_tool_bm25 to discover available tools first.`
985
+ text: `Tool "${targetToolName}" not found. Use mcp_search_tools to discover available tools first.`
840
986
  }
841
987
  ],
842
988
  isError: true
@@ -870,8 +1016,15 @@ async function executeMetaTool(toolName, args, router, callToolFn) {
870
1016
  return null;
871
1017
  }
872
1018
  }
1019
+ function formatToolSummaries(tools) {
1020
+ return tools.map(
1021
+ (t, i) => `${i + 1}. **${t.name}** (server: ${t.serverName}, serverId: ${t.serverId})
1022
+ ${t.description}
1023
+ Estimated tokens: ${t.estimatedTokens}`
1024
+ );
1025
+ }
873
1026
  function isMetaTool(toolName) {
874
- return toolName === "mcp_search_tool_bm25" || toolName === "mcp_search_tool_regex" || toolName === "mcp_get_tool_schema" || toolName === "mcp_execute_tool";
1027
+ return toolName === "mcp_search_tools" || toolName === "mcp_list_servers" || toolName === "mcp_search_tool_regex" || toolName === "mcp_get_tool_schema" || toolName === "mcp_execute_tool";
875
1028
  }
876
1029
  function resolveMetaToolProxy(toolName, args) {
877
1030
  if (toolName === "mcp_execute_tool") {
@@ -919,7 +1072,7 @@ var ToolRouter = class {
919
1072
  * This is the main method adapters should call.
920
1073
  *
921
1074
  * - `all` → returns all tools (unchanged behavior)
922
- * - `search` → returns only meta-tools (mcp_search_tool_bm25, mcp_get_tool_schema, mcp_execute_tool)
1075
+ * - `search` → returns only meta-tools (mcp_search_tools, mcp_get_tool_schema, mcp_execute_tool)
923
1076
  * - `groups` → returns tools from active groups only
924
1077
  */
925
1078
  async getFilteredTools() {
@@ -948,9 +1101,10 @@ var ToolRouter = class {
948
1101
  * Search tools by natural-language query.
949
1102
  * Works regardless of strategy.
950
1103
  */
951
- async searchTools(query, topK) {
1104
+ async searchTools(query, topK, options = {}) {
952
1105
  await this.ensureInitialized();
953
- return this.index.search(query, topK ?? this.maxTools);
1106
+ const limit = topK ?? this.maxTools;
1107
+ return this.index.search(query, limit, options);
954
1108
  }
955
1109
  /**
956
1110
  * Search tools by regex pattern.
@@ -960,12 +1114,22 @@ var ToolRouter = class {
960
1114
  await this.ensureInitialized();
961
1115
  return this.index.searchRegex(pattern, topK ?? this.maxTools);
962
1116
  }
1117
+ /** List connected MCP servers with indexed tool counts. */
1118
+ async listServers(options = {}) {
1119
+ await this.ensureInitialized();
1120
+ return this.index.listServers(options);
1121
+ }
1122
+ /** List tools deterministically, optionally scoped to a server. */
1123
+ async listTools(options = {}) {
1124
+ await this.ensureInitialized();
1125
+ return this.index.listTools(options);
1126
+ }
963
1127
  /**
964
1128
  * Get the full tool definition by name.
965
1129
  * If tool name is ambiguous, use namespace to specify the server.
966
1130
  */
967
- getToolSchema(toolName, namespace) {
968
- const matches = this.index.getTool(toolName, namespace);
1131
+ getToolSchema(toolName, namespace, options = {}) {
1132
+ const matches = this.index.getTool(toolName, namespace, options);
969
1133
  if (matches.length === 0) return void 0;
970
1134
  if (matches.length > 1) {
971
1135
  const servers = matches.map((m) => m.serverId).join(", ");
@@ -1044,7 +1208,7 @@ var ToolRouter = class {
1044
1208
  const indexedTool = this.getToolSchema(toolName, namespace);
1045
1209
  if (!indexedTool) {
1046
1210
  throw new Error(
1047
- `Tool "${toolName}" not found${namespace ? ` on server "${namespace}"` : ""}. Use mcp_search_tool_bm25 or mcp_search_tool_regex to discover available tools.`
1211
+ `Tool "${toolName}" not found${namespace ? ` on server "${namespace}"` : ""}. Use mcp_search_tools or mcp_search_tool_regex to discover available tools.`
1048
1212
  );
1049
1213
  }
1050
1214
  const clients = this.getClients();
@@ -1156,6 +1320,7 @@ var ToolRouter = class {
1156
1320
  getMetaToolDefinitions() {
1157
1321
  return [
1158
1322
  createSearchToolDefinition(),
1323
+ createListServersToolDefinition(),
1159
1324
  createRegexSearchToolDefinition(),
1160
1325
  createGetSchemaToolDefinition(),
1161
1326
  createExecuteToolDefinition()
@@ -1163,6 +1328,6 @@ var ToolRouter = class {
1163
1328
  }
1164
1329
  };
1165
1330
 
1166
- export { AuthenticationError, ConfigurationError, ConnectionError, DEFAULT_CLIENT_NAME, DEFAULT_CLIENT_URI, DEFAULT_HEARTBEAT_INTERVAL_MS, DEFAULT_LOGO_URI, DEFAULT_POLICY_URI, DisposableStore, Emitter, InvalidStateError, MCP_CLIENT_NAME, MCP_CLIENT_VERSION, McpError, NotConnectedError, REDIS_KEY_PREFIX, RpcErrorCodes, SESSION_TTL_SECONDS, SOFTWARE_ID, SOFTWARE_VERSION, STATE_EXPIRATION_MS, SchemaCompressor, SessionNotFoundError, SessionValidationError, TOKEN_EXPIRY_BUFFER_MS, ToolExecutionError, ToolIndex, ToolRouter, UnauthorizedError, createExecuteToolDefinition, createGetSchemaToolDefinition, createRegexSearchToolDefinition, createSearchToolDefinition, executeMetaTool, findToolByName, getToolUiResourceUri, isCallToolSuccess, isConnectAuthRequired, isConnectError, isConnectSuccess, isListToolsSuccess, isMetaTool, resolveMetaToolProxy, sanitizeServerLabel };
1331
+ export { AuthenticationError, ConfigurationError, ConnectionError, DEFAULT_CLIENT_NAME, DEFAULT_CLIENT_URI, DEFAULT_HEARTBEAT_INTERVAL_MS, DEFAULT_LOGO_URI, DEFAULT_POLICY_URI, DisposableStore, Emitter, InvalidStateError, MCP_CLIENT_NAME, MCP_CLIENT_VERSION, McpError, NotConnectedError, REDIS_KEY_PREFIX, RpcErrorCodes, SESSION_TTL_SECONDS, SOFTWARE_ID, SOFTWARE_VERSION, STATE_EXPIRATION_MS, SchemaCompressor, SessionNotFoundError, SessionValidationError, TOKEN_EXPIRY_BUFFER_MS, ToolExecutionError, ToolIndex, ToolRouter, UnauthorizedError, createExecuteToolDefinition, createGetSchemaToolDefinition, createListServersToolDefinition, createRegexSearchToolDefinition, createSearchToolDefinition, executeMetaTool, findToolByName, getToolUiResourceUri, isCallToolSuccess, isConnectAuthRequired, isConnectError, isConnectSuccess, isListToolsSuccess, isMetaTool, resolveMetaToolProxy, sanitizeServerLabel };
1167
1332
  //# sourceMappingURL=index.mjs.map
1168
1333
  //# sourceMappingURL=index.mjs.map