@mcp-ts/sdk 1.5.0 → 1.5.2

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 (66) hide show
  1. package/dist/adapters/agui-adapter.d.mts +1 -1
  2. package/dist/adapters/agui-adapter.d.ts +1 -1
  3. package/dist/adapters/agui-adapter.js +43 -9
  4. package/dist/adapters/agui-adapter.js.map +1 -1
  5. package/dist/adapters/agui-adapter.mjs +43 -9
  6. package/dist/adapters/agui-adapter.mjs.map +1 -1
  7. package/dist/adapters/agui-middleware.d.mts +1 -1
  8. package/dist/adapters/agui-middleware.d.ts +1 -1
  9. package/dist/adapters/agui-middleware.js.map +1 -1
  10. package/dist/adapters/agui-middleware.mjs.map +1 -1
  11. package/dist/adapters/ai-adapter.d.mts +1 -1
  12. package/dist/adapters/ai-adapter.d.ts +1 -1
  13. package/dist/adapters/ai-adapter.js +42 -8
  14. package/dist/adapters/ai-adapter.js.map +1 -1
  15. package/dist/adapters/ai-adapter.mjs +42 -8
  16. package/dist/adapters/ai-adapter.mjs.map +1 -1
  17. package/dist/adapters/langchain-adapter.d.mts +1 -1
  18. package/dist/adapters/langchain-adapter.d.ts +1 -1
  19. package/dist/adapters/langchain-adapter.js +42 -8
  20. package/dist/adapters/langchain-adapter.js.map +1 -1
  21. package/dist/adapters/langchain-adapter.mjs +42 -8
  22. package/dist/adapters/langchain-adapter.mjs.map +1 -1
  23. package/dist/client/react.d.mts +91 -2
  24. package/dist/client/react.d.ts +91 -2
  25. package/dist/client/react.js +339 -3
  26. package/dist/client/react.js.map +1 -1
  27. package/dist/client/react.mjs +335 -4
  28. package/dist/client/react.mjs.map +1 -1
  29. package/dist/client/vue.d.mts +10 -0
  30. package/dist/client/vue.d.ts +10 -0
  31. package/dist/client/vue.js +28 -2
  32. package/dist/client/vue.js.map +1 -1
  33. package/dist/client/vue.mjs +28 -2
  34. package/dist/client/vue.mjs.map +1 -1
  35. package/dist/index.d.mts +1 -1
  36. package/dist/index.d.ts +1 -1
  37. package/dist/index.js +170 -37
  38. package/dist/index.js.map +1 -1
  39. package/dist/index.mjs +170 -37
  40. package/dist/index.mjs.map +1 -1
  41. package/dist/server/index.js +55 -11
  42. package/dist/server/index.js.map +1 -1
  43. package/dist/server/index.mjs +55 -11
  44. package/dist/server/index.mjs.map +1 -1
  45. package/dist/shared/index.d.mts +2 -2
  46. package/dist/shared/index.d.ts +2 -2
  47. package/dist/shared/index.js +115 -26
  48. package/dist/shared/index.js.map +1 -1
  49. package/dist/shared/index.mjs +115 -26
  50. package/dist/shared/index.mjs.map +1 -1
  51. package/dist/{tool-router-XnWVxPzv.d.mts → tool-router-DK0RJblO.d.mts} +3 -0
  52. package/dist/{tool-router-Bo8qZbsD.d.ts → tool-router-DsKhRmJm.d.ts} +3 -0
  53. package/package.json +1 -1
  54. package/src/adapters/agui-adapter.ts +7 -7
  55. package/src/adapters/ai-adapter.ts +5 -5
  56. package/src/adapters/langchain-adapter.ts +5 -5
  57. package/src/client/react/index.ts +14 -0
  58. package/src/client/react/oauth-popup.tsx +446 -0
  59. package/src/client/react/use-mcp.ts +84 -3
  60. package/src/client/vue/use-mcp.ts +80 -3
  61. package/src/server/handlers/sse-handler.ts +39 -0
  62. package/src/server/mcp/oauth-client.ts +32 -14
  63. package/src/shared/meta-tools.ts +62 -13
  64. package/src/shared/tool-index.ts +85 -12
  65. package/src/shared/tool-router.ts +8 -7
  66. package/supabase/migrations/20260421010000_add_session_cleanup_cron.sql +32 -0
