@mcp-ts/sdk 1.4.0 → 1.5.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 (71) hide show
  1. package/README.md +20 -27
  2. package/dist/adapters/agui-adapter.d.mts +16 -0
  3. package/dist/adapters/agui-adapter.d.ts +16 -0
  4. package/dist/adapters/agui-adapter.js +185 -0
  5. package/dist/adapters/agui-adapter.js.map +1 -1
  6. package/dist/adapters/agui-adapter.mjs +185 -0
  7. package/dist/adapters/agui-adapter.mjs.map +1 -1
  8. package/dist/adapters/agui-middleware.d.mts +2 -0
  9. package/dist/adapters/agui-middleware.d.ts +2 -0
  10. package/dist/adapters/agui-middleware.js.map +1 -1
  11. package/dist/adapters/agui-middleware.mjs.map +1 -1
  12. package/dist/adapters/ai-adapter.d.mts +21 -0
  13. package/dist/adapters/ai-adapter.d.ts +21 -0
  14. package/dist/adapters/ai-adapter.js +175 -0
  15. package/dist/adapters/ai-adapter.js.map +1 -1
  16. package/dist/adapters/ai-adapter.mjs +175 -0
  17. package/dist/adapters/ai-adapter.mjs.map +1 -1
  18. package/dist/adapters/langchain-adapter.d.mts +16 -0
  19. package/dist/adapters/langchain-adapter.d.ts +16 -0
  20. package/dist/adapters/langchain-adapter.js +179 -0
  21. package/dist/adapters/langchain-adapter.js.map +1 -1
  22. package/dist/adapters/langchain-adapter.mjs +179 -0
  23. package/dist/adapters/langchain-adapter.mjs.map +1 -1
  24. package/dist/client/index.d.mts +2 -2
  25. package/dist/client/index.d.ts +2 -2
  26. package/dist/client/react.d.mts +14 -7
  27. package/dist/client/react.d.ts +14 -7
  28. package/dist/client/react.js +48 -23
  29. package/dist/client/react.js.map +1 -1
  30. package/dist/client/react.mjs +47 -24
  31. package/dist/client/react.mjs.map +1 -1
  32. package/dist/client/vue.d.mts +4 -4
  33. package/dist/client/vue.d.ts +4 -4
  34. package/dist/{index-CQr9q0bF.d.mts → index-DcYfpY3H.d.mts} +1 -1
  35. package/dist/{index-nE_7Io0I.d.ts → index-GfC_eNEv.d.ts} +1 -1
  36. package/dist/index.d.mts +4 -3
  37. package/dist/index.d.ts +4 -3
  38. package/dist/index.js +883 -1
  39. package/dist/index.js.map +1 -1
  40. package/dist/index.mjs +868 -2
  41. package/dist/index.mjs.map +1 -1
  42. package/dist/server/index.d.mts +2 -2
  43. package/dist/server/index.d.ts +2 -2
  44. package/dist/server/index.js +3 -1
  45. package/dist/server/index.js.map +1 -1
  46. package/dist/server/index.mjs +3 -1
  47. package/dist/server/index.mjs.map +1 -1
  48. package/dist/shared/index.d.mts +86 -4
  49. package/dist/shared/index.d.ts +86 -4
  50. package/dist/shared/index.js +874 -0
  51. package/dist/shared/index.js.map +1 -1
  52. package/dist/shared/index.mjs +865 -1
  53. package/dist/shared/index.mjs.map +1 -1
  54. package/dist/tool-router-Bo8qZbsD.d.ts +325 -0
  55. package/dist/tool-router-XnWVxPzv.d.mts +325 -0
  56. package/dist/{types-CW6lghof.d.mts → types-CfCoIsWI.d.mts} +27 -1
  57. package/dist/{types-CW6lghof.d.ts → types-CfCoIsWI.d.ts} +27 -1
  58. package/package.json +3 -2
  59. package/src/adapters/agui-adapter.ts +79 -0
  60. package/src/adapters/ai-adapter.ts +75 -0
  61. package/src/adapters/langchain-adapter.ts +74 -0
  62. package/src/client/react/index.ts +2 -0
  63. package/src/client/react/use-mcp-apps.tsx +50 -32
  64. package/src/server/index.ts +2 -0
  65. package/src/server/mcp/oauth-client.ts +3 -1
  66. package/src/shared/index.ts +36 -0
  67. package/src/shared/meta-tools.ts +387 -0
  68. package/src/shared/schema-compressor.ts +124 -0
  69. package/src/shared/tool-index.ts +499 -0
  70. package/src/shared/tool-router.ts +469 -0
  71. package/src/shared/types.ts +30 -0
