mountly-mcp 0.0.0 → 3.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (100) hide show
  1. package/LICENSE +201 -0
  2. package/README.md +258 -20
  3. package/dist/artifact/index.d.ts +49 -0
  4. package/dist/artifact/index.js +21 -0
  5. package/dist/artifact/index.js.map +1 -0
  6. package/dist/bridge/iframe-entry.d.ts +1 -0
  7. package/dist/bridge/iframe-entry.js +251 -209
  8. package/dist/bridge/index.d.ts +17 -12
  9. package/dist/bridge/index.js +2 -2
  10. package/dist/build/emit-html.d.ts +30 -0
  11. package/dist/build/emit-meta.d.ts +17 -0
  12. package/dist/build/index.d.ts +32 -47
  13. package/dist/build/index.js +9 -135
  14. package/dist/build/index.js.map +1 -1
  15. package/dist/chunk-33DMFKKD.js +111 -0
  16. package/dist/chunk-33DMFKKD.js.map +1 -0
  17. package/dist/chunk-4HC3OWAQ.js +185 -0
  18. package/dist/chunk-4HC3OWAQ.js.map +1 -0
  19. package/dist/chunk-4WAKOYMK.js +196 -0
  20. package/dist/chunk-4WAKOYMK.js.map +1 -0
  21. package/dist/chunk-5EHNJCMF.js +58 -0
  22. package/dist/chunk-5EHNJCMF.js.map +1 -0
  23. package/dist/chunk-6QHKKFO3.js +30 -0
  24. package/dist/chunk-6QHKKFO3.js.map +1 -0
  25. package/dist/chunk-DKK26TRS.js +199 -0
  26. package/dist/chunk-DKK26TRS.js.map +1 -0
  27. package/dist/{chunk-A64ZILAS.js → chunk-DQLQOMDM.js} +2 -1
  28. package/dist/{chunk-A64ZILAS.js.map → chunk-DQLQOMDM.js.map} +1 -1
  29. package/dist/chunk-KRAS266U.js +260 -0
  30. package/dist/chunk-KRAS266U.js.map +1 -0
  31. package/dist/chunk-NLQDVNZP.js +115 -0
  32. package/dist/chunk-NLQDVNZP.js.map +1 -0
  33. package/dist/chunk-SNWNF2XI.js +171 -0
  34. package/dist/chunk-SNWNF2XI.js.map +1 -0
  35. package/dist/chunk-UECZA34Q.js +52 -0
  36. package/dist/chunk-UECZA34Q.js.map +1 -0
  37. package/dist/chunk-YJA4H6IB.js +13 -0
  38. package/dist/chunk-YJA4H6IB.js.map +1 -0
  39. package/dist/cli.d.ts +2 -0
  40. package/dist/cli.js +286 -0
  41. package/dist/cli.js.map +1 -0
  42. package/dist/connect-server-7L4HGKKL.js +7 -0
  43. package/dist/connect-server-7L4HGKKL.js.map +1 -0
  44. package/dist/dev/connect-server.d.ts +13 -0
  45. package/dist/dev/host-entry.d.ts +13 -0
  46. package/dist/dev/host-entry.js +18330 -0
  47. package/dist/dev/index.d.ts +45 -0
  48. package/dist/dev/index.js +14 -0
  49. package/dist/dev/index.js.map +1 -0
  50. package/dist/dev/sandbox-entry.d.ts +7 -0
  51. package/dist/dev/sandbox-entry.js +80 -0
  52. package/dist/html.d.ts +4 -0
  53. package/dist/index.d.ts +6 -26
  54. package/dist/index.js +8 -3
  55. package/dist/json-render/app.d.ts +22 -0
  56. package/dist/json-render/app.js +10 -0
  57. package/dist/json-render/app.js.map +1 -0
  58. package/dist/json-render/index.d.ts +10 -0
  59. package/dist/json-render/index.js +119 -0
  60. package/dist/json-render/index.js.map +1 -0
  61. package/dist/json-render/mcp.d.ts +49 -0
  62. package/dist/json-render/mcp.js +11 -0
  63. package/dist/json-render/mcp.js.map +1 -0
  64. package/dist/json-render/server.d.ts +72 -0
  65. package/dist/json-render/server.js +98 -0
  66. package/dist/json-render/server.js.map +1 -0
  67. package/dist/json-render/spec-stream.d.ts +26 -0
  68. package/dist/json-render/use-spec-stream.d.ts +26 -0
  69. package/dist/json-render/widget.d.ts +59 -0
  70. package/dist/react/context.d.ts +14 -0
  71. package/dist/react/create-widget.d.ts +11 -0
  72. package/dist/react/hooks.d.ts +46 -0
  73. package/dist/react/index.d.ts +3 -0
  74. package/dist/react/index.js +35 -0
  75. package/dist/react/index.js.map +1 -0
  76. package/dist/sandbox/index.d.ts +16 -0
  77. package/dist/sandbox/index.js +8 -0
  78. package/dist/sandbox/index.js.map +1 -0
  79. package/dist/schema.d.ts +20 -0
  80. package/dist/server/index.d.ts +73 -0
  81. package/dist/server/index.js +235 -0
  82. package/dist/server/index.js.map +1 -0
  83. package/dist/svelte/index.d.ts +35 -0
  84. package/dist/svelte/index.js +9 -0
  85. package/dist/svelte/index.js.map +1 -0
  86. package/dist/testing/index.d.ts +27 -0
  87. package/dist/testing/index.js +312 -0
  88. package/dist/testing/index.js.map +1 -0
  89. package/dist/testing/render-artifact.d.ts +35 -0
  90. package/dist/types.d.ts +55 -0
  91. package/dist/vite/index.d.ts +23 -0
  92. package/dist/vite/index.js +211 -0
  93. package/dist/vite/index.js.map +1 -0
  94. package/dist/vue/index.d.ts +56 -0
  95. package/dist/vue/index.js +89 -0
  96. package/dist/vue/index.js.map +1 -0
  97. package/package.json +166 -20
  98. package/dist/chunk-BUGGLMNA.js +0 -132
  99. package/dist/chunk-BUGGLMNA.js.map +0 -1
  100. package/dist/types-B9JAWm4W.d.ts +0 -62
