@mcp-ts/sdk 1.0.1 → 1.2.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 (83) hide show
  1. package/README.md +42 -19
  2. package/dist/adapters/agui-adapter.d.mts +6 -6
  3. package/dist/adapters/agui-adapter.d.ts +6 -6
  4. package/dist/adapters/agui-adapter.js +50 -25
  5. package/dist/adapters/agui-adapter.js.map +1 -1
  6. package/dist/adapters/agui-adapter.mjs +50 -25
  7. package/dist/adapters/agui-adapter.mjs.map +1 -1
  8. package/dist/adapters/agui-middleware.d.mts +23 -8
  9. package/dist/adapters/agui-middleware.d.ts +23 -8
  10. package/dist/adapters/agui-middleware.js +71 -43
  11. package/dist/adapters/agui-middleware.js.map +1 -1
  12. package/dist/adapters/agui-middleware.mjs +71 -44
  13. package/dist/adapters/agui-middleware.mjs.map +1 -1
  14. package/dist/adapters/ai-adapter.d.mts +2 -2
  15. package/dist/adapters/ai-adapter.d.ts +2 -2
  16. package/dist/adapters/langchain-adapter.d.mts +2 -2
  17. package/dist/adapters/langchain-adapter.d.ts +2 -2
  18. package/dist/adapters/mastra-adapter.d.mts +2 -2
  19. package/dist/adapters/mastra-adapter.d.ts +2 -2
  20. package/dist/client/index.d.mts +182 -55
  21. package/dist/client/index.d.ts +182 -55
  22. package/dist/client/index.js +535 -130
  23. package/dist/client/index.js.map +1 -1
  24. package/dist/client/index.mjs +535 -131
  25. package/dist/client/index.mjs.map +1 -1
  26. package/dist/client/react.d.mts +386 -4
  27. package/dist/client/react.d.ts +386 -4
  28. package/dist/client/react.js +890 -143
  29. package/dist/client/react.js.map +1 -1
  30. package/dist/client/react.mjs +883 -145
  31. package/dist/client/react.mjs.map +1 -1
  32. package/dist/client/vue.d.mts +3 -3
  33. package/dist/client/vue.d.ts +3 -3
  34. package/dist/client/vue.js +546 -141
  35. package/dist/client/vue.js.map +1 -1
  36. package/dist/client/vue.mjs +546 -142
  37. package/dist/client/vue.mjs.map +1 -1
  38. package/dist/{events-BP6WyRNh.d.mts → events-BgeztGYZ.d.mts} +12 -1
  39. package/dist/{events-BP6WyRNh.d.ts → events-BgeztGYZ.d.ts} +12 -1
  40. package/dist/index.d.mts +4 -4
  41. package/dist/index.d.ts +4 -4
  42. package/dist/index.js +797 -248
  43. package/dist/index.js.map +1 -1
  44. package/dist/index.mjs +791 -245
  45. package/dist/index.mjs.map +1 -1
  46. package/dist/{multi-session-client-DMF3ED2O.d.mts → multi-session-client-CxogNckF.d.mts} +1 -1
  47. package/dist/{multi-session-client-BOFgPypS.d.ts → multi-session-client-cox_WXUj.d.ts} +1 -1
  48. package/dist/server/index.d.mts +41 -37
  49. package/dist/server/index.d.ts +41 -37
  50. package/dist/server/index.js +241 -116
  51. package/dist/server/index.js.map +1 -1
  52. package/dist/server/index.mjs +237 -112
  53. package/dist/server/index.mjs.map +1 -1
  54. package/dist/shared/index.d.mts +39 -3
  55. package/dist/shared/index.d.ts +39 -3
  56. package/dist/shared/index.js +19 -0
  57. package/dist/shared/index.js.map +1 -1
  58. package/dist/shared/index.mjs +18 -1
  59. package/dist/shared/index.mjs.map +1 -1
  60. package/package.json +9 -2
  61. package/src/adapters/agui-adapter.ts +58 -35
  62. package/src/adapters/agui-middleware.ts +83 -45
  63. package/src/client/core/app-host.ts +417 -0
  64. package/src/client/core/sse-client.ts +365 -212
  65. package/src/client/core/types.ts +31 -0
  66. package/src/client/index.ts +1 -0
  67. package/src/client/react/agui-subscriber.ts +275 -0
  68. package/src/client/react/index.ts +23 -3
  69. package/src/client/react/use-agui-subscriber.ts +270 -0
  70. package/src/client/react/use-app-host.ts +73 -0
  71. package/src/client/react/use-mcp-app-iframe.ts +164 -0
  72. package/src/client/react/{useMcp.ts → use-mcp.ts} +18 -0
  73. package/src/client/vue/index.ts +1 -1
  74. package/src/server/handlers/nextjs-handler.ts +8 -7
  75. package/src/server/handlers/sse-handler.ts +129 -165
  76. package/src/server/mcp/oauth-client.ts +32 -2
  77. package/src/server/storage/index.ts +17 -1
  78. package/src/server/storage/sqlite-backend.ts +185 -0
  79. package/src/shared/events.ts +12 -0
  80. package/src/shared/index.ts +6 -1
  81. package/src/shared/tool-utils.ts +61 -0
  82. package/src/shared/types.ts +3 -1
  83. /package/src/client/vue/{useMcp.ts → use-mcp.ts} +0 -0