@@ -2,6 +2,8 @@ import { MCPClient } from '../server/mcp/oauth-client';
2
2
  import { MultiSessionClient } from '../server/mcp/multi-session-client';
3
3
  import type { DynamicStructuredTool, StructuredTool } from '@langchain/core/tools';
4
4
  import type { z } from 'zod';
5
+ import { ToolRouter } from '../shared/tool-router.js';
6
+ import { executeMetaTool, isMetaTool } from '../shared/meta-tools.js';
5
7
 
6
8
  export interface LangChainAdapterOptions {
7
9
  /**
@@ -16,6 +18,12 @@ export interface LangChainAdapterOptions {
16
18
  * @default false
17
19
  */
18
20
  simplifyErrors?: boolean;
21
+
22
+ /**
23
+ * Optional ToolRouter for intelligent tool selection.
24
+ * See AIAdapterOptions.toolRouter for details.
25
+ */
26
+ toolRouter?: ToolRouter;
19
27
  }
20
28
 
21
29
  /**
@@ -99,6 +107,11 @@ export class LangChainAdapter {
99
107
  * Fetches tools from the MCP server and converts them to LangChain StructuredTools.
100
108
  */
101
109
  async getTools(): Promise<StructuredTool[]> {
110
+ // If a ToolRouter is provided, use its filtered output
111
+ if (this.options.toolRouter) {
112
+ return this.getToolsViaRouter(this.options.toolRouter);
113
+ }
114
+
102
115
  // Use duck typing instead of instanceof to handle module bundling issues
103
116
  const isMultiSession = typeof (this.client as any).getClients === 'function';
104
117
  const clients = isMultiSession
@@ -118,6 +131,67 @@ export class LangChainAdapter {
118
131
  return results.flat();
119
132
  }
120
133
 
134
+ /**
135
+ * Build StructuredTools from a ToolRouter's filtered output.
136
+ *
137
+ * In `search` strategy, only meta-tools are registered with the framework.
138
+ * Real tool execution is proxied through `mcp_execute_tool` which uses
139
+ * `router.callTool()` to route to the correct MCP client.
140
+ */
141
+ private async getToolsViaRouter(router: ToolRouter): Promise<StructuredTool[]> {
142
+ await this.ensureDependencies();
143
+
144
+ const filteredTools = await router.getFilteredTools();
145
+
146
+ return filteredTools.map((tool) => {
147
+ const routedTool = tool as typeof tool & { sessionId?: string; serverName?: string };
148
+ const namespace = routedTool.serverName ?? routedTool.sessionId;
149
+ const schema = this.jsonSchemaToZod(tool.inputSchema);
150
+
151
+ return new this.DynamicStructuredTool!({
152
+ name: isMetaTool(tool.name)
153
+ ? tool.name
154
+ : this.getRouterToolKey(tool.name, routedTool.sessionId, routedTool.serverName),
155
+ description: tool.description || `Tool ${tool.name}`,
156
+ schema: schema,
157
+ func: async (args: any) => {
158
+ try {
159
+ // Handle meta-tool calls via the router
160
+ if (isMetaTool(tool.name)) {
161
+ const result = await executeMetaTool(
162
+ tool.name,
163
+ args,
164
+ router,
165
+ (name, toolArgs, namespace) => router.callTool(name, toolArgs, namespace)
166
+ );
167
+ if (result) {
168
+ return result.content.map((c: any) => c.text ?? '').join('\n');
169
+ }
170
+ }
171
+
172
+ // For non-meta tools in 'all' or 'groups' strategy,
173
+ // route directly to the correct MCP client
174
+ return await router.callTool(tool.name, args, namespace);
175
+ } catch (error: any) {
176
+ if (this.options.simplifyErrors) {
177
+ return `Error: ${error.message}`;
178
+ }
179
+ throw error;
180
+ }
181
+ },
182
+ });
183
+ });
184
+ }
185
+
186
+ private getRouterToolKey(toolName: string, sessionId?: string, serverName?: string): string {
187
+ const namespace = sessionId ?? serverName ?? 'mcp';
188
+ const normalized = namespace
189
+ .toLowerCase()
190
+ .replace(/[^a-z0-9]+/g, '_')
191
+ .replace(/^_+|_+$/g, '') || 'mcp';
192
+ return `tool_${normalized}_${toolName}`;
193
+ }
194
+
121
195
  /**
122
196
  * Convenience static method to fetch tools in a single line.
123
197
  */
@@ -12,6 +12,8 @@ export { useAppHost } from './use-app-host.js';
12
12
  // Simplified MCP Apps Hook - the main API
13
13
  export {
14
14
  useMcpApps,
15
+ McpAppRenderer,
16
+ getMcpAppMetadata,
15
17
  type McpAppRendererProps,
16
18
  type McpAppRendererHandle,
17
19
  type McpAppMetadata,
@@ -15,7 +15,9 @@ import React, {
15
15
  useImperativeHandle,
16
16
  type MutableRefObject,
17
17
  } from 'react';
18
- import { useAppHost, type UseAppHostOptions } from './use-app-host.js';
18
+ import type { UseAppHostOptions } from './use-app-host.js';
19
+ import { useAppHost } from './use-app-host.js';
20
+ import { resolveMetaToolProxy } from '../../shared/meta-tools.js';
19
21
  import type { SSEClient } from '../core/sse-client.js';
20
22
  import { APP_HOST_DEFAULTS } from '../core/constants.js';
21
23
  import type { SandboxConfig } from '../core/app-host.js';
@@ -56,9 +58,10 @@ export interface McpAppRendererHandle {
56
58
  /** Props for {@link useMcpApps}'s `McpAppRenderer` (client is supplied via the hook). */
57
59
  export interface McpAppRendererProps extends Pick<UseAppHostOptions, 'sandbox' | 'hostContext' | 'onCallTool' | 'onReadResource' | 'onFallbackRequest' | 'onMessage' | 'onOpenLink' | 'onLoggingMessage' | 'onSizeChanged' | 'onError'> {
58
60
  name: string;
61
+ client?: McpClient | null;
59
62
  toolResourceUri?: string;
60
63
  html?: string;
61
- input?: Record<string, unknown>;
64
+ input?: Record<string, unknown> | null;
62
65
  result?: unknown;
63
66
  status?: 'executing' | 'inProgress' | 'complete' | 'idle';
64
67
  toolInputPartial?: any;
@@ -102,8 +105,10 @@ const McpAppViewInner = forwardRef<McpAppRendererHandle, McpAppViewProps>(functi
102
105
  },
103
106
  ref,
104
107
  ) {
108
+
105
109
  const mcpClient = clientRef.current;
106
- const metadata = getMcpAppMetadata(mcpClient, name);
110
+ const { toolName: resolvedToolName, args: resolvedInput } = resolveMetaToolProxy(name, input);
111
+ const metadata = getMcpAppMetadata(mcpClient, resolvedToolName, resolvedInput);
107
112
  const sseClient = mcpClient?.sseClient ?? null;
108
113
  const resourceUri = toolResourceUri || metadata?.resourceUri;
109
114
  const appSessionId = metadata?.sessionId;
@@ -194,7 +199,7 @@ const McpAppViewInner = forwardRef<McpAppRendererHandle, McpAppViewProps>(functi
194
199
 
195
200
  const sentInputRef = useRef(false);
196
201
  const sentResultRef = useRef(false);
197
- const lastInputRef = useRef(input);
202
+ const lastInputRef = useRef(resolvedInput);
198
203
  const lastResultRef = useRef(result);
199
204
  const lastStatusRef = useRef(status);
200
205
 
@@ -236,15 +241,16 @@ const McpAppViewInner = forwardRef<McpAppRendererHandle, McpAppViewProps>(functi
236
241
  .catch((err) => setError(err instanceof Error ? err : new Error(String(err))));
237
242
  }, [host, resourceUri, html, appSessionId]);
238
243
 
244
+ // Send tool inputs
239
245
  useEffect(() => {
240
- if (!host || !isLaunched || !resourceUri || !appSessionId || !input) return;
246
+ if (!host || !isLaunched || !resourceUri || !appSessionId || !resolvedInput) return;
241
247
 
242
- if (!sentInputRef.current || JSON.stringify(input) !== JSON.stringify(lastInputRef.current)) {
248
+ if (!sentInputRef.current || JSON.stringify(resolvedInput) !== JSON.stringify(lastInputRef.current)) {
243
249
  sentInputRef.current = true;
244
- lastInputRef.current = input;
245
- host.sendToolInput(input);
250
+ lastInputRef.current = resolvedInput;
251
+ host.sendToolInput(resolvedInput);
246
252
  }
247
- }, [host, isLaunched, input, resourceUri, appSessionId, name]);
253
+ }, [host, isLaunched, resolvedInput, resourceUri, appSessionId, resolvedToolName]);
248
254
 
249
255
  useEffect(() => {
250
256
  if (!host || !isLaunched || !resourceUri || !appSessionId || result === undefined) return;
@@ -259,7 +265,7 @@ const McpAppViewInner = forwardRef<McpAppRendererHandle, McpAppViewProps>(functi
259
265
  : result;
260
266
  host.sendToolResult(formattedResult);
261
267
  }
262
- }, [host, isLaunched, result, status, resourceUri, appSessionId, name]);
268
+ }, [host, isLaunched, result, status, resourceUri, appSessionId, resolvedToolName]);
263
269
 
264
270
  useEffect(() => {
265
271
  if (status === 'executing' && lastStatusRef.current !== 'executing') {
@@ -354,34 +360,44 @@ const McpAppViewInner = forwardRef<McpAppRendererHandle, McpAppViewProps>(functi
354
360
  const McpAppView = memo(McpAppViewInner);
355
361
  McpAppView.displayName = 'McpAppView';
356
362
 
363
+ /**
364
+ * Renders an interactive MCP application inside a sandboxed iframe.
365
+ */
366
+ export const McpAppRenderer = memo(
367
+ forwardRef<McpAppRendererHandle, McpAppRendererProps>(function McpAppRenderer(
368
+ { client, ...props },
369
+ ref
370
+ ) {
371
+ const clientRef = useRef(client || null);
372
+ clientRef.current = client || null;
373
+
374
+ return <McpAppView ref={ref} clientRef={clientRef} {...props} />;
375
+ })
376
+ );
377
+
357
378
  /**
358
379
  * Helpers scoped to one `mcpClient`. Pass the client here once; `McpAppRenderer` only needs per-tool props (`name`, `input`, `result`, `status`).
359
380
  *
360
381
  * @param mcpClient - From `useMcp()` or context (for example `useMcpContext()`).
382
+ * @deprecated Use the standalone `<McpAppRenderer>` component and `getMcpAppMetadata` utility directly.
361
383
  */
362
384
  export function useMcpApps(mcpClient: McpClient | null) {
363
- // Stable `McpAppRenderer` type: parent re-renders and `connections` updates must not remount the iframe.
364
- const clientRef = useRef(mcpClient);
365
- clientRef.current = mcpClient;
366
-
367
385
  const getAppMetadata = useCallback(
368
- (toolName: string) => getMcpAppMetadata(clientRef.current, toolName),
369
- []
386
+ (toolName: string) => getMcpAppMetadata(mcpClient, toolName),
387
+ [mcpClient]
370
388
  );
371
389
 
372
- const McpAppRenderer = useMemo(() => {
373
- const Inner = forwardRef<McpAppRendererHandle, McpAppRendererProps>(function McpAppRenderer(
374
- props,
375
- ref,
376
- ) {
377
- return <McpAppView ref={ref} clientRef={clientRef} {...props} />;
378
- });
379
- const Renderer = memo(Inner);
380
- Renderer.displayName = 'McpAppRenderer';
381
- return Renderer;
382
- }, []);
383
-
384
- return { getAppMetadata, McpAppRenderer };
390
+ const BoundMcpAppRenderer = useMemo(() => {
391
+ const Renderer = forwardRef<McpAppRendererHandle, Omit<McpAppRendererProps, 'client'>>(
392
+ function BoundMcpAppRenderer(props, ref) {
393
+ return <McpAppRenderer ref={ref} client={mcpClient} {...props} />;
394
+ }
395
+ );
396
+ Renderer.displayName = 'BoundMcpAppRenderer';
397
+ return memo(Renderer);
398
+ }, [mcpClient]);
399
+
400
+ return { getAppMetadata, McpAppRenderer: BoundMcpAppRenderer };
385
401
  }
386
402
 
387
403
  function extractToolName(fullName: string): string {
@@ -389,13 +405,15 @@ function extractToolName(fullName: string): string {
389
405
  return match?.[1] || fullName;
390
406
  }
391
407
 
392
- function getMcpAppMetadata(
408
+ export function getMcpAppMetadata(
393
409
  mcpClient: McpClient | null,
394
- toolName: string
410
+ toolName: string,
411
+ input?: Record<string, unknown> | null
395
412
  ): McpAppMetadata | undefined {
396
413
  if (!mcpClient) return undefined;
397
414
 
398
- const extractedName = extractToolName(toolName);
415
+ const { toolName: proxyToolName } = resolveMetaToolProxy(toolName, input);
416
+ const extractedName = extractToolName(proxyToolName);
399
417
 
400
418
  for (const conn of mcpClient.connections) {
401
419
  for (const tool of conn.tools) {
@@ -32,6 +32,8 @@ export type {
32
32
  } from '../shared/events';
33
33
 
34
34
  export type {
35
+ ToolClient,
36
+ ToolClientProvider,
35
37
  ToolInfo,
36
38
  McpRpcRequest,
37
39
  McpRpcResponse,
@@ -1108,7 +1108,9 @@ export class MCPClient {
1108
1108
  * @returns Server name or undefined
1109
1109
  */
1110
1110
  getServerName(): string | undefined {
1111
- return this.serverName;
1111
+ const info = (this.client as any)?.getServerVersion();
1112
+ console.log('server info ->', info);
1113
+ return info?.title ?? info?.name ?? this.serverName;
1112
1114
  }
1113
1115
 
1114
1116
  /**
@@ -22,6 +22,8 @@ export * from './errors';
22
22
 
23
23
  // Types
24
24
  export type {
25
+ ToolClient,
26
+ ToolClientProvider,
25
27
  ToolInfo,
26
28
  McpRpcRequest,
27
29
  McpRpcResponse,
@@ -73,3 +75,37 @@ export {
73
75
  type ToolUiConfig,
74
76
  } from './tool-utils.js';
75
77
 
78
+ // Tool Router — Context window optimization
79
+ export {
80
+ ToolRouter,
81
+ type ToolRouterOptions,
82
+ type ToolRouterStrategy,
83
+ type ToolRouterClientInput,
84
+ type ToolGroupInfo,
85
+ } from './tool-router.js';
86
+
87
+ export {
88
+ ToolIndex,
89
+ type ToolSummary,
90
+ type IndexedTool,
91
+ type ToolIndexOptions,
92
+ type EmbedFn,
93
+ } from './tool-index.js';
94
+
95
+ export {
96
+ SchemaCompressor,
97
+ type CompactTool,
98
+ type CompressionStats,
99
+ } from './schema-compressor.js';
100
+
101
+ export {
102
+ createSearchToolDefinition,
103
+ createRegexSearchToolDefinition,
104
+ createGetSchemaToolDefinition,
105
+ createExecuteToolDefinition,
106
+ executeMetaTool,
107
+ isMetaTool,
108
+ resolveMetaToolProxy,
109
+ type CallToolFn,
110
+ } from './meta-tools.js';
111
+