@@ -0,0 +1,115 @@
1
+ // src/react/context.ts
2
+ import { createContext } from "react";
3
+ var McpContext = createContext(null);
4
+ McpContext.displayName = "McpContext";
5
+
6
+ // src/react/hooks.ts
7
+ import { useContext } from "react";
8
+ import {
9
+ useAutoResize as useAutoResizeBase,
10
+ useDocumentTheme as useDocumentThemeBase,
11
+ useHostFonts as useHostFontsBase,
12
+ useHostStyleVariables as useHostStyleVariablesBase,
13
+ useHostStyles as useHostStylesBase
14
+ } from "@modelcontextprotocol/ext-apps/react";
15
+ function useEnsuredContext() {
16
+ const ctx = useContext(McpContext);
17
+ if (!ctx) {
18
+ throw new Error(
19
+ "mountly-mcp/react: useMcpHost/useToolInput/etc must be used inside a widget wrapped with createMcpWidget()."
20
+ );
21
+ }
22
+ return ctx;
23
+ }
24
+ function useMcpHost() {
25
+ return useEnsuredContext().app;
26
+ }
27
+ function useToolInput() {
28
+ return useEnsuredContext().toolInput;
29
+ }
30
+ function useToolInputPartial() {
31
+ return useEnsuredContext().toolInputPartial;
32
+ }
33
+ function useToolResult() {
34
+ return useEnsuredContext().toolResult;
35
+ }
36
+ function useHostContext() {
37
+ return useEnsuredContext().hostContext;
38
+ }
39
+ function useDisplayMode() {
40
+ return useHostContext()?.displayMode;
41
+ }
42
+ function useRequestDisplayMode() {
43
+ const { app, hostContext } = useEnsuredContext();
44
+ return async (mode) => {
45
+ const available = hostContext?.availableDisplayModes;
46
+ if (available && !available.includes(mode)) return hostContext?.displayMode;
47
+ const result = await app.requestDisplayMode({ mode });
48
+ return result.mode;
49
+ };
50
+ }
51
+ function useHostStyleVariables() {
52
+ const { app, hostContext } = useEnsuredContext();
53
+ useHostStyleVariablesBase(app, hostContext ?? null);
54
+ }
55
+ function useHostFonts() {
56
+ const { app, hostContext } = useEnsuredContext();
57
+ useHostFontsBase(app, hostContext ?? null);
58
+ }
59
+ function useHostStyles() {
60
+ const { app, hostContext } = useEnsuredContext();
61
+ useHostStylesBase(app, hostContext ?? null);
62
+ }
63
+ function useDocumentTheme() {
64
+ return useDocumentThemeBase();
65
+ }
66
+ function useUpdateModelContext() {
67
+ const { app } = useEnsuredContext();
68
+ return async (params) => {
69
+ await app.updateModelContext(params);
70
+ };
71
+ }
72
+ function useAutoResize(...args) {
73
+ return useAutoResizeBase(...args);
74
+ }
75
+
76
+ // src/react/create-widget.ts
77
+ import { createElement } from "react";
78
+ import { createWidget } from "mountly-react";
79
+ function createMcpWidget(Component, options) {
80
+ const Wrapped = (props) => {
81
+ const { mcp, toolInput, toolInputPartial, toolResult, hostContext, ...rest } = props;
82
+ const value = {
83
+ app: mcp,
84
+ toolInput,
85
+ toolInputPartial,
86
+ toolResult,
87
+ hostContext
88
+ };
89
+ return createElement(
90
+ McpContext.Provider,
91
+ { value },
92
+ createElement(Component, rest)
93
+ );
94
+ };
95
+ return createWidget(Wrapped, options);
96
+ }
97
+
98
+ export {
99
+ McpContext,
100
+ useMcpHost,
101
+ useToolInput,
102
+ useToolInputPartial,
103
+ useToolResult,
104
+ useHostContext,
105
+ useDisplayMode,
106
+ useRequestDisplayMode,
107
+ useHostStyleVariables,
108
+ useHostFonts,
109
+ useHostStyles,
110
+ useDocumentTheme,
111
+ useUpdateModelContext,
112
+ useAutoResize,
113
+ createMcpWidget
114
+ };
115
+ //# sourceMappingURL=chunk-NLQDVNZP.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/react/context.ts","../src/react/hooks.ts","../src/react/create-widget.ts"],"sourcesContent":["import { createContext } from \"react\";\nimport type {\n App,\n McpUiHostContext,\n McpUiToolInputNotification,\n McpUiToolInputPartialNotification,\n McpUiToolResultNotification,\n} from \"@modelcontextprotocol/ext-apps\";\n\n/**\n * Shared per-widget context. The bridge populates this on each mount/update,\n * so consumers can synchronously read the initial values (no event subscription\n * race) and the React tree re-renders when the bridge calls `update()`.\n */\nexport interface McpContextValue {\n app: App;\n toolInput?: McpUiToolInputNotification[\"params\"];\n toolInputPartial?: McpUiToolInputPartialNotification[\"params\"];\n toolResult?: McpUiToolResultNotification[\"params\"];\n hostContext?: McpUiHostContext;\n}\n\nexport const McpContext = createContext<McpContextValue | null>(null);\nMcpContext.displayName = \"McpContext\";\n","import { useContext } from \"react\";\nimport {\n useAutoResize as useAutoResizeBase,\n useDocumentTheme as useDocumentThemeBase,\n useHostFonts as useHostFontsBase,\n useHostStyleVariables as useHostStyleVariablesBase,\n useHostStyles as useHostStylesBase,\n} from \"@modelcontextprotocol/ext-apps/react\";\nimport type {\n App,\n McpUiDisplayMode,\n McpUiHostContext,\n McpUiUpdateModelContextRequest,\n} from \"@modelcontextprotocol/ext-apps\";\nimport { McpContext } from \"./context.js\";\n\nfunction useEnsuredContext() {\n const ctx = useContext(McpContext);\n if (!ctx) {\n throw new Error(\n \"mountly-mcp/react: useMcpHost/useToolInput/etc must be used inside a widget wrapped with createMcpWidget().\",\n );\n }\n return ctx;\n}\n\n/** The view-side ext-apps App. Use this to call server tools, send messages, open links, etc. */\nexport function useMcpHost(): App {\n return useEnsuredContext().app;\n}\n\n/** Complete notification params; read the tool arguments from `.arguments`. */\nexport function useToolInput<T = unknown>(): T | undefined {\n return useEnsuredContext().toolInput as T | undefined;\n}\n\n/**\n * Streaming tool arguments (`ui/notifications/tool-input-partial`), present only\n * when the bridge runs with `streamToolInput`. Best-effort recovered JSON —\n * fields may be missing or change between notifications, so render loading\n * states from it, never critical operations. Undefined once the complete\n * {@link useToolInput} arrives.\n */\nexport function useToolInputPartial<T = unknown>(): Partial<T> | undefined {\n return useEnsuredContext().toolInputPartial as Partial<T> | undefined;\n}\n\n/** Complete MCP tool result; structured data is available at `.structuredContent`. */\nexport function useToolResult<T = unknown>(): T | undefined {\n return useEnsuredContext().toolResult as T | undefined;\n}\n\n/** Latest host context snapshot (theme, styles, displayMode, container dimensions, etc.). */\nexport function useHostContext(): McpUiHostContext | undefined {\n return useEnsuredContext().hostContext;\n}\n\n/** Current display mode reported by the host. */\nexport function useDisplayMode(): McpUiDisplayMode | undefined {\n return useHostContext()?.displayMode;\n}\n\n/**\n * Request a display mode change, resolving to the mode the host actually\n * applied — which the spec allows to differ from the one asked for.\n *\n * Modes the host didn't list in `availableDisplayModes` are never requested\n * (the spec requires views to check first); the current mode comes back\n * unchanged instead.\n */\nexport function useRequestDisplayMode(): (\n mode: McpUiDisplayMode,\n) => Promise<McpUiDisplayMode | undefined> {\n const { app, hostContext } = useEnsuredContext();\n return async (mode) => {\n const available = hostContext?.availableDisplayModes;\n if (available && !available.includes(mode)) return hostContext?.displayMode;\n const result = await app.requestDisplayMode({ mode });\n return result.mode;\n };\n}\n\n/** Apply host CSS variables (and react to host-context changes). */\nexport function useHostStyleVariables(): void {\n const { app, hostContext } = useEnsuredContext();\n useHostStyleVariablesBase(app, hostContext ?? null);\n}\n\n/** Apply host-provided `@font-face`/`@import` rules. */\nexport function useHostFonts(): void {\n const { app, hostContext } = useEnsuredContext();\n useHostFontsBase(app, hostContext ?? null);\n}\n\n/** One-shot helper: apply both host style variables and host fonts. */\nexport function useHostStyles(): void {\n const { app, hostContext } = useEnsuredContext();\n useHostStylesBase(app, hostContext ?? null);\n}\n\n/** Track the document theme reactively. */\nexport function useDocumentTheme() {\n return useDocumentThemeBase();\n}\n\n/**\n * Return a function that calls `app.updateModelContext(params)`.\n *\n * Context updates are available to the model in future turns without\n * triggering an immediate response. Only the last update is kept.\n */\nexport function useUpdateModelContext(): (\n params: McpUiUpdateModelContextRequest[\"params\"],\n) => Promise<void> {\n const { app } = useEnsuredContext();\n return async (params) => {\n await app.updateModelContext(params);\n };\n}\n\n/** Manually control auto-resize (rarely needed — the bridge calls setupSizeChangedNotifications by default). */\nexport function useAutoResize(...args: Parameters<typeof useAutoResizeBase>) {\n return useAutoResizeBase(...args);\n}\n","import { createElement, type ComponentType } from \"react\";\nimport { createWidget } from \"mountly-react\";\nimport type { AdapterOptions, WidgetModule } from \"mountly/adapter\";\nimport type { McpWidgetProps } from \"../index.js\";\nimport { McpContext, type McpContextValue } from \"./context.js\";\n\n/**\n * Wraps a React component as a mountly `WidgetModule` driven by the\n * mountly-mcp bridge. The bridge passes spec-defined props\n * (`mcp` / `toolInput` / `toolResult` / `hostContext`) on each `mount` /\n * `update`. The wrapper consumes those bridge props and exposes them through\n * `useMcpHost()` and the other hooks from `mountly-mcp/react`; the wrapped\n * component's own props remain unchanged.\n */\nexport function createMcpWidget<P extends object>(\n Component: ComponentType<P>,\n options?: AdapterOptions,\n): WidgetModule {\n const Wrapped = (props: P & McpWidgetProps) => {\n const { mcp, toolInput, toolInputPartial, toolResult, hostContext, ...rest } =\n props as McpWidgetProps & P;\n const value: McpContextValue = {\n app: mcp,\n toolInput,\n toolInputPartial,\n toolResult,\n hostContext,\n };\n return createElement(\n McpContext.Provider,\n { value },\n createElement(Component as ComponentType, rest as P),\n );\n };\n return createWidget(Wrapped as ComponentType<P & McpWidgetProps>, options);\n}\n"],"mappings":";AAAA,SAAS,qBAAqB;AAsBvB,IAAM,aAAa,cAAsC,IAAI;AACpE,WAAW,cAAc;;;ACvBzB,SAAS,kBAAkB;AAC3B;AAAA,EACE,iBAAiB;AAAA,EACjB,oBAAoB;AAAA,EACpB,gBAAgB;AAAA,EAChB,yBAAyB;AAAA,EACzB,iBAAiB;AAAA,OACZ;AASP,SAAS,oBAAoB;AAC3B,QAAM,MAAM,WAAW,UAAU;AACjC,MAAI,CAAC,KAAK;AACR,UAAM,IAAI;AAAA,MACR;AAAA,IACF;AAAA,EACF;AACA,SAAO;AACT;AAGO,SAAS,aAAkB;AAChC,SAAO,kBAAkB,EAAE;AAC7B;AAGO,SAAS,eAA2C;AACzD,SAAO,kBAAkB,EAAE;AAC7B;AASO,SAAS,sBAA2D;AACzE,SAAO,kBAAkB,EAAE;AAC7B;AAGO,SAAS,gBAA4C;AAC1D,SAAO,kBAAkB,EAAE;AAC7B;AAGO,SAAS,iBAA+C;AAC7D,SAAO,kBAAkB,EAAE;AAC7B;AAGO,SAAS,iBAA+C;AAC7D,SAAO,eAAe,GAAG;AAC3B;AAUO,SAAS,wBAE2B;AACzC,QAAM,EAAE,KAAK,YAAY,IAAI,kBAAkB;AAC/C,SAAO,OAAO,SAAS;AACrB,UAAM,YAAY,aAAa;AAC/B,QAAI,aAAa,CAAC,UAAU,SAAS,IAAI,EAAG,QAAO,aAAa;AAChE,UAAM,SAAS,MAAM,IAAI,mBAAmB,EAAE,KAAK,CAAC;AACpD,WAAO,OAAO;AAAA,EAChB;AACF;AAGO,SAAS,wBAA8B;AAC5C,QAAM,EAAE,KAAK,YAAY,IAAI,kBAAkB;AAC/C,4BAA0B,KAAK,eAAe,IAAI;AACpD;AAGO,SAAS,eAAqB;AACnC,QAAM,EAAE,KAAK,YAAY,IAAI,kBAAkB;AAC/C,mBAAiB,KAAK,eAAe,IAAI;AAC3C;AAGO,SAAS,gBAAsB;AACpC,QAAM,EAAE,KAAK,YAAY,IAAI,kBAAkB;AAC/C,oBAAkB,KAAK,eAAe,IAAI;AAC5C;AAGO,SAAS,mBAAmB;AACjC,SAAO,qBAAqB;AAC9B;AAQO,SAAS,wBAEG;AACjB,QAAM,EAAE,IAAI,IAAI,kBAAkB;AAClC,SAAO,OAAO,WAAW;AACvB,UAAM,IAAI,mBAAmB,MAAM;AAAA,EACrC;AACF;AAGO,SAAS,iBAAiB,MAA4C;AAC3E,SAAO,kBAAkB,GAAG,IAAI;AAClC;;;AC3HA,SAAS,qBAAyC;AAClD,SAAS,oBAAoB;AAatB,SAAS,gBACd,WACA,SACc;AACd,QAAM,UAAU,CAAC,UAA8B;AAC7C,UAAM,EAAE,KAAK,WAAW,kBAAkB,YAAY,aAAa,GAAG,KAAK,IACzE;AACF,UAAM,QAAyB;AAAA,MAC7B,KAAK;AAAA,MACL;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,IACF;AACA,WAAO;AAAA,MACL,WAAW;AAAA,MACX,EAAE,MAAM;AAAA,MACR,cAAc,WAA4B,IAAS;AAAA,IACrD;AAAA,EACF;AACA,SAAO,aAAa,SAA8C,OAAO;AAC3E;","names":[]}
@@ -0,0 +1,171 @@
1
+ import {
2
+ MCP_ERROR_CODES
3
+ } from "./chunk-DQLQOMDM.js";
4
+
5
+ // src/bridge/index.ts
6
+ import {
7
+ App,
8
+ PostMessageTransport
9
+ } from "@modelcontextprotocol/ext-apps";
10
+ function renderErrorBoundary(container, code, message) {
11
+ container.setAttribute("data-mountly-mcp-state", "error");
12
+ const doc = container.ownerDocument;
13
+ if (!doc) return;
14
+ const errorDiv = doc.createElement("div");
15
+ errorDiv.setAttribute("data-mountly-mcp-error", code);
16
+ if (message !== void 0) errorDiv.textContent = message;
17
+ container.innerHTML = "";
18
+ container.appendChild(errorDiv);
19
+ }
20
+ function runBridge(options) {
21
+ const {
22
+ widget,
23
+ container,
24
+ awaitToolResult = true,
25
+ streamToolInput = false,
26
+ availableDisplayModes = ["inline"],
27
+ appInfo = { name: "mountly-mcp", version: "0.0.0" }
28
+ } = options;
29
+ const appCapabilities = {
30
+ availableDisplayModes: [...availableDisplayModes]
31
+ };
32
+ const app = options.app ?? new App(appInfo, appCapabilities);
33
+ let toolInput;
34
+ let toolInputPartial;
35
+ let toolResult;
36
+ let mounted = false;
37
+ let stopped = false;
38
+ let pending = Promise.resolve();
39
+ function currentProps() {
40
+ return {
41
+ mcp: app,
42
+ toolInput,
43
+ toolInputPartial,
44
+ toolResult,
45
+ hostContext: app.getHostContext()
46
+ };
47
+ }
48
+ function notifyError(code, error) {
49
+ const message = error instanceof Error ? error.message : String(error);
50
+ try {
51
+ void app.sendLog({ level: "error", data: { code, message } }).catch(() => void 0);
52
+ } catch {
53
+ }
54
+ renderErrorBoundary(container, code, message);
55
+ }
56
+ function renderWith(props) {
57
+ pending = pending.then(async () => {
58
+ if (stopped) return;
59
+ try {
60
+ if (!mounted) {
61
+ const r = widget.mount(container, props);
62
+ if (r instanceof Promise) await r;
63
+ mounted = true;
64
+ container.setAttribute("data-mountly-mcp-state", "mounted");
65
+ } else if (widget.update) {
66
+ const r = widget.update(container, props);
67
+ if (r instanceof Promise) await r;
68
+ } else {
69
+ await widget.unmount(container);
70
+ mounted = false;
71
+ const r = widget.mount(container, props);
72
+ if (r instanceof Promise) await r;
73
+ mounted = true;
74
+ }
75
+ } catch (error) {
76
+ notifyError(MCP_ERROR_CODES.WIDGET_MOUNT_THREW, error);
77
+ }
78
+ });
79
+ return pending;
80
+ }
81
+ async function unmountWidget() {
82
+ await pending;
83
+ if (!mounted) return;
84
+ mounted = false;
85
+ await widget.unmount(container);
86
+ }
87
+ const handleToolInput = (params) => {
88
+ toolInput = params;
89
+ toolInputPartial = void 0;
90
+ if (!awaitToolResult) return;
91
+ if (mounted || toolResult !== void 0) void renderWith(currentProps());
92
+ };
93
+ const handleToolInputPartial = (params) => {
94
+ if (!streamToolInput) return;
95
+ toolInputPartial = params;
96
+ void renderWith(currentProps());
97
+ };
98
+ const handleToolResult = (params) => {
99
+ toolResult = params;
100
+ void renderWith(currentProps());
101
+ };
102
+ const handleToolCancelled = () => {
103
+ void renderWith(currentProps());
104
+ };
105
+ const handleHostContextChanged = () => {
106
+ if (mounted) void renderWith(currentProps());
107
+ };
108
+ app.addEventListener("toolinput", handleToolInput);
109
+ app.addEventListener("toolinputpartial", handleToolInputPartial);
110
+ app.addEventListener("toolresult", handleToolResult);
111
+ app.addEventListener("toolcancelled", handleToolCancelled);
112
+ app.addEventListener("hostcontextchanged", handleHostContextChanged);
113
+ const previousTeardown = app.onteardown;
114
+ const bridgeTeardown = async (params, extra) => {
115
+ stopped = true;
116
+ detachTeardown();
117
+ detachAppHandlers();
118
+ await unmountWidget();
119
+ return await previousTeardown?.(params, extra) ?? {};
120
+ };
121
+ app.onteardown = bridgeTeardown;
122
+ function detachAppHandlers() {
123
+ app.removeEventListener("toolinput", handleToolInput);
124
+ app.removeEventListener("toolinputpartial", handleToolInputPartial);
125
+ app.removeEventListener("toolresult", handleToolResult);
126
+ app.removeEventListener("toolcancelled", handleToolCancelled);
127
+ app.removeEventListener("hostcontextchanged", handleHostContextChanged);
128
+ if (app.onteardown === bridgeTeardown) app.onteardown = previousTeardown;
129
+ }
130
+ const ready = (async () => {
131
+ try {
132
+ if (!options.app) {
133
+ await app.connect();
134
+ }
135
+ if (!awaitToolResult) {
136
+ await renderWith(currentProps());
137
+ }
138
+ } catch (error) {
139
+ const message = error instanceof Error ? error.message : String(error);
140
+ const code = /timeout/i.test(message) ? MCP_ERROR_CODES.INITIALIZE_TIMEOUT : MCP_ERROR_CODES.INITIALIZE_FAILED;
141
+ notifyError(code, error);
142
+ throw error;
143
+ }
144
+ })();
145
+ let detachTeardown = () => void 0;
146
+ function stopBridge() {
147
+ if (stopped) return;
148
+ stopped = true;
149
+ detachTeardown();
150
+ detachAppHandlers();
151
+ void unmountWidget();
152
+ if (!options.app) void app.close().catch(() => void 0);
153
+ }
154
+ detachTeardown = options.onTeardown?.(stopBridge) ?? (typeof window !== "undefined" ? (() => {
155
+ const h = () => stopBridge();
156
+ window.addEventListener("beforeunload", h);
157
+ return () => window.removeEventListener("beforeunload", h);
158
+ })() : () => void 0);
159
+ return {
160
+ ready,
161
+ app,
162
+ stop: stopBridge
163
+ };
164
+ }
165
+
166
+ export {
167
+ App,
168
+ PostMessageTransport,
169
+ runBridge
170
+ };
171
+ //# sourceMappingURL=chunk-SNWNF2XI.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/bridge/index.ts"],"sourcesContent":["/**\n * View-side bridge that turns an MCP Apps `App` into a mountly `WidgetModule`\n * lifecycle. The full spec handshake — `ui/initialize`,\n * `ui/notifications/initialized`, `ui/notifications/tool-input(-partial)`,\n * `ui/notifications/tool-result`, `ui/notifications/tool-cancelled`,\n * `ui/notifications/host-context-changed`, `ui/resource-teardown`,\n * `ui/notifications/size-changed` — is delegated to ext-apps's `App`.\n */\nimport {\n App,\n PostMessageTransport,\n type McpUiAppCapabilities,\n type McpUiDisplayMode,\n type McpUiToolInputNotification,\n type McpUiToolInputPartialNotification,\n type McpUiToolResultNotification,\n} from \"@modelcontextprotocol/ext-apps\";\nimport type { WidgetModule } from \"mountly/adapter\";\nimport { MCP_ERROR_CODES } from \"../schema.js\";\nimport type { McpWidgetProps } from \"../types.js\";\n\nexport interface RunBridgeOptions {\n /** Pre-constructed App (used by jsdom tests); otherwise one is created here. */\n app?: App;\n widget: WidgetModule;\n container: Element;\n /**\n * If true (default), mount is deferred until the first tool-result arrives;\n * the widget renders against `{ toolInput, toolResult, hostContext, mcp }`\n * props on each notification.\n *\n * If false, mount fires immediately after `ui/initialize` with `{ mcp }`\n * only — for \"stateless\" views that drive themselves via `mcp.callServerTool`.\n */\n awaitToolResult?: boolean;\n /**\n * Render progressive states from `ui/notifications/tool-input-partial`.\n *\n * Off by default — the spec lets views ignore partials, and they carry\n * best-effort recovered JSON that MUST NOT drive critical operations. When\n * on, partials arrive as `toolInputPartial` (mounting the widget early if\n * needed) and are cleared once the complete `tool-input` lands.\n */\n streamToolInput?: boolean;\n /** Display modes this view supports. Declared to the host during `ui/initialize`. */\n availableDisplayModes?: ReadonlyArray<McpUiDisplayMode>;\n /** App identity sent during `ui/initialize`. */\n appInfo?: { name: string; version: string };\n /** Override for tests; defaults to `window.addEventListener('beforeunload', ...)`. */\n onTeardown?: (handler: () => void) => () => void;\n}\n\nexport interface RunningBridge {\n /** Resolves once `ui/initialize` handshake completes and the first mount (or deferred mount) is wired. */\n ready: Promise<void>;\n /** The underlying App; exposed for hosts that want to drive the view directly. */\n app: App;\n /** Synchronously triggers teardown. */\n stop(): void;\n}\n\n/**\n * `data-mountly-mcp-state` is the View's machine-readable outcome, read by\n * `verify --render`. It only ever moves forward — `mounted` once the widget\n * has mounted, `error` if the boundary replaced it — so a state written here\n * can never be clobbered by a later lifecycle step.\n */\nfunction renderErrorBoundary(container: Element, code: string, message?: string): void {\n container.setAttribute(\"data-mountly-mcp-state\", \"error\");\n const doc = container.ownerDocument;\n if (!doc) return;\n const errorDiv = doc.createElement(\"div\");\n errorDiv.setAttribute(\"data-mountly-mcp-error\", code);\n if (message !== undefined) errorDiv.textContent = message;\n container.innerHTML = \"\";\n container.appendChild(errorDiv);\n}\n\nexport function runBridge(options: RunBridgeOptions): RunningBridge {\n const {\n widget,\n container,\n awaitToolResult = true,\n streamToolInput = false,\n availableDisplayModes = [\"inline\"],\n appInfo = { name: \"mountly-mcp\", version: \"0.0.0\" },\n } = options;\n\n const appCapabilities: McpUiAppCapabilities = {\n availableDisplayModes: [...availableDisplayModes],\n };\n\n const app = options.app ?? new App(appInfo, appCapabilities);\n\n let toolInput: McpUiToolInputNotification[\"params\"] | undefined;\n let toolInputPartial: McpUiToolInputPartialNotification[\"params\"] | undefined;\n let toolResult: McpUiToolResultNotification[\"params\"] | undefined;\n let mounted = false;\n let stopped = false;\n let pending: Promise<void> = Promise.resolve();\n\n function currentProps(): McpWidgetProps {\n return {\n mcp: app,\n toolInput,\n toolInputPartial,\n toolResult,\n hostContext: app.getHostContext(),\n };\n }\n\n function notifyError(code: string, error: unknown): void {\n const message = error instanceof Error ? error.message : String(error);\n try {\n void app.sendLog({ level: \"error\", data: { code, message } }).catch(() => undefined);\n } catch {\n // ignore — log channel may not be ready\n }\n renderErrorBoundary(container, code, message);\n }\n\n function renderWith(props: McpWidgetProps): Promise<void> {\n pending = pending.then(async () => {\n if (stopped) return;\n try {\n if (!mounted) {\n const r = widget.mount(container, props);\n if (r instanceof Promise) await r;\n mounted = true;\n container.setAttribute(\"data-mountly-mcp-state\", \"mounted\");\n } else if (widget.update) {\n const r = widget.update(container, props);\n if (r instanceof Promise) await r;\n } else {\n await widget.unmount(container);\n mounted = false;\n const r = widget.mount(container, props);\n if (r instanceof Promise) await r;\n mounted = true;\n }\n } catch (error) {\n notifyError(MCP_ERROR_CODES.WIDGET_MOUNT_THREW, error);\n }\n });\n return pending;\n }\n\n async function unmountWidget(): Promise<void> {\n await pending;\n if (!mounted) return;\n mounted = false;\n await widget.unmount(container);\n }\n\n // Event handlers MUST be registered before connect() — ext-apps will refuse\n // to attach handlers retroactively after the initialize handshake completes.\n const handleToolInput = (params: McpUiToolInputNotification[\"params\"]) => {\n toolInput = params;\n toolInputPartial = undefined;\n if (!awaitToolResult) return;\n if (mounted || toolResult !== undefined) void renderWith(currentProps());\n };\n\n const handleToolInputPartial = (params: McpUiToolInputPartialNotification[\"params\"]) => {\n // Views MAY ignore partial input per spec; opt in with `streamToolInput`.\n // Consumers wanting finer control can subscribe via app.addEventListener.\n if (!streamToolInput) return;\n toolInputPartial = params;\n void renderWith(currentProps());\n };\n\n const handleToolResult = (params: McpUiToolResultNotification[\"params\"]) => {\n toolResult = params;\n void renderWith(currentProps());\n };\n\n const handleToolCancelled = () => {\n void renderWith(currentProps());\n };\n\n const handleHostContextChanged = () => {\n if (mounted) void renderWith(currentProps());\n };\n\n app.addEventListener(\"toolinput\", handleToolInput);\n app.addEventListener(\"toolinputpartial\", handleToolInputPartial);\n app.addEventListener(\"toolresult\", handleToolResult);\n app.addEventListener(\"toolcancelled\", handleToolCancelled);\n app.addEventListener(\"hostcontextchanged\", handleHostContextChanged);\n\n const previousTeardown = app.onteardown;\n const bridgeTeardown: NonNullable<typeof app.onteardown> = async (params, extra) => {\n stopped = true;\n detachTeardown();\n detachAppHandlers();\n await unmountWidget();\n return (await previousTeardown?.(params, extra)) ?? {};\n };\n app.onteardown = bridgeTeardown;\n\n function detachAppHandlers(): void {\n app.removeEventListener(\"toolinput\", handleToolInput);\n app.removeEventListener(\"toolinputpartial\", handleToolInputPartial);\n app.removeEventListener(\"toolresult\", handleToolResult);\n app.removeEventListener(\"toolcancelled\", handleToolCancelled);\n app.removeEventListener(\"hostcontextchanged\", handleHostContextChanged);\n if (app.onteardown === bridgeTeardown) app.onteardown = previousTeardown;\n }\n\n const ready = (async () => {\n try {\n if (!options.app) {\n // App.connect() defaults to PostMessageTransport(window.parent, window.parent)\n // and owns automatic resize setup.\n await app.connect();\n }\n\n if (!awaitToolResult) {\n await renderWith(currentProps());\n }\n } catch (error) {\n const message = error instanceof Error ? error.message : String(error);\n const code = /timeout/i.test(message)\n ? MCP_ERROR_CODES.INITIALIZE_TIMEOUT\n : MCP_ERROR_CODES.INITIALIZE_FAILED;\n notifyError(code, error);\n throw error;\n }\n })();\n\n let detachTeardown: () => void = () => undefined;\n\n function stopBridge(): void {\n if (stopped) return;\n stopped = true;\n detachTeardown();\n detachAppHandlers();\n void unmountWidget();\n if (!options.app) void app.close().catch(() => undefined);\n }\n\n detachTeardown =\n options.onTeardown?.(stopBridge) ??\n (typeof window !== \"undefined\"\n ? (() => {\n const h = () => stopBridge();\n window.addEventListener(\"beforeunload\", h);\n return () => window.removeEventListener(\"beforeunload\", h);\n })()\n : () => undefined);\n\n return {\n ready,\n app,\n stop: stopBridge,\n };\n}\n\nexport { App, PostMessageTransport };\nexport type {\n McpUiAppCapabilities,\n McpUiHostCapabilities,\n McpUiHostContext,\n McpUiToolInputNotification,\n McpUiToolInputPartialNotification,\n McpUiToolResultNotification,\n McpUiToolCancelledNotification,\n McpUiHostContextChangedNotification,\n} from \"@modelcontextprotocol/ext-apps\";\n"],"mappings":"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","names":[]}
@@ -0,0 +1,52 @@
1
+ // src/dev/connect-server.ts
2
+ async function connectMcpServer(path) {
3
+ const { pathToFileURL } = await import("url");
4
+ const { resolve } = await import("path");
5
+ const mod = await import(pathToFileURL(resolve(path)).href);
6
+ if (mod.default === void 0) {
7
+ throw new Error(
8
+ `mountly-mcp: ${path} has no default export. Export your server (or a function returning it) as default.`
9
+ );
10
+ }
11
+ const value = typeof mod.default === "function" ? await mod.default() : mod.default;
12
+ let client;
13
+ if (value !== null && typeof value === "object" && "connectInProcess" in value && typeof value.connectInProcess === "function") {
14
+ const running = value;
15
+ ({ client } = await running.connectInProcess());
16
+ } else if (value !== null && typeof value === "object" && "connect" in value && typeof value.connect === "function") {
17
+ const [{ Client }, { InMemoryTransport }, { EXTENSION_ID, RESOURCE_MIME_TYPE }] = await Promise.all([
18
+ import("@modelcontextprotocol/sdk/client/index.js"),
19
+ import("@modelcontextprotocol/sdk/inMemory.js"),
20
+ import("@modelcontextprotocol/ext-apps/server")
21
+ ]);
22
+ const [clientTransport, serverTransport] = InMemoryTransport.createLinkedPair();
23
+ await value.connect(serverTransport);
24
+ client = new Client({ name: "mountly-mcp-dev", version: "0.0.1" }, {
25
+ capabilities: { extensions: { [EXTENSION_ID]: { mimeTypes: [RESOURCE_MIME_TYPE] } } }
26
+ });
27
+ await client.connect(clientTransport);
28
+ } else {
29
+ throw new TypeError(
30
+ `mountly-mcp: ${path} must default-export an MCP server, RunningMcpAppServer, or a function returning one`
31
+ );
32
+ }
33
+ return {
34
+ callTool: (name, args) => client.callTool({ name, arguments: args ?? {} }),
35
+ async toolFor(uri) {
36
+ const { tools } = await client.listTools();
37
+ const uiMeta = (tool) => tool._meta?.ui;
38
+ const bound = tools.filter((tool) => uiMeta(tool)?.resourceUri === uri);
39
+ const visible = bound.find((tool) => {
40
+ const visibility = uiMeta(tool)?.visibility;
41
+ return visibility === void 0 || visibility.includes("model");
42
+ });
43
+ return (visible ?? bound[0])?.name;
44
+ },
45
+ close: () => client.close()
46
+ };
47
+ }
48
+
49
+ export {
50
+ connectMcpServer
51
+ };
52
+ //# sourceMappingURL=chunk-UECZA34Q.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/dev/connect-server.ts"],"sourcesContent":["import type { McpUiToolMeta } from \"@modelcontextprotocol/ext-apps\";\n\nexport interface ConnectedMcpServer {\n callTool: (name: string, args: unknown) => Promise<unknown>;\n /** The model-visible tool bound to `uri` — the one a host would call. */\n toolFor(uri: string): Promise<string | undefined>;\n close(): Promise<void>;\n}\n\n/**\n * Connect a server module in-process for a development session.\n *\n * The module default-exports either the server or a function returning it: a\n * `RunningMcpAppServer` from `createMcpAppServer`, or a raw `McpServer`.\n */\nexport async function connectMcpServer(path: string): Promise<ConnectedMcpServer> {\n const { pathToFileURL } = await import(\"node:url\");\n const { resolve } = await import(\"node:path\");\n const mod = (await import(pathToFileURL(resolve(path)).href)) as { default?: unknown };\n if (mod.default === undefined) {\n throw new Error(\n `mountly-mcp: ${path} has no default export. Export your server (or a function returning it) as default.`,\n );\n }\n const value = typeof mod.default === \"function\" ? await mod.default() : mod.default;\n\n let client: import(\"@modelcontextprotocol/sdk/client/index.js\").Client;\n if (\n value !== null &&\n typeof value === \"object\" &&\n \"connectInProcess\" in value &&\n typeof value.connectInProcess === \"function\"\n ) {\n const running = value as { connectInProcess(): Promise<{ client: typeof client }> };\n ({ client } = await running.connectInProcess());\n } else if (\n value !== null &&\n typeof value === \"object\" &&\n \"connect\" in value &&\n typeof value.connect === \"function\"\n ) {\n const [{ Client }, { InMemoryTransport }, { EXTENSION_ID, RESOURCE_MIME_TYPE }] =\n await Promise.all([\n import(\"@modelcontextprotocol/sdk/client/index.js\"),\n import(\"@modelcontextprotocol/sdk/inMemory.js\"),\n import(\"@modelcontextprotocol/ext-apps/server\"),\n ]);\n const [clientTransport, serverTransport] = InMemoryTransport.createLinkedPair();\n await (value as { connect(transport: unknown): Promise<void> }).connect(serverTransport);\n client = new Client({ name: \"mountly-mcp-dev\", version: \"0.0.1\" }, {\n capabilities: { extensions: { [EXTENSION_ID]: { mimeTypes: [RESOURCE_MIME_TYPE] } } },\n } as never);\n await client.connect(clientTransport);\n } else {\n throw new TypeError(\n `mountly-mcp: ${path} must default-export an MCP server, RunningMcpAppServer, or a function returning one`,\n );\n }\n\n return {\n callTool: (name, args) =>\n client.callTool({ name, arguments: (args ?? {}) as Record<string, unknown> }),\n async toolFor(uri) {\n const { tools } = await client.listTools();\n const uiMeta = (tool: { _meta?: unknown }): McpUiToolMeta | undefined =>\n (tool._meta as { ui?: McpUiToolMeta } | undefined)?.ui;\n const bound = tools.filter((tool) => uiMeta(tool)?.resourceUri === uri);\n const visible = bound.find((tool) => {\n const visibility = uiMeta(tool)?.visibility;\n return visibility === undefined || visibility.includes(\"model\");\n });\n return (visible ?? bound[0])?.name;\n },\n close: () => client.close(),\n };\n}\n"],"mappings":";AAeA,eAAsB,iBAAiB,MAA2C;AAChF,QAAM,EAAE,cAAc,IAAI,MAAM,OAAO,KAAU;AACjD,QAAM,EAAE,QAAQ,IAAI,MAAM,OAAO,MAAW;AAC5C,QAAM,MAAO,MAAM,OAAO,cAAc,QAAQ,IAAI,CAAC,EAAE;AACvD,MAAI,IAAI,YAAY,QAAW;AAC7B,UAAM,IAAI;AAAA,MACR,gBAAgB,IAAI;AAAA,IACtB;AAAA,EACF;AACA,QAAM,QAAQ,OAAO,IAAI,YAAY,aAAa,MAAM,IAAI,QAAQ,IAAI,IAAI;AAE5E,MAAI;AACJ,MACE,UAAU,QACV,OAAO,UAAU,YACjB,sBAAsB,SACtB,OAAO,MAAM,qBAAqB,YAClC;AACA,UAAM,UAAU;AAChB,KAAC,EAAE,OAAO,IAAI,MAAM,QAAQ,iBAAiB;AAAA,EAC/C,WACE,UAAU,QACV,OAAO,UAAU,YACjB,aAAa,SACb,OAAO,MAAM,YAAY,YACzB;AACA,UAAM,CAAC,EAAE,OAAO,GAAG,EAAE,kBAAkB,GAAG,EAAE,cAAc,mBAAmB,CAAC,IAC5E,MAAM,QAAQ,IAAI;AAAA,MAChB,OAAO,2CAA2C;AAAA,MAClD,OAAO,uCAAuC;AAAA,MAC9C,OAAO,uCAAuC;AAAA,IAChD,CAAC;AACH,UAAM,CAAC,iBAAiB,eAAe,IAAI,kBAAkB,iBAAiB;AAC9E,UAAO,MAAyD,QAAQ,eAAe;AACvF,aAAS,IAAI,OAAO,EAAE,MAAM,mBAAmB,SAAS,QAAQ,GAAG;AAAA,MACjE,cAAc,EAAE,YAAY,EAAE,CAAC,YAAY,GAAG,EAAE,WAAW,CAAC,kBAAkB,EAAE,EAAE,EAAE;AAAA,IACtF,CAAU;AACV,UAAM,OAAO,QAAQ,eAAe;AAAA,EACtC,OAAO;AACL,UAAM,IAAI;AAAA,MACR,gBAAgB,IAAI;AAAA,IACtB;AAAA,EACF;AAEA,SAAO;AAAA,IACL,UAAU,CAAC,MAAM,SACf,OAAO,SAAS,EAAE,MAAM,WAAY,QAAQ,CAAC,EAA8B,CAAC;AAAA,IAC9E,MAAM,QAAQ,KAAK;AACjB,YAAM,EAAE,MAAM,IAAI,MAAM,OAAO,UAAU;AACzC,YAAM,SAAS,CAAC,SACb,KAAK,OAA8C;AACtD,YAAM,QAAQ,MAAM,OAAO,CAAC,SAAS,OAAO,IAAI,GAAG,gBAAgB,GAAG;AACtE,YAAM,UAAU,MAAM,KAAK,CAAC,SAAS;AACnC,cAAM,aAAa,OAAO,IAAI,GAAG;AACjC,eAAO,eAAe,UAAa,WAAW,SAAS,OAAO;AAAA,MAChE,CAAC;AACD,cAAQ,WAAW,MAAM,CAAC,IAAI;AAAA,IAChC;AAAA,IACA,OAAO,MAAM,OAAO,MAAM;AAAA,EAC5B;AACF;","names":[]}
@@ -0,0 +1,13 @@
1
+ // src/html.ts
2
+ function escapeInlineScript(value) {
3
+ return value.replace(/<\/script/gi, "<\\/script");
4
+ }
5
+ function serializeInlineScriptValue(value) {
6
+ return JSON.stringify(value).replace(/</g, "\\u003c");
7
+ }
8
+
9
+ export {
10
+ escapeInlineScript,
11
+ serializeInlineScriptValue
12
+ };
13
+ //# sourceMappingURL=chunk-YJA4H6IB.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/html.ts"],"sourcesContent":["/** Keep generated JavaScript from terminating the inline script that owns it. */\nexport function escapeInlineScript(value: string): string {\n return value.replace(/<\\/script/gi, \"<\\\\/script\");\n}\n\n/** Serialize a value so no HTML tag can begin inside an inline script. */\nexport function serializeInlineScriptValue(value: unknown): string {\n return JSON.stringify(value).replace(/</g, \"\\\\u003c\");\n}\n"],"mappings":";AACO,SAAS,mBAAmB,OAAuB;AACxD,SAAO,MAAM,QAAQ,eAAe,YAAY;AAClD;AAGO,SAAS,2BAA2B,OAAwB;AACjE,SAAO,KAAK,UAAU,KAAK,EAAE,QAAQ,MAAM,SAAS;AACtD;","names":[]}
package/dist/cli.d.ts ADDED
@@ -0,0 +1,2 @@
1
+ #!/usr/bin/env node
2
+ export {};