@@ -20,11 +20,32 @@ import {
20
20
  } from '@ag-ui/client';
21
21
  import { type AguiTool, cleanSchema } from './agui-adapter.js';
22
22
 
23
+ /** New event type for MCP UI triggers */
24
+ export const MCP_APP_UI_EVENT = 'mcp-apps-ui';
25
+ /**
26
+ * MCP Apps UI trigger event.
27
+ *
28
+ * IMPORTANT: This must be emitted as an AG-UI CustomEvent so subscribers
29
+ * (e.g. CopilotKit `onCustomEvent`) can receive it.
30
+ */
31
+ export interface McpAppUiEventPayload {
32
+ toolCallId: string;
33
+ resourceUri: string;
34
+ sessionId?: string;
35
+ toolName: string;
36
+ result?: any;
37
+ }
38
+
23
39
  /** Tool execution result for continuation */
24
40
  interface ToolResult {
25
41
  toolCallId: string;
26
42
  toolName: string;
27
43
  result: string;
44
+ /**
45
+ * Raw result object (if available).
46
+ * Used to preserve metadata (e.g. `_meta`) that is lost in the stringified `result`.
47
+ */
48
+ rawResult?: any;
28
49
  messageId: string;
29
50
  }
30
51
 
@@ -43,8 +64,6 @@ interface RunState {
43
64
  export interface McpMiddlewareConfig {
44
65
  /** Pre-loaded tools with handlers (required) */
45
66
  tools: AguiTool[];
46
- /** Max result length in chars (default: 50000) */
47
- maxResultLength?: number;
48
67
  }
49
68
 
50
69
  /**
@@ -53,20 +72,29 @@ export interface McpMiddlewareConfig {
53
72
  export class McpMiddleware extends Middleware {
54
73
  private tools: AguiTool[];
55
74
  private toolSchemas: Tool[];
56
- private maxResultLength: number;
57
75
 
58
76
  constructor(config: McpMiddlewareConfig) {
59
77
  super();
60
78
  this.tools = config.tools;
61
- this.maxResultLength = config.maxResultLength ?? 50000;
62
79
  this.toolSchemas = this.tools.map((t: AguiTool) => ({
63
80
  name: t.name,
64
81
  description: t.description,
65
82
  parameters: cleanSchema(t.parameters),
83
+ _meta: t._meta, // Include _meta in the tool definition passed to the agent
66
84
  }));
67
85
  }
68
86
 
87
+ /**
88
+ * Extract base tool name from prefixed format for event emission
89
+ * e.g., "tool_abc123_get-time" -> "get-time"
90
+ */
91
+ private getBaseToolName(toolName: string): string {
92
+ const match = toolName.match(/^tool_[^_]+_(.+)$/);
93
+ return match ? match[1] : toolName;
94
+ }
95
+
69
96
  private isMcpTool(toolName: string): boolean {
97
+ // Direct comparison - tool names should match as-is
70
98
  return this.tools.some(t => t.name === toolName);
71
99
  }
72
100
 
@@ -91,29 +119,31 @@ export class McpMiddleware extends Middleware {
91
119
  }
92
120
  }
