@agent-native/core 0.20.9 → 0.21.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/dist/action.d.ts +61 -0
- package/dist/action.d.ts.map +1 -1
- package/dist/action.js +14 -0
- package/dist/action.js.map +1 -1
- package/dist/agent/production-agent.d.ts +4 -0
- package/dist/agent/production-agent.d.ts.map +1 -1
- package/dist/agent/production-agent.js +19 -7
- package/dist/agent/production-agent.js.map +1 -1
- package/dist/agent/types.d.ts +2 -0
- package/dist/agent/types.d.ts.map +1 -1
- package/dist/agent/types.js.map +1 -1
- package/dist/cli/code-agent-executor.d.ts.map +1 -1
- package/dist/cli/code-agent-executor.js +1 -0
- package/dist/cli/code-agent-executor.js.map +1 -1
- package/dist/cli/connect.d.ts +13 -0
- package/dist/cli/connect.d.ts.map +1 -1
- package/dist/cli/connect.js +492 -4
- package/dist/cli/connect.js.map +1 -1
- package/dist/client/AssistantChat.d.ts.map +1 -1
- package/dist/client/AssistantChat.js +6 -5
- package/dist/client/AssistantChat.js.map +1 -1
- package/dist/client/code-agent-chat-adapter.js +1 -0
- package/dist/client/code-agent-chat-adapter.js.map +1 -1
- package/dist/client/conversation/AgentConversation.d.ts.map +1 -1
- package/dist/client/conversation/AgentConversation.js +3 -2
- package/dist/client/conversation/AgentConversation.js.map +1 -1
- package/dist/client/conversation/code-agent-transcript.js +1 -0
- package/dist/client/conversation/code-agent-transcript.js.map +1 -1
- package/dist/client/conversation/types.d.ts +2 -0
- package/dist/client/conversation/types.d.ts.map +1 -1
- package/dist/client/conversation/types.js.map +1 -1
- package/dist/client/index.d.ts +1 -0
- package/dist/client/index.d.ts.map +1 -1
- package/dist/client/index.js +1 -0
- package/dist/client/index.js.map +1 -1
- package/dist/client/mcp-apps/McpAppRenderer.d.ts +10 -0
- package/dist/client/mcp-apps/McpAppRenderer.d.ts.map +1 -0
- package/dist/client/mcp-apps/McpAppRenderer.js +296 -0
- package/dist/client/mcp-apps/McpAppRenderer.js.map +1 -0
- package/dist/client/sse-event-processor.d.ts +3 -0
- package/dist/client/sse-event-processor.d.ts.map +1 -1
- package/dist/client/sse-event-processor.js +2 -0
- package/dist/client/sse-event-processor.js.map +1 -1
- package/dist/code-agents/transcript-normalizer.d.ts +2 -0
- package/dist/code-agents/transcript-normalizer.d.ts.map +1 -1
- package/dist/code-agents/transcript-normalizer.js +17 -0
- package/dist/code-agents/transcript-normalizer.js.map +1 -1
- package/dist/db/client.d.ts.map +1 -1
- package/dist/db/client.js +22 -20
- package/dist/db/client.js.map +1 -1
- package/dist/index.browser.d.ts +1 -1
- package/dist/index.browser.d.ts.map +1 -1
- package/dist/index.browser.js +1 -1
- package/dist/index.browser.js.map +1 -1
- package/dist/index.d.ts +1 -1
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +1 -1
- package/dist/index.js.map +1 -1
- package/dist/mcp/build-server.d.ts.map +1 -1
- package/dist/mcp/build-server.js +154 -4
- package/dist/mcp/build-server.js.map +1 -1
- package/dist/mcp/stdio.d.ts +2 -2
- package/dist/mcp/stdio.d.ts.map +1 -1
- package/dist/mcp/stdio.js +26 -8
- package/dist/mcp/stdio.js.map +1 -1
- package/dist/mcp-client/app-result.d.ts +40 -0
- package/dist/mcp-client/app-result.d.ts.map +1 -0
- package/dist/mcp-client/app-result.js +19 -0
- package/dist/mcp-client/app-result.js.map +1 -0
- package/dist/mcp-client/index.d.ts +5 -2
- package/dist/mcp-client/index.d.ts.map +1 -1
- package/dist/mcp-client/index.js +185 -23
- package/dist/mcp-client/index.js.map +1 -1
- package/dist/mcp-client/manager.d.ts +16 -0
- package/dist/mcp-client/manager.d.ts.map +1 -1
- package/dist/mcp-client/manager.js +58 -1
- package/dist/mcp-client/manager.js.map +1 -1
- package/dist/mcp-client/routes.d.ts +4 -1
- package/dist/mcp-client/routes.d.ts.map +1 -1
- package/dist/mcp-client/routes.js +146 -0
- package/dist/mcp-client/routes.js.map +1 -1
- package/dist/styles/agent-conversation.css +53 -0
- package/docs/content/actions.md +25 -2
- package/docs/content/external-agents.md +62 -8
- package/docs/content/key-concepts.md +1 -1
- package/docs/content/mcp-clients.md +1 -1
- package/docs/content/mcp-protocol.md +16 -11
- package/package.json +2 -1
package/dist/mcp-client/index.js
CHANGED
|
@@ -5,7 +5,7 @@
|
|
|
5
5
|
* to the agent-chat tool-use loop.
|
|
6
6
|
*/
|
|
7
7
|
export { loadMcpConfig, autoDetectMcpConfig, } from "./config.js";
|
|
8
|
-
export { McpClientManager, parseMcpToolName, MCP_TOOL_PREFIX, } from "./manager.js";
|
|
8
|
+
export { McpClientManager, buildMcpToolName, parseMcpToolName, MCP_TOOL_PREFIX, } from "./manager.js";
|
|
9
9
|
export { listRemoteServers, addRemoteServer, removeRemoteServer, validateRemoteUrl, normalizeServerName, mergedConfigKey, parseMergedKey, hashEmail, toHttpServerConfig, toHttpServerConfigAsync, materializeHeaders, } from "./remote-store.js";
|
|
10
10
|
export { BUILTIN_MCP_CAPABILITIES, getBuiltinMcpCapability, isBuiltinMcpCapabilityAvailable, normalizeBuiltinMcpCapabilityIds, toBuiltinMcpServerConfig, } from "./builtin-capabilities.js";
|
|
11
11
|
export { builtinMcpCapabilitiesSettingsKey, listEnabledBuiltinMcpCapabilities, setEnabledBuiltinMcpCapabilities, setBuiltinMcpCapabilityEnabled, } from "./builtin-store.js";
|
|
@@ -14,9 +14,13 @@ export { mountMcpHubRoutes, listHubServers, getHubStatus, isHubServeEnabled, isH
|
|
|
14
14
|
export { fetchHubServers } from "./hub-client.js";
|
|
15
15
|
export { isMcpToolAllowedForRequest } from "./visibility.js";
|
|
16
16
|
import { isMcpToolAllowedForRequest } from "./visibility.js";
|
|
17
|
+
export { MCP_ACTION_RESULT_MARKER, isMcpActionResult, } from "./app-result.js";
|
|
18
|
+
import { MCP_ACTION_RESULT_MARKER, toolForMcpAppPayload, } from "./app-result.js";
|
|
19
|
+
import { getToolUiResourceUri, isToolVisibilityAppOnly, isToolVisibilityModelOnly, } from "@modelcontextprotocol/ext-apps/app-bridge";
|
|
20
|
+
import { MCP_APP_MIME_TYPE } from "../action.js";
|
|
17
21
|
export function mcpToolsToActionEntries(manager) {
|
|
18
22
|
const entries = {};
|
|
19
|
-
for (const tool of manager.getTools()) {
|
|
23
|
+
for (const tool of manager.getTools().filter(isVisibleToModel)) {
|
|
20
24
|
entries[tool.name] = mcpToolToActionEntry(manager, tool);
|
|
21
25
|
}
|
|
22
26
|
return entries;
|
|
@@ -32,7 +36,7 @@ export function mcpToolsToActionEntries(manager) {
|
|
|
32
36
|
*/
|
|
33
37
|
export function syncMcpActionEntries(manager, target) {
|
|
34
38
|
const current = new Set();
|
|
35
|
-
for (const tool of manager.getTools()) {
|
|
39
|
+
for (const tool of manager.getTools().filter(isVisibleToModel)) {
|
|
36
40
|
current.add(tool.name);
|
|
37
41
|
if (!target[tool.name]) {
|
|
38
42
|
target[tool.name] = mcpToolToActionEntry(manager, tool);
|
|
@@ -60,26 +64,7 @@ function mcpToolToActionEntry(manager, tool) {
|
|
|
60
64
|
}
|
|
61
65
|
try {
|
|
62
66
|
const result = await manager.callTool(tool.name, args);
|
|
63
|
-
|
|
64
|
-
// Flatten text content for the agent's string-based tool result slot.
|
|
65
|
-
if (result &&
|
|
66
|
-
typeof result === "object" &&
|
|
67
|
-
Array.isArray(result.content)) {
|
|
68
|
-
const parts = result.content;
|
|
69
|
-
const text = parts
|
|
70
|
-
.map((p) => {
|
|
71
|
-
if (p?.type === "text" && typeof p.text === "string")
|
|
72
|
-
return p.text;
|
|
73
|
-
if (p?.type === "image")
|
|
74
|
-
return `[image: ${p?.mimeType ?? "unknown"}]`;
|
|
75
|
-
return JSON.stringify(p);
|
|
76
|
-
})
|
|
77
|
-
.join("\n");
|
|
78
|
-
if (result.isError)
|
|
79
|
-
return `Error: ${text}`;
|
|
80
|
-
return text || "(no output)";
|
|
81
|
-
}
|
|
82
|
-
return typeof result === "string" ? result : JSON.stringify(result);
|
|
67
|
+
return await buildMcpActionResult(manager, tool, args, result);
|
|
83
68
|
}
|
|
84
69
|
catch (err) {
|
|
85
70
|
return `Error calling MCP tool ${tool.name}: ${err?.message ?? err}`;
|
|
@@ -87,4 +72,181 @@ function mcpToolToActionEntry(manager, tool) {
|
|
|
87
72
|
},
|
|
88
73
|
};
|
|
89
74
|
}
|
|
75
|
+
function isVisibleToModel(tool) {
|
|
76
|
+
try {
|
|
77
|
+
return !isToolVisibilityAppOnly(tool.raw);
|
|
78
|
+
}
|
|
79
|
+
catch {
|
|
80
|
+
return true;
|
|
81
|
+
}
|
|
82
|
+
}
|
|
83
|
+
export function isVisibleToMcpApp(tool) {
|
|
84
|
+
try {
|
|
85
|
+
return !isToolVisibilityModelOnly(tool.raw);
|
|
86
|
+
}
|
|
87
|
+
catch {
|
|
88
|
+
return true;
|
|
89
|
+
}
|
|
90
|
+
}
|
|
91
|
+
export function flattenMcpToolResult(result) {
|
|
92
|
+
if (result &&
|
|
93
|
+
typeof result === "object" &&
|
|
94
|
+
Array.isArray(result.content)) {
|
|
95
|
+
const parts = result.content;
|
|
96
|
+
const text = parts.map(formatMcpContentPart).join("\n");
|
|
97
|
+
const fallback = text ||
|
|
98
|
+
(hasStructuredContent(result)
|
|
99
|
+
? JSON.stringify(result.structuredContent, null, 2)
|
|
100
|
+
: "(no output)");
|
|
101
|
+
if (result.isError)
|
|
102
|
+
return `Error: ${fallback}`;
|
|
103
|
+
return fallback;
|
|
104
|
+
}
|
|
105
|
+
return typeof result === "string" ? result : JSON.stringify(result);
|
|
106
|
+
}
|
|
107
|
+
function formatMcpContentPart(part) {
|
|
108
|
+
if (part?.type === "text" && typeof part.text === "string") {
|
|
109
|
+
return part.text;
|
|
110
|
+
}
|
|
111
|
+
if (part?.type === "image") {
|
|
112
|
+
return `[image: ${part?.mimeType ?? "unknown"}]`;
|
|
113
|
+
}
|
|
114
|
+
if (part?.type === "resource") {
|
|
115
|
+
const resource = part.resource ?? {};
|
|
116
|
+
const uri = typeof resource.uri === "string" ? ` ${resource.uri}` : "";
|
|
117
|
+
return `[resource: ${resource.mimeType ?? "unknown"}${uri}]`;
|
|
118
|
+
}
|
|
119
|
+
if (part?.type === "resource_link") {
|
|
120
|
+
const uri = typeof part.uri === "string" ? ` ${part.uri}` : "";
|
|
121
|
+
return `[resource: ${part.mimeType ?? "unknown"}${uri}]`;
|
|
122
|
+
}
|
|
123
|
+
return JSON.stringify(part);
|
|
124
|
+
}
|
|
125
|
+
function hasStructuredContent(result) {
|
|
126
|
+
return (!!result &&
|
|
127
|
+
typeof result === "object" &&
|
|
128
|
+
Object.prototype.hasOwnProperty.call(result, "structuredContent"));
|
|
129
|
+
}
|
|
130
|
+
async function buildMcpActionResult(manager, tool, input, raw) {
|
|
131
|
+
const text = flattenMcpToolResult(raw);
|
|
132
|
+
const mcpApp = await extractMcpAppPayload(manager, tool, input, raw);
|
|
133
|
+
return {
|
|
134
|
+
[MCP_ACTION_RESULT_MARKER]: true,
|
|
135
|
+
text,
|
|
136
|
+
raw,
|
|
137
|
+
serverId: tool.source,
|
|
138
|
+
toolName: tool.name,
|
|
139
|
+
originalToolName: tool.originalName,
|
|
140
|
+
input,
|
|
141
|
+
...(mcpApp ? { mcpApp } : {}),
|
|
142
|
+
};
|
|
143
|
+
}
|
|
144
|
+
async function extractMcpAppPayload(manager, tool, input, raw) {
|
|
145
|
+
const inlineResource = findInlineMcpAppResource(raw);
|
|
146
|
+
const resourceUri = inlineResource?.uri ??
|
|
147
|
+
resourceUriFromTool(tool) ??
|
|
148
|
+
resourceUriFromResult(raw);
|
|
149
|
+
if (!resourceUri)
|
|
150
|
+
return undefined;
|
|
151
|
+
const resource = inlineResource ?? (await readMcpAppResource(manager, tool, resourceUri));
|
|
152
|
+
return {
|
|
153
|
+
serverId: tool.source,
|
|
154
|
+
toolName: tool.name,
|
|
155
|
+
originalToolName: tool.originalName,
|
|
156
|
+
resourceUri,
|
|
157
|
+
toolInput: input,
|
|
158
|
+
toolResult: raw && typeof raw === "object"
|
|
159
|
+
? { ...raw }
|
|
160
|
+
: { content: [{ type: "text", text: String(raw ?? "") }] },
|
|
161
|
+
tool: toolForMcpAppPayload(tool),
|
|
162
|
+
...(resource ? { resource } : {}),
|
|
163
|
+
};
|
|
164
|
+
}
|
|
165
|
+
function resourceUriFromTool(tool) {
|
|
166
|
+
try {
|
|
167
|
+
return getToolUiResourceUri(tool.raw);
|
|
168
|
+
}
|
|
169
|
+
catch {
|
|
170
|
+
return undefined;
|
|
171
|
+
}
|
|
172
|
+
}
|
|
173
|
+
function resourceUriFromResult(raw) {
|
|
174
|
+
if (!raw || typeof raw !== "object")
|
|
175
|
+
return undefined;
|
|
176
|
+
const meta = raw._meta;
|
|
177
|
+
const nested = meta?.ui?.resourceUri;
|
|
178
|
+
if (typeof nested === "string" && nested.startsWith("ui://"))
|
|
179
|
+
return nested;
|
|
180
|
+
const flat = meta?.["ui/resourceUri"] ?? meta?.["ui.resourceUri"];
|
|
181
|
+
if (typeof flat === "string" && flat.startsWith("ui://"))
|
|
182
|
+
return flat;
|
|
183
|
+
return findInlineMcpAppResource(raw)?.uri;
|
|
184
|
+
}
|
|
185
|
+
function findInlineMcpAppResource(raw) {
|
|
186
|
+
if (!raw || typeof raw !== "object")
|
|
187
|
+
return undefined;
|
|
188
|
+
const content = Array.isArray(raw.content)
|
|
189
|
+
? raw.content
|
|
190
|
+
: [];
|
|
191
|
+
for (const part of content) {
|
|
192
|
+
const resource = normalizeMcpAppResourceContent(part);
|
|
193
|
+
if (resource)
|
|
194
|
+
return resource;
|
|
195
|
+
}
|
|
196
|
+
return undefined;
|
|
197
|
+
}
|
|
198
|
+
function normalizeMcpAppResourceContent(part) {
|
|
199
|
+
if (!part || typeof part !== "object")
|
|
200
|
+
return undefined;
|
|
201
|
+
const candidate = part.type === "resource"
|
|
202
|
+
? part.resource
|
|
203
|
+
: (part.resource ?? part);
|
|
204
|
+
if (!candidate || typeof candidate !== "object")
|
|
205
|
+
return undefined;
|
|
206
|
+
const uri = candidate.uri;
|
|
207
|
+
if (typeof uri !== "string" || !uri.startsWith("ui://"))
|
|
208
|
+
return undefined;
|
|
209
|
+
const mimeType = typeof candidate.mimeType === "string"
|
|
210
|
+
? candidate.mimeType
|
|
211
|
+
: undefined;
|
|
212
|
+
if (mimeType && !mimeType.includes(MCP_APP_MIME_TYPE))
|
|
213
|
+
return undefined;
|
|
214
|
+
const text = typeof candidate.text === "string"
|
|
215
|
+
? candidate.text
|
|
216
|
+
: undefined;
|
|
217
|
+
const blob = typeof candidate.blob === "string"
|
|
218
|
+
? candidate.blob
|
|
219
|
+
: undefined;
|
|
220
|
+
const meta = candidate._meta && typeof candidate._meta === "object"
|
|
221
|
+
? candidate._meta
|
|
222
|
+
: part._meta && typeof part._meta === "object"
|
|
223
|
+
? part._meta
|
|
224
|
+
: undefined;
|
|
225
|
+
return {
|
|
226
|
+
uri,
|
|
227
|
+
...(mimeType ? { mimeType } : {}),
|
|
228
|
+
...(text ? { text } : {}),
|
|
229
|
+
...(blob ? { blob } : {}),
|
|
230
|
+
...(meta ? { _meta: meta } : {}),
|
|
231
|
+
};
|
|
232
|
+
}
|
|
233
|
+
async function readMcpAppResource(manager, tool, resourceUri) {
|
|
234
|
+
try {
|
|
235
|
+
const result = await manager.readResourceForTool(tool.name, resourceUri);
|
|
236
|
+
const contents = Array.isArray(result?.contents)
|
|
237
|
+
? result.contents
|
|
238
|
+
: [];
|
|
239
|
+
for (const content of contents) {
|
|
240
|
+
const resource = normalizeMcpAppResourceContent(content);
|
|
241
|
+
if (resource?.uri === resourceUri ||
|
|
242
|
+
(resource && contents.length === 1)) {
|
|
243
|
+
return resource;
|
|
244
|
+
}
|
|
245
|
+
}
|
|
246
|
+
}
|
|
247
|
+
catch (err) {
|
|
248
|
+
console.warn(`[mcp-client] Failed to read MCP App resource ${resourceUri}: ${err?.message ?? err}`);
|
|
249
|
+
}
|
|
250
|
+
return undefined;
|
|
251
|
+
}
|
|
90
252
|
//# sourceMappingURL=index.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/mcp-client/index.ts"],"names":[],"mappings":"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","sourcesContent":["/**\n * MCP client module — symmetric counterpart to `@agent-native/core/mcp`\n * (the MCP server). Connects to local MCP servers configured in\n * `mcp.config.json` or the `MCP_SERVERS` env var and exposes their tools\n * to the agent-chat tool-use loop.\n */\n\nexport {\n loadMcpConfig,\n autoDetectMcpConfig,\n type McpConfig,\n type McpServerConfig,\n} from \"./config.js\";\n\nexport {\n McpClientManager,\n parseMcpToolName,\n MCP_TOOL_PREFIX,\n type McpTool,\n type McpClientManagerOptions,\n} from \"./manager.js\";\n\nexport {\n listRemoteServers,\n addRemoteServer,\n removeRemoteServer,\n validateRemoteUrl,\n normalizeServerName,\n mergedConfigKey,\n parseMergedKey,\n hashEmail,\n toHttpServerConfig,\n toHttpServerConfigAsync,\n materializeHeaders,\n type RemoteMcpScope,\n type StoredRemoteMcpServer,\n} from \"./remote-store.js\";\n\nexport {\n BUILTIN_MCP_CAPABILITIES,\n getBuiltinMcpCapability,\n isBuiltinMcpCapabilityAvailable,\n normalizeBuiltinMcpCapabilityIds,\n toBuiltinMcpServerConfig,\n type BuiltinMcpCapability,\n type BuiltinMcpCapabilityId,\n} from \"./builtin-capabilities.js\";\n\nexport {\n builtinMcpCapabilitiesSettingsKey,\n listEnabledBuiltinMcpCapabilities,\n setEnabledBuiltinMcpCapabilities,\n setBuiltinMcpCapabilityEnabled,\n type StoredBuiltinMcpCapabilities,\n} from \"./builtin-store.js\";\n\nexport {\n mountMcpServersRoutes,\n buildMergedConfig,\n builtinMergedConfigKey,\n type ClientBuiltinCapability,\n} from \"./routes.js\";\n\nexport {\n mountMcpHubRoutes,\n listHubServers,\n getHubStatus,\n isHubServeEnabled,\n isHubConsumeEnabled,\n type HubServerRecord,\n type HubServersResponse,\n} from \"./hub-routes.js\";\n\nexport { fetchHubServers } from \"./hub-client.js\";\n\nexport { isMcpToolAllowedForRequest } from \"./visibility.js\";\nimport { isMcpToolAllowedForRequest } from \"./visibility.js\";\n\n/**\n * Convert MCP tools into `ActionEntry` values suitable for registration in\n * the agent's action registry. Each tool is marked `http: false` so it's\n * never auto-mounted as an HTTP endpoint — MCP tools are agent-only.\n */\nimport type { ActionEntry } from \"../agent/production-agent.js\";\nimport type { McpClientManager, McpTool } from \"./manager.js\";\n\nexport function mcpToolsToActionEntries(\n manager: McpClientManager,\n): Record<string, ActionEntry> {\n const entries: Record<string, ActionEntry> = {};\n for (const tool of manager.getTools()) {\n entries[tool.name] = mcpToolToActionEntry(manager, tool);\n }\n return entries;\n}\n\n/**\n * Mutate a target action dict in place so it matches the current MCP tool set:\n * - adds new `mcp__*` keys that aren't in target,\n * - removes `mcp__*` keys that no longer exist in the manager,\n * - leaves non-MCP keys untouched.\n *\n * Used by the agent-chat plugin to keep its `prodActions` / `devActions`\n * registries in sync after `McpClientManager.reconfigure()` runs.\n */\nexport function syncMcpActionEntries(\n manager: McpClientManager,\n target: Record<string, ActionEntry>,\n): void {\n const current = new Set<string>();\n for (const tool of manager.getTools()) {\n current.add(tool.name);\n if (!target[tool.name]) {\n target[tool.name] = mcpToolToActionEntry(manager, tool);\n }\n }\n for (const key of Object.keys(target)) {\n if (key.startsWith(\"mcp__\") && !current.has(key)) {\n delete target[key];\n }\n }\n}\n\nfunction mcpToolToActionEntry(\n manager: McpClientManager,\n tool: McpTool,\n): ActionEntry {\n return {\n tool: {\n description: tool.description,\n parameters: tool.inputSchema as any,\n },\n http: false,\n run: async (args: Record<string, string>) => {\n // Defense-in-depth: even if a cross-scope MCP tool somehow makes it\n // into the LLM's visible tool list, reject invocation here so we never\n // execute a user's credentials on behalf of another user.\n if (!isMcpToolAllowedForRequest(tool.name)) {\n return `Error: MCP tool ${tool.name} is not available in the current request scope.`;\n }\n try {\n const result = await manager.callTool(tool.name, args);\n // MCP tool results are typically `{ content: [{ type: \"text\", text: ... }], isError? }`.\n // Flatten text content for the agent's string-based tool result slot.\n if (\n result &&\n typeof result === \"object\" &&\n Array.isArray((result as any).content)\n ) {\n const parts = (result as any).content as Array<Record<string, any>>;\n const text = parts\n .map((p) => {\n if (p?.type === \"text\" && typeof p.text === \"string\")\n return p.text;\n if (p?.type === \"image\")\n return `[image: ${p?.mimeType ?? \"unknown\"}]`;\n return JSON.stringify(p);\n })\n .join(\"\\n\");\n if ((result as any).isError) return `Error: ${text}`;\n return text || \"(no output)\";\n }\n return typeof result === \"string\" ? result : JSON.stringify(result);\n } catch (err: any) {\n return `Error calling MCP tool ${tool.name}: ${err?.message ?? err}`;\n }\n },\n };\n}\n"]}
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/mcp-client/index.ts"],"names":[],"mappings":"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","sourcesContent":["/**\n * MCP client module — symmetric counterpart to `@agent-native/core/mcp`\n * (the MCP server). Connects to local MCP servers configured in\n * `mcp.config.json` or the `MCP_SERVERS` env var and exposes their tools\n * to the agent-chat tool-use loop.\n */\n\nexport {\n loadMcpConfig,\n autoDetectMcpConfig,\n type McpConfig,\n type McpServerConfig,\n} from \"./config.js\";\n\nexport {\n McpClientManager,\n buildMcpToolName,\n parseMcpToolName,\n MCP_TOOL_PREFIX,\n type McpTool,\n type McpClientManagerOptions,\n} from \"./manager.js\";\n\nexport {\n listRemoteServers,\n addRemoteServer,\n removeRemoteServer,\n validateRemoteUrl,\n normalizeServerName,\n mergedConfigKey,\n parseMergedKey,\n hashEmail,\n toHttpServerConfig,\n toHttpServerConfigAsync,\n materializeHeaders,\n type RemoteMcpScope,\n type StoredRemoteMcpServer,\n} from \"./remote-store.js\";\n\nexport {\n BUILTIN_MCP_CAPABILITIES,\n getBuiltinMcpCapability,\n isBuiltinMcpCapabilityAvailable,\n normalizeBuiltinMcpCapabilityIds,\n toBuiltinMcpServerConfig,\n type BuiltinMcpCapability,\n type BuiltinMcpCapabilityId,\n} from \"./builtin-capabilities.js\";\n\nexport {\n builtinMcpCapabilitiesSettingsKey,\n listEnabledBuiltinMcpCapabilities,\n setEnabledBuiltinMcpCapabilities,\n setBuiltinMcpCapabilityEnabled,\n type StoredBuiltinMcpCapabilities,\n} from \"./builtin-store.js\";\n\nexport {\n mountMcpServersRoutes,\n buildMergedConfig,\n builtinMergedConfigKey,\n type ClientBuiltinCapability,\n} from \"./routes.js\";\n\nexport {\n mountMcpHubRoutes,\n listHubServers,\n getHubStatus,\n isHubServeEnabled,\n isHubConsumeEnabled,\n type HubServerRecord,\n type HubServersResponse,\n} from \"./hub-routes.js\";\n\nexport { fetchHubServers } from \"./hub-client.js\";\n\nexport { isMcpToolAllowedForRequest } from \"./visibility.js\";\nimport { isMcpToolAllowedForRequest } from \"./visibility.js\";\nexport {\n MCP_ACTION_RESULT_MARKER,\n isMcpActionResult,\n type AgentMcpAppPayload,\n type AgentMcpAppResourceContent,\n type McpActionResult,\n} from \"./app-result.js\";\nimport {\n MCP_ACTION_RESULT_MARKER,\n toolForMcpAppPayload,\n type AgentMcpAppPayload,\n type AgentMcpAppResourceContent,\n type McpActionResult,\n} from \"./app-result.js\";\nimport {\n getToolUiResourceUri,\n isToolVisibilityAppOnly,\n isToolVisibilityModelOnly,\n} from \"@modelcontextprotocol/ext-apps/app-bridge\";\nimport { MCP_APP_MIME_TYPE } from \"../action.js\";\n\n/**\n * Convert MCP tools into `ActionEntry` values suitable for registration in\n * the agent's action registry. Each tool is marked `http: false` so it's\n * never auto-mounted as an HTTP endpoint — MCP tools are agent-only.\n */\nimport type { ActionEntry } from \"../agent/production-agent.js\";\nimport type { McpClientManager, McpTool } from \"./manager.js\";\n\nexport function mcpToolsToActionEntries(\n manager: McpClientManager,\n): Record<string, ActionEntry> {\n const entries: Record<string, ActionEntry> = {};\n for (const tool of manager.getTools().filter(isVisibleToModel)) {\n entries[tool.name] = mcpToolToActionEntry(manager, tool);\n }\n return entries;\n}\n\n/**\n * Mutate a target action dict in place so it matches the current MCP tool set:\n * - adds new `mcp__*` keys that aren't in target,\n * - removes `mcp__*` keys that no longer exist in the manager,\n * - leaves non-MCP keys untouched.\n *\n * Used by the agent-chat plugin to keep its `prodActions` / `devActions`\n * registries in sync after `McpClientManager.reconfigure()` runs.\n */\nexport function syncMcpActionEntries(\n manager: McpClientManager,\n target: Record<string, ActionEntry>,\n): void {\n const current = new Set<string>();\n for (const tool of manager.getTools().filter(isVisibleToModel)) {\n current.add(tool.name);\n if (!target[tool.name]) {\n target[tool.name] = mcpToolToActionEntry(manager, tool);\n }\n }\n for (const key of Object.keys(target)) {\n if (key.startsWith(\"mcp__\") && !current.has(key)) {\n delete target[key];\n }\n }\n}\n\nfunction mcpToolToActionEntry(\n manager: McpClientManager,\n tool: McpTool,\n): ActionEntry {\n return {\n tool: {\n description: tool.description,\n parameters: tool.inputSchema as any,\n },\n http: false,\n run: async (args: Record<string, string>) => {\n // Defense-in-depth: even if a cross-scope MCP tool somehow makes it\n // into the LLM's visible tool list, reject invocation here so we never\n // execute a user's credentials on behalf of another user.\n if (!isMcpToolAllowedForRequest(tool.name)) {\n return `Error: MCP tool ${tool.name} is not available in the current request scope.`;\n }\n try {\n const result = await manager.callTool(tool.name, args);\n return await buildMcpActionResult(manager, tool, args, result);\n } catch (err: any) {\n return `Error calling MCP tool ${tool.name}: ${err?.message ?? err}`;\n }\n },\n };\n}\n\nfunction isVisibleToModel(tool: McpTool): boolean {\n try {\n return !isToolVisibilityAppOnly(tool.raw as any);\n } catch {\n return true;\n }\n}\n\nexport function isVisibleToMcpApp(tool: McpTool): boolean {\n try {\n return !isToolVisibilityModelOnly(tool.raw as any);\n } catch {\n return true;\n }\n}\n\nexport function flattenMcpToolResult(result: unknown): string {\n if (\n result &&\n typeof result === \"object\" &&\n Array.isArray((result as any).content)\n ) {\n const parts = (result as any).content as Array<Record<string, any>>;\n const text = parts.map(formatMcpContentPart).join(\"\\n\");\n const fallback =\n text ||\n (hasStructuredContent(result)\n ? JSON.stringify((result as any).structuredContent, null, 2)\n : \"(no output)\");\n if ((result as any).isError) return `Error: ${fallback}`;\n return fallback;\n }\n return typeof result === \"string\" ? result : JSON.stringify(result);\n}\n\nfunction formatMcpContentPart(part: Record<string, any>): string {\n if (part?.type === \"text\" && typeof part.text === \"string\") {\n return part.text;\n }\n if (part?.type === \"image\") {\n return `[image: ${part?.mimeType ?? \"unknown\"}]`;\n }\n if (part?.type === \"resource\") {\n const resource = part.resource ?? {};\n const uri = typeof resource.uri === \"string\" ? ` ${resource.uri}` : \"\";\n return `[resource: ${resource.mimeType ?? \"unknown\"}${uri}]`;\n }\n if (part?.type === \"resource_link\") {\n const uri = typeof part.uri === \"string\" ? ` ${part.uri}` : \"\";\n return `[resource: ${part.mimeType ?? \"unknown\"}${uri}]`;\n }\n return JSON.stringify(part);\n}\n\nfunction hasStructuredContent(result: unknown): boolean {\n return (\n !!result &&\n typeof result === \"object\" &&\n Object.prototype.hasOwnProperty.call(result, \"structuredContent\")\n );\n}\n\nasync function buildMcpActionResult(\n manager: McpClientManager,\n tool: McpTool,\n input: Record<string, unknown>,\n raw: unknown,\n): Promise<McpActionResult> {\n const text = flattenMcpToolResult(raw);\n const mcpApp = await extractMcpAppPayload(manager, tool, input, raw);\n return {\n [MCP_ACTION_RESULT_MARKER]: true,\n text,\n raw,\n serverId: tool.source,\n toolName: tool.name,\n originalToolName: tool.originalName,\n input,\n ...(mcpApp ? { mcpApp } : {}),\n };\n}\n\nasync function extractMcpAppPayload(\n manager: McpClientManager,\n tool: McpTool,\n input: Record<string, unknown>,\n raw: unknown,\n): Promise<AgentMcpAppPayload | undefined> {\n const inlineResource = findInlineMcpAppResource(raw);\n const resourceUri =\n inlineResource?.uri ??\n resourceUriFromTool(tool) ??\n resourceUriFromResult(raw);\n if (!resourceUri) return undefined;\n\n const resource =\n inlineResource ?? (await readMcpAppResource(manager, tool, resourceUri));\n\n return {\n serverId: tool.source,\n toolName: tool.name,\n originalToolName: tool.originalName,\n resourceUri,\n toolInput: input,\n toolResult:\n raw && typeof raw === \"object\"\n ? ({ ...(raw as Record<string, unknown>) } as Record<string, unknown>)\n : { content: [{ type: \"text\", text: String(raw ?? \"\") }] },\n tool: toolForMcpAppPayload(tool),\n ...(resource ? { resource } : {}),\n };\n}\n\nfunction resourceUriFromTool(tool: McpTool): string | undefined {\n try {\n return getToolUiResourceUri(tool.raw as any);\n } catch {\n return undefined;\n }\n}\n\nfunction resourceUriFromResult(raw: unknown): string | undefined {\n if (!raw || typeof raw !== \"object\") return undefined;\n const meta = (raw as any)._meta;\n const nested = meta?.ui?.resourceUri;\n if (typeof nested === \"string\" && nested.startsWith(\"ui://\")) return nested;\n const flat = meta?.[\"ui/resourceUri\"] ?? meta?.[\"ui.resourceUri\"];\n if (typeof flat === \"string\" && flat.startsWith(\"ui://\")) return flat;\n return findInlineMcpAppResource(raw)?.uri;\n}\n\nfunction findInlineMcpAppResource(\n raw: unknown,\n): AgentMcpAppResourceContent | undefined {\n if (!raw || typeof raw !== \"object\") return undefined;\n const content = Array.isArray((raw as any).content)\n ? ((raw as any).content as unknown[])\n : [];\n for (const part of content) {\n const resource = normalizeMcpAppResourceContent(part);\n if (resource) return resource;\n }\n return undefined;\n}\n\nfunction normalizeMcpAppResourceContent(\n part: unknown,\n): AgentMcpAppResourceContent | undefined {\n if (!part || typeof part !== \"object\") return undefined;\n const candidate =\n (part as any).type === \"resource\"\n ? (part as any).resource\n : ((part as any).resource ?? part);\n if (!candidate || typeof candidate !== \"object\") return undefined;\n const uri = (candidate as any).uri;\n if (typeof uri !== \"string\" || !uri.startsWith(\"ui://\")) return undefined;\n const mimeType =\n typeof (candidate as any).mimeType === \"string\"\n ? (candidate as any).mimeType\n : undefined;\n if (mimeType && !mimeType.includes(MCP_APP_MIME_TYPE)) return undefined;\n const text =\n typeof (candidate as any).text === \"string\"\n ? (candidate as any).text\n : undefined;\n const blob =\n typeof (candidate as any).blob === \"string\"\n ? (candidate as any).blob\n : undefined;\n const meta =\n (candidate as any)._meta && typeof (candidate as any)._meta === \"object\"\n ? ((candidate as any)._meta as Record<string, unknown>)\n : (part as any)._meta && typeof (part as any)._meta === \"object\"\n ? ((part as any)._meta as Record<string, unknown>)\n : undefined;\n return {\n uri,\n ...(mimeType ? { mimeType } : {}),\n ...(text ? { text } : {}),\n ...(blob ? { blob } : {}),\n ...(meta ? { _meta: meta } : {}),\n };\n}\n\nasync function readMcpAppResource(\n manager: McpClientManager,\n tool: McpTool,\n resourceUri: string,\n): Promise<AgentMcpAppResourceContent | undefined> {\n try {\n const result = await manager.readResourceForTool(tool.name, resourceUri);\n const contents = Array.isArray((result as any)?.contents)\n ? ((result as any).contents as unknown[])\n : [];\n for (const content of contents) {\n const resource = normalizeMcpAppResourceContent(content);\n if (\n resource?.uri === resourceUri ||\n (resource && contents.length === 1)\n ) {\n return resource;\n }\n }\n } catch (err: any) {\n console.warn(\n `[mcp-client] Failed to read MCP App resource ${resourceUri}: ${err?.message ?? err}`,\n );\n }\n return undefined;\n}\n"]}
|
|
@@ -20,7 +20,18 @@ export interface McpTool {
|
|
|
20
20
|
description: string;
|
|
21
21
|
/** JSON-Schema input spec forwarded verbatim from the server */
|
|
22
22
|
inputSchema: Record<string, unknown>;
|
|
23
|
+
/** Optional title as reported by the MCP server */
|
|
24
|
+
title?: string;
|
|
25
|
+
/** JSON-Schema output spec forwarded verbatim from the server */
|
|
26
|
+
outputSchema?: Record<string, unknown>;
|
|
27
|
+
/** MCP tool annotations forwarded verbatim from the server */
|
|
28
|
+
annotations?: Record<string, unknown>;
|
|
29
|
+
/** MCP metadata forwarded verbatim from the server */
|
|
30
|
+
_meta?: Record<string, unknown>;
|
|
31
|
+
/** Full raw tool object for extensions that depend on fields core does not know yet. */
|
|
32
|
+
raw: Record<string, unknown>;
|
|
23
33
|
}
|
|
34
|
+
export declare function buildMcpToolName(serverId: string, toolName: string): string;
|
|
24
35
|
/**
|
|
25
36
|
* Parse a prefixed tool name back into its server id and original tool name.
|
|
26
37
|
* Returns `null` if the name doesn't match the MCP prefix convention.
|
|
@@ -102,11 +113,16 @@ export declare class McpClientManager {
|
|
|
102
113
|
private reconfigureInternal;
|
|
103
114
|
/** Flattened tool list across all connected servers. */
|
|
104
115
|
getTools(): McpTool[];
|
|
116
|
+
getTool(prefixedName: string): McpTool | null;
|
|
117
|
+
getToolsForServer(serverId: string): McpTool[];
|
|
118
|
+
hasServer(serverId: string): boolean;
|
|
105
119
|
/**
|
|
106
120
|
* Invoke an MCP tool by prefixed name. Routes to the owning server based on
|
|
107
121
|
* the `mcp__<serverId>__` prefix.
|
|
108
122
|
*/
|
|
109
123
|
callTool(prefixedName: string, args: unknown): Promise<unknown>;
|
|
124
|
+
readResource(serverId: string, uri: string): Promise<unknown>;
|
|
125
|
+
readResourceForTool(prefixedName: string, uri: string): Promise<unknown>;
|
|
110
126
|
/** Cleanly close all MCP clients and child processes. */
|
|
111
127
|
stop(): Promise<void>;
|
|
112
128
|
/** Diagnostic snapshot used by `/_agent-native/mcp/status`. */
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"manager.d.ts","sourceRoot":"","sources":["../../src/mcp-client/manager.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AAEH,OAAO,KAAK,EAAE,SAAS,EAAmB,MAAM,aAAa,CAAC;
|
|
1
|
+
{"version":3,"file":"manager.d.ts","sourceRoot":"","sources":["../../src/mcp-client/manager.ts"],"names":[],"mappings":"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"}
|
|
@@ -8,6 +8,7 @@
|
|
|
8
8
|
* lets callers add or remove servers at runtime without restarting the process.
|
|
9
9
|
*/
|
|
10
10
|
import { formatMcpConnectError } from "./errors.js";
|
|
11
|
+
import { MCP_APP_EXTENSION_ID, MCP_APP_MIME_TYPE } from "../action.js";
|
|
11
12
|
export const MCP_TOOL_PREFIX = "mcp__";
|
|
12
13
|
function isNode() {
|
|
13
14
|
return (typeof process !== "undefined" &&
|
|
@@ -17,6 +18,9 @@ function isNode() {
|
|
|
17
18
|
function buildPrefixedName(serverId, toolName) {
|
|
18
19
|
return `${MCP_TOOL_PREFIX}${serverId}__${toolName}`;
|
|
19
20
|
}
|
|
21
|
+
export function buildMcpToolName(serverId, toolName) {
|
|
22
|
+
return buildPrefixedName(serverId, toolName);
|
|
23
|
+
}
|
|
20
24
|
/**
|
|
21
25
|
* Parse a prefixed tool name back into its server id and original tool name.
|
|
22
26
|
* Returns `null` if the name doesn't match the MCP prefix convention.
|
|
@@ -282,7 +286,15 @@ export class McpClientManager {
|
|
|
282
286
|
cwd,
|
|
283
287
|
});
|
|
284
288
|
}
|
|
285
|
-
const client = new Client({ name: "agent-native-mcp-client", version: "1.0.0" }, {
|
|
289
|
+
const client = new Client({ name: "agent-native-mcp-client", version: "1.0.0" }, {
|
|
290
|
+
capabilities: {
|
|
291
|
+
extensions: {
|
|
292
|
+
[MCP_APP_EXTENSION_ID]: {
|
|
293
|
+
mimeTypes: [MCP_APP_MIME_TYPE],
|
|
294
|
+
},
|
|
295
|
+
},
|
|
296
|
+
},
|
|
297
|
+
});
|
|
286
298
|
const recordConnectionError = () => { };
|
|
287
299
|
const restoreClientClose = guardClose(client, recordConnectionError);
|
|
288
300
|
const restoreTransportClose = guardClose(transport, recordConnectionError);
|
|
@@ -310,11 +322,16 @@ export class McpClientManager {
|
|
|
310
322
|
source: entry.id,
|
|
311
323
|
name: buildPrefixedName(entry.id, t.name),
|
|
312
324
|
originalName: t.name,
|
|
325
|
+
...(t.title ? { title: t.title } : {}),
|
|
313
326
|
description: t.description ?? t.name,
|
|
314
327
|
inputSchema: (t.inputSchema ?? {
|
|
315
328
|
type: "object",
|
|
316
329
|
properties: {},
|
|
317
330
|
}),
|
|
331
|
+
...(t.outputSchema ? { outputSchema: t.outputSchema } : {}),
|
|
332
|
+
...(t.annotations ? { annotations: t.annotations } : {}),
|
|
333
|
+
...(t._meta ? { _meta: t._meta } : {}),
|
|
334
|
+
raw: { ...t },
|
|
318
335
|
}));
|
|
319
336
|
client.onerror = (error) => {
|
|
320
337
|
entry.error = formatMcpConnectError(error);
|
|
@@ -425,6 +442,20 @@ export class McpClientManager {
|
|
|
425
442
|
}
|
|
426
443
|
return out;
|
|
427
444
|
}
|
|
445
|
+
getTool(prefixedName) {
|
|
446
|
+
const parsed = parseMcpToolName(prefixedName);
|
|
447
|
+
if (!parsed)
|
|
448
|
+
return null;
|
|
449
|
+
const entry = this.servers.get(parsed.serverId);
|
|
450
|
+
return entry?.tools.find((t) => t.name === prefixedName) ?? null;
|
|
451
|
+
}
|
|
452
|
+
getToolsForServer(serverId) {
|
|
453
|
+
return [...(this.servers.get(serverId)?.tools ?? [])];
|
|
454
|
+
}
|
|
455
|
+
hasServer(serverId) {
|
|
456
|
+
const entry = this.servers.get(serverId);
|
|
457
|
+
return !!entry?.client && !entry.error;
|
|
458
|
+
}
|
|
428
459
|
/**
|
|
429
460
|
* Invoke an MCP tool by prefixed name. Routes to the owning server based on
|
|
430
461
|
* the `mcp__<serverId>__` prefix.
|
|
@@ -452,6 +483,32 @@ export class McpClientManager {
|
|
|
452
483
|
});
|
|
453
484
|
return result;
|
|
454
485
|
}
|
|
486
|
+
async readResource(serverId, uri) {
|
|
487
|
+
if (!uri.startsWith("ui://")) {
|
|
488
|
+
throw new Error(`Only ui:// MCP App resources can be read by this host`);
|
|
489
|
+
}
|
|
490
|
+
const entry = this.servers.get(serverId);
|
|
491
|
+
if (!entry || !entry.client) {
|
|
492
|
+
throw new Error(`MCP server "${serverId}" is not connected${entry?.error ? `: ${entry.error}` : ""}`);
|
|
493
|
+
}
|
|
494
|
+
if (typeof entry.client.readResource === "function") {
|
|
495
|
+
return entry.client.readResource({ uri });
|
|
496
|
+
}
|
|
497
|
+
if (typeof entry.client.request === "function") {
|
|
498
|
+
return entry.client.request({
|
|
499
|
+
method: "resources/read",
|
|
500
|
+
params: { uri },
|
|
501
|
+
});
|
|
502
|
+
}
|
|
503
|
+
throw new Error(`MCP server "${serverId}" does not support resources/read`);
|
|
504
|
+
}
|
|
505
|
+
async readResourceForTool(prefixedName, uri) {
|
|
506
|
+
const parsed = parseMcpToolName(prefixedName);
|
|
507
|
+
if (!parsed) {
|
|
508
|
+
throw new Error(`Tool name "${prefixedName}" does not look like an MCP tool (expected mcp__<server>__<tool>)`);
|
|
509
|
+
}
|
|
510
|
+
return this.readResource(parsed.serverId, uri);
|
|
511
|
+
}
|
|
455
512
|
/** Cleanly close all MCP clients and child processes. */
|
|
456
513
|
async stop() {
|
|
457
514
|
const entries = Array.from(this.servers.values());
|