@mcp-ts/sdk 1.0.0 → 1.1.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.
- package/README.md +25 -13
- package/dist/adapters/agui-adapter.d.mts +21 -44
- package/dist/adapters/agui-adapter.d.ts +21 -44
- package/dist/adapters/agui-adapter.js +93 -67
- package/dist/adapters/agui-adapter.js.map +1 -1
- package/dist/adapters/agui-adapter.mjs +93 -68
- package/dist/adapters/agui-adapter.mjs.map +1 -1
- package/dist/adapters/agui-middleware.d.mts +32 -134
- package/dist/adapters/agui-middleware.d.ts +32 -134
- package/dist/adapters/agui-middleware.js +314 -350
- package/dist/adapters/agui-middleware.js.map +1 -1
- package/dist/adapters/agui-middleware.mjs +314 -351
- package/dist/adapters/agui-middleware.mjs.map +1 -1
- package/dist/adapters/ai-adapter.d.mts +2 -2
- package/dist/adapters/ai-adapter.d.ts +2 -2
- package/dist/adapters/langchain-adapter.d.mts +2 -2
- package/dist/adapters/langchain-adapter.d.ts +2 -2
- package/dist/adapters/mastra-adapter.d.mts +2 -2
- package/dist/adapters/mastra-adapter.d.ts +2 -2
- package/dist/client/index.d.mts +184 -57
- package/dist/client/index.d.ts +184 -57
- package/dist/client/index.js +535 -130
- package/dist/client/index.js.map +1 -1
- package/dist/client/index.mjs +535 -131
- package/dist/client/index.mjs.map +1 -1
- package/dist/client/react.d.mts +40 -6
- package/dist/client/react.d.ts +40 -6
- package/dist/client/react.js +587 -142
- package/dist/client/react.js.map +1 -1
- package/dist/client/react.mjs +586 -143
- package/dist/client/react.mjs.map +1 -1
- package/dist/client/vue.d.mts +5 -5
- package/dist/client/vue.d.ts +5 -5
- package/dist/client/vue.js +545 -140
- package/dist/client/vue.js.map +1 -1
- package/dist/client/vue.mjs +545 -141
- package/dist/client/vue.mjs.map +1 -1
- package/dist/{events-BP6WyRNh.d.mts → events-BgeztGYZ.d.mts} +12 -1
- package/dist/{events-BP6WyRNh.d.ts → events-BgeztGYZ.d.ts} +12 -1
- package/dist/index.d.mts +4 -4
- package/dist/index.d.ts +4 -4
- package/dist/index.js +779 -248
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +775 -245
- package/dist/index.mjs.map +1 -1
- package/dist/{multi-session-client-DMF3ED2O.d.mts → multi-session-client-CxogNckF.d.mts} +1 -1
- package/dist/{multi-session-client-BOFgPypS.d.ts → multi-session-client-cox_WXUj.d.ts} +1 -1
- package/dist/server/index.d.mts +44 -40
- package/dist/server/index.d.ts +44 -40
- package/dist/server/index.js +242 -116
- package/dist/server/index.js.map +1 -1
- package/dist/server/index.mjs +238 -112
- package/dist/server/index.mjs.map +1 -1
- package/dist/shared/index.d.mts +2 -2
- package/dist/shared/index.d.ts +2 -2
- package/dist/shared/index.js.map +1 -1
- package/dist/shared/index.mjs.map +1 -1
- package/dist/{types-SbDlA2VX.d.mts → types-CLccx9wW.d.mts} +1 -1
- package/dist/{types-SbDlA2VX.d.ts → types-CLccx9wW.d.ts} +1 -1
- package/package.json +8 -1
- package/src/adapters/agui-adapter.ts +121 -107
- package/src/adapters/agui-middleware.ts +474 -512
- package/src/client/core/app-host.ts +417 -0
- package/src/client/core/sse-client.ts +365 -212
- package/src/client/core/types.ts +31 -0
- package/src/client/index.ts +1 -0
- package/src/client/react/index.ts +1 -0
- package/src/client/react/use-mcp-app.ts +73 -0
- package/src/client/react/useMcp.ts +18 -0
- package/src/server/handlers/nextjs-handler.ts +8 -7
- package/src/server/handlers/sse-handler.ts +131 -164
- package/src/server/mcp/oauth-client.ts +32 -2
- package/src/server/storage/index.ts +17 -1
- package/src/server/storage/sqlite-backend.ts +185 -0
- package/src/server/storage/types.ts +1 -1
- package/src/shared/events.ts +12 -0
- package/src/shared/types.ts +4 -2
|
@@ -4,410 +4,373 @@ var rxjs = require('rxjs');
|
|
|
4
4
|
var client = require('@ag-ui/client');
|
|
5
5
|
|
|
6
6
|
var __defProp = Object.defineProperty;
|
|
7
|
-
var __getOwnPropNames = Object.getOwnPropertyNames;
|
|
8
7
|
var __defNormalProp = (obj, key, value) => key in obj ? __defProp(obj, key, { enumerable: true, configurable: true, writable: true, value }) : obj[key] = value;
|
|
9
|
-
var __esm = (fn, res) => function __init() {
|
|
10
|
-
return fn && (res = (0, fn[__getOwnPropNames(fn)[0]])(fn = 0)), res;
|
|
11
|
-
};
|
|
12
|
-
var __export = (target, all) => {
|
|
13
|
-
for (var name in all)
|
|
14
|
-
__defProp(target, name, { get: all[name], enumerable: true });
|
|
15
|
-
};
|
|
16
8
|
var __publicField = (obj, key, value) => __defNormalProp(obj, typeof key !== "symbol" ? key + "" : key, value);
|
|
17
9
|
|
|
18
10
|
// src/adapters/agui-adapter.ts
|
|
19
|
-
var
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
"
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
}
|
|
54
|
-
async transformTools(client) {
|
|
55
|
-
if (!client.isConnected()) {
|
|
56
|
-
return [];
|
|
57
|
-
}
|
|
58
|
-
const result = await client.listTools();
|
|
59
|
-
const prefix = this.options.prefix ?? client.getServerId() ?? "mcp";
|
|
60
|
-
const tools = [];
|
|
61
|
-
for (const tool of result.tools) {
|
|
62
|
-
const toolName = `${prefix}_${tool.name}`;
|
|
63
|
-
tools.push({
|
|
64
|
-
name: toolName,
|
|
65
|
-
description: tool.description || `Execute ${tool.name}`,
|
|
66
|
-
parameters: tool.inputSchema || { type: "object", properties: {} },
|
|
67
|
-
handler: async (args) => {
|
|
68
|
-
console.log(`[AguiAdapter] Executing MCP tool: ${tool.name}`, args);
|
|
69
|
-
const result2 = await client.callTool(tool.name, args);
|
|
70
|
-
if (result2.content && Array.isArray(result2.content)) {
|
|
71
|
-
const textContent = result2.content.filter((c) => c.type === "text").map((c) => c.text).join("\n");
|
|
72
|
-
return textContent || result2;
|
|
73
|
-
}
|
|
74
|
-
return result2;
|
|
75
|
-
}
|
|
76
|
-
});
|
|
77
|
-
}
|
|
78
|
-
return tools;
|
|
79
|
-
}
|
|
80
|
-
/**
|
|
81
|
-
* Get tools as a function (for dynamic loading).
|
|
82
|
-
*
|
|
83
|
-
* @returns Function that returns a Promise of tools
|
|
84
|
-
*/
|
|
85
|
-
getToolsFunction() {
|
|
86
|
-
return async () => this.getTools();
|
|
87
|
-
}
|
|
88
|
-
/**
|
|
89
|
-
* Get tool definitions in JSON Schema format for passing to remote agents.
|
|
90
|
-
*
|
|
91
|
-
* This format is compatible with:
|
|
92
|
-
* - OpenAI's function calling API
|
|
93
|
-
* - AG-UI input.tools format
|
|
94
|
-
* - Most LLM tool/function calling implementations
|
|
95
|
-
*
|
|
96
|
-
* @returns Array of AguiToolDefinition objects
|
|
97
|
-
*/
|
|
98
|
-
async getToolDefinitions() {
|
|
99
|
-
const isMultiSession = typeof this.client.getClients === "function";
|
|
100
|
-
if (isMultiSession) {
|
|
101
|
-
const clients = this.client.getClients();
|
|
102
|
-
const allTools = [];
|
|
103
|
-
for (const client of clients) {
|
|
104
|
-
const tools = await this.transformToolDefinitions(client);
|
|
105
|
-
allTools.push(...tools);
|
|
106
|
-
}
|
|
107
|
-
return allTools;
|
|
108
|
-
}
|
|
109
|
-
return this.transformToolDefinitions(this.client);
|
|
110
|
-
}
|
|
111
|
-
async transformToolDefinitions(client) {
|
|
112
|
-
if (!client.isConnected()) {
|
|
113
|
-
return [];
|
|
114
|
-
}
|
|
115
|
-
const result = await client.listTools();
|
|
116
|
-
const prefix = this.options.prefix ?? client.getServerId() ?? "mcp";
|
|
117
|
-
const tools = [];
|
|
118
|
-
for (const tool of result.tools) {
|
|
119
|
-
tools.push({
|
|
120
|
-
name: `${prefix}_${tool.name}`,
|
|
121
|
-
description: tool.description || `Execute ${tool.name}`,
|
|
122
|
-
parameters: tool.inputSchema || { type: "object", properties: {} }
|
|
123
|
-
});
|
|
124
|
-
}
|
|
125
|
-
return tools;
|
|
11
|
+
var PYDANTIC_FORBIDDEN_PROPS = [
|
|
12
|
+
// JSON Schema meta-properties
|
|
13
|
+
"$schema",
|
|
14
|
+
"$id",
|
|
15
|
+
"$comment",
|
|
16
|
+
"$defs",
|
|
17
|
+
"definitions",
|
|
18
|
+
// Extended properties used by some MCP servers (e.g., Apify)
|
|
19
|
+
"prefill",
|
|
20
|
+
"examples",
|
|
21
|
+
"enumTitles",
|
|
22
|
+
"enumDescriptions",
|
|
23
|
+
// Other common extensions
|
|
24
|
+
"deprecated",
|
|
25
|
+
"readOnly",
|
|
26
|
+
"writeOnly",
|
|
27
|
+
"contentMediaType",
|
|
28
|
+
"contentEncoding"
|
|
29
|
+
];
|
|
30
|
+
function cleanSchema(schema) {
|
|
31
|
+
if (!schema) {
|
|
32
|
+
return { type: "object", properties: {} };
|
|
33
|
+
}
|
|
34
|
+
const cleaned = { ...schema };
|
|
35
|
+
for (const prop of PYDANTIC_FORBIDDEN_PROPS) {
|
|
36
|
+
delete cleaned[prop];
|
|
37
|
+
}
|
|
38
|
+
if (cleaned.properties && typeof cleaned.properties === "object") {
|
|
39
|
+
const cleanedProps = {};
|
|
40
|
+
for (const [key, value] of Object.entries(cleaned.properties)) {
|
|
41
|
+
if (typeof value === "object" && value !== null) {
|
|
42
|
+
cleanedProps[key] = cleanSchema(value);
|
|
43
|
+
} else {
|
|
44
|
+
cleanedProps[key] = value;
|
|
126
45
|
}
|
|
127
|
-
}
|
|
46
|
+
}
|
|
47
|
+
cleaned.properties = cleanedProps;
|
|
128
48
|
}
|
|
129
|
-
|
|
49
|
+
if (cleaned.items && typeof cleaned.items === "object") {
|
|
50
|
+
cleaned.items = cleanSchema(cleaned.items);
|
|
51
|
+
}
|
|
52
|
+
if (cleaned.additionalProperties && typeof cleaned.additionalProperties === "object") {
|
|
53
|
+
cleaned.additionalProperties = cleanSchema(cleaned.additionalProperties);
|
|
54
|
+
}
|
|
55
|
+
return cleaned;
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
// src/adapters/agui-middleware.ts
|
|
59
|
+
var MCP_APP_UI_EVENT = "mcp-apps-ui";
|
|
130
60
|
var McpMiddleware = class extends client.Middleware {
|
|
131
61
|
constructor(config) {
|
|
132
62
|
super();
|
|
133
|
-
__publicField(this, "client");
|
|
134
|
-
__publicField(this, "toolPrefix");
|
|
135
|
-
__publicField(this, "actions");
|
|
136
63
|
__publicField(this, "tools");
|
|
137
|
-
__publicField(this, "
|
|
138
|
-
this.
|
|
139
|
-
this.
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
}
|
|
146
|
-
}
|
|
147
|
-
/**
|
|
148
|
-
* Convert actions to AG-UI tool format
|
|
149
|
-
*/
|
|
150
|
-
actionsToTools(actions) {
|
|
151
|
-
return actions.map((action) => ({
|
|
152
|
-
name: action.name,
|
|
153
|
-
description: action.description,
|
|
154
|
-
parameters: action.parameters || { type: "object", properties: {} }
|
|
64
|
+
__publicField(this, "toolSchemas");
|
|
65
|
+
this.tools = config.tools;
|
|
66
|
+
this.toolSchemas = this.tools.map((t) => ({
|
|
67
|
+
name: t.name,
|
|
68
|
+
description: t.description,
|
|
69
|
+
parameters: cleanSchema(t.parameters),
|
|
70
|
+
_meta: t._meta
|
|
71
|
+
// Include _meta in the tool definition passed to the agent
|
|
155
72
|
}));
|
|
156
73
|
}
|
|
157
|
-
/**
|
|
158
|
-
* Check if a tool name is an MCP tool (matches the configured prefix)
|
|
159
|
-
*/
|
|
160
74
|
isMcpTool(toolName) {
|
|
161
|
-
return
|
|
75
|
+
return this.tools.some((t) => t.name === toolName);
|
|
162
76
|
}
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
77
|
+
parseArgs(argsString) {
|
|
78
|
+
if (!argsString?.trim()) return {};
|
|
79
|
+
try {
|
|
80
|
+
return JSON.parse(argsString);
|
|
81
|
+
} catch {
|
|
82
|
+
const trimmed = argsString.trim();
|
|
83
|
+
if (trimmed.includes("}{")) {
|
|
84
|
+
const firstObject = trimmed.slice(0, trimmed.indexOf("}{") + 1);
|
|
85
|
+
try {
|
|
86
|
+
return JSON.parse(firstObject);
|
|
87
|
+
} catch {
|
|
88
|
+
console.error(`[McpMiddleware] Failed to parse JSON:`, firstObject);
|
|
89
|
+
}
|
|
90
|
+
}
|
|
91
|
+
console.error(`[McpMiddleware] Failed to parse args:`, argsString);
|
|
92
|
+
return {};
|
|
93
|
+
}
|
|
172
94
|
}
|
|
173
|
-
/**
|
|
174
|
-
* Execute an MCP tool and return the result as a string
|
|
175
|
-
*/
|
|
176
95
|
async executeTool(toolName, args) {
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
return `Error: Tool not found: ${toolName}`;
|
|
181
|
-
}
|
|
182
|
-
if (!action.handler) {
|
|
183
|
-
return `Error: Tool has no handler: ${toolName}`;
|
|
96
|
+
const tool = this.tools.find((t) => t.name === toolName);
|
|
97
|
+
if (!tool?.handler) {
|
|
98
|
+
return { resultStr: `Error: Tool ${tool ? "has no handler" : "not found"}: ${toolName}` };
|
|
184
99
|
}
|
|
185
100
|
try {
|
|
186
101
|
console.log(`[McpMiddleware] Executing tool: ${toolName}`, args);
|
|
187
|
-
const result = await
|
|
188
|
-
|
|
189
|
-
|
|
102
|
+
const result = await tool.handler(args);
|
|
103
|
+
let resultStr;
|
|
104
|
+
if (typeof result === "string") {
|
|
105
|
+
resultStr = result;
|
|
106
|
+
} else if (result && typeof result === "object") {
|
|
107
|
+
resultStr = JSON.stringify(result);
|
|
108
|
+
} else {
|
|
109
|
+
resultStr = String(result);
|
|
110
|
+
}
|
|
111
|
+
console.log(`[McpMiddleware] Tool result:`, resultStr.slice(0, 200));
|
|
112
|
+
return { resultStr, rawResult: result };
|
|
190
113
|
} catch (error) {
|
|
191
114
|
console.error(`[McpMiddleware] Error executing tool:`, error);
|
|
192
|
-
return `Error
|
|
115
|
+
return { resultStr: `Error: ${error.message || String(error)}` };
|
|
116
|
+
}
|
|
117
|
+
}
|
|
118
|
+
generateId(prefix) {
|
|
119
|
+
return `${prefix}_${Date.now()}_${Math.random().toString(36).slice(2, 9)}`;
|
|
120
|
+
}
|
|
121
|
+
ensureIds(input) {
|
|
122
|
+
const anyInput = input;
|
|
123
|
+
if (!anyInput.threadId) anyInput.threadId = this.generateId("mcp_thread");
|
|
124
|
+
if (!anyInput.runId) anyInput.runId = this.generateId("mcp_run");
|
|
125
|
+
}
|
|
126
|
+
/** Process tool call events and update state */
|
|
127
|
+
handleToolCallEvent(event, state) {
|
|
128
|
+
const { toolCallArgsBuffer, toolCallNames, pendingMcpCalls } = state;
|
|
129
|
+
if (event.type === client.EventType.TEXT_MESSAGE_CHUNK) {
|
|
130
|
+
const e = event;
|
|
131
|
+
if (e.delta) {
|
|
132
|
+
state.textContent = (state.textContent || "") + e.delta;
|
|
133
|
+
}
|
|
134
|
+
}
|
|
135
|
+
if (event.type === client.EventType.TOOL_CALL_START) {
|
|
136
|
+
const e = event;
|
|
137
|
+
if (e.toolCallId && e.toolCallName) {
|
|
138
|
+
toolCallNames.set(e.toolCallId, e.toolCallName);
|
|
139
|
+
if (this.isMcpTool(e.toolCallName)) {
|
|
140
|
+
pendingMcpCalls.add(e.toolCallId);
|
|
141
|
+
}
|
|
142
|
+
console.log(`[McpMiddleware] TOOL_CALL_START: ${e.toolCallName} (id: ${e.toolCallId}, isMCP: ${this.isMcpTool(e.toolCallName)})`);
|
|
143
|
+
}
|
|
144
|
+
}
|
|
145
|
+
if (event.type === client.EventType.TOOL_CALL_ARGS) {
|
|
146
|
+
const e = event;
|
|
147
|
+
if (e.toolCallId && e.delta) {
|
|
148
|
+
const existing = toolCallArgsBuffer.get(e.toolCallId) || "";
|
|
149
|
+
toolCallArgsBuffer.set(e.toolCallId, existing + e.delta);
|
|
150
|
+
}
|
|
151
|
+
}
|
|
152
|
+
if (event.type === client.EventType.TOOL_CALL_END) {
|
|
153
|
+
const e = event;
|
|
154
|
+
console.log(`[McpMiddleware] TOOL_CALL_END: ${toolCallNames.get(e.toolCallId) ?? "unknown"} (id: ${e.toolCallId})`);
|
|
155
|
+
}
|
|
156
|
+
if (event.type === client.EventType.MESSAGES_SNAPSHOT) {
|
|
157
|
+
const messages = event.messages || [];
|
|
158
|
+
if (messages.length > 0) {
|
|
159
|
+
const lastMsg = messages[messages.length - 1];
|
|
160
|
+
if (lastMsg.role === "assistant" && lastMsg.content) {
|
|
161
|
+
state.textContent = lastMsg.content;
|
|
162
|
+
}
|
|
163
|
+
for (let i = messages.length - 1; i >= 0; i--) {
|
|
164
|
+
const msg = messages[i];
|
|
165
|
+
const tools = Array.isArray(msg.toolCalls) ? msg.toolCalls : Array.isArray(msg.tool_calls) ? msg.tool_calls : [];
|
|
166
|
+
if (msg.role === "assistant" && tools.length > 0) {
|
|
167
|
+
for (const tc of tools) {
|
|
168
|
+
if (tc.id && tc.function?.name && !toolCallNames.has(tc.id)) {
|
|
169
|
+
toolCallNames.set(tc.id, tc.function.name);
|
|
170
|
+
toolCallArgsBuffer.set(tc.id, tc.function.arguments || "{}");
|
|
171
|
+
if (this.isMcpTool(tc.function.name)) {
|
|
172
|
+
pendingMcpCalls.add(tc.id);
|
|
173
|
+
console.log(`[McpMiddleware] MESSAGES_SNAPSHOT: Discovered ${tc.function.name} (id: ${tc.id})`);
|
|
174
|
+
}
|
|
175
|
+
}
|
|
176
|
+
}
|
|
177
|
+
break;
|
|
178
|
+
}
|
|
179
|
+
}
|
|
180
|
+
}
|
|
193
181
|
}
|
|
194
182
|
}
|
|
195
|
-
/**
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
183
|
+
/** Execute pending MCP tools and return results */
|
|
184
|
+
async executeTools(state) {
|
|
185
|
+
const { toolCallArgsBuffer, toolCallNames, pendingMcpCalls } = state;
|
|
186
|
+
const results = [];
|
|
187
|
+
const promises = [...pendingMcpCalls].map(async (toolCallId) => {
|
|
188
|
+
const toolName = toolCallNames.get(toolCallId);
|
|
189
|
+
if (!toolName) return;
|
|
190
|
+
const args = this.parseArgs(toolCallArgsBuffer.get(toolCallId) || "{}");
|
|
191
|
+
console.log(`[McpMiddleware] Executing pending tool: ${toolName}`);
|
|
192
|
+
const { resultStr, rawResult } = await this.executeTool(toolName, args);
|
|
193
|
+
results.push({
|
|
194
|
+
toolCallId,
|
|
195
|
+
toolName,
|
|
196
|
+
result: resultStr,
|
|
197
|
+
rawResult,
|
|
198
|
+
messageId: this.generateId("mcp_result")
|
|
199
|
+
});
|
|
200
|
+
pendingMcpCalls.delete(toolCallId);
|
|
201
|
+
});
|
|
202
|
+
await Promise.all(promises);
|
|
203
|
+
return results;
|
|
204
|
+
}
|
|
205
|
+
emitToolResults(observer, results) {
|
|
206
|
+
for (const { toolCallId, toolName, result, rawResult, messageId } of results) {
|
|
207
|
+
const toolDef = this.tools.find((t) => t.name === toolName);
|
|
208
|
+
const sessionId = toolDef?._meta?.sessionId;
|
|
209
|
+
const resourceUri = rawResult?._meta?.ui?.resourceUri ?? rawResult?._meta?.["ui/resourceUri"] ?? toolDef?._meta?.ui?.resourceUri ?? toolDef?._meta?.["ui/resourceUri"];
|
|
210
|
+
if (resourceUri) {
|
|
211
|
+
const payload = {
|
|
212
|
+
toolCallId,
|
|
213
|
+
resourceUri,
|
|
214
|
+
sessionId,
|
|
215
|
+
toolName,
|
|
216
|
+
result: rawResult ?? result
|
|
217
|
+
};
|
|
218
|
+
observer.next({
|
|
219
|
+
type: client.EventType.CUSTOM,
|
|
220
|
+
name: MCP_APP_UI_EVENT,
|
|
221
|
+
value: payload,
|
|
222
|
+
timestamp: Date.now(),
|
|
223
|
+
role: "tool"
|
|
224
|
+
});
|
|
225
|
+
console.log(`[McpMiddleware] Emitting CustomEvent(${MCP_APP_UI_EVENT}) for: ${toolName} (session: ${sessionId})`);
|
|
226
|
+
}
|
|
227
|
+
observer.next({
|
|
228
|
+
type: client.EventType.TOOL_CALL_RESULT,
|
|
229
|
+
toolCallId,
|
|
230
|
+
messageId,
|
|
231
|
+
content: result,
|
|
232
|
+
role: "tool",
|
|
233
|
+
timestamp: Date.now()
|
|
234
|
+
});
|
|
235
|
+
console.log(`[McpMiddleware] Emitting TOOL_CALL_RESULT for: ${toolName}`);
|
|
236
|
+
}
|
|
200
237
|
}
|
|
201
|
-
/**
|
|
202
|
-
* Run the middleware, intercepting and executing MCP tool calls
|
|
203
|
-
*/
|
|
204
238
|
run(input, next) {
|
|
205
239
|
return new rxjs.Observable((observer) => {
|
|
206
|
-
const
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
240
|
+
const state = {
|
|
241
|
+
toolCallArgsBuffer: /* @__PURE__ */ new Map(),
|
|
242
|
+
toolCallNames: /* @__PURE__ */ new Map(),
|
|
243
|
+
pendingMcpCalls: /* @__PURE__ */ new Set(),
|
|
244
|
+
textContent: "",
|
|
245
|
+
error: false
|
|
246
|
+
};
|
|
247
|
+
this.ensureIds(input);
|
|
248
|
+
const anyInput = input;
|
|
249
|
+
console.log(`[McpMiddleware] === NEW RUN ===`);
|
|
250
|
+
console.log(`[McpMiddleware] threadId: ${anyInput.threadId}, runId: ${anyInput.runId}`);
|
|
251
|
+
console.log(`[McpMiddleware] messages: ${input.messages?.length ?? 0}, tools: ${this.tools?.length ?? 0}`);
|
|
252
|
+
if (this.toolSchemas?.length) {
|
|
253
|
+
input.tools = [...input.tools || [], ...this.toolSchemas];
|
|
254
|
+
console.log(`[McpMiddleware] Injected ${this.toolSchemas.length} tools:`, this.toolSchemas.map((t) => t.name));
|
|
217
255
|
}
|
|
218
|
-
const handleRunFinished = async (
|
|
219
|
-
if (
|
|
220
|
-
|
|
256
|
+
const handleRunFinished = async () => {
|
|
257
|
+
if (state.error) return;
|
|
258
|
+
if (state.pendingMcpCalls.size === 0) {
|
|
259
|
+
observer.next({
|
|
260
|
+
type: client.EventType.RUN_FINISHED,
|
|
261
|
+
threadId: anyInput.threadId,
|
|
262
|
+
runId: anyInput.runId,
|
|
263
|
+
timestamp: Date.now()
|
|
264
|
+
});
|
|
221
265
|
observer.complete();
|
|
222
266
|
return;
|
|
223
267
|
}
|
|
224
|
-
console.log(`[McpMiddleware] RUN_FINISHED
|
|
225
|
-
const
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
const
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
|
|
268
|
+
console.log(`[McpMiddleware] RUN_FINISHED with ${state.pendingMcpCalls.size} pending calls`);
|
|
269
|
+
const toolCalls = [];
|
|
270
|
+
for (const toolCallId of state.pendingMcpCalls) {
|
|
271
|
+
const name = state.toolCallNames.get(toolCallId);
|
|
272
|
+
const args = state.toolCallArgsBuffer.get(toolCallId) || "{}";
|
|
273
|
+
if (name) {
|
|
274
|
+
toolCalls.push({
|
|
275
|
+
id: toolCallId,
|
|
276
|
+
type: "function",
|
|
277
|
+
function: { name, arguments: args }
|
|
278
|
+
});
|
|
234
279
|
}
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
const
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
|
|
243
|
-
role: "tool",
|
|
244
|
-
timestamp: Date.now()
|
|
280
|
+
}
|
|
281
|
+
if (toolCalls.length > 0 || state.textContent) {
|
|
282
|
+
const assistantMsg = {
|
|
283
|
+
id: this.generateId("msg_ast"),
|
|
284
|
+
role: "assistant",
|
|
285
|
+
content: state.textContent || null,
|
|
286
|
+
// Ensure null if empty string for strict LLMs
|
|
287
|
+
tool_calls: toolCalls.length > 0 ? toolCalls : void 0
|
|
245
288
|
};
|
|
246
|
-
|
|
247
|
-
|
|
289
|
+
input.messages.push(assistantMsg);
|
|
290
|
+
console.log(`[McpMiddleware] Added assistant message to history before tools: ${state.textContent?.slice(0, 50)}... [${toolCalls.length} tools]`);
|
|
291
|
+
}
|
|
292
|
+
const results = await this.executeTools(state);
|
|
293
|
+
this.emitToolResults(observer, results);
|
|
294
|
+
console.log(`[McpMiddleware] Triggering continuation with ${results.length} results`);
|
|
295
|
+
for (const { toolCallId, result, messageId } of results) {
|
|
248
296
|
input.messages.push({
|
|
249
297
|
id: messageId,
|
|
250
298
|
role: "tool",
|
|
251
|
-
toolCallId,
|
|
299
|
+
tool_call_id: toolCallId,
|
|
252
300
|
content: result
|
|
253
301
|
});
|
|
254
|
-
|
|
255
|
-
|
|
256
|
-
|
|
257
|
-
|
|
258
|
-
|
|
259
|
-
|
|
260
|
-
|
|
261
|
-
|
|
262
|
-
|
|
302
|
+
}
|
|
303
|
+
state.toolCallArgsBuffer.clear();
|
|
304
|
+
state.toolCallNames.clear();
|
|
305
|
+
state.textContent = "";
|
|
306
|
+
anyInput.runId = this.generateId("mcp_run");
|
|
307
|
+
console.log(`[McpMiddleware] === CONTINUATION RUN === messages: ${input.messages.length}`);
|
|
308
|
+
next.run(input).subscribe({
|
|
309
|
+
next: (event) => {
|
|
310
|
+
if (state.error) return;
|
|
311
|
+
this.handleToolCallEvent(event, state);
|
|
312
|
+
if (event.type === client.EventType.RUN_ERROR) {
|
|
313
|
+
console.log(`[McpMiddleware] RUN_ERROR received in continuation`);
|
|
314
|
+
state.error = true;
|
|
315
|
+
observer.next(event);
|
|
316
|
+
observer.complete();
|
|
317
|
+
return;
|
|
318
|
+
}
|
|
319
|
+
if (event.type === client.EventType.RUN_STARTED) {
|
|
320
|
+
console.log(`[McpMiddleware] Filtering RUN_STARTED from continuation`);
|
|
321
|
+
return;
|
|
322
|
+
}
|
|
323
|
+
if (event.type === client.EventType.RUN_FINISHED) {
|
|
324
|
+
if (state.pendingMcpCalls.size > 0) {
|
|
325
|
+
handleRunFinished();
|
|
326
|
+
} else {
|
|
327
|
+
observer.next(event);
|
|
328
|
+
observer.complete();
|
|
329
|
+
}
|
|
330
|
+
return;
|
|
331
|
+
}
|
|
332
|
+
observer.next(event);
|
|
333
|
+
},
|
|
334
|
+
error: (err) => {
|
|
335
|
+
state.error = true;
|
|
336
|
+
observer.error(err);
|
|
337
|
+
},
|
|
338
|
+
complete: () => {
|
|
339
|
+
if (!state.error && state.pendingMcpCalls.size === 0) observer.complete();
|
|
340
|
+
}
|
|
263
341
|
});
|
|
264
|
-
console.log(`[McpMiddleware] Triggering new run`);
|
|
265
|
-
this.triggerNewRun(observer, input, next, toolCallArgsBuffer, toolCallNames, pendingMcpCalls);
|
|
266
342
|
};
|
|
267
343
|
const subscription = next.run(input).subscribe({
|
|
268
344
|
next: (event) => {
|
|
269
|
-
if (
|
|
270
|
-
|
|
271
|
-
|
|
272
|
-
|
|
273
|
-
|
|
274
|
-
|
|
275
|
-
|
|
276
|
-
|
|
277
|
-
}
|
|
278
|
-
}
|
|
279
|
-
}
|
|
280
|
-
if (event.type === client.EventType.TOOL_CALL_ARGS) {
|
|
281
|
-
const argsEvent = event;
|
|
282
|
-
if (argsEvent.toolCallId && argsEvent.delta) {
|
|
283
|
-
const existing = toolCallArgsBuffer.get(argsEvent.toolCallId) || "";
|
|
284
|
-
toolCallArgsBuffer.set(argsEvent.toolCallId, existing + argsEvent.delta);
|
|
285
|
-
}
|
|
286
|
-
}
|
|
287
|
-
if (event.type === client.EventType.TOOL_CALL_END) {
|
|
288
|
-
const endEvent = event;
|
|
289
|
-
const toolName = toolCallNames.get(endEvent.toolCallId);
|
|
290
|
-
console.log(`[McpMiddleware] TOOL_CALL_END: ${toolName ?? "unknown"} (id: ${endEvent.toolCallId})`);
|
|
345
|
+
if (state.error) return;
|
|
346
|
+
this.handleToolCallEvent(event, state);
|
|
347
|
+
if (event.type === client.EventType.RUN_ERROR) {
|
|
348
|
+
console.log(`[McpMiddleware] RUN_ERROR received`);
|
|
349
|
+
state.error = true;
|
|
350
|
+
observer.next(event);
|
|
351
|
+
observer.complete();
|
|
352
|
+
return;
|
|
291
353
|
}
|
|
292
354
|
if (event.type === client.EventType.RUN_FINISHED) {
|
|
293
|
-
handleRunFinished(
|
|
355
|
+
handleRunFinished();
|
|
294
356
|
return;
|
|
295
357
|
}
|
|
296
358
|
observer.next(event);
|
|
297
359
|
},
|
|
298
|
-
error: (
|
|
299
|
-
|
|
360
|
+
error: (err) => {
|
|
361
|
+
state.error = true;
|
|
362
|
+
observer.error(err);
|
|
300
363
|
},
|
|
301
364
|
complete: () => {
|
|
302
|
-
if (pendingMcpCalls.size === 0)
|
|
303
|
-
observer.complete();
|
|
304
|
-
}
|
|
305
|
-
}
|
|
306
|
-
});
|
|
307
|
-
return () => {
|
|
308
|
-
subscription.unsubscribe();
|
|
309
|
-
};
|
|
310
|
-
});
|
|
311
|
-
}
|
|
312
|
-
triggerNewRun(observer, input, next, toolCallArgsBuffer, toolCallNames, pendingMcpCalls) {
|
|
313
|
-
toolCallArgsBuffer.clear();
|
|
314
|
-
toolCallNames.clear();
|
|
315
|
-
pendingMcpCalls.clear();
|
|
316
|
-
console.log(`[McpMiddleware] Starting new run with updated messages`);
|
|
317
|
-
next.run(input).subscribe({
|
|
318
|
-
next: (event) => {
|
|
319
|
-
if (event.type === client.EventType.TOOL_CALL_START) {
|
|
320
|
-
const startEvent = event;
|
|
321
|
-
if (startEvent.toolCallId && startEvent.toolCallName) {
|
|
322
|
-
toolCallNames.set(startEvent.toolCallId, startEvent.toolCallName);
|
|
323
|
-
const isMcp = this.isMcpTool(startEvent.toolCallName);
|
|
324
|
-
console.log(`[McpMiddleware] TOOL_CALL_START: ${startEvent.toolCallName} (id: ${startEvent.toolCallId}, isMCP: ${isMcp})`);
|
|
325
|
-
if (isMcp) {
|
|
326
|
-
pendingMcpCalls.add(startEvent.toolCallId);
|
|
327
|
-
}
|
|
328
|
-
}
|
|
365
|
+
if (!state.error && state.pendingMcpCalls.size === 0) observer.complete();
|
|
329
366
|
}
|
|
330
|
-
if (event.type === client.EventType.TOOL_CALL_ARGS) {
|
|
331
|
-
const argsEvent = event;
|
|
332
|
-
if (argsEvent.toolCallId && argsEvent.delta) {
|
|
333
|
-
const existing = toolCallArgsBuffer.get(argsEvent.toolCallId) || "";
|
|
334
|
-
toolCallArgsBuffer.set(argsEvent.toolCallId, existing + argsEvent.delta);
|
|
335
|
-
}
|
|
336
|
-
}
|
|
337
|
-
if (event.type === client.EventType.TOOL_CALL_END) {
|
|
338
|
-
const endEvent = event;
|
|
339
|
-
const toolName = toolCallNames.get(endEvent.toolCallId);
|
|
340
|
-
console.log(`[McpMiddleware] TOOL_CALL_END: ${toolName ?? "unknown"} (id: ${endEvent.toolCallId})`);
|
|
341
|
-
}
|
|
342
|
-
if (event.type === client.EventType.RUN_FINISHED) {
|
|
343
|
-
if (pendingMcpCalls.size > 0) {
|
|
344
|
-
console.log(`[McpMiddleware] RUN_FINISHED with ${pendingMcpCalls.size} pending calls, executing...`);
|
|
345
|
-
this.handlePendingCalls(observer, input, next, toolCallArgsBuffer, toolCallNames, pendingMcpCalls);
|
|
346
|
-
} else {
|
|
347
|
-
observer.next(event);
|
|
348
|
-
observer.complete();
|
|
349
|
-
}
|
|
350
|
-
return;
|
|
351
|
-
}
|
|
352
|
-
observer.next(event);
|
|
353
|
-
},
|
|
354
|
-
error: (error) => observer.error(error),
|
|
355
|
-
complete: () => {
|
|
356
|
-
if (pendingMcpCalls.size === 0) {
|
|
357
|
-
observer.complete();
|
|
358
|
-
}
|
|
359
|
-
}
|
|
360
|
-
});
|
|
361
|
-
}
|
|
362
|
-
async handlePendingCalls(observer, input, next, toolCallArgsBuffer, toolCallNames, pendingMcpCalls) {
|
|
363
|
-
const callPromises = [...pendingMcpCalls].map(async (toolCallId) => {
|
|
364
|
-
const toolName = toolCallNames.get(toolCallId);
|
|
365
|
-
if (!toolName) return;
|
|
366
|
-
const argsString = toolCallArgsBuffer.get(toolCallId) || "{}";
|
|
367
|
-
let args = {};
|
|
368
|
-
try {
|
|
369
|
-
args = JSON.parse(argsString);
|
|
370
|
-
} catch (e) {
|
|
371
|
-
console.error(`[McpMiddleware] Failed to parse args:`, argsString);
|
|
372
|
-
}
|
|
373
|
-
console.log(`[McpMiddleware] Executing pending tool: ${toolName}`);
|
|
374
|
-
const result = await this.executeTool(toolName, args);
|
|
375
|
-
const messageId = this.generateMessageId();
|
|
376
|
-
const resultEvent = {
|
|
377
|
-
type: client.EventType.TOOL_CALL_RESULT,
|
|
378
|
-
toolCallId,
|
|
379
|
-
messageId,
|
|
380
|
-
content: result,
|
|
381
|
-
role: "tool",
|
|
382
|
-
timestamp: Date.now()
|
|
383
|
-
};
|
|
384
|
-
console.log(`[McpMiddleware] Emitting TOOL_CALL_RESULT for: ${toolName}`);
|
|
385
|
-
observer.next(resultEvent);
|
|
386
|
-
input.messages.push({
|
|
387
|
-
id: messageId,
|
|
388
|
-
role: "tool",
|
|
389
|
-
toolCallId,
|
|
390
|
-
content: result
|
|
391
367
|
});
|
|
392
|
-
|
|
393
|
-
});
|
|
394
|
-
await Promise.all(callPromises);
|
|
395
|
-
console.log(`[McpMiddleware] Pending tools executed, emitting RUN_FINISHED`);
|
|
396
|
-
observer.next({
|
|
397
|
-
type: client.EventType.RUN_FINISHED,
|
|
398
|
-
threadId: input.threadId,
|
|
399
|
-
runId: input.runId,
|
|
400
|
-
timestamp: Date.now()
|
|
368
|
+
return () => subscription.unsubscribe();
|
|
401
369
|
});
|
|
402
|
-
console.log(`[McpMiddleware] Triggering new run`);
|
|
403
|
-
this.triggerNewRun(observer, input, next, toolCallArgsBuffer, toolCallNames, pendingMcpCalls);
|
|
404
370
|
}
|
|
405
371
|
};
|
|
406
|
-
function createMcpMiddleware(
|
|
407
|
-
const middleware = new McpMiddleware(
|
|
408
|
-
client,
|
|
409
|
-
...options
|
|
410
|
-
});
|
|
372
|
+
function createMcpMiddleware(options) {
|
|
373
|
+
const middleware = new McpMiddleware(options);
|
|
411
374
|
return (input, next) => {
|
|
412
375
|
return middleware.run(input, next);
|
|
413
376
|
};
|
|
@@ -421,6 +384,7 @@ Object.defineProperty(exports, "Middleware", {
|
|
|
421
384
|
enumerable: true,
|
|
422
385
|
get: function () { return client.Middleware; }
|
|
423
386
|
});
|
|
387
|
+
exports.MCP_APP_UI_EVENT = MCP_APP_UI_EVENT;
|
|
424
388
|
exports.McpMiddleware = McpMiddleware;
|
|
425
389
|
exports.McpToolExecutorMiddleware = McpMiddleware;
|
|
426
390
|
exports.createMcpMiddleware = createMcpMiddleware;
|