93
121
 
94
- private async executeTool(toolName: string, args: Record<string, any>): Promise<string> {
122
+ private async executeTool(toolName: string, args: Record<string, any>): Promise<{ resultStr: string, rawResult?: any }> {
95
123
  const tool = this.tools.find(t => t.name === toolName);
96
124
  if (!tool?.handler) {
97
- return `Error: Tool ${tool ? 'has no handler' : 'not found'}: ${toolName}`;
125
+ return { resultStr: `Error: Tool ${tool ? 'has no handler' : 'not found'}: ${toolName}` };
98
126
  }
99
127
 
100
128
  try {
101
- console.log(`[McpMiddleware] Executing tool: ${toolName}`, args);
129
+ // Result can be a string (legacy) or an object (MCP Result with content array)
102
130
  const result = await tool.handler(args);
103
- let resultStr = typeof result === 'string' ? result : JSON.stringify(result);
104
131
 
105
- if (resultStr.length > this.maxResultLength) {
106
- const original = resultStr.length;
107
- resultStr = resultStr.slice(0, this.maxResultLength) +
108
- `\n\n[... Truncated from ${original} to ${this.maxResultLength} chars]`;
109
- console.log(`[McpMiddleware] Tool result truncated from ${original} to ${this.maxResultLength} chars`);
132
+ let resultStr: string;
133
+
134
+ if (typeof result === 'string') {
135
+ resultStr = result;
136
+ } else if (result && typeof result === 'object') {
137
+ // Determine if we should preserve the object structure (e.g. for MCP Tool Results)
138
+ resultStr = JSON.stringify(result);
139
+ } else {
140
+ resultStr = String(result);
110
141
  }
111
142
 
112
- console.log(`[McpMiddleware] Tool result:`, resultStr.slice(0, 200));
113
- return resultStr;
143
+ return { resultStr, rawResult: result };
114
144
  } catch (error: any) {
115
145
  console.error(`[McpMiddleware] Error executing tool:`, error);
116
- return `Error: ${error.message || String(error)}`;
146
+ return { resultStr: `Error: ${error.message || String(error)}` };
117
147
  }
118
148
  }
119
149
 
@@ -146,7 +176,6 @@ export class McpMiddleware extends Middleware {
146
176
  if (this.isMcpTool(e.toolCallName)) {
147
177
  pendingMcpCalls.add(e.toolCallId);
148
178
  }
149
- console.log(`[McpMiddleware] TOOL_CALL_START: ${e.toolCallName} (id: ${e.toolCallId}, isMCP: ${this.isMcpTool(e.toolCallName)})`);
150
179
  }
151
180
  }
152
181
 
@@ -159,8 +188,7 @@ export class McpMiddleware extends Middleware {
159
188
  }
160
189
 
161
190
  if (event.type === EventType.TOOL_CALL_END) {
162
- const e = event as ToolCallEndEvent;
163
- console.log(`[McpMiddleware] TOOL_CALL_END: ${toolCallNames.get(e.toolCallId) ?? 'unknown'} (id: ${e.toolCallId})`);
191
+ // Track tool call end event
164
192
  }
165
193
 
166
194
  // Workaround: Extract parallel tool calls from MESSAGES_SNAPSHOT
@@ -186,7 +214,6 @@ export class McpMiddleware extends Middleware {
186
214
  toolCallArgsBuffer.set(tc.id, tc.function.arguments || '{}');
187
215
  if (this.isMcpTool(tc.function.name)) {
188
216
  pendingMcpCalls.add(tc.id);
189
- console.log(`[McpMiddleware] MESSAGES_SNAPSHOT: Discovered ${tc.function.name} (id: ${tc.id})`);
190
217
  }
191
218
  }
192
219
  }
