@copilotkit/mcp-apps-renderer 1.71.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +21 -0
- package/README.md +45 -0
- package/dist/activity.cjs +9 -0
- package/dist/activity.d.cts +4 -0
- package/dist/activity.d.mts +4 -0
- package/dist/activity.mjs +5 -0
- package/dist/activity.umd.js +91 -0
- package/dist/activity.umd.js.map +1 -0
- package/dist/constants.cjs +32 -0
- package/dist/constants.cjs.map +1 -0
- package/dist/constants.d.cts +23 -0
- package/dist/constants.d.cts.map +1 -0
- package/dist/constants.d.mts +23 -0
- package/dist/constants.d.mts.map +1 -0
- package/dist/constants.mjs +30 -0
- package/dist/constants.mjs.map +1 -0
- package/dist/content-schema.cjs +23 -0
- package/dist/content-schema.cjs.map +1 -0
- package/dist/content-schema.d.cts +51 -0
- package/dist/content-schema.d.cts.map +1 -0
- package/dist/content-schema.d.mts +51 -0
- package/dist/content-schema.d.mts.map +1 -0
- package/dist/content-schema.mjs +23 -0
- package/dist/content-schema.mjs.map +1 -0
- package/dist/follow-up.cjs +34 -0
- package/dist/follow-up.cjs.map +1 -0
- package/dist/follow-up.d.cts +42 -0
- package/dist/follow-up.d.cts.map +1 -0
- package/dist/follow-up.d.mts +42 -0
- package/dist/follow-up.d.mts.map +1 -0
- package/dist/follow-up.mjs +33 -0
- package/dist/follow-up.mjs.map +1 -0
- package/dist/index.d.mts +7 -0
- package/dist/index.mjs +8 -0
- package/dist/request-queue.d.mts +31 -0
- package/dist/request-queue.d.mts.map +1 -0
- package/dist/request-queue.mjs +93 -0
- package/dist/request-queue.mjs.map +1 -0
- package/dist/sandbox.d.mts +16 -0
- package/dist/sandbox.d.mts.map +1 -0
- package/dist/sandbox.mjs +52 -0
- package/dist/sandbox.mjs.map +1 -0
- package/dist/session.d.mts +81 -0
- package/dist/session.d.mts.map +1 -0
- package/dist/session.mjs +221 -0
- package/dist/session.mjs.map +1 -0
- package/package.json +77 -0
package/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
The MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) Atai Barkai
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in
|
|
13
|
+
all copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
|
21
|
+
THE SOFTWARE.
|
package/README.md
ADDED
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
# @copilotkit/mcp-apps-renderer
|
|
2
|
+
|
|
3
|
+
Framework-agnostic MCP Apps host for CopilotKit: the app↔host protocol on top of
|
|
4
|
+
[`@modelcontextprotocol/ext-apps`](https://www.npmjs.com/package/@modelcontextprotocol/ext-apps)
|
|
5
|
+
(AppBridge + PostMessage transport, sandbox proxy, per-thread request queue,
|
|
6
|
+
`ui/message` / `ui/open-link` / `tools/call` proxy, tool input/result forwarding,
|
|
7
|
+
`ui/request-display-mode`). The React / Vue / Angular renderers consume it as thin
|
|
8
|
+
adapters: they create the sandbox iframe and wire reactive state, while all
|
|
9
|
+
protocol logic lives in `bindMcpApp`.
|
|
10
|
+
|
|
11
|
+
## Entry points
|
|
12
|
+
|
|
13
|
+
| Import | Contents | Bundle |
|
|
14
|
+
| ---------------------------------------- | ------------------------------------------------------------------------ | ---------------------------------------------------------------------------------------------------------------- |
|
|
15
|
+
| `@copilotkit/mcp-apps-renderer` | `bindMcpApp` + the full session API | **ESM only** — it wraps the ESM-only ext-apps bridge, and is meant to be loaded lazily via a dynamic `import()`. |
|
|
16
|
+
| `@copilotkit/mcp-apps-renderer/activity` | `MCPAppsActivityType`, `MCPAppsActivityContentSchema`, `ɵrunMcpFollowUp` | ESM + CJS. Bridge-free: importing it to register the activity does **not** pull the ext-apps bundle. |
|
|
17
|
+
|
|
18
|
+
The root is ESM-only on purpose: `@modelcontextprotocol/ext-apps` ships ESM only,
|
|
19
|
+
so a CommonJS root would emit a `require()` of an ES module and fail with
|
|
20
|
+
`ERR_REQUIRE_ESM`. Consume `bindMcpApp` via a dynamic `import()` (which resolves
|
|
21
|
+
ESM from any module system), and import the bridge-free `/activity` surface for
|
|
22
|
+
synchronous activity registration.
|
|
23
|
+
|
|
24
|
+
## Script-tag / UMD usage
|
|
25
|
+
|
|
26
|
+
This package also ships a UMD build of the bridge-free `/activity` entry:
|
|
27
|
+
`dist/activity.umd.js`, which defines the global
|
|
28
|
+
`CopilotKitMcpAppsRendererActivity`.
|
|
29
|
+
|
|
30
|
+
`@copilotkit/react-core`'s UMD build references that global (it externalizes
|
|
31
|
+
`@copilotkit/mcp-apps-renderer/activity` to register the built-in MCP Apps
|
|
32
|
+
activity). **Script-tag consumers of react-core's UMD must therefore load
|
|
33
|
+
`activity.umd.js` before `@copilotkit/react-core`'s UMD bundle**, alongside the
|
|
34
|
+
other UMD globals it depends on (React, `CopilotKitCore`,
|
|
35
|
+
`CopilotKitA2UIRenderer`, …):
|
|
36
|
+
|
|
37
|
+
```html
|
|
38
|
+
<!-- ...React, @copilotkit/core, @copilotkit/a2ui-renderer, etc. first... -->
|
|
39
|
+
<script src="https://unpkg.com/@copilotkit/mcp-apps-renderer/dist/activity.umd.js"></script>
|
|
40
|
+
<script src="https://unpkg.com/@copilotkit/react-core/dist/index.umd.js"></script>
|
|
41
|
+
```
|
|
42
|
+
|
|
43
|
+
Only the bridge-free `/activity` surface has a UMD build; the ext-apps bridge
|
|
44
|
+
itself (`bindMcpApp`) is loaded lazily via `import()` and is not part of the UMD
|
|
45
|
+
graph, so it only loads when an MCP App is actually rendered.
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
Object.defineProperty(exports, Symbol.toStringTag, { value: 'Module' });
|
|
2
|
+
const require_constants = require('./constants.cjs');
|
|
3
|
+
const require_content_schema = require('./content-schema.cjs');
|
|
4
|
+
const require_follow_up = require('./follow-up.cjs');
|
|
5
|
+
|
|
6
|
+
exports.MCPAppsActivityContentSchema = require_content_schema.MCPAppsActivityContentSchema;
|
|
7
|
+
exports.MCPAppsActivityType = require_constants.MCPAppsActivityType;
|
|
8
|
+
exports.MCP_OPEN_LINK_BLOCKED_SCHEMES = require_constants.MCP_OPEN_LINK_BLOCKED_SCHEMES;
|
|
9
|
+
exports.ɵrunMcpFollowUp = require_follow_up.ɵrunMcpFollowUp;
|
|
@@ -0,0 +1,4 @@
|
|
|
1
|
+
import { MCPAppsActivityType, MCP_OPEN_LINK_BLOCKED_SCHEMES } from "./constants.cjs";
|
|
2
|
+
import { MCPAppsActivityContent, MCPAppsActivityContentSchema } from "./content-schema.cjs";
|
|
3
|
+
import { ɵMcpFollowUpHost, ɵrunMcpFollowUp } from "./follow-up.cjs";
|
|
4
|
+
export { MCPAppsActivityContent, MCPAppsActivityContentSchema, MCPAppsActivityType, MCP_OPEN_LINK_BLOCKED_SCHEMES, ɵMcpFollowUpHost, ɵrunMcpFollowUp };
|
|
@@ -0,0 +1,4 @@
|
|
|
1
|
+
import { MCPAppsActivityType, MCP_OPEN_LINK_BLOCKED_SCHEMES } from "./constants.mjs";
|
|
2
|
+
import { MCPAppsActivityContent, MCPAppsActivityContentSchema } from "./content-schema.mjs";
|
|
3
|
+
import { ɵMcpFollowUpHost, ɵrunMcpFollowUp } from "./follow-up.mjs";
|
|
4
|
+
export { MCPAppsActivityContent, MCPAppsActivityContentSchema, MCPAppsActivityType, MCP_OPEN_LINK_BLOCKED_SCHEMES, ɵMcpFollowUpHost, ɵrunMcpFollowUp };
|
|
@@ -0,0 +1,5 @@
|
|
|
1
|
+
import { MCPAppsActivityType, MCP_OPEN_LINK_BLOCKED_SCHEMES } from "./constants.mjs";
|
|
2
|
+
import { MCPAppsActivityContentSchema } from "./content-schema.mjs";
|
|
3
|
+
import { ɵrunMcpFollowUp } from "./follow-up.mjs";
|
|
4
|
+
|
|
5
|
+
export { MCPAppsActivityContentSchema, MCPAppsActivityType, MCP_OPEN_LINK_BLOCKED_SCHEMES, ɵrunMcpFollowUp };
|
|
@@ -0,0 +1,91 @@
|
|
|
1
|
+
(function(global, factory) {
|
|
2
|
+
typeof exports === 'object' && typeof module !== 'undefined' ? factory(exports, require('zod')) :
|
|
3
|
+
typeof define === 'function' && define.amd ? define(['exports', 'zod'], factory) :
|
|
4
|
+
(global = typeof globalThis !== 'undefined' ? globalThis : global || self, factory((global.CopilotKitMcpAppsRendererActivity = {}), global.Zod));
|
|
5
|
+
})(this, function(exports, zod) {
|
|
6
|
+
Object.defineProperty(exports, Symbol.toStringTag, { value: 'Module' });
|
|
7
|
+
|
|
8
|
+
//#region src/constants.ts
|
|
9
|
+
/**
|
|
10
|
+
* Activity type for MCP Apps events - must match the middleware's MCPAppsActivityType.
|
|
11
|
+
*/
|
|
12
|
+
const MCPAppsActivityType = "mcp-apps";
|
|
13
|
+
/**
|
|
14
|
+
* URL schemes a widget may NOT open via ui/open-link. The ext-apps schema
|
|
15
|
+
* validates `url` as a plain string only (noopener/noreferrer does not restrict
|
|
16
|
+
* the scheme), so ui/open-link could otherwise become an XSS vector.
|
|
17
|
+
*
|
|
18
|
+
* We use a denylist rather than an allowlist on purpose: deep links use
|
|
19
|
+
* arbitrary, app-defined schemes (`myapp:`, `whatsapp:`, `slack:`, `spotify:`,
|
|
20
|
+
* `sms:`, ...) that an allowlist could never enumerate, and `window.open`ing them
|
|
21
|
+
* just hands off to an OS handler - it does not execute script in the page, so
|
|
22
|
+
* it is not an XSS risk. Universal links / App Links are plain `https:` URLs and
|
|
23
|
+
* pass regardless. What IS dangerous is the small, well-known set of schemes
|
|
24
|
+
* that execute script or render attacker HTML in the page context; block those
|
|
25
|
+
* and allow everything else (including deep links).
|
|
26
|
+
*/
|
|
27
|
+
const MCP_OPEN_LINK_BLOCKED_SCHEMES = new Set([
|
|
28
|
+
"javascript:",
|
|
29
|
+
"data:",
|
|
30
|
+
"vbscript:",
|
|
31
|
+
"blob:",
|
|
32
|
+
"file:"
|
|
33
|
+
]);
|
|
34
|
+
|
|
35
|
+
//#endregion
|
|
36
|
+
//#region src/content-schema.ts
|
|
37
|
+
/**
|
|
38
|
+
* Zod schema for MCP Apps activity content (middleware 0.0.2 format). The
|
|
39
|
+
* framework activity registries validate the activity content with this before
|
|
40
|
+
* handing it to the renderer/session.
|
|
41
|
+
*/
|
|
42
|
+
const MCPAppsActivityContentSchema = zod.z.object({
|
|
43
|
+
result: zod.z.object({
|
|
44
|
+
content: zod.z.array(zod.z.any()).optional(),
|
|
45
|
+
structuredContent: zod.z.any().optional(),
|
|
46
|
+
isError: zod.z.boolean().optional()
|
|
47
|
+
}),
|
|
48
|
+
resourceUri: zod.z.string(),
|
|
49
|
+
serverHash: zod.z.string(),
|
|
50
|
+
serverId: zod.z.string().optional(),
|
|
51
|
+
toolInput: zod.z.record(zod.z.string(), zod.z.unknown()).optional()
|
|
52
|
+
});
|
|
53
|
+
|
|
54
|
+
//#endregion
|
|
55
|
+
//#region src/follow-up.ts
|
|
56
|
+
/**
|
|
57
|
+
* Run an MCP app `ui/message` follow-up, scoped to the thread it was enqueued
|
|
58
|
+
* for (issue #5819).
|
|
59
|
+
*
|
|
60
|
+
* The MCP request queue delays follow-up work until the agent is idle. There is
|
|
61
|
+
* a single shared registry agent per id, and switching threads overwrites its
|
|
62
|
+
* `threadId`/`messages` in place. So if the host switches threads while a
|
|
63
|
+
* follow-up is queued, running it now would execute against — and stream into —
|
|
64
|
+
* the now-foreground thread.
|
|
65
|
+
*
|
|
66
|
+
* - **Same thread** (the common case): run on the shared agent, unchanged.
|
|
67
|
+
* - **Thread changed**: the shared agent has moved on, so the follow-up can no
|
|
68
|
+
* longer run in its originating thread's context. Drop it rather than leak it
|
|
69
|
+
* into the current thread. (The MCP app already received its `ui/message` ack
|
|
70
|
+
* at enqueue time; only the optional agent turn is skipped.)
|
|
71
|
+
*
|
|
72
|
+
* @internal exported for testing.
|
|
73
|
+
*/
|
|
74
|
+
async function ɵrunMcpFollowUp({ host, agent, capturedThreadId }) {
|
|
75
|
+
const currentThreadId = agent.threadId || "default";
|
|
76
|
+
const originThreadId = capturedThreadId || "default";
|
|
77
|
+
if (currentThreadId === originThreadId) return host.runAgent({ agent });
|
|
78
|
+
console.warn(`[MCPAppsRenderer] ui/message follow-up dropped: the thread changed (${originThreadId} → ${currentThreadId}) between enqueue and execution, so running it would leak into the now-foreground thread.`);
|
|
79
|
+
return {
|
|
80
|
+
result: void 0,
|
|
81
|
+
newMessages: []
|
|
82
|
+
};
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
//#endregion
|
|
86
|
+
exports.MCPAppsActivityContentSchema = MCPAppsActivityContentSchema;
|
|
87
|
+
exports.MCPAppsActivityType = MCPAppsActivityType;
|
|
88
|
+
exports.MCP_OPEN_LINK_BLOCKED_SCHEMES = MCP_OPEN_LINK_BLOCKED_SCHEMES;
|
|
89
|
+
exports.ɵrunMcpFollowUp = ɵrunMcpFollowUp;
|
|
90
|
+
});
|
|
91
|
+
//# sourceMappingURL=activity.umd.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"activity.umd.js","names":["z"],"sources":["../src/constants.ts","../src/content-schema.ts","../src/follow-up.ts"],"sourcesContent":["/**\n * Activity type for MCP Apps events - must match the middleware's MCPAppsActivityType.\n */\nexport const MCPAppsActivityType = \"mcp-apps\";\n\n/**\n * URL schemes a widget may NOT open via ui/open-link. The ext-apps schema\n * validates `url` as a plain string only (noopener/noreferrer does not restrict\n * the scheme), so ui/open-link could otherwise become an XSS vector.\n *\n * We use a denylist rather than an allowlist on purpose: deep links use\n * arbitrary, app-defined schemes (`myapp:`, `whatsapp:`, `slack:`, `spotify:`,\n * `sms:`, ...) that an allowlist could never enumerate, and `window.open`ing them\n * just hands off to an OS handler - it does not execute script in the page, so\n * it is not an XSS risk. Universal links / App Links are plain `https:` URLs and\n * pass regardless. What IS dangerous is the small, well-known set of schemes\n * that execute script or render attacker HTML in the page context; block those\n * and allow everything else (including deep links).\n */\nexport const MCP_OPEN_LINK_BLOCKED_SCHEMES = new Set([\n \"javascript:\",\n \"data:\",\n \"vbscript:\",\n \"blob:\",\n \"file:\",\n]);\n","import { z } from \"zod\";\n\n/**\n * Zod schema for MCP Apps activity content (middleware 0.0.2 format). The\n * framework activity registries validate the activity content with this before\n * handing it to the renderer/session.\n */\nexport const MCPAppsActivityContentSchema = z.object({\n result: z.object({\n content: z.array(z.any()).optional(),\n structuredContent: z.any().optional(),\n isError: z.boolean().optional(),\n }),\n // Resource URI to fetch (e.g., \"ui://server/dashboard\")\n resourceUri: z.string(),\n // MD5 hash of server config (renamed from serverId in 0.0.1)\n serverHash: z.string(),\n // Optional stable server ID from config (takes precedence over serverHash)\n serverId: z.string().optional(),\n // Original tool input arguments\n toolInput: z.record(z.string(), z.unknown()).optional(),\n});\n\nexport type MCPAppsActivityContent = z.infer<\n typeof MCPAppsActivityContentSchema\n>;\n","import type { AbstractAgent, RunAgentResult } from \"@ag-ui/client\";\n\n/**\n * The subset of `CopilotKitCore` that {@link ɵrunMcpFollowUp} depends on.\n * Declared structurally so the runner can be unit-tested without a full core.\n */\nexport interface ɵMcpFollowUpHost {\n runAgent(params: { agent: AbstractAgent }): Promise<RunAgentResult>;\n}\n\n/**\n * Run an MCP app `ui/message` follow-up, scoped to the thread it was enqueued\n * for (issue #5819).\n *\n * The MCP request queue delays follow-up work until the agent is idle. There is\n * a single shared registry agent per id, and switching threads overwrites its\n * `threadId`/`messages` in place. So if the host switches threads while a\n * follow-up is queued, running it now would execute against — and stream into —\n * the now-foreground thread.\n *\n * - **Same thread** (the common case): run on the shared agent, unchanged.\n * - **Thread changed**: the shared agent has moved on, so the follow-up can no\n * longer run in its originating thread's context. Drop it rather than leak it\n * into the current thread. (The MCP app already received its `ui/message` ack\n * at enqueue time; only the optional agent turn is skipped.)\n *\n * @internal exported for testing.\n */\nexport async function ɵrunMcpFollowUp({\n host,\n agent,\n capturedThreadId,\n}: {\n host: ɵMcpFollowUpHost;\n agent: AbstractAgent;\n capturedThreadId: string;\n}): Promise<RunAgentResult> {\n const currentThreadId = agent.threadId || \"default\";\n const originThreadId = capturedThreadId || \"default\";\n\n if (currentThreadId === originThreadId) {\n return host.runAgent({ agent });\n }\n\n console.warn(\n \"[MCPAppsRenderer] ui/message follow-up dropped: the thread changed \" +\n `(${originThreadId} → ${currentThreadId}) between enqueue and execution, ` +\n \"so running it would leak into the now-foreground thread.\",\n );\n return { result: undefined, newMessages: [] };\n}\n"],"mappings":";;;;;;;;;;;CAGA,MAAa,sBAAsB;;;;;;;;;;;;;;;CAgBnC,MAAa,gCAAgC,IAAI,IAAI;EACnD;EACA;EACA;EACA;EACA;EACD,CAAC;;;;;;;;;CClBF,MAAa,+BAA+BA,MAAE,OAAO;EACnD,QAAQA,MAAE,OAAO;GACf,SAASA,MAAE,MAAMA,MAAE,KAAK,CAAC,CAAC,UAAU;GACpC,mBAAmBA,MAAE,KAAK,CAAC,UAAU;GACrC,SAASA,MAAE,SAAS,CAAC,UAAU;GAChC,CAAC;EAEF,aAAaA,MAAE,QAAQ;EAEvB,YAAYA,MAAE,QAAQ;EAEtB,UAAUA,MAAE,QAAQ,CAAC,UAAU;EAE/B,WAAWA,MAAE,OAAOA,MAAE,QAAQ,EAAEA,MAAE,SAAS,CAAC,CAAC,UAAU;EACxD,CAAC;;;;;;;;;;;;;;;;;;;;;;CCOF,eAAsB,gBAAgB,EACpC,MACA,OACA,oBAK0B;EAC1B,MAAM,kBAAkB,MAAM,YAAY;EAC1C,MAAM,iBAAiB,oBAAoB;AAE3C,MAAI,oBAAoB,eACtB,QAAO,KAAK,SAAS,EAAE,OAAO,CAAC;AAGjC,UAAQ,KACN,uEACM,eAAe,KAAK,gBAAgB,2FAE3C;AACD,SAAO;GAAE,QAAQ;GAAW,aAAa,EAAE;GAAE"}
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
|
|
2
|
+
//#region src/constants.ts
|
|
3
|
+
/**
|
|
4
|
+
* Activity type for MCP Apps events - must match the middleware's MCPAppsActivityType.
|
|
5
|
+
*/
|
|
6
|
+
const MCPAppsActivityType = "mcp-apps";
|
|
7
|
+
/**
|
|
8
|
+
* URL schemes a widget may NOT open via ui/open-link. The ext-apps schema
|
|
9
|
+
* validates `url` as a plain string only (noopener/noreferrer does not restrict
|
|
10
|
+
* the scheme), so ui/open-link could otherwise become an XSS vector.
|
|
11
|
+
*
|
|
12
|
+
* We use a denylist rather than an allowlist on purpose: deep links use
|
|
13
|
+
* arbitrary, app-defined schemes (`myapp:`, `whatsapp:`, `slack:`, `spotify:`,
|
|
14
|
+
* `sms:`, ...) that an allowlist could never enumerate, and `window.open`ing them
|
|
15
|
+
* just hands off to an OS handler - it does not execute script in the page, so
|
|
16
|
+
* it is not an XSS risk. Universal links / App Links are plain `https:` URLs and
|
|
17
|
+
* pass regardless. What IS dangerous is the small, well-known set of schemes
|
|
18
|
+
* that execute script or render attacker HTML in the page context; block those
|
|
19
|
+
* and allow everything else (including deep links).
|
|
20
|
+
*/
|
|
21
|
+
const MCP_OPEN_LINK_BLOCKED_SCHEMES = new Set([
|
|
22
|
+
"javascript:",
|
|
23
|
+
"data:",
|
|
24
|
+
"vbscript:",
|
|
25
|
+
"blob:",
|
|
26
|
+
"file:"
|
|
27
|
+
]);
|
|
28
|
+
|
|
29
|
+
//#endregion
|
|
30
|
+
exports.MCPAppsActivityType = MCPAppsActivityType;
|
|
31
|
+
exports.MCP_OPEN_LINK_BLOCKED_SCHEMES = MCP_OPEN_LINK_BLOCKED_SCHEMES;
|
|
32
|
+
//# sourceMappingURL=constants.cjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"constants.cjs","names":[],"sources":["../src/constants.ts"],"sourcesContent":["/**\n * Activity type for MCP Apps events - must match the middleware's MCPAppsActivityType.\n */\nexport const MCPAppsActivityType = \"mcp-apps\";\n\n/**\n * URL schemes a widget may NOT open via ui/open-link. The ext-apps schema\n * validates `url` as a plain string only (noopener/noreferrer does not restrict\n * the scheme), so ui/open-link could otherwise become an XSS vector.\n *\n * We use a denylist rather than an allowlist on purpose: deep links use\n * arbitrary, app-defined schemes (`myapp:`, `whatsapp:`, `slack:`, `spotify:`,\n * `sms:`, ...) that an allowlist could never enumerate, and `window.open`ing them\n * just hands off to an OS handler - it does not execute script in the page, so\n * it is not an XSS risk. Universal links / App Links are plain `https:` URLs and\n * pass regardless. What IS dangerous is the small, well-known set of schemes\n * that execute script or render attacker HTML in the page context; block those\n * and allow everything else (including deep links).\n */\nexport const MCP_OPEN_LINK_BLOCKED_SCHEMES = new Set([\n \"javascript:\",\n \"data:\",\n \"vbscript:\",\n \"blob:\",\n \"file:\",\n]);\n"],"mappings":";;;;;AAGA,MAAa,sBAAsB;;;;;;;;;;;;;;;AAgBnC,MAAa,gCAAgC,IAAI,IAAI;CACnD;CACA;CACA;CACA;CACA;CACD,CAAC"}
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
//#region src/constants.d.ts
|
|
2
|
+
/**
|
|
3
|
+
* Activity type for MCP Apps events - must match the middleware's MCPAppsActivityType.
|
|
4
|
+
*/
|
|
5
|
+
declare const MCPAppsActivityType = "mcp-apps";
|
|
6
|
+
/**
|
|
7
|
+
* URL schemes a widget may NOT open via ui/open-link. The ext-apps schema
|
|
8
|
+
* validates `url` as a plain string only (noopener/noreferrer does not restrict
|
|
9
|
+
* the scheme), so ui/open-link could otherwise become an XSS vector.
|
|
10
|
+
*
|
|
11
|
+
* We use a denylist rather than an allowlist on purpose: deep links use
|
|
12
|
+
* arbitrary, app-defined schemes (`myapp:`, `whatsapp:`, `slack:`, `spotify:`,
|
|
13
|
+
* `sms:`, ...) that an allowlist could never enumerate, and `window.open`ing them
|
|
14
|
+
* just hands off to an OS handler - it does not execute script in the page, so
|
|
15
|
+
* it is not an XSS risk. Universal links / App Links are plain `https:` URLs and
|
|
16
|
+
* pass regardless. What IS dangerous is the small, well-known set of schemes
|
|
17
|
+
* that execute script or render attacker HTML in the page context; block those
|
|
18
|
+
* and allow everything else (including deep links).
|
|
19
|
+
*/
|
|
20
|
+
declare const MCP_OPEN_LINK_BLOCKED_SCHEMES: Set<string>;
|
|
21
|
+
//#endregion
|
|
22
|
+
export { MCPAppsActivityType, MCP_OPEN_LINK_BLOCKED_SCHEMES };
|
|
23
|
+
//# sourceMappingURL=constants.d.cts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"constants.d.cts","names":[],"sources":["../src/constants.ts"],"mappings":";;AAGA;;cAAa,mBAAA;;;AAgBb;;;;;;;;;;;;cAAa,6BAAA,EAA6B,GAAA"}
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
//#region src/constants.d.ts
|
|
2
|
+
/**
|
|
3
|
+
* Activity type for MCP Apps events - must match the middleware's MCPAppsActivityType.
|
|
4
|
+
*/
|
|
5
|
+
declare const MCPAppsActivityType = "mcp-apps";
|
|
6
|
+
/**
|
|
7
|
+
* URL schemes a widget may NOT open via ui/open-link. The ext-apps schema
|
|
8
|
+
* validates `url` as a plain string only (noopener/noreferrer does not restrict
|
|
9
|
+
* the scheme), so ui/open-link could otherwise become an XSS vector.
|
|
10
|
+
*
|
|
11
|
+
* We use a denylist rather than an allowlist on purpose: deep links use
|
|
12
|
+
* arbitrary, app-defined schemes (`myapp:`, `whatsapp:`, `slack:`, `spotify:`,
|
|
13
|
+
* `sms:`, ...) that an allowlist could never enumerate, and `window.open`ing them
|
|
14
|
+
* just hands off to an OS handler - it does not execute script in the page, so
|
|
15
|
+
* it is not an XSS risk. Universal links / App Links are plain `https:` URLs and
|
|
16
|
+
* pass regardless. What IS dangerous is the small, well-known set of schemes
|
|
17
|
+
* that execute script or render attacker HTML in the page context; block those
|
|
18
|
+
* and allow everything else (including deep links).
|
|
19
|
+
*/
|
|
20
|
+
declare const MCP_OPEN_LINK_BLOCKED_SCHEMES: Set<string>;
|
|
21
|
+
//#endregion
|
|
22
|
+
export { MCPAppsActivityType, MCP_OPEN_LINK_BLOCKED_SCHEMES };
|
|
23
|
+
//# sourceMappingURL=constants.d.mts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"constants.d.mts","names":[],"sources":["../src/constants.ts"],"mappings":";;AAGA;;cAAa,mBAAA;;;AAgBb;;;;;;;;;;;;cAAa,6BAAA,EAA6B,GAAA"}
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
//#region src/constants.ts
|
|
2
|
+
/**
|
|
3
|
+
* Activity type for MCP Apps events - must match the middleware's MCPAppsActivityType.
|
|
4
|
+
*/
|
|
5
|
+
const MCPAppsActivityType = "mcp-apps";
|
|
6
|
+
/**
|
|
7
|
+
* URL schemes a widget may NOT open via ui/open-link. The ext-apps schema
|
|
8
|
+
* validates `url` as a plain string only (noopener/noreferrer does not restrict
|
|
9
|
+
* the scheme), so ui/open-link could otherwise become an XSS vector.
|
|
10
|
+
*
|
|
11
|
+
* We use a denylist rather than an allowlist on purpose: deep links use
|
|
12
|
+
* arbitrary, app-defined schemes (`myapp:`, `whatsapp:`, `slack:`, `spotify:`,
|
|
13
|
+
* `sms:`, ...) that an allowlist could never enumerate, and `window.open`ing them
|
|
14
|
+
* just hands off to an OS handler - it does not execute script in the page, so
|
|
15
|
+
* it is not an XSS risk. Universal links / App Links are plain `https:` URLs and
|
|
16
|
+
* pass regardless. What IS dangerous is the small, well-known set of schemes
|
|
17
|
+
* that execute script or render attacker HTML in the page context; block those
|
|
18
|
+
* and allow everything else (including deep links).
|
|
19
|
+
*/
|
|
20
|
+
const MCP_OPEN_LINK_BLOCKED_SCHEMES = new Set([
|
|
21
|
+
"javascript:",
|
|
22
|
+
"data:",
|
|
23
|
+
"vbscript:",
|
|
24
|
+
"blob:",
|
|
25
|
+
"file:"
|
|
26
|
+
]);
|
|
27
|
+
|
|
28
|
+
//#endregion
|
|
29
|
+
export { MCPAppsActivityType, MCP_OPEN_LINK_BLOCKED_SCHEMES };
|
|
30
|
+
//# sourceMappingURL=constants.mjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"constants.mjs","names":[],"sources":["../src/constants.ts"],"sourcesContent":["/**\n * Activity type for MCP Apps events - must match the middleware's MCPAppsActivityType.\n */\nexport const MCPAppsActivityType = \"mcp-apps\";\n\n/**\n * URL schemes a widget may NOT open via ui/open-link. The ext-apps schema\n * validates `url` as a plain string only (noopener/noreferrer does not restrict\n * the scheme), so ui/open-link could otherwise become an XSS vector.\n *\n * We use a denylist rather than an allowlist on purpose: deep links use\n * arbitrary, app-defined schemes (`myapp:`, `whatsapp:`, `slack:`, `spotify:`,\n * `sms:`, ...) that an allowlist could never enumerate, and `window.open`ing them\n * just hands off to an OS handler - it does not execute script in the page, so\n * it is not an XSS risk. Universal links / App Links are plain `https:` URLs and\n * pass regardless. What IS dangerous is the small, well-known set of schemes\n * that execute script or render attacker HTML in the page context; block those\n * and allow everything else (including deep links).\n */\nexport const MCP_OPEN_LINK_BLOCKED_SCHEMES = new Set([\n \"javascript:\",\n \"data:\",\n \"vbscript:\",\n \"blob:\",\n \"file:\",\n]);\n"],"mappings":";;;;AAGA,MAAa,sBAAsB;;;;;;;;;;;;;;;AAgBnC,MAAa,gCAAgC,IAAI,IAAI;CACnD;CACA;CACA;CACA;CACA;CACD,CAAC"}
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
let zod = require("zod");
|
|
2
|
+
|
|
3
|
+
//#region src/content-schema.ts
|
|
4
|
+
/**
|
|
5
|
+
* Zod schema for MCP Apps activity content (middleware 0.0.2 format). The
|
|
6
|
+
* framework activity registries validate the activity content with this before
|
|
7
|
+
* handing it to the renderer/session.
|
|
8
|
+
*/
|
|
9
|
+
const MCPAppsActivityContentSchema = zod.z.object({
|
|
10
|
+
result: zod.z.object({
|
|
11
|
+
content: zod.z.array(zod.z.any()).optional(),
|
|
12
|
+
structuredContent: zod.z.any().optional(),
|
|
13
|
+
isError: zod.z.boolean().optional()
|
|
14
|
+
}),
|
|
15
|
+
resourceUri: zod.z.string(),
|
|
16
|
+
serverHash: zod.z.string(),
|
|
17
|
+
serverId: zod.z.string().optional(),
|
|
18
|
+
toolInput: zod.z.record(zod.z.string(), zod.z.unknown()).optional()
|
|
19
|
+
});
|
|
20
|
+
|
|
21
|
+
//#endregion
|
|
22
|
+
exports.MCPAppsActivityContentSchema = MCPAppsActivityContentSchema;
|
|
23
|
+
//# sourceMappingURL=content-schema.cjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"content-schema.cjs","names":["z"],"sources":["../src/content-schema.ts"],"sourcesContent":["import { z } from \"zod\";\n\n/**\n * Zod schema for MCP Apps activity content (middleware 0.0.2 format). The\n * framework activity registries validate the activity content with this before\n * handing it to the renderer/session.\n */\nexport const MCPAppsActivityContentSchema = z.object({\n result: z.object({\n content: z.array(z.any()).optional(),\n structuredContent: z.any().optional(),\n isError: z.boolean().optional(),\n }),\n // Resource URI to fetch (e.g., \"ui://server/dashboard\")\n resourceUri: z.string(),\n // MD5 hash of server config (renamed from serverId in 0.0.1)\n serverHash: z.string(),\n // Optional stable server ID from config (takes precedence over serverHash)\n serverId: z.string().optional(),\n // Original tool input arguments\n toolInput: z.record(z.string(), z.unknown()).optional(),\n});\n\nexport type MCPAppsActivityContent = z.infer<\n typeof MCPAppsActivityContentSchema\n>;\n"],"mappings":";;;;;;;;AAOA,MAAa,+BAA+BA,MAAE,OAAO;CACnD,QAAQA,MAAE,OAAO;EACf,SAASA,MAAE,MAAMA,MAAE,KAAK,CAAC,CAAC,UAAU;EACpC,mBAAmBA,MAAE,KAAK,CAAC,UAAU;EACrC,SAASA,MAAE,SAAS,CAAC,UAAU;EAChC,CAAC;CAEF,aAAaA,MAAE,QAAQ;CAEvB,YAAYA,MAAE,QAAQ;CAEtB,UAAUA,MAAE,QAAQ,CAAC,UAAU;CAE/B,WAAWA,MAAE,OAAOA,MAAE,QAAQ,EAAEA,MAAE,SAAS,CAAC,CAAC,UAAU;CACxD,CAAC"}
|
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
import { z } from "zod";
|
|
2
|
+
|
|
3
|
+
//#region src/content-schema.d.ts
|
|
4
|
+
/**
|
|
5
|
+
* Zod schema for MCP Apps activity content (middleware 0.0.2 format). The
|
|
6
|
+
* framework activity registries validate the activity content with this before
|
|
7
|
+
* handing it to the renderer/session.
|
|
8
|
+
*/
|
|
9
|
+
declare const MCPAppsActivityContentSchema: z.ZodObject<{
|
|
10
|
+
result: z.ZodObject<{
|
|
11
|
+
content: z.ZodOptional<z.ZodArray<z.ZodAny, "many">>;
|
|
12
|
+
structuredContent: z.ZodOptional<z.ZodAny>;
|
|
13
|
+
isError: z.ZodOptional<z.ZodBoolean>;
|
|
14
|
+
}, "strip", z.ZodTypeAny, {
|
|
15
|
+
content?: any[] | undefined;
|
|
16
|
+
structuredContent?: any;
|
|
17
|
+
isError?: boolean | undefined;
|
|
18
|
+
}, {
|
|
19
|
+
content?: any[] | undefined;
|
|
20
|
+
structuredContent?: any;
|
|
21
|
+
isError?: boolean | undefined;
|
|
22
|
+
}>;
|
|
23
|
+
resourceUri: z.ZodString;
|
|
24
|
+
serverHash: z.ZodString;
|
|
25
|
+
serverId: z.ZodOptional<z.ZodString>;
|
|
26
|
+
toolInput: z.ZodOptional<z.ZodRecord<z.ZodString, z.ZodUnknown>>;
|
|
27
|
+
}, "strip", z.ZodTypeAny, {
|
|
28
|
+
result: {
|
|
29
|
+
content?: any[] | undefined;
|
|
30
|
+
structuredContent?: any;
|
|
31
|
+
isError?: boolean | undefined;
|
|
32
|
+
};
|
|
33
|
+
resourceUri: string;
|
|
34
|
+
serverHash: string;
|
|
35
|
+
serverId?: string | undefined;
|
|
36
|
+
toolInput?: Record<string, unknown> | undefined;
|
|
37
|
+
}, {
|
|
38
|
+
result: {
|
|
39
|
+
content?: any[] | undefined;
|
|
40
|
+
structuredContent?: any;
|
|
41
|
+
isError?: boolean | undefined;
|
|
42
|
+
};
|
|
43
|
+
resourceUri: string;
|
|
44
|
+
serverHash: string;
|
|
45
|
+
serverId?: string | undefined;
|
|
46
|
+
toolInput?: Record<string, unknown> | undefined;
|
|
47
|
+
}>;
|
|
48
|
+
type MCPAppsActivityContent = z.infer<typeof MCPAppsActivityContentSchema>;
|
|
49
|
+
//#endregion
|
|
50
|
+
export { MCPAppsActivityContent, MCPAppsActivityContentSchema };
|
|
51
|
+
//# sourceMappingURL=content-schema.d.cts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"content-schema.d.cts","names":[],"sources":["../src/content-schema.ts"],"mappings":";;;;;AAOA;;;cAAa,4BAAA,EAA4B,CAAA,CAAA,SAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;KAgB7B,sBAAA,GAAyB,CAAA,CAAE,KAAA,QAC9B,4BAAA"}
|
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
import { z } from "zod";
|
|
2
|
+
|
|
3
|
+
//#region src/content-schema.d.ts
|
|
4
|
+
/**
|
|
5
|
+
* Zod schema for MCP Apps activity content (middleware 0.0.2 format). The
|
|
6
|
+
* framework activity registries validate the activity content with this before
|
|
7
|
+
* handing it to the renderer/session.
|
|
8
|
+
*/
|
|
9
|
+
declare const MCPAppsActivityContentSchema: z.ZodObject<{
|
|
10
|
+
result: z.ZodObject<{
|
|
11
|
+
content: z.ZodOptional<z.ZodArray<z.ZodAny, "many">>;
|
|
12
|
+
structuredContent: z.ZodOptional<z.ZodAny>;
|
|
13
|
+
isError: z.ZodOptional<z.ZodBoolean>;
|
|
14
|
+
}, "strip", z.ZodTypeAny, {
|
|
15
|
+
content?: any[] | undefined;
|
|
16
|
+
structuredContent?: any;
|
|
17
|
+
isError?: boolean | undefined;
|
|
18
|
+
}, {
|
|
19
|
+
content?: any[] | undefined;
|
|
20
|
+
structuredContent?: any;
|
|
21
|
+
isError?: boolean | undefined;
|
|
22
|
+
}>;
|
|
23
|
+
resourceUri: z.ZodString;
|
|
24
|
+
serverHash: z.ZodString;
|
|
25
|
+
serverId: z.ZodOptional<z.ZodString>;
|
|
26
|
+
toolInput: z.ZodOptional<z.ZodRecord<z.ZodString, z.ZodUnknown>>;
|
|
27
|
+
}, "strip", z.ZodTypeAny, {
|
|
28
|
+
result: {
|
|
29
|
+
content?: any[] | undefined;
|
|
30
|
+
structuredContent?: any;
|
|
31
|
+
isError?: boolean | undefined;
|
|
32
|
+
};
|
|
33
|
+
resourceUri: string;
|
|
34
|
+
serverHash: string;
|
|
35
|
+
serverId?: string | undefined;
|
|
36
|
+
toolInput?: Record<string, unknown> | undefined;
|
|
37
|
+
}, {
|
|
38
|
+
result: {
|
|
39
|
+
content?: any[] | undefined;
|
|
40
|
+
structuredContent?: any;
|
|
41
|
+
isError?: boolean | undefined;
|
|
42
|
+
};
|
|
43
|
+
resourceUri: string;
|
|
44
|
+
serverHash: string;
|
|
45
|
+
serverId?: string | undefined;
|
|
46
|
+
toolInput?: Record<string, unknown> | undefined;
|
|
47
|
+
}>;
|
|
48
|
+
type MCPAppsActivityContent = z.infer<typeof MCPAppsActivityContentSchema>;
|
|
49
|
+
//#endregion
|
|
50
|
+
export { MCPAppsActivityContent, MCPAppsActivityContentSchema };
|
|
51
|
+
//# sourceMappingURL=content-schema.d.mts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"content-schema.d.mts","names":[],"sources":["../src/content-schema.ts"],"mappings":";;;;;AAOA;;;cAAa,4BAAA,EAA4B,CAAA,CAAA,SAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;KAgB7B,sBAAA,GAAyB,CAAA,CAAE,KAAA,QAC9B,4BAAA"}
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
import { z } from "zod";
|
|
2
|
+
|
|
3
|
+
//#region src/content-schema.ts
|
|
4
|
+
/**
|
|
5
|
+
* Zod schema for MCP Apps activity content (middleware 0.0.2 format). The
|
|
6
|
+
* framework activity registries validate the activity content with this before
|
|
7
|
+
* handing it to the renderer/session.
|
|
8
|
+
*/
|
|
9
|
+
const MCPAppsActivityContentSchema = z.object({
|
|
10
|
+
result: z.object({
|
|
11
|
+
content: z.array(z.any()).optional(),
|
|
12
|
+
structuredContent: z.any().optional(),
|
|
13
|
+
isError: z.boolean().optional()
|
|
14
|
+
}),
|
|
15
|
+
resourceUri: z.string(),
|
|
16
|
+
serverHash: z.string(),
|
|
17
|
+
serverId: z.string().optional(),
|
|
18
|
+
toolInput: z.record(z.string(), z.unknown()).optional()
|
|
19
|
+
});
|
|
20
|
+
|
|
21
|
+
//#endregion
|
|
22
|
+
export { MCPAppsActivityContentSchema };
|
|
23
|
+
//# sourceMappingURL=content-schema.mjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"content-schema.mjs","names":[],"sources":["../src/content-schema.ts"],"sourcesContent":["import { z } from \"zod\";\n\n/**\n * Zod schema for MCP Apps activity content (middleware 0.0.2 format). The\n * framework activity registries validate the activity content with this before\n * handing it to the renderer/session.\n */\nexport const MCPAppsActivityContentSchema = z.object({\n result: z.object({\n content: z.array(z.any()).optional(),\n structuredContent: z.any().optional(),\n isError: z.boolean().optional(),\n }),\n // Resource URI to fetch (e.g., \"ui://server/dashboard\")\n resourceUri: z.string(),\n // MD5 hash of server config (renamed from serverId in 0.0.1)\n serverHash: z.string(),\n // Optional stable server ID from config (takes precedence over serverHash)\n serverId: z.string().optional(),\n // Original tool input arguments\n toolInput: z.record(z.string(), z.unknown()).optional(),\n});\n\nexport type MCPAppsActivityContent = z.infer<\n typeof MCPAppsActivityContentSchema\n>;\n"],"mappings":";;;;;;;;AAOA,MAAa,+BAA+B,EAAE,OAAO;CACnD,QAAQ,EAAE,OAAO;EACf,SAAS,EAAE,MAAM,EAAE,KAAK,CAAC,CAAC,UAAU;EACpC,mBAAmB,EAAE,KAAK,CAAC,UAAU;EACrC,SAAS,EAAE,SAAS,CAAC,UAAU;EAChC,CAAC;CAEF,aAAa,EAAE,QAAQ;CAEvB,YAAY,EAAE,QAAQ;CAEtB,UAAU,EAAE,QAAQ,CAAC,UAAU;CAE/B,WAAW,EAAE,OAAO,EAAE,QAAQ,EAAE,EAAE,SAAS,CAAC,CAAC,UAAU;CACxD,CAAC"}
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
|
|
2
|
+
//#region src/follow-up.ts
|
|
3
|
+
/**
|
|
4
|
+
* Run an MCP app `ui/message` follow-up, scoped to the thread it was enqueued
|
|
5
|
+
* for (issue #5819).
|
|
6
|
+
*
|
|
7
|
+
* The MCP request queue delays follow-up work until the agent is idle. There is
|
|
8
|
+
* a single shared registry agent per id, and switching threads overwrites its
|
|
9
|
+
* `threadId`/`messages` in place. So if the host switches threads while a
|
|
10
|
+
* follow-up is queued, running it now would execute against — and stream into —
|
|
11
|
+
* the now-foreground thread.
|
|
12
|
+
*
|
|
13
|
+
* - **Same thread** (the common case): run on the shared agent, unchanged.
|
|
14
|
+
* - **Thread changed**: the shared agent has moved on, so the follow-up can no
|
|
15
|
+
* longer run in its originating thread's context. Drop it rather than leak it
|
|
16
|
+
* into the current thread. (The MCP app already received its `ui/message` ack
|
|
17
|
+
* at enqueue time; only the optional agent turn is skipped.)
|
|
18
|
+
*
|
|
19
|
+
* @internal exported for testing.
|
|
20
|
+
*/
|
|
21
|
+
async function ɵrunMcpFollowUp({ host, agent, capturedThreadId }) {
|
|
22
|
+
const currentThreadId = agent.threadId || "default";
|
|
23
|
+
const originThreadId = capturedThreadId || "default";
|
|
24
|
+
if (currentThreadId === originThreadId) return host.runAgent({ agent });
|
|
25
|
+
console.warn(`[MCPAppsRenderer] ui/message follow-up dropped: the thread changed (${originThreadId} → ${currentThreadId}) between enqueue and execution, so running it would leak into the now-foreground thread.`);
|
|
26
|
+
return {
|
|
27
|
+
result: void 0,
|
|
28
|
+
newMessages: []
|
|
29
|
+
};
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
//#endregion
|
|
33
|
+
exports.ɵrunMcpFollowUp = ɵrunMcpFollowUp;
|
|
34
|
+
//# sourceMappingURL=follow-up.cjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"follow-up.cjs","names":[],"sources":["../src/follow-up.ts"],"sourcesContent":["import type { AbstractAgent, RunAgentResult } from \"@ag-ui/client\";\n\n/**\n * The subset of `CopilotKitCore` that {@link ɵrunMcpFollowUp} depends on.\n * Declared structurally so the runner can be unit-tested without a full core.\n */\nexport interface ɵMcpFollowUpHost {\n runAgent(params: { agent: AbstractAgent }): Promise<RunAgentResult>;\n}\n\n/**\n * Run an MCP app `ui/message` follow-up, scoped to the thread it was enqueued\n * for (issue #5819).\n *\n * The MCP request queue delays follow-up work until the agent is idle. There is\n * a single shared registry agent per id, and switching threads overwrites its\n * `threadId`/`messages` in place. So if the host switches threads while a\n * follow-up is queued, running it now would execute against — and stream into —\n * the now-foreground thread.\n *\n * - **Same thread** (the common case): run on the shared agent, unchanged.\n * - **Thread changed**: the shared agent has moved on, so the follow-up can no\n * longer run in its originating thread's context. Drop it rather than leak it\n * into the current thread. (The MCP app already received its `ui/message` ack\n * at enqueue time; only the optional agent turn is skipped.)\n *\n * @internal exported for testing.\n */\nexport async function ɵrunMcpFollowUp({\n host,\n agent,\n capturedThreadId,\n}: {\n host: ɵMcpFollowUpHost;\n agent: AbstractAgent;\n capturedThreadId: string;\n}): Promise<RunAgentResult> {\n const currentThreadId = agent.threadId || \"default\";\n const originThreadId = capturedThreadId || \"default\";\n\n if (currentThreadId === originThreadId) {\n return host.runAgent({ agent });\n }\n\n console.warn(\n \"[MCPAppsRenderer] ui/message follow-up dropped: the thread changed \" +\n `(${originThreadId} → ${currentThreadId}) between enqueue and execution, ` +\n \"so running it would leak into the now-foreground thread.\",\n );\n return { result: undefined, newMessages: [] };\n}\n"],"mappings":";;;;;;;;;;;;;;;;;;;;AA4BA,eAAsB,gBAAgB,EACpC,MACA,OACA,oBAK0B;CAC1B,MAAM,kBAAkB,MAAM,YAAY;CAC1C,MAAM,iBAAiB,oBAAoB;AAE3C,KAAI,oBAAoB,eACtB,QAAO,KAAK,SAAS,EAAE,OAAO,CAAC;AAGjC,SAAQ,KACN,uEACM,eAAe,KAAK,gBAAgB,2FAE3C;AACD,QAAO;EAAE,QAAQ;EAAW,aAAa,EAAE;EAAE"}
|
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
import { AbstractAgent, RunAgentResult } from "@ag-ui/client";
|
|
2
|
+
|
|
3
|
+
//#region src/follow-up.d.ts
|
|
4
|
+
/**
|
|
5
|
+
* The subset of `CopilotKitCore` that {@link ɵrunMcpFollowUp} depends on.
|
|
6
|
+
* Declared structurally so the runner can be unit-tested without a full core.
|
|
7
|
+
*/
|
|
8
|
+
interface ɵMcpFollowUpHost {
|
|
9
|
+
runAgent(params: {
|
|
10
|
+
agent: AbstractAgent;
|
|
11
|
+
}): Promise<RunAgentResult>;
|
|
12
|
+
}
|
|
13
|
+
/**
|
|
14
|
+
* Run an MCP app `ui/message` follow-up, scoped to the thread it was enqueued
|
|
15
|
+
* for (issue #5819).
|
|
16
|
+
*
|
|
17
|
+
* The MCP request queue delays follow-up work until the agent is idle. There is
|
|
18
|
+
* a single shared registry agent per id, and switching threads overwrites its
|
|
19
|
+
* `threadId`/`messages` in place. So if the host switches threads while a
|
|
20
|
+
* follow-up is queued, running it now would execute against — and stream into —
|
|
21
|
+
* the now-foreground thread.
|
|
22
|
+
*
|
|
23
|
+
* - **Same thread** (the common case): run on the shared agent, unchanged.
|
|
24
|
+
* - **Thread changed**: the shared agent has moved on, so the follow-up can no
|
|
25
|
+
* longer run in its originating thread's context. Drop it rather than leak it
|
|
26
|
+
* into the current thread. (The MCP app already received its `ui/message` ack
|
|
27
|
+
* at enqueue time; only the optional agent turn is skipped.)
|
|
28
|
+
*
|
|
29
|
+
* @internal exported for testing.
|
|
30
|
+
*/
|
|
31
|
+
declare function ɵrunMcpFollowUp({
|
|
32
|
+
host,
|
|
33
|
+
agent,
|
|
34
|
+
capturedThreadId
|
|
35
|
+
}: {
|
|
36
|
+
host: ɵMcpFollowUpHost;
|
|
37
|
+
agent: AbstractAgent;
|
|
38
|
+
capturedThreadId: string;
|
|
39
|
+
}): Promise<RunAgentResult>;
|
|
40
|
+
//#endregion
|
|
41
|
+
export { ɵMcpFollowUpHost, ɵrunMcpFollowUp };
|
|
42
|
+
//# sourceMappingURL=follow-up.d.cts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"follow-up.d.cts","names":[],"sources":["../src/follow-up.ts"],"mappings":";;;;;AAMA;;UAAiB,gBAAA;EACf,QAAA,CAAS,MAAA;IAAU,KAAA,EAAO,aAAA;EAAA,IAAkB,OAAA,CAAQ,cAAA;AAAA;;;;;;;;;;AAqBtD;;;;;;;;;iBAAsB,eAAA,CAAA;EACpB,IAAA;EACA,KAAA;EACA;AAAA;EAEA,IAAA,EAAM,gBAAA;EACN,KAAA,EAAO,aAAA;EACP,gBAAA;AAAA,IACE,OAAA,CAAQ,cAAA"}
|
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
import { AbstractAgent, RunAgentResult } from "@ag-ui/client";
|
|
2
|
+
|
|
3
|
+
//#region src/follow-up.d.ts
|
|
4
|
+
/**
|
|
5
|
+
* The subset of `CopilotKitCore` that {@link ɵrunMcpFollowUp} depends on.
|
|
6
|
+
* Declared structurally so the runner can be unit-tested without a full core.
|
|
7
|
+
*/
|
|
8
|
+
interface ɵMcpFollowUpHost {
|
|
9
|
+
runAgent(params: {
|
|
10
|
+
agent: AbstractAgent;
|
|
11
|
+
}): Promise<RunAgentResult>;
|
|
12
|
+
}
|
|
13
|
+
/**
|
|
14
|
+
* Run an MCP app `ui/message` follow-up, scoped to the thread it was enqueued
|
|
15
|
+
* for (issue #5819).
|
|
16
|
+
*
|
|
17
|
+
* The MCP request queue delays follow-up work until the agent is idle. There is
|
|
18
|
+
* a single shared registry agent per id, and switching threads overwrites its
|
|
19
|
+
* `threadId`/`messages` in place. So if the host switches threads while a
|
|
20
|
+
* follow-up is queued, running it now would execute against — and stream into —
|
|
21
|
+
* the now-foreground thread.
|
|
22
|
+
*
|
|
23
|
+
* - **Same thread** (the common case): run on the shared agent, unchanged.
|
|
24
|
+
* - **Thread changed**: the shared agent has moved on, so the follow-up can no
|
|
25
|
+
* longer run in its originating thread's context. Drop it rather than leak it
|
|
26
|
+
* into the current thread. (The MCP app already received its `ui/message` ack
|
|
27
|
+
* at enqueue time; only the optional agent turn is skipped.)
|
|
28
|
+
*
|
|
29
|
+
* @internal exported for testing.
|
|
30
|
+
*/
|
|
31
|
+
declare function ɵrunMcpFollowUp({
|
|
32
|
+
host,
|
|
33
|
+
agent,
|
|
34
|
+
capturedThreadId
|
|
35
|
+
}: {
|
|
36
|
+
host: ɵMcpFollowUpHost;
|
|
37
|
+
agent: AbstractAgent;
|
|
38
|
+
capturedThreadId: string;
|
|
39
|
+
}): Promise<RunAgentResult>;
|
|
40
|
+
//#endregion
|
|
41
|
+
export { ɵMcpFollowUpHost, ɵrunMcpFollowUp };
|
|
42
|
+
//# sourceMappingURL=follow-up.d.mts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"follow-up.d.mts","names":[],"sources":["../src/follow-up.ts"],"mappings":";;;;;AAMA;;UAAiB,gBAAA;EACf,QAAA,CAAS,MAAA;IAAU,KAAA,EAAO,aAAA;EAAA,IAAkB,OAAA,CAAQ,cAAA;AAAA;;;;;;;;;;AAqBtD;;;;;;;;;iBAAsB,eAAA,CAAA;EACpB,IAAA;EACA,KAAA;EACA;AAAA;EAEA,IAAA,EAAM,gBAAA;EACN,KAAA,EAAO,aAAA;EACP,gBAAA;AAAA,IACE,OAAA,CAAQ,cAAA"}
|