@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.
- package/README.md +32 -0
- package/dist/engine/context-builder.d.ts +5 -0
- package/dist/engine/context-builder.d.ts.map +1 -0
- package/dist/engine/context-builder.js +22 -0
- package/dist/engine/context-builder.js.map +1 -0
- package/dist/engine/pipeline-executor.d.ts +21 -0
- package/dist/engine/pipeline-executor.d.ts.map +1 -0
- package/dist/engine/pipeline-executor.js +80 -0
- package/dist/engine/pipeline-executor.js.map +1 -0
- package/dist/framework/active-modules.d.ts +30 -0
- package/dist/framework/active-modules.d.ts.map +1 -0
- package/dist/framework/active-modules.js +44 -0
- package/dist/framework/active-modules.js.map +1 -0
- package/dist/framework/catalogue.d.ts +148 -0
- package/dist/framework/catalogue.d.ts.map +1 -0
- package/dist/framework/catalogue.js +132 -0
- package/dist/framework/catalogue.js.map +1 -0
- package/dist/framework/dashboard-store.d.ts +136 -0
- package/dist/framework/dashboard-store.d.ts.map +1 -0
- package/dist/framework/dashboard-store.js +301 -0
- package/dist/framework/dashboard-store.js.map +1 -0
- package/dist/framework/layout-schemas.d.ts +106 -0
- package/dist/framework/layout-schemas.d.ts.map +1 -0
- package/dist/framework/layout-schemas.js +67 -0
- package/dist/framework/layout-schemas.js.map +1 -0
- package/dist/framework/layout-types.d.ts +25 -0
- package/dist/framework/layout-types.d.ts.map +1 -0
- package/dist/framework/layout-types.js +7 -0
- package/dist/framework/layout-types.js.map +1 -0
- package/dist/framework/manifest.d.ts +65 -0
- package/dist/framework/manifest.d.ts.map +1 -0
- package/dist/framework/manifest.js +47 -0
- package/dist/framework/manifest.js.map +1 -0
- package/dist/framework/render-view.d.ts +53 -0
- package/dist/framework/render-view.d.ts.map +1 -0
- package/dist/framework/render-view.js +73 -0
- package/dist/framework/render-view.js.map +1 -0
- package/dist/framework/view-builders.d.ts +79 -0
- package/dist/framework/view-builders.d.ts.map +1 -0
- package/dist/framework/view-builders.js +113 -0
- package/dist/framework/view-builders.js.map +1 -0
- package/dist/i18n/index.d.ts +3 -0
- package/dist/i18n/index.d.ts.map +1 -0
- package/dist/i18n/index.js +6 -0
- package/dist/i18n/index.js.map +1 -0
- package/dist/i18n/translator.d.ts +59 -0
- package/dist/i18n/translator.d.ts.map +1 -0
- package/dist/i18n/translator.js +48 -0
- package/dist/i18n/translator.js.map +1 -0
- package/dist/index.d.ts +31 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +27 -0
- package/dist/index.js.map +1 -0
- package/dist/middleware/org-gate.d.ts +22 -0
- package/dist/middleware/org-gate.d.ts.map +1 -0
- package/dist/middleware/org-gate.js +28 -0
- package/dist/middleware/org-gate.js.map +1 -0
- package/dist/middleware/role-filter.d.ts +79 -0
- package/dist/middleware/role-filter.d.ts.map +1 -0
- package/dist/middleware/role-filter.js +95 -0
- package/dist/middleware/role-filter.js.map +1 -0
- package/dist/registry/app-loader.d.ts +35 -0
- package/dist/registry/app-loader.d.ts.map +1 -0
- package/dist/registry/app-loader.js +55 -0
- package/dist/registry/app-loader.js.map +1 -0
- package/dist/registry/step-registry.d.ts +27 -0
- package/dist/registry/step-registry.d.ts.map +1 -0
- package/dist/registry/step-registry.js +53 -0
- package/dist/registry/step-registry.js.map +1 -0
- package/dist/registry/widget-registry.d.ts +15 -0
- package/dist/registry/widget-registry.d.ts.map +1 -0
- package/dist/registry/widget-registry.js +28 -0
- package/dist/registry/widget-registry.js.map +1 -0
- package/dist/rest/client.d.ts +3 -0
- package/dist/rest/client.d.ts.map +1 -0
- package/dist/rest/client.js +155 -0
- package/dist/rest/client.js.map +1 -0
- package/dist/rest/errors.d.ts +14 -0
- package/dist/rest/errors.d.ts.map +1 -0
- package/dist/rest/errors.js +21 -0
- package/dist/rest/errors.js.map +1 -0
- package/dist/rest/index.d.ts +6 -0
- package/dist/rest/index.d.ts.map +1 -0
- package/dist/rest/index.js +4 -0
- package/dist/rest/index.js.map +1 -0
- package/dist/rest/tool.d.ts +60 -0
- package/dist/rest/tool.d.ts.map +1 -0
- package/dist/rest/tool.js +81 -0
- package/dist/rest/tool.js.map +1 -0
- package/dist/rest/types.d.ts +66 -0
- package/dist/rest/types.d.ts.map +1 -0
- package/dist/rest/types.js +2 -0
- package/dist/rest/types.js.map +1 -0
- package/dist/tools/app-resource-uri.d.ts +28 -0
- package/dist/tools/app-resource-uri.d.ts.map +1 -0
- package/dist/tools/app-resource-uri.js +30 -0
- package/dist/tools/app-resource-uri.js.map +1 -0
- package/dist/tools/backend-registry.d.ts +111 -0
- package/dist/tools/backend-registry.d.ts.map +1 -0
- package/dist/tools/backend-registry.js +154 -0
- package/dist/tools/backend-registry.js.map +1 -0
- package/dist/tools/create-framework-app.d.ts +147 -0
- package/dist/tools/create-framework-app.d.ts.map +1 -0
- package/dist/tools/create-framework-app.js +111 -0
- package/dist/tools/create-framework-app.js.map +1 -0
- package/dist/tools/index.d.ts +22 -0
- package/dist/tools/index.d.ts.map +1 -0
- package/dist/tools/index.js +15 -0
- package/dist/tools/index.js.map +1 -0
- package/dist/tools/register-catalogue-tool.d.ts +22 -0
- package/dist/tools/register-catalogue-tool.d.ts.map +1 -0
- package/dist/tools/register-catalogue-tool.js +45 -0
- package/dist/tools/register-catalogue-tool.js.map +1 -0
- package/dist/tools/register-dashboard-tools.d.ts +32 -0
- package/dist/tools/register-dashboard-tools.d.ts.map +1 -0
- package/dist/tools/register-dashboard-tools.js +149 -0
- package/dist/tools/register-dashboard-tools.js.map +1 -0
- package/dist/tools/register-framework-tools.d.ts +83 -0
- package/dist/tools/register-framework-tools.d.ts.map +1 -0
- package/dist/tools/register-framework-tools.js +154 -0
- package/dist/tools/register-framework-tools.js.map +1 -0
- package/dist/tools/register-tool.d.ts +45 -0
- package/dist/tools/register-tool.d.ts.map +1 -0
- package/dist/tools/register-tool.js +82 -0
- package/dist/tools/register-tool.js.map +1 -0
- package/dist/tools/register-widget-tool.d.ts +51 -0
- package/dist/tools/register-widget-tool.d.ts.map +1 -0
- package/dist/tools/register-widget-tool.js +45 -0
- package/dist/tools/register-widget-tool.js.map +1 -0
- package/dist/tools/tool-call-name.d.ts +53 -0
- package/dist/tools/tool-call-name.d.ts.map +1 -0
- package/dist/tools/tool-call-name.js +92 -0
- package/dist/tools/tool-call-name.js.map +1 -0
- package/dist/tools/with-tool-errors.d.ts +16 -0
- package/dist/tools/with-tool-errors.d.ts.map +1 -0
- package/dist/tools/with-tool-errors.js +28 -0
- package/dist/tools/with-tool-errors.js.map +1 -0
- package/dist/types/app.d.ts +44 -0
- package/dist/types/app.d.ts.map +1 -0
- package/dist/types/app.js +2 -0
- package/dist/types/app.js.map +1 -0
- package/dist/types/config.d.ts +15 -0
- package/dist/types/config.d.ts.map +1 -0
- package/dist/types/config.js +2 -0
- package/dist/types/config.js.map +1 -0
- package/dist/types/context.d.ts +18 -0
- package/dist/types/context.d.ts.map +1 -0
- package/dist/types/context.js +2 -0
- package/dist/types/context.js.map +1 -0
- package/dist/types/index.d.ts +10 -0
- package/dist/types/index.d.ts.map +1 -0
- package/dist/types/index.js +2 -0
- package/dist/types/index.js.map +1 -0
- package/dist/types/meta.d.ts +99 -0
- package/dist/types/meta.d.ts.map +1 -0
- package/dist/types/meta.js +66 -0
- package/dist/types/meta.js.map +1 -0
- package/dist/types/pipeline.d.ts +9 -0
- package/dist/types/pipeline.d.ts.map +1 -0
- package/dist/types/pipeline.js +2 -0
- package/dist/types/pipeline.js.map +1 -0
- package/dist/types/step.d.ts +51 -0
- package/dist/types/step.d.ts.map +1 -0
- package/dist/types/step.js +2 -0
- package/dist/types/step.js.map +1 -0
- package/dist/types/view-data.d.ts +67 -0
- package/dist/types/view-data.d.ts.map +1 -0
- package/dist/types/view-data.js +2 -0
- package/dist/types/view-data.js.map +1 -0
- package/dist/types/widget.d.ts +57 -0
- package/dist/types/widget.d.ts.map +1 -0
- package/dist/types/widget.js +2 -0
- package/dist/types/widget.js.map +1 -0
- 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"}
|