@miragon/mcp-toolkit-core 0.10.1

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 (174) hide show
  1. package/README.md +32 -0
  2. package/dist/engine/context-builder.d.ts +5 -0
  3. package/dist/engine/context-builder.d.ts.map +1 -0
  4. package/dist/engine/context-builder.js +22 -0
  5. package/dist/engine/context-builder.js.map +1 -0
  6. package/dist/engine/pipeline-executor.d.ts +21 -0
  7. package/dist/engine/pipeline-executor.d.ts.map +1 -0
  8. package/dist/engine/pipeline-executor.js +80 -0
  9. package/dist/engine/pipeline-executor.js.map +1 -0
  10. package/dist/framework/active-modules.d.ts +30 -0
  11. package/dist/framework/active-modules.d.ts.map +1 -0
  12. package/dist/framework/active-modules.js +44 -0
  13. package/dist/framework/active-modules.js.map +1 -0
  14. package/dist/framework/catalogue.d.ts +148 -0
  15. package/dist/framework/catalogue.d.ts.map +1 -0
  16. package/dist/framework/catalogue.js +132 -0
  17. package/dist/framework/catalogue.js.map +1 -0
  18. package/dist/framework/dashboard-store.d.ts +136 -0
  19. package/dist/framework/dashboard-store.d.ts.map +1 -0
  20. package/dist/framework/dashboard-store.js +301 -0
  21. package/dist/framework/dashboard-store.js.map +1 -0
  22. package/dist/framework/layout-schemas.d.ts +106 -0
  23. package/dist/framework/layout-schemas.d.ts.map +1 -0
  24. package/dist/framework/layout-schemas.js +67 -0
  25. package/dist/framework/layout-schemas.js.map +1 -0
  26. package/dist/framework/layout-types.d.ts +25 -0
  27. package/dist/framework/layout-types.d.ts.map +1 -0
  28. package/dist/framework/layout-types.js +7 -0
  29. package/dist/framework/layout-types.js.map +1 -0
  30. package/dist/framework/manifest.d.ts +65 -0
  31. package/dist/framework/manifest.d.ts.map +1 -0
  32. package/dist/framework/manifest.js +47 -0
  33. package/dist/framework/manifest.js.map +1 -0
  34. package/dist/framework/render-view.d.ts +53 -0
  35. package/dist/framework/render-view.d.ts.map +1 -0
  36. package/dist/framework/render-view.js +73 -0
  37. package/dist/framework/render-view.js.map +1 -0
  38. package/dist/framework/view-builders.d.ts +79 -0
  39. package/dist/framework/view-builders.d.ts.map +1 -0
  40. package/dist/framework/view-builders.js +113 -0
  41. package/dist/framework/view-builders.js.map +1 -0
  42. package/dist/i18n/index.d.ts +3 -0
  43. package/dist/i18n/index.d.ts.map +1 -0
  44. package/dist/i18n/index.js +6 -0
  45. package/dist/i18n/index.js.map +1 -0
  46. package/dist/i18n/translator.d.ts +59 -0
  47. package/dist/i18n/translator.d.ts.map +1 -0
  48. package/dist/i18n/translator.js +48 -0
  49. package/dist/i18n/translator.js.map +1 -0
  50. package/dist/index.d.ts +31 -0
  51. package/dist/index.d.ts.map +1 -0
  52. package/dist/index.js +27 -0
  53. package/dist/index.js.map +1 -0
  54. package/dist/middleware/org-gate.d.ts +22 -0
  55. package/dist/middleware/org-gate.d.ts.map +1 -0
  56. package/dist/middleware/org-gate.js +28 -0
  57. package/dist/middleware/org-gate.js.map +1 -0
  58. package/dist/middleware/role-filter.d.ts +79 -0
  59. package/dist/middleware/role-filter.d.ts.map +1 -0
  60. package/dist/middleware/role-filter.js +95 -0
  61. package/dist/middleware/role-filter.js.map +1 -0
  62. package/dist/registry/app-loader.d.ts +35 -0
  63. package/dist/registry/app-loader.d.ts.map +1 -0
  64. package/dist/registry/app-loader.js +55 -0
  65. package/dist/registry/app-loader.js.map +1 -0
  66. package/dist/registry/step-registry.d.ts +27 -0
  67. package/dist/registry/step-registry.d.ts.map +1 -0
  68. package/dist/registry/step-registry.js +53 -0
  69. package/dist/registry/step-registry.js.map +1 -0
  70. package/dist/registry/widget-registry.d.ts +15 -0
  71. package/dist/registry/widget-registry.d.ts.map +1 -0
  72. package/dist/registry/widget-registry.js +28 -0
  73. package/dist/registry/widget-registry.js.map +1 -0
  74. package/dist/rest/client.d.ts +3 -0
  75. package/dist/rest/client.d.ts.map +1 -0
  76. package/dist/rest/client.js +155 -0
  77. package/dist/rest/client.js.map +1 -0
  78. package/dist/rest/errors.d.ts +14 -0
  79. package/dist/rest/errors.d.ts.map +1 -0
  80. package/dist/rest/errors.js +21 -0
  81. package/dist/rest/errors.js.map +1 -0
  82. package/dist/rest/index.d.ts +6 -0
  83. package/dist/rest/index.d.ts.map +1 -0
  84. package/dist/rest/index.js +4 -0
  85. package/dist/rest/index.js.map +1 -0
  86. package/dist/rest/tool.d.ts +60 -0
  87. package/dist/rest/tool.d.ts.map +1 -0
  88. package/dist/rest/tool.js +81 -0
  89. package/dist/rest/tool.js.map +1 -0
  90. package/dist/rest/types.d.ts +66 -0
  91. package/dist/rest/types.d.ts.map +1 -0
  92. package/dist/rest/types.js +2 -0
  93. package/dist/rest/types.js.map +1 -0
  94. package/dist/tools/app-resource-uri.d.ts +28 -0
  95. package/dist/tools/app-resource-uri.d.ts.map +1 -0
  96. package/dist/tools/app-resource-uri.js +30 -0
  97. package/dist/tools/app-resource-uri.js.map +1 -0
  98. package/dist/tools/backend-registry.d.ts +111 -0
  99. package/dist/tools/backend-registry.d.ts.map +1 -0
  100. package/dist/tools/backend-registry.js +154 -0
  101. package/dist/tools/backend-registry.js.map +1 -0
  102. package/dist/tools/create-framework-app.d.ts +147 -0
  103. package/dist/tools/create-framework-app.d.ts.map +1 -0
  104. package/dist/tools/create-framework-app.js +111 -0
  105. package/dist/tools/create-framework-app.js.map +1 -0
  106. package/dist/tools/index.d.ts +22 -0
  107. package/dist/tools/index.d.ts.map +1 -0
  108. package/dist/tools/index.js +15 -0
  109. package/dist/tools/index.js.map +1 -0
  110. package/dist/tools/register-catalogue-tool.d.ts +22 -0
  111. package/dist/tools/register-catalogue-tool.d.ts.map +1 -0
  112. package/dist/tools/register-catalogue-tool.js +45 -0
  113. package/dist/tools/register-catalogue-tool.js.map +1 -0
  114. package/dist/tools/register-dashboard-tools.d.ts +32 -0
  115. package/dist/tools/register-dashboard-tools.d.ts.map +1 -0
  116. package/dist/tools/register-dashboard-tools.js +149 -0
  117. package/dist/tools/register-dashboard-tools.js.map +1 -0
  118. package/dist/tools/register-framework-tools.d.ts +83 -0
  119. package/dist/tools/register-framework-tools.d.ts.map +1 -0
  120. package/dist/tools/register-framework-tools.js +154 -0
  121. package/dist/tools/register-framework-tools.js.map +1 -0
  122. package/dist/tools/register-tool.d.ts +45 -0
  123. package/dist/tools/register-tool.d.ts.map +1 -0
  124. package/dist/tools/register-tool.js +82 -0
  125. package/dist/tools/register-tool.js.map +1 -0
  126. package/dist/tools/register-widget-tool.d.ts +51 -0
  127. package/dist/tools/register-widget-tool.d.ts.map +1 -0
  128. package/dist/tools/register-widget-tool.js +45 -0
  129. package/dist/tools/register-widget-tool.js.map +1 -0
  130. package/dist/tools/tool-call-name.d.ts +53 -0
  131. package/dist/tools/tool-call-name.d.ts.map +1 -0
  132. package/dist/tools/tool-call-name.js +92 -0
  133. package/dist/tools/tool-call-name.js.map +1 -0
  134. package/dist/tools/with-tool-errors.d.ts +16 -0
  135. package/dist/tools/with-tool-errors.d.ts.map +1 -0
  136. package/dist/tools/with-tool-errors.js +28 -0
  137. package/dist/tools/with-tool-errors.js.map +1 -0
  138. package/dist/types/app.d.ts +44 -0
  139. package/dist/types/app.d.ts.map +1 -0
  140. package/dist/types/app.js +2 -0
  141. package/dist/types/app.js.map +1 -0
  142. package/dist/types/config.d.ts +15 -0
  143. package/dist/types/config.d.ts.map +1 -0
  144. package/dist/types/config.js +2 -0
  145. package/dist/types/config.js.map +1 -0
  146. package/dist/types/context.d.ts +18 -0
  147. package/dist/types/context.d.ts.map +1 -0
  148. package/dist/types/context.js +2 -0
  149. package/dist/types/context.js.map +1 -0
  150. package/dist/types/index.d.ts +10 -0
  151. package/dist/types/index.d.ts.map +1 -0
  152. package/dist/types/index.js +2 -0
  153. package/dist/types/index.js.map +1 -0
  154. package/dist/types/meta.d.ts +99 -0
  155. package/dist/types/meta.d.ts.map +1 -0
  156. package/dist/types/meta.js +66 -0
  157. package/dist/types/meta.js.map +1 -0
  158. package/dist/types/pipeline.d.ts +9 -0
  159. package/dist/types/pipeline.d.ts.map +1 -0
  160. package/dist/types/pipeline.js +2 -0
  161. package/dist/types/pipeline.js.map +1 -0
  162. package/dist/types/step.d.ts +51 -0
  163. package/dist/types/step.d.ts.map +1 -0
  164. package/dist/types/step.js +2 -0
  165. package/dist/types/step.js.map +1 -0
  166. package/dist/types/view-data.d.ts +67 -0
  167. package/dist/types/view-data.d.ts.map +1 -0
  168. package/dist/types/view-data.js +2 -0
  169. package/dist/types/view-data.js.map +1 -0
  170. package/dist/types/widget.d.ts +57 -0
  171. package/dist/types/widget.d.ts.map +1 -0
  172. package/dist/types/widget.js +2 -0
  173. package/dist/types/widget.js.map +1 -0
  174. package/package.json +50 -0
