@miragon/mcp-toolkit-ui 2.4.1 → 2.5.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +1 -1
- package/dist/app/mcp-app-view-chrome.d.ts +7 -0
- package/dist/app/mcp-app-view-chrome.d.ts.map +1 -1
- package/dist/app/mcp-app-view-chrome.js +14 -2
- package/dist/app/mcp-app-view-chrome.js.map +1 -1
- package/dist/app/mcp-app-view.d.ts.map +1 -1
- package/dist/app/mcp-app-view.js +8 -4
- package/dist/app/mcp-app-view.js.map +1 -1
- package/dist/hooks/use-tool-result-recovery.d.ts +14 -2
- package/dist/hooks/use-tool-result-recovery.d.ts.map +1 -1
- package/dist/hooks/use-tool-result-recovery.js +11 -4
- package/dist/hooks/use-tool-result-recovery.js.map +1 -1
- package/package.json +15 -15
- package/src/app/mcp-app-view-chrome.test.tsx +25 -0
- package/src/app/mcp-app-view-chrome.tsx +35 -2
- package/src/app/mcp-app-view.tsx +8 -9
- package/src/hooks/use-tool-result-recovery.ts +20 -5
package/README.md
CHANGED
|
@@ -9,7 +9,7 @@ Published to the public npm registry under the `@miragon` scope — no `.npmrc`
|
|
|
9
9
|
or token needed.
|
|
10
10
|
|
|
11
11
|
```sh
|
|
12
|
-
pnpm add @miragon/mcp-toolkit-ui @miragon/mcp-toolkit-core mcp-use@2.
|
|
12
|
+
pnpm add @miragon/mcp-toolkit-ui @miragon/mcp-toolkit-core mcp-use@2.7.1 react@19.2.8 react-dom@19.2.8 tailwindcss@4.3.3
|
|
13
13
|
```
|
|
14
14
|
|
|
15
15
|
Peer versions are pinned exactly — install the versions above.
|
|
@@ -3,6 +3,8 @@ import { type LayoutBuilderProps } from "./layout-builder.js";
|
|
|
3
3
|
import { type WidgetComponent } from "./widget-renderer.js";
|
|
4
4
|
export interface McpAppViewLabels {
|
|
5
5
|
loading?: string;
|
|
6
|
+
/** Shown instead of the loading skeleton when the host cancelled the rendering tool call. */
|
|
7
|
+
cancelled?: string;
|
|
6
8
|
refresh?: string;
|
|
7
9
|
refreshing?: string;
|
|
8
10
|
enterFullscreen?: string;
|
|
@@ -48,6 +50,11 @@ export interface ViewData {
|
|
|
48
50
|
* recovery hook's `isValid` dependency.
|
|
49
51
|
*/
|
|
50
52
|
export declare function isCompleteViewData(value: unknown): value is ViewData;
|
|
53
|
+
export declare function ViewPlaceholder({ cancelled, labels, }: {
|
|
54
|
+
/** The host cancelled the rendering call — no payload will arrive. */
|
|
55
|
+
cancelled: boolean;
|
|
56
|
+
labels: Required<McpAppViewLabels>;
|
|
57
|
+
}): import("react").JSX.Element;
|
|
51
58
|
export interface ViewToolbarProps {
|
|
52
59
|
/** The toolbar hides entirely while build mode owns the surface. */
|
|
53
60
|
hidden: boolean;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"mcp-app-view-chrome.d.ts","sourceRoot":"","sources":["../../src/app/mcp-app-view-chrome.tsx"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"mcp-app-view-chrome.d.ts","sourceRoot":"","sources":["../../src/app/mcp-app-view-chrome.tsx"],"names":[],"mappings":"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"}
|
|
@@ -1,15 +1,18 @@
|
|
|
1
1
|
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
2
2
|
/**
|
|
3
|
-
* Presentational chrome for `McpAppView` — the
|
|
4
|
-
* list, and the build/render body — plus the
|
|
3
|
+
* Presentational chrome for `McpAppView` — the pre-payload placeholder, the
|
|
4
|
+
* toolbar, the pipeline error list, and the build/render body — plus the
|
|
5
|
+
* view-envelope types they share.
|
|
5
6
|
* Split out of `mcp-app-view.tsx` so the shell component keeps only the
|
|
6
7
|
* host-sync and state logic while this file stays hook-free.
|
|
7
8
|
*/
|
|
8
9
|
import { Maximize2, Minimize2, Pencil, RefreshCw } from "lucide-react";
|
|
10
|
+
import { Skeleton } from "../primitives/skeleton.js";
|
|
9
11
|
import { LayoutBuilder } from "./layout-builder.js";
|
|
10
12
|
import { WidgetRenderer } from "./widget-renderer.js";
|
|
11
13
|
export const DEFAULT_LABELS = {
|
|
12
14
|
loading: "Waiting for pipeline result...",
|
|
15
|
+
cancelled: "Tool call was cancelled.",
|
|
13
16
|
refresh: "Refresh",
|
|
14
17
|
refreshing: "Loading...",
|
|
15
18
|
enterFullscreen: "Fullscreen",
|
|
@@ -25,6 +28,15 @@ export function isCompleteViewData(value) {
|
|
|
25
28
|
const v = value;
|
|
26
29
|
return Boolean(v?.context && v?.layout);
|
|
27
30
|
}
|
|
31
|
+
// -------------------------------------------------------------------------- //
|
|
32
|
+
// Placeholder: shown until a view payload exists
|
|
33
|
+
// -------------------------------------------------------------------------- //
|
|
34
|
+
export function ViewPlaceholder({ cancelled, labels, }) {
|
|
35
|
+
if (cancelled) {
|
|
36
|
+
return (_jsx("div", { className: "p-4", children: _jsx("p", { className: "text-muted-foreground text-sm", children: labels.cancelled }) }));
|
|
37
|
+
}
|
|
38
|
+
return (_jsxs("div", { className: "flex flex-col gap-4 p-4", children: [_jsx(Skeleton, { className: "h-8 w-48" }), _jsx(Skeleton, { className: "h-32 w-full" }), _jsx("p", { className: "text-muted-foreground text-sm", children: labels.loading })] }));
|
|
39
|
+
}
|
|
28
40
|
export function ViewToolbar({ hidden, viewData, builderAvailable, isFullscreen, isRefreshing, labels, onRefresh, onEnterBuildMode, onToggleFullscreen, }) {
|
|
29
41
|
if (hidden)
|
|
30
42
|
return null;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"mcp-app-view-chrome.js","sourceRoot":"","sources":["../../src/app/mcp-app-view-chrome.tsx"],"names":[],"mappings":";AAAA
|
|
1
|
+
{"version":3,"file":"mcp-app-view-chrome.js","sourceRoot":"","sources":["../../src/app/mcp-app-view-chrome.tsx"],"names":[],"mappings":"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"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"mcp-app-view.d.ts","sourceRoot":"","sources":["../../src/app/mcp-app-view.tsx"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"mcp-app-view.d.ts","sourceRoot":"","sources":["../../src/app/mcp-app-view.tsx"],"names":[],"mappings":"AAOA,OAAO,EAOL,KAAK,gBAAgB,EAEtB,MAAM,0BAA0B,CAAA;AACjC,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,sBAAsB,CAAA;AAE3D,YAAY,EAAE,gBAAgB,EAAE,MAAM,0BAA0B,CAAA;AAEhE,MAAM,WAAW,eAAe;IAC9B;;;;;OAKG;IACH,OAAO,EAAE,MAAM,CAAC,MAAM,EAAE,eAAe,CAAC,CAAA;IACxC;;;;OAIG;IACH,eAAe,CAAC,EAAE,MAAM,CAAA;IACxB;;;;;;;;;;OAUG;IACH,cAAc,CAAC,EAAE,OAAO,CAAA;IACxB;;;OAGG;IACH,MAAM,CAAC,EAAE,gBAAgB,CAAA;CAC1B;AAED,wBAAgB,UAAU,CAAC,EACzB,OAAO,EACP,eAAgC,EAChC,cAAc,EACd,MAAM,GACP,EAAE,eAAe,+BA+MjB"}
|
package/dist/app/mcp-app-view.js
CHANGED
|
@@ -1,12 +1,11 @@
|
|
|
1
1
|
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
2
2
|
import { useState, useCallback } from "react";
|
|
3
|
-
import { useDisplayMode, useHostContext, useToolContext } from "mcp-use/react";
|
|
4
|
-
import { Skeleton } from "../primitives/skeleton.js";
|
|
3
|
+
import { ToolCancelledError, useDisplayMode, useHostContext, useToolContext } from "mcp-use/react";
|
|
5
4
|
import { AppQueryProvider, queryClient } from "../providers/query-provider.js";
|
|
6
5
|
import { useToolResultRecovery } from "../hooks/use-tool-result-recovery.js";
|
|
7
6
|
import { parseToolResult } from "../lib/parse-tool-result.js";
|
|
8
7
|
import { useHostBridge } from "./host-bridge.js";
|
|
9
|
-
import { DEFAULT_LABELS, isCompleteViewData, StepErrors, ViewBody, ViewToolbar, } from "./mcp-app-view-chrome.js";
|
|
8
|
+
import { DEFAULT_LABELS, isCompleteViewData, StepErrors, ViewBody, ViewPlaceholder, ViewToolbar, } from "./mcp-app-view-chrome.js";
|
|
10
9
|
export function McpAppView({ widgets, refreshToolName = "refresh-view", builderEnabled, labels, }) {
|
|
11
10
|
const effectiveLabels = { ...DEFAULT_LABELS, ...labels };
|
|
12
11
|
// Since mcp-use 2.x the shell reads the view channels through the dedicated
|
|
@@ -19,6 +18,10 @@ export function McpAppView({ widgets, refreshToolName = "refresh-view", builderE
|
|
|
19
18
|
const bridge = useHostBridge();
|
|
20
19
|
const callTool = useCallback((name, args) => bridge.callTool(name, args), [bridge]);
|
|
21
20
|
const isPending = tool.status === "pending";
|
|
21
|
+
// Since mcp-use 2.7.1 a host cancellation of the rendering call latches as a
|
|
22
|
+
// terminal `status: "error"` — show it instead of the skeleton, and never
|
|
23
|
+
// let the recovery below re-run the call the user stopped.
|
|
24
|
+
const isCancelled = tool.status === "error" && tool.error instanceof ToolCancelledError;
|
|
22
25
|
const initialViewData = tool.status === "ready" ? tool.toolOutput : undefined;
|
|
23
26
|
const toolInput = tool.toolInput;
|
|
24
27
|
const [viewData, setViewData] = useState(null);
|
|
@@ -54,6 +57,7 @@ export function McpAppView({ widgets, refreshToolName = "refresh-view", builderE
|
|
|
54
57
|
// there.
|
|
55
58
|
const recovery = useToolResultRecovery({
|
|
56
59
|
resultReady: !isPending,
|
|
60
|
+
cancelled: isCancelled,
|
|
57
61
|
props: initialViewData,
|
|
58
62
|
isValid: isCompleteViewData,
|
|
59
63
|
toolInput,
|
|
@@ -130,7 +134,7 @@ export function McpAppView({ widgets, refreshToolName = "refresh-view", builderE
|
|
|
130
134
|
// `structuredContent` the 2.x latch stays "pending" forever, and recovered
|
|
131
135
|
// viewData still has to replace the skeleton.
|
|
132
136
|
if (!viewData) {
|
|
133
|
-
return
|
|
137
|
+
return _jsx(ViewPlaceholder, { cancelled: isCancelled, labels: effectiveLabels });
|
|
134
138
|
}
|
|
135
139
|
const isFullscreen = displayMode === "fullscreen";
|
|
136
140
|
// Follow the server's own signal by default: render-view reports
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"mcp-app-view.js","sourceRoot":"","sources":["../../src/app/mcp-app-view.tsx"],"names":[],"mappings":";AAAA,OAAO,EAAE,QAAQ,EAAE,WAAW,EAAE,MAAM,OAAO,CAAA;AAC7C,OAAO,EAAE,
|
|
1
|
+
{"version":3,"file":"mcp-app-view.js","sourceRoot":"","sources":["../../src/app/mcp-app-view.tsx"],"names":[],"mappings":"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"}
|
|
@@ -17,6 +17,11 @@
|
|
|
17
17
|
* decoded payload. Spec-conforming hosts (e.g. the mcp-use inspector) deliver
|
|
18
18
|
* a valid payload up front, so the recovery never fires there.
|
|
19
19
|
*
|
|
20
|
+
* A call the host cancelled is never recovered: since mcp-use 2.7.1 the
|
|
21
|
+
* cancellation latches as `status: "error"` (a `ToolCancelledError`), which
|
|
22
|
+
* would otherwise count as a ready-but-invalid result — re-executing it would
|
|
23
|
+
* override the user's decision to stop the call.
|
|
24
|
+
*
|
|
20
25
|
* Assumes the originating tool is a read-only render pipeline (true for all
|
|
21
26
|
* toolkit `render-view`/`show_*` tools) — the re-execution must be safe to
|
|
22
27
|
* repeat, and may rarely run concurrently with the original invocation when
|
|
@@ -32,10 +37,17 @@ export declare const DEFAULT_ASSUME_STRIPPED_AFTER_MS = 2500;
|
|
|
32
37
|
export interface ToolResultRecoveryOptions {
|
|
33
38
|
/**
|
|
34
39
|
* The latch fired (`useToolContext().status !== "pending"`) — a structured
|
|
35
|
-
* result
|
|
36
|
-
* this never turns true; the grace timer below covers
|
|
40
|
+
* result, a tool error, or a host cancellation arrived. On hosts that strip
|
|
41
|
+
* `structuredContent` this never turns true; the grace timer below covers
|
|
42
|
+
* that case.
|
|
37
43
|
*/
|
|
38
44
|
resultReady: boolean;
|
|
45
|
+
/**
|
|
46
|
+
* The host cancelled the originating call (`useToolContext().error` is a
|
|
47
|
+
* `ToolCancelledError`). Suppresses the recovery: nothing fires, and an
|
|
48
|
+
* attempt already in flight is dropped. Defaults to `false`.
|
|
49
|
+
*/
|
|
50
|
+
cancelled?: boolean;
|
|
39
51
|
/** The payload the host delivered (`useToolContext().toolOutput`). */
|
|
40
52
|
props: unknown;
|
|
41
53
|
/**
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"use-tool-result-recovery.d.ts","sourceRoot":"","sources":["../../src/hooks/use-tool-result-recovery.ts"],"names":[],"mappings":"AAGA
|
|
1
|
+
{"version":3,"file":"use-tool-result-recovery.d.ts","sourceRoot":"","sources":["../../src/hooks/use-tool-result-recovery.ts"],"names":[],"mappings":"AAGA;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA4BG;AAEH;;;;;GAKG;AACH,eAAO,MAAM,gCAAgC,OAAO,CAAA;AAEpD,MAAM,WAAW,yBAAyB;IACxC;;;;;OAKG;IACH,WAAW,EAAE,OAAO,CAAA;IACpB;;;;OAIG;IACH,SAAS,CAAC,EAAE,OAAO,CAAA;IACnB,sEAAsE;IACtE,KAAK,EAAE,OAAO,CAAA;IACd;;;OAGG;IACH,OAAO,EAAE,CAAC,KAAK,EAAE,OAAO,KAAK,OAAO,CAAA;IACpC,4FAA4F;IAC5F,SAAS,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,IAAI,GAAG,SAAS,CAAA;IACrD,gGAAgG;IAChG,WAAW,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,IAAI,GAAG,SAAS,CAAA;IACvD,oCAAoC;IACpC,QAAQ,EAAE,CAAC,IAAI,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,KAAK,OAAO,CAAC,OAAO,CAAC,CAAA;IAC3E;;;;;;OAMG;IACH,qBAAqB,CAAC,EAAE,MAAM,CAAA;CAC/B;AAED,MAAM,WAAW,uBAAuB,CAAC,CAAC;IACxC,yFAAyF;IACzF,IAAI,EAAE,CAAC,GAAG,IAAI,CAAA;IACd,oGAAoG;IACpG,MAAM,EAAE,OAAO,CAAA;CAChB;AAID;;;;GAIG;AACH,wBAAgB,uBAAuB,CAAC,WAAW,EAAE,OAAO,GAAG,MAAM,GAAG,SAAS,CAehF;AAED;;;GAGG;AACH,wBAAgB,qBAAqB,CAAC,CAAC,EACrC,MAAM,EAAE,OAAO,EACf,OAAO,EAAE,CAAC,KAAK,EAAE,OAAO,KAAK,OAAO,GACnC,CAAC,GAAG,IAAI,CAQV;AAED,wBAAgB,qBAAqB,CAAC,CAAC,EACrC,OAAO,EAAE,yBAAyB,GACjC,uBAAuB,CAAC,CAAC,CAAC,CAsF5B"}
|
|
@@ -19,6 +19,11 @@ import { parseToolResult } from "../lib/parse-tool-result.js";
|
|
|
19
19
|
* decoded payload. Spec-conforming hosts (e.g. the mcp-use inspector) deliver
|
|
20
20
|
* a valid payload up front, so the recovery never fires there.
|
|
21
21
|
*
|
|
22
|
+
* A call the host cancelled is never recovered: since mcp-use 2.7.1 the
|
|
23
|
+
* cancellation latches as `status: "error"` (a `ToolCancelledError`), which
|
|
24
|
+
* would otherwise count as a ready-but-invalid result — re-executing it would
|
|
25
|
+
* override the user's decision to stop the call.
|
|
26
|
+
*
|
|
22
27
|
* Assumes the originating tool is a read-only render pipeline (true for all
|
|
23
28
|
* toolkit `render-view`/`show_*` tools) — the re-execution must be safe to
|
|
24
29
|
* repeat, and may rarely run concurrently with the original invocation when
|
|
@@ -71,7 +76,7 @@ export function decodeRecoveredResult(result, isValid) {
|
|
|
71
76
|
return decoded !== null && isValid(decoded) ? decoded : null;
|
|
72
77
|
}
|
|
73
78
|
export function useToolResultRecovery(options) {
|
|
74
|
-
const { resultReady, props, isValid, toolInput, hostContext, callTool, assumeStrippedAfterMs = DEFAULT_ASSUME_STRIPPED_AFTER_MS, } = options;
|
|
79
|
+
const { resultReady, cancelled = false, props, isValid, toolInput, hostContext, callTool, assumeStrippedAfterMs = DEFAULT_ASSUME_STRIPPED_AFTER_MS, } = options;
|
|
75
80
|
const [state, setState] = useState(IDLE);
|
|
76
81
|
// Single-flight: the promise ref survives StrictMode's dev-mode
|
|
77
82
|
// effect re-run (cleanup + setup on the same instance), so the re-run
|
|
@@ -95,12 +100,14 @@ export function useToolResultRecovery(options) {
|
|
|
95
100
|
setAssumedReady(false);
|
|
96
101
|
}
|
|
97
102
|
useEffect(() => {
|
|
98
|
-
if (resultReady || toolName === undefined)
|
|
103
|
+
if (resultReady || cancelled || toolName === undefined)
|
|
99
104
|
return;
|
|
100
105
|
const timer = setTimeout(() => setAssumedReady(true), assumeStrippedAfterMs);
|
|
101
106
|
return () => clearTimeout(timer);
|
|
102
|
-
}, [resultReady, toolName, toolInput, assumeStrippedAfterMs]);
|
|
103
|
-
|
|
107
|
+
}, [resultReady, cancelled, toolName, toolInput, assumeStrippedAfterMs]);
|
|
108
|
+
// A cancelled call never counts as ready, so the effect below invalidates
|
|
109
|
+
// any in-flight attempt the same way it does for a superseded run.
|
|
110
|
+
const ready = !cancelled && (resultReady || assumedReady);
|
|
104
111
|
useEffect(() => {
|
|
105
112
|
// A new tool run (result no longer ready, or fresh tool-input identity)
|
|
106
113
|
// invalidates any previous recovery attempt and re-arms the single-flight.
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"use-tool-result-recovery.js","sourceRoot":"","sources":["../../src/hooks/use-tool-result-recovery.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,SAAS,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,OAAO,CAAA;AACnD,OAAO,EAAE,eAAe,EAAE,MAAM,6BAA6B,CAAA;AAE7D
|
|
1
|
+
{"version":3,"file":"use-tool-result-recovery.js","sourceRoot":"","sources":["../../src/hooks/use-tool-result-recovery.ts"],"names":[],"mappings":"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"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@miragon/mcp-toolkit-ui",
|
|
3
|
-
"version": "2.
|
|
3
|
+
"version": "2.5.0",
|
|
4
4
|
"description": "React UI for MCP servers: shadcn primitives, composite components, TanStack Query hooks, and the MCP App shell (McpAppView + WidgetRenderer).",
|
|
5
5
|
"repository": {
|
|
6
6
|
"type": "git",
|
|
@@ -38,37 +38,37 @@
|
|
|
38
38
|
"access": "public"
|
|
39
39
|
},
|
|
40
40
|
"peerDependencies": {
|
|
41
|
-
"mcp-use": "2.
|
|
41
|
+
"mcp-use": "2.7.1",
|
|
42
42
|
"react": "^19.2.0",
|
|
43
43
|
"react-dom": "^19.2.0",
|
|
44
44
|
"tailwindcss": "^4.3.0",
|
|
45
|
-
"@miragon/mcp-toolkit-core": "~2.
|
|
45
|
+
"@miragon/mcp-toolkit-core": "~2.5.0"
|
|
46
46
|
},
|
|
47
47
|
"dependencies": {
|
|
48
48
|
"@base-ui/react": "1.8.0",
|
|
49
49
|
"@fontsource-variable/geist": "5.3.0",
|
|
50
|
-
"@tanstack/react-query": "5.
|
|
50
|
+
"@tanstack/react-query": "5.103.2",
|
|
51
51
|
"class-variance-authority": "0.7.1",
|
|
52
52
|
"clsx": "2.1.1",
|
|
53
|
-
"lucide-react": "1.
|
|
53
|
+
"lucide-react": "1.47.0",
|
|
54
54
|
"radix-ui": "1.6.7",
|
|
55
|
-
"tailwind-merge": "3.
|
|
55
|
+
"tailwind-merge": "3.7.0",
|
|
56
56
|
"tw-animate-css": "1.4.0"
|
|
57
57
|
},
|
|
58
58
|
"devDependencies": {
|
|
59
59
|
"@stryker-mutator/core": "10.0.0",
|
|
60
60
|
"@stryker-mutator/vitest-runner": "10.0.0",
|
|
61
|
-
"@types/react": "19.
|
|
62
|
-
"@types/react-dom": "19.
|
|
63
|
-
"@vitest/coverage-v8": "
|
|
64
|
-
"fast-check": "4.
|
|
65
|
-
"mcp-use": "2.
|
|
66
|
-
"react": "19.
|
|
67
|
-
"react-dom": "19.
|
|
61
|
+
"@types/react": "19.3.0",
|
|
62
|
+
"@types/react-dom": "19.3.0",
|
|
63
|
+
"@vitest/coverage-v8": "5.0.1",
|
|
64
|
+
"fast-check": "4.10.2",
|
|
65
|
+
"mcp-use": "2.7.1",
|
|
66
|
+
"react": "19.3.0",
|
|
67
|
+
"react-dom": "19.3.0",
|
|
68
68
|
"tailwindcss": "4.3.3",
|
|
69
69
|
"typescript": "6.0.3",
|
|
70
|
-
"vitest": "
|
|
71
|
-
"@miragon/mcp-toolkit-core": "2.
|
|
70
|
+
"vitest": "5.0.1",
|
|
71
|
+
"@miragon/mcp-toolkit-core": "2.5.0"
|
|
72
72
|
},
|
|
73
73
|
"engines": {
|
|
74
74
|
"node": ">=22.22.2"
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
import { renderToStaticMarkup } from "react-dom/server"
|
|
2
|
+
import { describe, expect, it } from "vitest"
|
|
3
|
+
import { DEFAULT_LABELS, ViewPlaceholder } from "./mcp-app-view-chrome.js"
|
|
4
|
+
|
|
5
|
+
describe("ViewPlaceholder", () => {
|
|
6
|
+
it("shows the loading skeleton while the rendering call is still open", () => {
|
|
7
|
+
const html = renderToStaticMarkup(<ViewPlaceholder cancelled={false} labels={DEFAULT_LABELS} />)
|
|
8
|
+
expect(html).toContain('data-slot="skeleton"')
|
|
9
|
+
expect(html).toContain(DEFAULT_LABELS.loading)
|
|
10
|
+
expect(html).not.toContain(DEFAULT_LABELS.cancelled)
|
|
11
|
+
})
|
|
12
|
+
|
|
13
|
+
it("replaces the skeleton with the cancellation notice once the host cancelled the call", () => {
|
|
14
|
+
const html = renderToStaticMarkup(<ViewPlaceholder cancelled labels={DEFAULT_LABELS} />)
|
|
15
|
+
expect(html).toContain(DEFAULT_LABELS.cancelled)
|
|
16
|
+
expect(html).not.toContain('data-slot="skeleton"')
|
|
17
|
+
expect(html).not.toContain(DEFAULT_LABELS.loading)
|
|
18
|
+
})
|
|
19
|
+
|
|
20
|
+
it("renders the consumer's label override", () => {
|
|
21
|
+
const labels = { ...DEFAULT_LABELS, cancelled: "Abgebrochen." }
|
|
22
|
+
const html = renderToStaticMarkup(<ViewPlaceholder cancelled labels={labels} />)
|
|
23
|
+
expect(html).toContain("Abgebrochen.")
|
|
24
|
+
})
|
|
25
|
+
})
|
|
@@ -1,16 +1,20 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* Presentational chrome for `McpAppView` — the
|
|
3
|
-
* list, and the build/render body — plus the
|
|
2
|
+
* Presentational chrome for `McpAppView` — the pre-payload placeholder, the
|
|
3
|
+
* toolbar, the pipeline error list, and the build/render body — plus the
|
|
4
|
+
* view-envelope types they share.
|
|
4
5
|
* Split out of `mcp-app-view.tsx` so the shell component keeps only the
|
|
5
6
|
* host-sync and state logic while this file stays hook-free.
|
|
6
7
|
*/
|
|
7
8
|
import { Maximize2, Minimize2, Pencil, RefreshCw } from "lucide-react"
|
|
8
9
|
import type { LayoutConfig, PipelineStepRef } from "@miragon/mcp-toolkit-core"
|
|
10
|
+
import { Skeleton } from "../primitives/skeleton.js"
|
|
9
11
|
import { LayoutBuilder, type LayoutBuilderProps } from "./layout-builder.js"
|
|
10
12
|
import { WidgetRenderer, type WidgetComponent } from "./widget-renderer.js"
|
|
11
13
|
|
|
12
14
|
export interface McpAppViewLabels {
|
|
13
15
|
loading?: string
|
|
16
|
+
/** Shown instead of the loading skeleton when the host cancelled the rendering tool call. */
|
|
17
|
+
cancelled?: string
|
|
14
18
|
refresh?: string
|
|
15
19
|
refreshing?: string
|
|
16
20
|
enterFullscreen?: string
|
|
@@ -20,6 +24,7 @@ export interface McpAppViewLabels {
|
|
|
20
24
|
|
|
21
25
|
export const DEFAULT_LABELS: Required<McpAppViewLabels> = {
|
|
22
26
|
loading: "Waiting for pipeline result...",
|
|
27
|
+
cancelled: "Tool call was cancelled.",
|
|
23
28
|
refresh: "Refresh",
|
|
24
29
|
refreshing: "Loading...",
|
|
25
30
|
enterFullscreen: "Fullscreen",
|
|
@@ -66,6 +71,34 @@ export function isCompleteViewData(value: unknown): value is ViewData {
|
|
|
66
71
|
return Boolean(v?.context && v?.layout)
|
|
67
72
|
}
|
|
68
73
|
|
|
74
|
+
// -------------------------------------------------------------------------- //
|
|
75
|
+
// Placeholder: shown until a view payload exists
|
|
76
|
+
// -------------------------------------------------------------------------- //
|
|
77
|
+
|
|
78
|
+
export function ViewPlaceholder({
|
|
79
|
+
cancelled,
|
|
80
|
+
labels,
|
|
81
|
+
}: {
|
|
82
|
+
/** The host cancelled the rendering call — no payload will arrive. */
|
|
83
|
+
cancelled: boolean
|
|
84
|
+
labels: Required<McpAppViewLabels>
|
|
85
|
+
}) {
|
|
86
|
+
if (cancelled) {
|
|
87
|
+
return (
|
|
88
|
+
<div className="p-4">
|
|
89
|
+
<p className="text-muted-foreground text-sm">{labels.cancelled}</p>
|
|
90
|
+
</div>
|
|
91
|
+
)
|
|
92
|
+
}
|
|
93
|
+
return (
|
|
94
|
+
<div className="flex flex-col gap-4 p-4">
|
|
95
|
+
<Skeleton className="h-8 w-48" />
|
|
96
|
+
<Skeleton className="h-32 w-full" />
|
|
97
|
+
<p className="text-muted-foreground text-sm">{labels.loading}</p>
|
|
98
|
+
</div>
|
|
99
|
+
)
|
|
100
|
+
}
|
|
101
|
+
|
|
69
102
|
// -------------------------------------------------------------------------- //
|
|
70
103
|
// Toolbar
|
|
71
104
|
// -------------------------------------------------------------------------- //
|
package/src/app/mcp-app-view.tsx
CHANGED
|
@@ -1,7 +1,6 @@
|
|
|
1
1
|
import { useState, useCallback } from "react"
|
|
2
|
-
import { useDisplayMode, useHostContext, useToolContext } from "mcp-use/react"
|
|
2
|
+
import { ToolCancelledError, useDisplayMode, useHostContext, useToolContext } from "mcp-use/react"
|
|
3
3
|
import type { LayoutConfig, PipelineStepRef } from "@miragon/mcp-toolkit-core"
|
|
4
|
-
import { Skeleton } from "../primitives/skeleton.js"
|
|
5
4
|
import { AppQueryProvider, queryClient } from "../providers/query-provider.js"
|
|
6
5
|
import { useToolResultRecovery } from "../hooks/use-tool-result-recovery.js"
|
|
7
6
|
import { parseToolResult } from "../lib/parse-tool-result.js"
|
|
@@ -11,6 +10,7 @@ import {
|
|
|
11
10
|
isCompleteViewData,
|
|
12
11
|
StepErrors,
|
|
13
12
|
ViewBody,
|
|
13
|
+
ViewPlaceholder,
|
|
14
14
|
ViewToolbar,
|
|
15
15
|
type McpAppViewLabels,
|
|
16
16
|
type ViewData,
|
|
@@ -73,6 +73,10 @@ export function McpAppView({
|
|
|
73
73
|
)
|
|
74
74
|
|
|
75
75
|
const isPending = tool.status === "pending"
|
|
76
|
+
// Since mcp-use 2.7.1 a host cancellation of the rendering call latches as a
|
|
77
|
+
// terminal `status: "error"` — show it instead of the skeleton, and never
|
|
78
|
+
// let the recovery below re-run the call the user stopped.
|
|
79
|
+
const isCancelled = tool.status === "error" && tool.error instanceof ToolCancelledError
|
|
76
80
|
const initialViewData = tool.status === "ready" ? (tool.toolOutput as ViewData) : undefined
|
|
77
81
|
const toolInput = tool.toolInput
|
|
78
82
|
|
|
@@ -114,6 +118,7 @@ export function McpAppView({
|
|
|
114
118
|
// there.
|
|
115
119
|
const recovery = useToolResultRecovery<ViewData>({
|
|
116
120
|
resultReady: !isPending,
|
|
121
|
+
cancelled: isCancelled,
|
|
117
122
|
props: initialViewData,
|
|
118
123
|
isValid: isCompleteViewData,
|
|
119
124
|
toolInput,
|
|
@@ -207,13 +212,7 @@ export function McpAppView({
|
|
|
207
212
|
// `structuredContent` the 2.x latch stays "pending" forever, and recovered
|
|
208
213
|
// viewData still has to replace the skeleton.
|
|
209
214
|
if (!viewData) {
|
|
210
|
-
return
|
|
211
|
-
<div className="flex flex-col gap-4 p-4">
|
|
212
|
-
<Skeleton className="h-8 w-48" />
|
|
213
|
-
<Skeleton className="h-32 w-full" />
|
|
214
|
-
<p className="text-muted-foreground text-sm">{effectiveLabels.loading}</p>
|
|
215
|
-
</div>
|
|
216
|
-
)
|
|
215
|
+
return <ViewPlaceholder cancelled={isCancelled} labels={effectiveLabels} />
|
|
217
216
|
}
|
|
218
217
|
|
|
219
218
|
const isFullscreen = displayMode === "fullscreen"
|
|
@@ -20,6 +20,11 @@ import { parseToolResult } from "../lib/parse-tool-result.js"
|
|
|
20
20
|
* decoded payload. Spec-conforming hosts (e.g. the mcp-use inspector) deliver
|
|
21
21
|
* a valid payload up front, so the recovery never fires there.
|
|
22
22
|
*
|
|
23
|
+
* A call the host cancelled is never recovered: since mcp-use 2.7.1 the
|
|
24
|
+
* cancellation latches as `status: "error"` (a `ToolCancelledError`), which
|
|
25
|
+
* would otherwise count as a ready-but-invalid result — re-executing it would
|
|
26
|
+
* override the user's decision to stop the call.
|
|
27
|
+
*
|
|
23
28
|
* Assumes the originating tool is a read-only render pipeline (true for all
|
|
24
29
|
* toolkit `render-view`/`show_*` tools) — the re-execution must be safe to
|
|
25
30
|
* repeat, and may rarely run concurrently with the original invocation when
|
|
@@ -37,10 +42,17 @@ export const DEFAULT_ASSUME_STRIPPED_AFTER_MS = 2500
|
|
|
37
42
|
export interface ToolResultRecoveryOptions {
|
|
38
43
|
/**
|
|
39
44
|
* The latch fired (`useToolContext().status !== "pending"`) — a structured
|
|
40
|
-
* result
|
|
41
|
-
* this never turns true; the grace timer below covers
|
|
45
|
+
* result, a tool error, or a host cancellation arrived. On hosts that strip
|
|
46
|
+
* `structuredContent` this never turns true; the grace timer below covers
|
|
47
|
+
* that case.
|
|
42
48
|
*/
|
|
43
49
|
resultReady: boolean
|
|
50
|
+
/**
|
|
51
|
+
* The host cancelled the originating call (`useToolContext().error` is a
|
|
52
|
+
* `ToolCancelledError`). Suppresses the recovery: nothing fires, and an
|
|
53
|
+
* attempt already in flight is dropped. Defaults to `false`.
|
|
54
|
+
*/
|
|
55
|
+
cancelled?: boolean
|
|
44
56
|
/** The payload the host delivered (`useToolContext().toolOutput`). */
|
|
45
57
|
props: unknown
|
|
46
58
|
/**
|
|
@@ -117,6 +129,7 @@ export function useToolResultRecovery<T>(
|
|
|
117
129
|
): ToolResultRecoveryState<T> {
|
|
118
130
|
const {
|
|
119
131
|
resultReady,
|
|
132
|
+
cancelled = false,
|
|
120
133
|
props,
|
|
121
134
|
isValid,
|
|
122
135
|
toolInput,
|
|
@@ -148,12 +161,14 @@ export function useToolResultRecovery<T>(
|
|
|
148
161
|
if (assumedReady) setAssumedReady(false)
|
|
149
162
|
}
|
|
150
163
|
useEffect(() => {
|
|
151
|
-
if (resultReady || toolName === undefined) return
|
|
164
|
+
if (resultReady || cancelled || toolName === undefined) return
|
|
152
165
|
const timer = setTimeout(() => setAssumedReady(true), assumeStrippedAfterMs)
|
|
153
166
|
return () => clearTimeout(timer)
|
|
154
|
-
}, [resultReady, toolName, toolInput, assumeStrippedAfterMs])
|
|
167
|
+
}, [resultReady, cancelled, toolName, toolInput, assumeStrippedAfterMs])
|
|
155
168
|
|
|
156
|
-
|
|
169
|
+
// A cancelled call never counts as ready, so the effect below invalidates
|
|
170
|
+
// any in-flight attempt the same way it does for a superseded run.
|
|
171
|
+
const ready = !cancelled && (resultReady || assumedReady)
|
|
157
172
|
|
|
158
173
|
useEffect(() => {
|
|
159
174
|
// A new tool run (result no longer ready, or fresh tool-input identity)
|