package/dist/index.js CHANGED
@@ -1785,13 +1785,8 @@ var MCPClient = class _MCPClient {
1785
1785
  this.transportType = transportType;
1786
1786
  this.emitStateChange("CONNECTED");
1787
1787
  this.emitProgress("Connected successfully");
1788
- const existingSession = await storage.getSession(this.identity, this.sessionId);
1789
- const needsTransportUpdate = !existingSession || existingSession.transportType !== this.transportType;
1790
- const needsTtlPromotion = !existingSession || existingSession.active !== true;
1791
- if (needsTransportUpdate || needsTtlPromotion) {
1792
- console.log(`[MCPClient] Saving session ${this.sessionId} with 12hr TTL (connect success)`);
1793
- await this.saveSession(SESSION_TTL_SECONDS, true);
1794
- }
1788
+ console.log(`[MCPClient] Saving session ${this.sessionId} with 12hr TTL (connect success)`);
1789
+ await this.saveSession(SESSION_TTL_SECONDS, true);
1795
1790
  } catch (error) {
1796
1791
  if (error instanceof auth_js.UnauthorizedError || error instanceof Error && error.message.toLowerCase().includes("unauthorized")) {
1797
1792
  let authUrl = "";
@@ -1829,6 +1824,13 @@ var MCPClient = class _MCPClient {
1829
1824
  const errorMessage = error instanceof Error ? error.message : "Connection failed";
1830
1825
  this.emitError(errorMessage, "connection");
1831
1826
  this.emitStateChange("FAILED");
1827
+ try {
1828
+ const existingSession = await storage.getSession(this.identity, this.sessionId);
1829
+ if (!existingSession || existingSession.active !== true) {
1830
+ await storage.removeSession(this.identity, this.sessionId);
1831
+ }
1832
+ } catch {
1833
+ }
1832
1834
  throw error;
1833
1835
  }
1834
1836
  }
@@ -1852,6 +1854,7 @@ var MCPClient = class _MCPClient {
1852
1854
  const transportsToTry = this.transportType ? [this.transportType] : ["streamable_http", "sse"];
1853
1855
  let lastError;
1854
1856
  let tokensExchanged = false;
1857
+ let authenticatedStateEmitted = false;
1855
1858
  for (const currentType of transportsToTry) {
1856
1859
  const isLastAttempt = currentType === transportsToTry[transportsToTry.length - 1];
1857
1860
  try {
@@ -1863,8 +1866,10 @@ var MCPClient = class _MCPClient {
1863
1866
  } else {
1864
1867
  this.emitProgress(`Tokens already exchanged, skipping auth step for ${currentType}...`);
1865
1868
  }
1866
- this.transportType = currentType;
1867
- this.emitStateChange("AUTHENTICATED");
1869
+ if (!authenticatedStateEmitted) {
1870
+ this.emitStateChange("AUTHENTICATED");
1871
+ authenticatedStateEmitted = true;
1872
+ }
1868
1873
  this.emitProgress("Creating authenticated client...");
1869
1874
  this.client = new index_js.Client(
1870
1875
  {
@@ -1883,6 +1888,7 @@ var MCPClient = class _MCPClient {
1883
1888
  );
1884
1889
  this.emitStateChange("CONNECTING");
1885
1890
  await this.client.connect(this.transport);
1891
+ this.transportType = currentType;
1886
1892
  this.emitStateChange("CONNECTED");
1887
1893
  console.log(`[MCPClient] Updating session ${this.sessionId} to 12hr TTL (OAuth complete)`);
1888
1894
  await this.saveSession(SESSION_TTL_SECONDS, true);
@@ -2754,9 +2760,23 @@ var SSEConnectionManager = class {
2754
2760
  if (existing) {
2755
2761
  return existing;
2756
2762
  }
2763
+ const session = await storage.getSession(this.identity, sessionId);
2764
+ if (!session) {
2765
+ throw new Error("Session not found");
2766
+ }
2757
2767
  const client = new MCPClient({
2758
2768
  identity: this.identity,
2759
- sessionId
2769
+ sessionId,
2770
+ // These fields are optional in MCPClient, but when rehydrating a known
2771
+ // stored session on the server we pass them explicitly to preserve the
2772
+ // original transport/connection metadata instead of relying on lazy
2773
+ // reloading during initialize().
2774
+ serverId: session.serverId,
2775
+ serverName: session.serverName,
2776
+ serverUrl: session.serverUrl,
2777
+ callbackUrl: session.callbackUrl,
2778
+ transportType: session.transportType,
2779
+ headers: session.headers
2760
2780
  });
2761
2781
  client.onConnectionEvent((event) => this.emitConnectionEvent(event));
2762
2782
  client.onObservabilityEvent((event) => this.sendEvent(event));
@@ -2813,6 +2833,16 @@ var SSEConnectionManager = class {
2813
2833
  const client = new MCPClient({
2814
2834
  identity: this.identity,
2815
2835
  sessionId,
2836
+ // These fields are optional in MCPClient, but when rehydrating a known
2837
+ // stored session on the server we pass them explicitly to preserve the
2838
+ // original transport/connection metadata instead of relying on lazy
2839
+ // reloading during initialize().
2840
+ serverId: session.serverId,
2841
+ serverName: session.serverName,
2842
+ serverUrl: session.serverUrl,
2843
+ callbackUrl: session.callbackUrl,
2844
+ transportType: session.transportType,
2845
+ headers: session.headers,
2816
2846
  ...clientMetadata
2817
2847
  });
2818
2848
  client.onConnectionEvent((event) => this.emitConnectionEvent(event));
@@ -2845,7 +2875,21 @@ var SSEConnectionManager = class {
2845
2875
  try {
2846
2876
  const client = new MCPClient({
2847
2877
  identity: this.identity,
2848
- sessionId
2878
+ sessionId,
2879
+ // These fields are optional in MCPClient, but when rehydrating a known
2880
+ // stored session on the server we pass them explicitly to preserve the
2881
+ // original connection metadata instead of relying on lazy
2882
+ // reloading during initialize().
2883
+ serverId: session.serverId,
2884
+ serverName: session.serverName,
2885
+ serverUrl: session.serverUrl,
2886
+ callbackUrl: session.callbackUrl,
2887
+ // NOTE: transportType is intentionally omitted here.
2888
+ // The session's stored transportType is a placeholder ('streamable_http')
2889
+ // set before transport negotiation. Omitting it lets MCPClient auto-negotiate
2890
+ // (try streamable_http → SSE fallback), which is critical for servers like
2891
+ // Neon that only support SSE transport.
2892
+ headers: session.headers
2849
2893
  });
2850
2894
  client.onConnectionEvent((event) => this.emitConnectionEvent(event));
2851
2895
  await client.finishAuth(code);
@@ -3937,6 +3981,7 @@ var ToolIndex = class _ToolIndex {
3937
3981
  name: tool.name,
3938
3982
  description: tool.description ?? "",
3939
3983
  serverName: tool.serverName,
3984
+ serverId: tool.serverId,
3940
3985
  sessionId: tool.sessionId,
3941
3986
  estimatedTokens
3942
3987
  });
@@ -3999,12 +4044,50 @@ var ToolIndex = class _ToolIndex {
3999
4044
  */
4000
4045
  async search(query, topK = 5) {
4001
4046
  if (this.tools.size === 0) return [];
4002
- const queryLower = query.toLowerCase();
4003
- const queryTokens = this.tokenize(queryLower);
4047
+ const queryLower = query.toLowerCase().trim();
4048
+ const exactMatches = [...this.toolSummaries.values()].filter(
4049
+ (summary) => summary.name.toLowerCase() === queryLower
4050
+ );
4051
+ if (exactMatches.length > 0) {
4052
+ return exactMatches.slice(0, topK);
4053
+ }
4054
+ if (queryLower.startsWith("mcp__") && queryLower.length > 5) {
4055
+ const prefixMatches = [...this.toolSummaries.values()].filter((t) => t.name.toLowerCase().startsWith(queryLower)).slice(0, topK);
4056
+ if (prefixMatches.length > 0) return prefixMatches;
4057
+ }
4058
+ const queryTermsRaw = queryLower.split(/\s+/).filter((t) => t.length > 0);
4059
+ const requiredTerms = [];
4060
+ const optionalTerms = [];
4061
+ for (const term of queryTermsRaw) {
4062
+ if (term.startsWith("+") && term.length > 1) {
4063
+ requiredTerms.push(term.slice(1));
4064
+ } else {
4065
+ optionalTerms.push(term);
4066
+ }
4067
+ }
4068
+ const allScoringTerms = requiredTerms.length > 0 ? [...requiredTerms, ...optionalTerms] : queryTermsRaw;
4069
+ const normalizedQueryText = allScoringTerms.join(" ").trim();
4070
+ const queryTokens = this.tokenize(allScoringTerms.join(" "));
4071
+ const candidateKeys = /* @__PURE__ */ new Set();
4072
+ for (const docKey of this.toolSummaries.keys()) {
4073
+ if (requiredTerms.length > 0) {
4074
+ const text = this.searchTexts.get(docKey) || "";
4075
+ const summary = this.toolSummaries.get(docKey);
4076
+ const nameLower = summary.name.toLowerCase();
4077
+ const matchesAll = requiredTerms.every(
4078
+ (term) => text.includes(term) || nameLower.includes(term)
4079
+ );
4080
+ if (!matchesAll) continue;
4081
+ }
4082
+ candidateKeys.add(docKey);
4083
+ }
4004
4084
  const keywordScores = /* @__PURE__ */ new Map();
4005
4085
  const k1 = 1.2;
4006
4086
  const b = 0.75;
4007
- for (const [docKey, docTf] of this.tfVectors) {
4087
+ for (const docKey of candidateKeys) {
4088
+ const docTf = this.tfVectors.get(docKey);
4089
+ if (!docTf) continue;
4090
+ const summary = this.toolSummaries.get(docKey);
4008
4091
  let score = 0;
4009
4092
  const docLen = this.docLengths.get(docKey) ?? 0;
4010
4093
  for (const tok of queryTokens) {
@@ -4015,16 +4098,31 @@ var ToolIndex = class _ToolIndex {
4015
4098
  const denominator = tfVal + k1 * (1 - b + b * (docLen / this.avgDocLength));
4016
4099
  score += idf * (numerator / denominator);
4017
4100
  }
4018
- keywordScores.set(docKey, score);
4101
+ const serverLower = (summary.serverName || summary.serverId || "").toLowerCase();
4102
+ const toolLower = summary.name.toLowerCase();
4103
+ for (const term of allScoringTerms) {
4104
+ if (serverLower.includes(term)) {
4105
+ score += 10;
4106
+ }
4107
+ if (toolLower.includes(term)) {
4108
+ score += 5;
4109
+ }
4110
+ }
4111
+ if (score > 0) {
4112
+ keywordScores.set(docKey, score);
4113
+ }
4019
4114
  }
4020
4115
  let embeddingScores = null;
4021
4116
  if (this.options.embedFn && this.embeddings.size > 0) {
4022
4117
  try {
4023
- const [queryEmbedding] = await this.options.embedFn([queryLower]);
4118
+ const [queryEmbedding] = await this.options.embedFn([normalizedQueryText]);
4024
4119
  if (queryEmbedding) {
4025
4120
  embeddingScores = /* @__PURE__ */ new Map();
4026
- for (const [docKey, vec] of this.embeddings) {
4027
- embeddingScores.set(docKey, this.cosineSimilarity(queryEmbedding, vec));
4121
+ for (const docKey of candidateKeys) {
4122
+ const vec = this.embeddings.get(docKey);
4123
+ if (vec) {
4124
+ embeddingScores.set(docKey, this.cosineSimilarity(queryEmbedding, vec));
4125
+ }
4028
4126
  }
4029
4127
  }
4030
4128
  } catch {
@@ -4032,7 +4130,7 @@ var ToolIndex = class _ToolIndex {
4032
4130
  }
4033
4131
  const kw = this.options.keywordWeight;
4034
4132
  const finalScores = [];
4035
- for (const docKey of this.toolSummaries.keys()) {
4133
+ for (const docKey of candidateKeys) {
4036
4134
  const kwScore = keywordScores.get(docKey) ?? 0;
4037
4135
  const embScore = embeddingScores?.get(docKey) ?? 0;
4038
4136
  const score = embeddingScores ? kw * kwScore + (1 - kw) * embScore : kwScore;
@@ -4090,7 +4188,7 @@ var ToolIndex = class _ToolIndex {
4090
4188
  getTool(name, namespace) {
4091
4189
  const list = this.tools.get(name) ?? [];
4092
4190
  if (!namespace) return list;
4093
- return list.filter((t) => t.sessionId === namespace || t.serverName === namespace);
4191
+ return list.filter((t) => t.sessionId === namespace || t.serverId === namespace);
4094
4192
  }
4095
4193
  /** All indexed tool names. */
4096
4194
  getToolNames() {
@@ -4150,7 +4248,7 @@ var ToolIndex = class _ToolIndex {
4150
4248
  return parts.join(" ");
4151
4249
  }
4152
4250
  getDocumentKey(tool) {
4153
- return `${tool.sessionId}::${tool.serverName}::${tool.name}`;
4251
+ return `${tool.sessionId}::${tool.serverId}::${tool.name}`;
4154
4252
  }
4155
4253
  /** Simple whitespace + camelCase + snake_case tokenizer. */
4156
4254
  tokenize(text) {
@@ -4238,13 +4336,13 @@ init_cjs_shims();
4238
4336
  function createSearchToolDefinition() {
4239
4337
  return {
4240
4338
  name: "mcp_search_tool_bm25",
4241
- description: 'Search the catalog of available tools using BM25 natural language ranking. Returns tool names, descriptions, and server info. Use this FIRST to find relevant tools before calling them. Example queries: "database query", "send email", "github pull request".',
4339
+ 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',
4242
4340
  inputSchema: {
4243
4341
  type: "object",
4244
4342
  properties: {
4245
4343
  query: {
4246
4344
  type: "string",
4247
- description: "Natural language description of the capability you need."
4345
+ description: 'Query to find tools. Use "select:<tool_name>" for direct selection, or keywords to search. Prefix keywords with + to require them.'
4248
4346
  },
4249
4347
  limit: {
4250
4348
  type: "number",
@@ -4286,9 +4384,9 @@ function createGetSchemaToolDefinition() {
4286
4384
  type: "string",
4287
4385
  description: "The exact tool name returned by mcp_search_tool_bm25."
4288
4386
  },
4289
- serverName: {
4387
+ serverId: {
4290
4388
  type: "string",
4291
- description: "Optional: The server name provided in mcp_search_tool_bm25. Required if multiple tools have the same name."
4389
+ description: "Optional: The server ID provided in mcp_search_tool_bm25. Required if multiple tools have the same name."
4292
4390
  }
4293
4391
  },
4294
4392
  required: ["toolName"]
@@ -4306,9 +4404,9 @@ function createExecuteToolDefinition() {
4306
4404
  type: "string",
4307
4405
  description: "The exact tool name from mcp_search_tool_bm25 results."
4308
4406
  },
4309
- serverName: {
4407
+ serverId: {
4310
4408
  type: "string",
4311
- description: "Optional: The server name provided in mcp_search_tool_bm25. Required if multiple tools have the same name."
4409
+ description: "Optional: The server ID provided in mcp_search_tool_bm25. Required if multiple tools have the same name."
4312
4410
  },
4313
4411
  args: {
4314
4412
  type: "object",
@@ -4338,9 +4436,43 @@ async function executeMetaTool(toolName, args, router, callToolFn) {
4338
4436
  case "mcp_search_tool_bm25": {
4339
4437
  const query = String(args.query ?? "");
4340
4438
  const limit = Math.min(Number(args.limit) || 5, 20);
4439
+ const selectMatch = query.match(/^select:(.+)$/i);
4440
+ if (selectMatch) {
4441
+ const requested = selectMatch[1].split(",").map((s) => s.trim()).filter(Boolean);
4442
+ const found = [];
4443
+ const errors = [];
4444
+ for (const requestedToolName of requested) {
4445
+ const { tool, error } = resolveToolSchema(requestedToolName);
4446
+ if (error) {
4447
+ const errorMsg = error.content[0]?.type === "text" ? error.content[0].text : "Unknown error";
4448
+ errors.push(`- **${requestedToolName}**: ${errorMsg}`);
4449
+ } else if (tool) {
4450
+ found.push(tool);
4451
+ } else {
4452
+ errors.push(`- **${requestedToolName}**: Tool not found. Try searching with mcp_search_tool_bm25.`);
4453
+ }
4454
+ }
4455
+ const lines = [];
4456
+ if (found.length > 0) {
4457
+ lines.push(...found.map(
4458
+ (t, i) => `${i + 1}. **${t.name}** (server: ${t.serverName}, serverId: ${t.serverId})
4459
+ ${t.description}`
4460
+ ));
4461
+ }
4462
+ if (errors.length > 0) {
4463
+ if (lines.length > 0) lines.push("");
4464
+ lines.push("Errors resolving some tools:");
4465
+ lines.push(...errors);
4466
+ }
4467
+ const text2 = lines.length > 0 ? lines.join("\n") : `No tools found matching select query: ${requested.join(", ")}`;
4468
+ return {
4469
+ content: [{ type: "text", text: text2 }],
4470
+ isError: found.length === 0
4471
+ };
4472
+ }
4341
4473
  const results = await router.searchTools(query, limit);
4342
4474
  const text = results.length === 0 ? "No tools found matching your query. Try different keywords." : results.map(
4343
- (t, i) => `${i + 1}. **${t.name}** (server: ${t.serverName})
4475
+ (t, i) => `${i + 1}. **${t.name}** (server: ${t.serverName}, serverId: ${t.serverId})
4344
4476
  ${t.description}
4345
4477
  Estimated tokens: ${t.estimatedTokens}`
4346
4478
  ).join("\n");
@@ -4354,7 +4486,7 @@ async function executeMetaTool(toolName, args, router, callToolFn) {
4354
4486
  const limit = Math.min(Number(args.limit) || 5, 20);
4355
4487
  const results = await router.searchToolsRegex(pattern, limit);
4356
4488
  const text = results.length === 0 ? "No tools matched your regex pattern. Try a broader pattern." : results.map(
4357
- (t, i) => `${i + 1}. **${t.name}** (server: ${t.serverName})
4489
+ (t, i) => `${i + 1}. **${t.name}** (server: ${t.serverName}, serverId: ${t.serverId})
4358
4490
  ${t.description}
4359
4491
  Estimated tokens: ${t.estimatedTokens}`
4360
4492
  ).join("\n");
@@ -4365,7 +4497,7 @@ async function executeMetaTool(toolName, args, router, callToolFn) {
4365
4497
  }
4366
4498
  case "mcp_get_tool_schema": {
4367
4499
  const name = String(args.toolName ?? "");
4368
- const namespace = String(args.serverName ?? "") || void 0;
4500
+ const namespace = String(args.serverId ?? "") || void 0;
4369
4501
  const { tool, error } = resolveToolSchema(name, namespace);
4370
4502
  if (error) {
4371
4503
  return error;
@@ -4393,7 +4525,7 @@ async function executeMetaTool(toolName, args, router, callToolFn) {
4393
4525
  }
4394
4526
  case "mcp_execute_tool": {
4395
4527
  const targetToolName = String(args.toolName ?? "");
4396
- const namespace = String(args.serverName ?? "") || void 0;
4528
+ const namespace = String(args.serverId ?? "") || void 0;
4397
4529
  const toolArgs = args.args ?? {};
4398
4530
  if (!targetToolName) {
4399
4531
  return {
@@ -4542,9 +4674,9 @@ var ToolRouter = class {
4542
4674
  const matches = this.index.getTool(toolName, namespace);
4543
4675
  if (matches.length === 0) return void 0;
4544
4676
  if (matches.length > 1) {
4545
- const servers = matches.map((m) => m.serverName).join(", ");
4677
+ const servers = matches.map((m) => m.serverId).join(", ");
4546
4678
  throw new Error(
4547
- `Tool "${toolName}" is provided by multiple servers: [${servers}]. Please specify the desired "serverName" as a namespace.`
4679
+ `Tool "${toolName}" is provided by multiple servers: [${servers}]. Please specify the desired "serverId" as a namespace.`
4548
4680
  );
4549
4681
  }
4550
4682
  return matches[0];
@@ -4655,6 +4787,7 @@ var ToolRouter = class {
4655
4787
  for (const tool of tools) {
4656
4788
  result.push({
4657
4789
  ...tool,
4790
+ serverId,
4658
4791
  serverName,
4659
4792
  sessionId
4660
4793
  });
@@ -4688,16 +4821,16 @@ var ToolRouter = class {
4688
4821
  } else {
4689
4822
  const serverTools = /* @__PURE__ */ new Map();
4690
4823
  for (const tool of this.allTools) {
4691
- const group = tool.serverName;
4824
+ const group = tool.serverId;
4692
4825
  if (!serverTools.has(group)) {
4693
4826
  serverTools.set(group, []);
4694
4827
  }
4695
4828
  serverTools.get(group).push(tool.name);
4696
4829
  }
4697
- for (const [serverName, tools] of serverTools) {
4698
- this.groupsMap.set(serverName, {
4830
+ for (const [serverId, tools] of serverTools) {
4831
+ this.groupsMap.set(serverId, {
4699
4832
  tools,
4700
- active: this.activeGroups.size === 0 || this.activeGroups.has(serverName)
4833
+ active: this.activeGroups.size === 0 || this.activeGroups.has(serverId)
4701
4834
  });
4702
4835
  }
4703
4836
  }