@@ -0,0 +1,149 @@
1
+ import { object } from "mcp-use/server";
2
+ import { z } from "zod";
3
+ import { collectLayoutWidgets } from "../framework/view-builders.js";
4
+ import { layoutSchema } from "../framework/layout-schemas.js";
5
+ const stepRefSchema = z.object({
6
+ id: z.string(),
7
+ step: z.string(),
8
+ optional: z.boolean().optional(),
9
+ });
10
+ const saveSchema = z.object({
11
+ id: z
12
+ .string()
13
+ .optional()
14
+ .describe("Existing dashboard id to update. Omit to create a new record."),
15
+ name: z.string().describe("Human-readable dashboard name shown in lists."),
16
+ description: z.string().optional(),
17
+ keys: z.record(z.string(), z.unknown()).optional(),
18
+ steps: z.array(stepRefSchema).optional(),
19
+ layout: layoutSchema,
20
+ title: z.string().optional().describe("View title rendered above the widget grid."),
21
+ });
22
+ const idSchema = z.object({
23
+ id: z.string().describe("Dashboard id as returned by `save-dashboard` or `list-dashboards`."),
24
+ });
25
+ function extractUserId(ctx) {
26
+ const user = ctx?.auth?.user;
27
+ return typeof user?.userId === "string" ? user.userId : undefined;
28
+ }
29
+ /**
30
+ * Registers `save-dashboard`, `list-dashboards`, `load-dashboard`, and
31
+ * `delete-dashboard`. The tools are thin CRUD wrappers around the injected
32
+ * `DashboardStore`; auth scoping is applied here (never in the store) via
33
+ * the standard `ctx.auth.user.userId` extraction.
34
+ *
35
+ * `load-dashboard` returns the full record as JSON in `content[0].text`
36
+ * (mirrored into `structuredContent`) so the model itself receives the
37
+ * bundle — `structuredContent` alone is "not added to model context" per
38
+ * MCP. The `{ keys, steps, layout, title }` fields can be piped straight
39
+ * into `render-view` to re-render the saved dashboard.
40
+ *
41
+ * Registered by `createFrameworkApp` only when `app.builder` is `true` —
42
+ * dashboard persistence is part of the opt-in visual builder platform
43
+ * (lean by default). With the builder off, none of these tools exist and
44
+ * the `app.dashboardStore` option has no effect.
45
+ */
46
+ export function registerDashboardTools(server, options) {
47
+ const { store, widgetRegistry } = options;
48
+ server.tool({
49
+ name: "save-dashboard",
50
+ title: "Save Dashboard",
51
+ description: "Persists a dashboard (render-view input bundle + name). Pass an existing `id` to update, omit to create. The builder UI's Save button invokes this tool.",
52
+ schema: saveSchema,
53
+ }, async (params, ctx) => {
54
+ // Warn (never reject) on unknown widget ids — usually a typo. A save is
55
+ // deliberately never blocked on a cosmetic layout mistake; the unknown
56
+ // ids surface in the text summary so the user can spot and fix it.
57
+ const unknownWidgets = widgetRegistry
58
+ ? [...new Set(collectLayoutWidgets(params.layout))].filter((id) => !widgetRegistry.get(id))
59
+ : [];
60
+ const record = await store.save({
61
+ id: params.id,
62
+ name: params.name,
63
+ description: params.description,
64
+ userId: extractUserId(ctx),
65
+ keys: params.keys,
66
+ steps: params.steps,
67
+ layout: params.layout,
68
+ title: params.title,
69
+ });
70
+ const summaryLines = [
71
+ `Saved dashboard "${record.name}" (${record.id}).`,
72
+ unknownWidgets.length > 0
73
+ ? `Warning: layout references widget ids not registered on this server: ${unknownWidgets.join(", ")}. They will not render — check for typos or register the widgets.`
74
+ : "",
75
+ ].filter(Boolean);
76
+ return {
77
+ content: [{ type: "text", text: summaryLines.join("\n") }],
78
+ structuredContent: {
79
+ id: record.id,
80
+ name: record.name,
81
+ createdAt: record.createdAt,
82
+ updatedAt: record.updatedAt,
83
+ ...(unknownWidgets.length > 0 ? { unknownWidgets } : {}),
84
+ },
85
+ };
86
+ });
87
+ server.tool({
88
+ name: "list-dashboards",
89
+ title: "List Dashboards",
90
+ description: "Returns the dashboards visible to the caller (scoped by userId when auth is enabled). Metadata only — fetch a full record via `load-dashboard`.",
91
+ annotations: { readOnlyHint: true },
92
+ }, async (_params, ctx) => {
93
+ const items = await store.list({ userId: extractUserId(ctx) });
94
+ return object({ items });
95
+ });
96
+ server.tool({
97
+ name: "load-dashboard",
98
+ title: "Load Dashboard",
99
+ description: "Returns the full dashboard bundle. The returned `{ keys, steps, layout, title }` fields can be handed straight to `render-view`.",
100
+ schema: idSchema,
101
+ annotations: { readOnlyHint: true },
102
+ }, async ({ id }, ctx) => {
103
+ const record = await store.get(id, { userId: extractUserId(ctx) });
104
+ if (!record) {
105
+ return {
106
+ content: [{ type: "text", text: `Dashboard "${id}" not found.` }],
107
+ isError: true,
108
+ };
109
+ }
110
+ // Validate the persisted layout before handing it back: a corrupted
111
+ // store file could otherwise feed a malformed layout straight into
112
+ // `render-view` (and the model). Surface a clear error instead of
113
+ // silently forwarding garbage.
114
+ const parsed = layoutSchema.safeParse(record.layout);
115
+ if (!parsed.success) {
116
+ return {
117
+ content: [
118
+ {
119
+ type: "text",
120
+ text: `Dashboard "${id}" has an invalid layout and cannot be loaded: ${parsed.error.issues
121
+ .map((issue) => `${issue.path.join(".") || "<root>"}: ${issue.message}`)
122
+ .join("; ")}`,
123
+ },
124
+ ],
125
+ isError: true,
126
+ };
127
+ }
128
+ return object(record);
129
+ });
130
+ server.tool({
131
+ name: "delete-dashboard",
132
+ title: "Delete Dashboard",
133
+ description: "Permanently removes a dashboard by id.",
134
+ schema: idSchema,
135
+ }, async ({ id }, ctx) => {
136
+ const deleted = await store.delete(id, { userId: extractUserId(ctx) });
137
+ return {
138
+ content: [
139
+ {
140
+ type: "text",
141
+ text: deleted ? `Deleted dashboard "${id}"` : `Dashboard "${id}" not found.`,
142
+ },
143
+ ],
144
+ structuredContent: { deleted },
145
+ isError: !deleted,
146
+ };
147
+ });
148
+ }
149
+ //# sourceMappingURL=register-dashboard-tools.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"register-dashboard-tools.js","sourceRoot":"","sources":["../../src/tools/register-dashboard-tools.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,83 @@
1
+ import { type MCPServer } from "mcp-use/server";
2
+ import type { StepRegistry } from "../registry/step-registry.js";
3
+ import type { WidgetRegistry } from "../registry/widget-registry.js";
4
+ import type { AppConfig, AppPlugin } from "../types/index.js";
5
+ /**
6
+ * CSP advertised on the widget resource, in the SEP-1865 camelCase shape
7
+ * (`_meta.ui.csp`). All entries are full origins (e.g. `https://server.example`).
8
+ * The Apps SDK tool-meta variant (`openai/widgetCSP`, snake_cased) is derived
9
+ * from the same value.
10
+ */
11
+ export interface AppResourceCsp {
12
+ /** Origins allowed for fetch/XHR/WebSocket from inside the widget iframe. */
13
+ connectDomains?: string[];
14
+ /** Origins allowed for images, scripts, stylesheets, fonts. */
15
+ resourceDomains?: string[];
16
+ /** Allowed iframe origins. */
17
+ frameDomains?: string[];
18
+ /** Allowed `base-uri` origins. */
19
+ baseUriDomains?: string[];
20
+ }
21
+ export interface RegisterFrameworkToolsOptions {
22
+ stepRegistry: StepRegistry;
23
+ widgetRegistry: WidgetRegistry;
24
+ config: AppConfig;
25
+ appConfigs: Record<string, Record<string, unknown>>;
26
+ plugins: AppPlugin[];
27
+ /**
28
+ * The MCP UI resource URI that hosts the widget bundle (typically the
29
+ * compiled `mcp-app.html`). Referenced by `render-view` / `refresh-view`
30
+ * via the `_meta.ui.resourceUri` convention.
31
+ */
32
+ resourceUri: string;
33
+ /** Absolute path to the bundled `mcp-app.html` served behind `resourceUri`. */
34
+ htmlPath: string;
35
+ /**
36
+ * Tool name for the refresh hook the UI calls to re-run the pipeline.
37
+ * The `@miragon/mcp-toolkit-ui` default matches this — change both in
38
+ * sync if you override.
39
+ */
40
+ refreshToolName?: string;
41
+ /**
42
+ * Whether the in-iframe visual builder platform is enabled (i.e.
43
+ * `app.builder` is true and `get-builder-catalogue` is registered).
44
+ * Forwarded into every `render-view` / `refresh-view` payload as
45
+ * `structuredContent.builderAvailable` so the `McpAppView` shell only
46
+ * shows its Build affordance when the server can service it. Defaults to
47
+ * `false`.
48
+ */
49
+ builderAvailable?: boolean;
50
+ /**
51
+ * Public base URL the server advertises. Its origin is auto-injected into
52
+ * the resource CSP's connect/resource/baseUri domains — mirroring native
53
+ * mcp-use's server-origin enrichment — so widgets can reach the server
54
+ * origin without CSP violations. Without it (and without {@link csp}) the
55
+ * resource advertises no CSP, which ext-apps hosts treat as the secure
56
+ * "no network" default; fine for a fully inlined bundle.
57
+ */
58
+ baseUrl?: string;
59
+ /**
60
+ * Additional CSP origins advertised on the widget resource
61
+ * (`_meta.ui.csp`) and, snake_cased, on widget tools (`openai/widgetCSP`).
62
+ * Merged with the origin derived from {@link baseUrl}.
63
+ */
64
+ csp?: AppResourceCsp;
65
+ }
66
+ /**
67
+ * Merges the configured CSP with the server origin derived from `baseUrl`
68
+ * (injected into connect/resource/baseUri domains, deduplicated) — the same
69
+ * enrichment native mcp-use applies to its widget definitions. Returns
70
+ * `undefined` when there is nothing to advertise.
71
+ */
72
+ export declare function buildAppResourceCsp(baseUrl: string | undefined, csp: AppResourceCsp | undefined): AppResourceCsp | undefined;
73
+ /**
74
+ * Registers the framework-level MCP tools that make up a Miranum-style MCP
75
+ * app: the manifest tool, the `render-view` / `refresh-view` pair, the widget
76
+ * bundle resource, plus any widget-action tools each plugin contributes.
77
+ *
78
+ * Intended to be called from `createFrameworkApp`, but exposed directly so
79
+ * consumers that build their own server can still opt into the framework
80
+ * tools without the rest of the boot helper.
81
+ */
82
+ export declare function registerFrameworkTools(server: MCPServer, options: RegisterFrameworkToolsOptions): void;
83
+ //# sourceMappingURL=register-framework-tools.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"register-framework-tools.d.ts","sourceRoot":"","sources":["../../src/tools/register-framework-tools.ts"],"names":[],"mappings":"AACA,OAAO,EAAyB,KAAK,SAAS,EAA4B,MAAM,gBAAgB,CAAA;AAKhG,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,8BAA8B,CAAA;AAChE,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,gCAAgC,CAAA;AACpE,OAAO,KAAK,EAAE,SAAS,EAAE,SAAS,EAAE,MAAM,mBAAmB,CAAA;AAG7D;;;;;GAKG;AACH,MAAM,WAAW,cAAc;IAC7B,6EAA6E;IAC7E,cAAc,CAAC,EAAE,MAAM,EAAE,CAAA;IACzB,+DAA+D;IAC/D,eAAe,CAAC,EAAE,MAAM,EAAE,CAAA;IAC1B,8BAA8B;IAC9B,YAAY,CAAC,EAAE,MAAM,EAAE,CAAA;IACvB,kCAAkC;IAClC,cAAc,CAAC,EAAE,MAAM,EAAE,CAAA;CAC1B;AAED,MAAM,WAAW,6BAA6B;IAC5C,YAAY,EAAE,YAAY,CAAA;IAC1B,cAAc,EAAE,cAAc,CAAA;IAC9B,MAAM,EAAE,SAAS,CAAA;IACjB,UAAU,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC,CAAA;IACnD,OAAO,EAAE,SAAS,EAAE,CAAA;IACpB;;;;OAIG;IACH,WAAW,EAAE,MAAM,CAAA;IACnB,+EAA+E;IAC/E,QAAQ,EAAE,MAAM,CAAA;IAChB;;;;OAIG;IACH,eAAe,CAAC,EAAE,MAAM,CAAA;IACxB;;;;;;;OAOG;IACH,gBAAgB,CAAC,EAAE,OAAO,CAAA;IAC1B;;;;;;;OAOG;IACH,OAAO,CAAC,EAAE,MAAM,CAAA;IAChB;;;;OAIG;IACH,GAAG,CAAC,EAAE,cAAc,CAAA;CACrB;AA+CD;;;;;GAKG;AACH,wBAAgB,mBAAmB,CACjC,OAAO,EAAE,MAAM,GAAG,SAAS,EAC3B,GAAG,EAAE,cAAc,GAAG,SAAS,GAC9B,cAAc,GAAG,SAAS,CAgB5B;AAYD;;;;;;;;GAQG;AACH,wBAAgB,sBAAsB,CACpC,MAAM,EAAE,SAAS,EACjB,OAAO,EAAE,6BAA6B,GACrC,IAAI,CAyGN"}
@@ -0,0 +1,154 @@
1
+ import fs from "node:fs/promises";
2
+ import { createMcpAppsResource, RESOURCE_MIME_TYPE, text } from "mcp-use/server";
3
+ import { z } from "zod";
4
+ import { getFrameworkManifest } from "../framework/manifest.js";
5
+ import { layoutInputSchema } from "../framework/layout-schemas.js";
6
+ import { renderView } from "../framework/render-view.js";
7
+ import { uiMeta } from "../types/meta.js";
8
+ const stepRefSchema = z.object({
9
+ id: z.string().describe("Context key under which the step's result is stored, e.g. 'invoice'."),
10
+ step: z.string().describe("Registered step id, e.g. 'lexoffice:load-invoice'."),
11
+ optional: z.boolean().optional(),
12
+ });
13
+ const renderViewSchema = z.object({
14
+ keys: z
15
+ .record(z.string(), z.unknown())
16
+ .optional()
17
+ .describe("Keys the widgets will receive, e.g. { 'lexoffice:invoiceId': '…' }."),
18
+ steps: z
19
+ .array(stepRefSchema)
20
+ .optional()
21
+ .describe("Optional pipeline steps to compute keys before rendering. Without steps only the passed-in keys are used."),
22
+ // `layoutInputSchema` (not `layoutSchema`): also accepts the layout as a
23
+ // JSON-encoded string — hosts confronted with the type-less `anyOf` this
24
+ // union emits sometimes stringify the parameter (see layout-schemas.ts).
25
+ layout: layoutInputSchema,
26
+ title: z.string().optional().describe("Optional view title."),
27
+ });
28
+ function extractUserId(ctx) {
29
+ const user = ctx?.auth?.user;
30
+ return typeof user?.userId === "string" ? user.userId : undefined;
31
+ }
32
+ function withOrigin(list, origin) {
33
+ if (!list)
34
+ return [origin];
35
+ return list.includes(origin) ? list : [...list, origin];
36
+ }
37
+ /**
38
+ * Merges the configured CSP with the server origin derived from `baseUrl`
39
+ * (injected into connect/resource/baseUri domains, deduplicated) — the same
40
+ * enrichment native mcp-use applies to its widget definitions. Returns
41
+ * `undefined` when there is nothing to advertise.
42
+ */
43
+ export function buildAppResourceCsp(baseUrl, csp) {
44
+ let origin;
45
+ if (baseUrl) {
46
+ try {
47
+ origin = new URL(baseUrl).origin;
48
+ }
49
+ catch {
50
+ // Invalid baseUrl — skip origin injection rather than failing boot.
51
+ }
52
+ }
53
+ if (!origin)
54
+ return csp;
55
+ return {
56
+ ...csp,
57
+ connectDomains: withOrigin(csp?.connectDomains, origin),
58
+ resourceDomains: withOrigin(csp?.resourceDomains, origin),
59
+ baseUriDomains: withOrigin(csp?.baseUriDomains, origin),
60
+ };
61
+ }
62
+ /** Converts the camelCase resource CSP into the snake_cased `openai/widgetCSP` shape. */
63
+ function toWidgetCspMeta(csp) {
64
+ const meta = {};
65
+ if (csp.connectDomains)
66
+ meta.connect_domains = csp.connectDomains;
67
+ if (csp.resourceDomains)
68
+ meta.resource_domains = csp.resourceDomains;
69
+ if (csp.frameDomains)
70
+ meta.frame_domains = csp.frameDomains;
71
+ if (csp.baseUriDomains)
72
+ meta.base_uri_domains = csp.baseUriDomains;
73
+ return meta;
74
+ }
75
+ /**
76
+ * Registers the framework-level MCP tools that make up a Miranum-style MCP
77
+ * app: the manifest tool, the `render-view` / `refresh-view` pair, the widget
78
+ * bundle resource, plus any widget-action tools each plugin contributes.
79
+ *
80
+ * Intended to be called from `createFrameworkApp`, but exposed directly so
81
+ * consumers that build their own server can still opt into the framework
82
+ * tools without the rest of the boot helper.
83
+ */
84
+ export function registerFrameworkTools(server, options) {
85
+ const { stepRegistry, widgetRegistry, config, appConfigs, plugins, resourceUri, htmlPath, refreshToolName = "refresh-view", builderAvailable = false, baseUrl, csp, } = options;
86
+ const resourceCsp = buildAppResourceCsp(baseUrl, csp);
87
+ const widgetCSP = resourceCsp ? toWidgetCspMeta(resourceCsp) : undefined;
88
+ server.tool({
89
+ name: "get-framework-manifest",
90
+ description: "Returns all active apps, available pipeline steps, widgets, and their key contracts. Call this first to discover which step-ids and widget-ids exist — and which `props` each widget accepts (see each widget's `propsSchema`) — before building a view.",
91
+ annotations: { readOnlyHint: true },
92
+ },
93
+ // eslint-disable-next-line @typescript-eslint/require-await
94
+ async () => {
95
+ const manifest = getFrameworkManifest(stepRegistry, widgetRegistry, config);
96
+ return text(JSON.stringify(manifest, null, 2));
97
+ });
98
+ const renderHandler = async (params, ctx) => {
99
+ return renderView({
100
+ input: {
101
+ keys: params.keys,
102
+ steps: params.steps,
103
+ layout: params.layout,
104
+ title: params.title,
105
+ },
106
+ stepRegistry,
107
+ appConfigs,
108
+ ctx: { userId: extractUserId(ctx) },
109
+ builderAvailable,
110
+ });
111
+ };
112
+ server.tool({
113
+ name: "render-view",
114
+ title: "Render View",
115
+ description: "Builds a UI from pipeline steps and widgets. IMPORTANT: call get-framework-manifest first to learn which step-ids and widget-ids are available — only use ids listed there. Each widget entry's optional `propsSchema` (JSON Schema) describes the per-instance `props` you can set on a layout cell to scope or configure that widget (e.g. one tab per `processDefinitionKey`).",
116
+ schema: renderViewSchema,
117
+ _meta: uiMeta({
118
+ resourceUri,
119
+ title: "Render View",
120
+ invoking: "Rendering view...",
121
+ invoked: "View rendered",
122
+ widgetDescription: "Interactive view composed of pipeline-driven widgets",
123
+ widgetCSP,
124
+ }),
125
+ }, renderHandler);
126
+ for (const plugin of plugins) {
127
+ plugin.registerWidgetTools?.(server, resourceUri, { widgetCSP });
128
+ }
129
+ server.tool({
130
+ name: refreshToolName,
131
+ title: "Refresh View",
132
+ description: "Re-runs the pipeline with the stored parameters.",
133
+ schema: renderViewSchema,
134
+ _meta: uiMeta({ resourceUri, appOnly: true }),
135
+ }, renderHandler);
136
+ // The resource `_meta.ui.csp` must appear on the LISTING (resources/list)
137
+ // and on the READ contents — ext-apps hosts read it from the contents when
138
+ // sandboxing the iframe. `createMcpAppsResource` produces exactly the shape
139
+ // native mcp-use emits (mimeType `text/html;profile=mcp-app` + `_meta.ui`).
140
+ const resourceMeta = resourceCsp ? { ui: { csp: resourceCsp } } : undefined;
141
+ server.resource({
142
+ name: "mcp-app-html",
143
+ uri: resourceUri,
144
+ mimeType: RESOURCE_MIME_TYPE,
145
+ ...(resourceMeta ? { _meta: resourceMeta } : {}),
146
+ }, async () => {
147
+ // Read lazily per request so dev servers pick up a rebuilt bundle
148
+ // without a restart (same behaviour as before).
149
+ const html = await fs.readFile(htmlPath, "utf-8");
150
+ const uiResource = createMcpAppsResource(resourceUri, html, resourceCsp ? { csp: resourceCsp } : undefined);
151
+ return { contents: [uiResource.resource] };
152
+ });
153
+ }
154
+ //# sourceMappingURL=register-framework-tools.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"register-framework-tools.js","sourceRoot":"","sources":["../../src/tools/register-framework-tools.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,45 @@
1
+ import { type MCPServer } from "mcp-use/server";
2
+ import { z } from "zod";
3
+ type ZodRawShape = Record<string, z.ZodTypeAny>;
4
+ /**
5
+ * The validated args a handler receives. When an `inputSchema` shape is
6
+ * declared, this is inferred from it (`z.infer`), so handlers get precise types
7
+ * for free instead of a loose `Record<string, any>`. With no `inputSchema` it
8
+ * falls back to a permissive record, matching the pre-generic behaviour.
9
+ */
10
+ export type ToolArgs<TShape extends ZodRawShape = ZodRawShape> = z.infer<z.ZodObject<TShape>>;
11
+ export interface ToolConfig<TClient, TShape extends ZodRawShape = ZodRawShape> {
12
+ name: string;
13
+ description: string;
14
+ category?: string;
15
+ inputSchema?: TShape;
16
+ /**
17
+ * Zod schema describing the tool's structured output. Mirrored into the
18
+ * MCP `outputSchema` advertised to clients and used to populate
19
+ * `structuredContent` on each response.
20
+ *
21
+ * If you pass a `z.array(...)`, the schema is auto-wrapped to
22
+ * `z.object({ data: <array> })` because MCP requires `structuredContent`
23
+ * to be an object. The runtime wrapping happens automatically too — your
24
+ * handler can return either the bare array or `{ data: [...] }`.
25
+ */
26
+ outputSchema?: z.ZodTypeAny;
27
+ annotations?: {
28
+ readOnlyHint?: boolean;
29
+ destructiveHint?: boolean;
30
+ idempotentHint?: boolean;
31
+ openWorldHint?: boolean;
32
+ };
33
+ handler: (client: TClient, args: ToolArgs<TShape>) => Promise<unknown>;
34
+ formatResult?: (result: unknown, args: ToolArgs<TShape>) => string;
35
+ }
36
+ export interface RegisteredToolMeta {
37
+ name: string;
38
+ category?: string;
39
+ }
40
+ export declare function createToolRegistrar<TClient>(server: MCPServer, client: TClient): {
41
+ <TShape extends ZodRawShape = ZodRawShape>(config: ToolConfig<TClient, TShape>): void;
42
+ getRegisteredTools(): RegisteredToolMeta[];
43
+ };
44
+ export {};
45
+ //# sourceMappingURL=register-tool.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"register-tool.d.ts","sourceRoot":"","sources":["../../src/tools/register-tool.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,KAAK,SAAS,EAAuB,MAAM,gBAAgB,CAAA;AACpE,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAA;AAGvB,KAAK,WAAW,GAAG,MAAM,CAAC,MAAM,EAAE,CAAC,CAAC,UAAU,CAAC,CAAA;AAK/C;;;;;GAKG;AACH,MAAM,MAAM,QAAQ,CAAC,MAAM,SAAS,WAAW,GAAG,WAAW,IAAI,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,SAAS,CAAC,MAAM,CAAC,CAAC,CAAA;AAE7F,MAAM,WAAW,UAAU,CAAC,OAAO,EAAE,MAAM,SAAS,WAAW,GAAG,WAAW;IAC3E,IAAI,EAAE,MAAM,CAAA;IACZ,WAAW,EAAE,MAAM,CAAA;IACnB,QAAQ,CAAC,EAAE,MAAM,CAAA;IACjB,WAAW,CAAC,EAAE,MAAM,CAAA;IACpB;;;;;;;;;OASG;IACH,YAAY,CAAC,EAAE,CAAC,CAAC,UAAU,CAAA;IAC3B,WAAW,CAAC,EAAE;QACZ,YAAY,CAAC,EAAE,OAAO,CAAA;QACtB,eAAe,CAAC,EAAE,OAAO,CAAA;QACzB,cAAc,CAAC,EAAE,OAAO,CAAA;QACxB,aAAa,CAAC,EAAE,OAAO,CAAA;KACxB,CAAA;IACD,OAAO,EAAE,CAAC,MAAM,EAAE,OAAO,EAAE,IAAI,EAAE,QAAQ,CAAC,MAAM,CAAC,KAAK,OAAO,CAAC,OAAO,CAAC,CAAA;IACtE,YAAY,CAAC,EAAE,CAAC,MAAM,EAAE,OAAO,EAAE,IAAI,EAAE,QAAQ,CAAC,MAAM,CAAC,KAAK,MAAM,CAAA;CACnE;AAED,MAAM,WAAW,kBAAkB;IACjC,IAAI,EAAE,MAAM,CAAA;IACZ,QAAQ,CAAC,EAAE,MAAM,CAAA;CAClB;AA+BD,wBAAgB,mBAAmB,CAAC,OAAO,EAAE,MAAM,EAAE,SAAS,EAAE,MAAM,EAAE,OAAO;KAG3D,MAAM,SAAS,WAAW,wBAAwB,UAAU,CAAC,OAAO,EAAE,MAAM,CAAC;;EAmDhG"}
@@ -0,0 +1,82 @@
1
+ import { array, object, text } from "mcp-use/server";
2
+ import { z } from "zod";
3
+ import { withToolErrors } from "./with-tool-errors.js";
4
+ function wrapArraySchema(schema) {
5
+ if (!schema)
6
+ return undefined;
7
+ return schema instanceof z.ZodArray ? z.object({ data: schema }) : schema;
8
+ }
9
+ /**
10
+ * Coerces a handler result into the `structuredContent` object shape MCP
11
+ * requires, mirroring {@link wrapArraySchema}: bare arrays become `{ data }`,
12
+ * objects pass through.
13
+ *
14
+ * A declared `outputSchema` is a promise to the client that this tool emits an
15
+ * *object* `structuredContent`. If the handler instead returns a scalar,
16
+ * `null`, or `undefined`, the SDK would reject the response with an opaque
17
+ * protocol error ("has an output schema but no structured content" / "invalid
18
+ * structured content"). We turn that into a clear, house-style tool error
19
+ * instead — thrown here and caught by {@link withToolErrors}, which surfaces it
20
+ * as an `isError` result the SDK passes through without output-schema
21
+ * validation.
22
+ */
23
+ function toStructuredContent(result, toolName) {
24
+ if (Array.isArray(result))
25
+ return { data: result };
26
+ if (result !== null && typeof result === "object")
27
+ return result;
28
+ const kind = result === null ? "null" : typeof result;
29
+ throw new Error(`Tool "${toolName}" declares an outputSchema but its handler returned a ${kind} value; ` +
30
+ `structured output must be an object or array.`);
31
+ }
32
+ export function createToolRegistrar(server, client) {
33
+ const registeredTools = [];
34
+ function register(config) {
35
+ registeredTools.push({ name: config.name, category: config.category });
36
+ server.tool({
37
+ name: config.name,
38
+ description: config.description,
39
+ schema: config.inputSchema ? z.object(config.inputSchema) : undefined,
40
+ outputSchema: wrapArraySchema(config.outputSchema),
41
+ annotations: config.annotations,
42
+ },
43
+ // The SDK validates args against the schema above, so the loose callback
44
+ // arg is safely the handler's precise `ToolArgs<TShape>`.
45
+ withToolErrors(async (looseArgs) => {
46
+ const args = looseArgs;
47
+ const result = await config.handler(client, args);
48
+ if (config.formatResult) {
49
+ const formatted = text(config.formatResult(result, args));
50
+ // When an outputSchema is declared the tool promised structured
51
+ // output, so mirror the raw result into structuredContent alongside
52
+ // the human-readable text instead of dropping it. Without an
53
+ // outputSchema the formatResult path stays text-only as before.
54
+ if (config.outputSchema) {
55
+ return { ...formatted, structuredContent: toStructuredContent(result, config.name) };
56
+ }
57
+ return formatted;
58
+ }
59
+ if (Array.isArray(result)) {
60
+ return array(result);
61
+ }
62
+ if (result !== null && typeof result === "object") {
63
+ return object(result);
64
+ }
65
+ // A declared outputSchema requires an object `structuredContent`; a
66
+ // scalar/null/undefined result would make the SDK reject the response
67
+ // with an opaque protocol error. Surface a clear tool error instead
68
+ // (see toStructuredContent). Without an outputSchema, the text-only
69
+ // fallbacks below are valid.
70
+ if (config.outputSchema) {
71
+ return object(toStructuredContent(result, config.name));
72
+ }
73
+ if (result !== null && result !== undefined) {
74
+ return text(JSON.stringify(result, null, 2));
75
+ }
76
+ return text("Success (no content returned)");
77
+ }));
78
+ }
79
+ register.getRegisteredTools = () => registeredTools;
80
+ return register;
81
+ }
82
+ //# sourceMappingURL=register-tool.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"register-tool.js","sourceRoot":"","sources":["../../src/tools/register-tool.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,51 @@
1
+ import { type MCPServer, type ToolAnnotations } from "mcp-use/server";
2
+ import { z } from "zod";
3
+ import { type WidgetToolMetaDefaults } from "../types/meta.js";
4
+ import type { ToolArgs } from "./register-tool.js";
5
+ type ZodRawShape = Record<string, z.ZodTypeAny>;
6
+ interface WidgetToolResult {
7
+ text: string;
8
+ structuredContent: Record<string, unknown>;
9
+ }
10
+ /**
11
+ * Tool visibility per SEP-1865 (`_meta.ui.visibility`). `"app"` hides the tool
12
+ * from the LLM tool surface while keeping it callable from a widget; `"model"`
13
+ * exposes it to the LLM. Pass an array to advertise both surfaces.
14
+ */
15
+ export type WidgetToolVisibility = "app" | "model" | ("app" | "model")[];
16
+ export interface WidgetToolConfig<TClient, TShape extends ZodRawShape = ZodRawShape> {
17
+ name: string;
18
+ title?: string;
19
+ description: string;
20
+ inputSchema?: TShape;
21
+ /** MCP tool annotations (e.g. `readOnlyHint`) advertised to the host. */
22
+ annotations?: ToolAnnotations;
23
+ /**
24
+ * SEP-1865 visibility. Defaults to `"app"` (the historical behaviour — widget
25
+ * tools are app-only). Use `"model"` to expose the tool to the LLM; in that
26
+ * case the `_meta.ui` carries only `{ resourceUri }` and no `visibility`.
27
+ */
28
+ visibility?: WidgetToolVisibility;
29
+ /**
30
+ * Extra `_meta` entries merged flat into the emitted `_meta`, alongside the
31
+ * `ui` block this registrar builds. The `ui` key is reserved for the
32
+ * registrar; collisions are overwritten by the registrar's `ui`.
33
+ */
34
+ meta?: Record<string, unknown>;
35
+ /**
36
+ * Host status line while the tool call runs
37
+ * (`openai/toolInvocation/invoking`). Defaults to `Loading <title>...`.
38
+ * Only emitted on model-visible widget tools.
39
+ */
40
+ invoking?: string;
41
+ /**
42
+ * Host status line once the tool call finished
43
+ * (`openai/toolInvocation/invoked`). Defaults to `<title> ready`.
44
+ * Only emitted on model-visible widget tools.
45
+ */
46
+ invoked?: string;
47
+ handler: (client: TClient, params: ToolArgs<TShape>) => Promise<WidgetToolResult>;
48
+ }
49
+ export declare function createWidgetToolRegistrar<TClient>(server: MCPServer, client: TClient, resourceUri: string, metaDefaults?: WidgetToolMetaDefaults): <TShape extends ZodRawShape = ZodRawShape>(config: WidgetToolConfig<TClient, TShape>) => void;
50
+ export {};
51
+ //# sourceMappingURL=register-widget-tool.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"register-widget-tool.d.ts","sourceRoot":"","sources":["../../src/tools/register-widget-tool.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,KAAK,SAAS,EAAE,KAAK,eAAe,EAAE,MAAM,gBAAgB,CAAA;AACrE,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAA;AACvB,OAAO,EAAU,KAAK,sBAAsB,EAAE,MAAM,kBAAkB,CAAA;AAEtE,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,oBAAoB,CAAA;AAElD,KAAK,WAAW,GAAG,MAAM,CAAC,MAAM,EAAE,CAAC,CAAC,UAAU,CAAC,CAAA;AAK/C,UAAU,gBAAgB;IACxB,IAAI,EAAE,MAAM,CAAA;IACZ,iBAAiB,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAA;CAC3C;AAED;;;;GAIG;AACH,MAAM,MAAM,oBAAoB,GAAG,KAAK,GAAG,OAAO,GAAG,CAAC,KAAK,GAAG,OAAO,CAAC,EAAE,CAAA;AAExE,MAAM,WAAW,gBAAgB,CAAC,OAAO,EAAE,MAAM,SAAS,WAAW,GAAG,WAAW;IACjF,IAAI,EAAE,MAAM,CAAA;IACZ,KAAK,CAAC,EAAE,MAAM,CAAA;IACd,WAAW,EAAE,MAAM,CAAA;IACnB,WAAW,CAAC,EAAE,MAAM,CAAA;IACpB,yEAAyE;IACzE,WAAW,CAAC,EAAE,eAAe,CAAA;IAC7B;;;;OAIG;IACH,UAAU,CAAC,EAAE,oBAAoB,CAAA;IACjC;;;;OAIG;IACH,IAAI,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAA;IAC9B;;;;OAIG;IACH,QAAQ,CAAC,EAAE,MAAM,CAAA;IACjB;;;;OAIG;IACH,OAAO,CAAC,EAAE,MAAM,CAAA;IAChB,OAAO,EAAE,CAAC,MAAM,EAAE,OAAO,EAAE,MAAM,EAAE,QAAQ,CAAC,MAAM,CAAC,KAAK,OAAO,CAAC,gBAAgB,CAAC,CAAA;CAClF;AAYD,wBAAgB,yBAAyB,CAAC,OAAO,EAC/C,MAAM,EAAE,SAAS,EACjB,MAAM,EAAE,OAAO,EACf,WAAW,EAAE,MAAM,EACnB,YAAY,CAAC,EAAE,sBAAsB,IAEZ,MAAM,SAAS,WAAW,GAAG,WAAW,EAC/D,QAAQ,gBAAgB,CAAC,OAAO,EAAE,MAAM,CAAC,UAsC5C"}