@@ -207,13 +234,12 @@ export class McpMiddleware extends Middleware {
207
234
  if (!toolName) return;
208
235
 
209
236
  const args = this.parseArgs(toolCallArgsBuffer.get(toolCallId) || '{}');
210
- console.log(`[McpMiddleware] Executing pending tool: ${toolName}`);
211
-
212
- const result = await this.executeTool(toolName, args);
237
+ const { resultStr, rawResult } = await this.executeTool(toolName, args);
213
238
  results.push({
214
239
  toolCallId,
215
240
  toolName,
216
- result,
241
+ result: resultStr,
242
+ rawResult,
217
243
  messageId: this.generateId('mcp_result'),
218
244
  });
219
245
  pendingMcpCalls.delete(toolCallId);
@@ -223,9 +249,39 @@ export class McpMiddleware extends Middleware {
223
249
  return results;
224
250
  }
225
251
 
226
- /** Emit tool results (without RUN_FINISHED - that's emitted when truly done) */
227
252
  private emitToolResults(observer: Subscriber<BaseEvent>, results: ToolResult[]): void {
228
- for (const { toolCallId, toolName, result, messageId } of results) {
253
+ for (const { toolCallId, toolName, result, rawResult, messageId } of results) {
254
+ // UI metadata may appear either on the tool CALL result (rawResult._meta)
255
+ // or only on the tool DEFINITION (listTools result). We support both.
256
+ const toolDef = this.tools.find(t => t.name === toolName);
257
+ const sessionId = toolDef?._meta?.sessionId;
258
+ const resourceUri =
259
+ rawResult?._meta?.ui?.resourceUri ??
260
+ rawResult?._meta?.['ui/resourceUri'] ??
261
+ toolDef?._meta?.ui?.resourceUri ??
262
+ toolDef?._meta?.['ui/resourceUri'];
263
+
264
+ if (resourceUri) {
265
+ // Extract base name for event emission to match metadata
266
+ const baseToolName = this.getBaseToolName(toolName);
267
+
268
+ const payload: McpAppUiEventPayload = {
269
+ toolCallId,
270
+ resourceUri,
271
+ sessionId,
272
+ toolName: baseToolName, // Use base name to match metadata
273
+ result: rawResult ?? result,
274
+ };
275
+
276
+ observer.next({
277
+ type: EventType.CUSTOM,
278
+ name: MCP_APP_UI_EVENT,
279
+ value: payload,
280
+ timestamp: Date.now(),
281
+ role: 'tool',
282
+ } as any);
283
+ }
284
+
229
285
  observer.next({
230
286
  type: EventType.TOOL_CALL_RESULT,
231
287
  toolCallId,
@@ -234,7 +290,6 @@ export class McpMiddleware extends Middleware {
234
290
  role: 'tool',
235
291
  timestamp: Date.now(),
236
292
  } as any);
237
- console.log(`[McpMiddleware] Emitting TOOL_CALL_RESULT for: ${toolName}`);
238
293
  }
239
294
  }
240
295
 
@@ -251,14 +306,9 @@ export class McpMiddleware extends Middleware {
251
306
  this.ensureIds(input);
252
307
  const anyInput = input as any;
253
308
 
254
- console.log(`[McpMiddleware] === NEW RUN ===`);
255
- console.log(`[McpMiddleware] threadId: ${anyInput.threadId}, runId: ${anyInput.runId}`);
256
- console.log(`[McpMiddleware] messages: ${input.messages?.length ?? 0}, tools: ${this.tools?.length ?? 0}`);
257
-
258
309
  // Inject MCP tools
259
310
  if (this.toolSchemas?.length) {
260
311
  input.tools = [...(input.tools || []), ...this.toolSchemas];
261
- console.log(`[McpMiddleware] Injected ${this.toolSchemas.length} tools:`, this.toolSchemas.map((t: Tool) => t.name));
262
312
  }
263
313
 
264
314
  const handleRunFinished = async () => {
@@ -275,8 +325,6 @@ export class McpMiddleware extends Middleware {
275
325
  return;
276
326
  }
277
327
 
278
- console.log(`[McpMiddleware] RUN_FINISHED with ${state.pendingMcpCalls.size} pending calls`);
279
-
280
328
  // Reconstruct the Assistant Message that triggered these tools
281
329
  const toolCalls = [];
282
330
  for (const toolCallId of state.pendingMcpCalls) {
@@ -300,16 +348,12 @@ export class McpMiddleware extends Middleware {
300
348
  tool_calls: toolCalls.length > 0 ? toolCalls : undefined
301
349
  };
302
350
  input.messages.push(assistantMsg as any);
303
- console.log(`[McpMiddleware] Added assistant message to history before tools: ${state.textContent?.slice(0, 50)}... [${toolCalls.length} tools]`);
304
351
  }
305
352
 
306
353
  // Execute tools and emit results (no RUN_FINISHED yet - continuation follows)
307
354
  const results = await this.executeTools(state);
308
355
  this.emitToolResults(observer, results);
309
356
 
310
- // Prepare continuation
311
- console.log(`[McpMiddleware] Triggering continuation with ${results.length} results`);
312
-
313
357
  // Add tool result messages to history
314
358
  for (const { toolCallId, result, messageId } of results) {
315
359
  input.messages.push({
@@ -326,7 +370,6 @@ export class McpMiddleware extends Middleware {
326
370
  state.textContent = ''; // Clear text content for next turn
327
371
 
328
372
  anyInput.runId = this.generateId('mcp_run');
329
- console.log(`[McpMiddleware] === CONTINUATION RUN === messages: ${input.messages.length}`);
330
373
 
331
374
  // Subscribe to continuation
332
375
  next.run(input).subscribe({
@@ -336,7 +379,6 @@ export class McpMiddleware extends Middleware {
336
379
  this.handleToolCallEvent(event, state);
337
380
 
338
381
  if (event.type === EventType.RUN_ERROR) {
339
- console.log(`[McpMiddleware] RUN_ERROR received in continuation`);
340
382
  state.error = true;
341
383
  observer.next(event);
342
384
  observer.complete();
@@ -344,7 +386,6 @@ export class McpMiddleware extends Middleware {
344
386
  }
345
387
 
346
388
  if (event.type === EventType.RUN_STARTED) {
347
- console.log(`[McpMiddleware] Filtering RUN_STARTED from continuation`);
348
389
  return;
349
390
  }
350
391
 
@@ -376,7 +417,6 @@ export class McpMiddleware extends Middleware {
376
417
  this.handleToolCallEvent(event, state);
377
418
 
378
419
  if (event.type === EventType.RUN_ERROR) {
379
- console.log(`[McpMiddleware] RUN_ERROR received`);
380
420
  state.error = true;
381
421
  observer.next(event);
382
422
  observer.complete();
@@ -406,9 +446,7 @@ export class McpMiddleware extends Middleware {
406
446
  /**
407
447
  * Factory function to create MCP middleware.
408
448
  */
409
- export function createMcpMiddleware(
410
- options: { tools: AguiTool[]; maxResultLength?: number }
411
- ) {
449
+ export function createMcpMiddleware(options: { tools: AguiTool[] }) {
412
450
  const middleware = new McpMiddleware(options);
413
451
  return (input: RunAgentInput, next: AbstractAgent): Observable<BaseEvent> => {
414
452
  return middleware.run(input, next);