@mcpmake/core 0.3.7 → 0.4.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 (61) hide show
  1. package/dist/analyzer/dom-parser.d.ts.map +1 -1
  2. package/dist/analyzer/dom-parser.js +34 -19
  3. package/dist/analyzer/dom-parser.js.map +1 -1
  4. package/dist/analyzer/semantic-analyzer.d.ts.map +1 -1
  5. package/dist/analyzer/semantic-analyzer.js +10 -3
  6. package/dist/analyzer/semantic-analyzer.js.map +1 -1
  7. package/dist/emitter/a2a.d.ts +101 -0
  8. package/dist/emitter/a2a.d.ts.map +1 -0
  9. package/dist/emitter/a2a.js +366 -0
  10. package/dist/emitter/a2a.js.map +1 -0
  11. package/dist/emitter/code-writer.js +10 -10
  12. package/dist/emitter/code-writer.js.map +1 -1
  13. package/dist/emitter/composite-tools.d.ts +99 -0
  14. package/dist/emitter/composite-tools.d.ts.map +1 -0
  15. package/dist/emitter/composite-tools.js +391 -0
  16. package/dist/emitter/composite-tools.js.map +1 -0
  17. package/dist/emitter/mcp-ui.d.ts +42 -0
  18. package/dist/emitter/mcp-ui.d.ts.map +1 -0
  19. package/dist/emitter/mcp-ui.js +146 -0
  20. package/dist/emitter/mcp-ui.js.map +1 -0
  21. package/dist/emitter/mcpb-bundler.d.ts +56 -7
  22. package/dist/emitter/mcpb-bundler.d.ts.map +1 -1
  23. package/dist/emitter/mcpb-bundler.js +60 -11
  24. package/dist/emitter/mcpb-bundler.js.map +1 -1
  25. package/dist/emitter/normalize-tree.d.ts +17 -0
  26. package/dist/emitter/normalize-tree.d.ts.map +1 -0
  27. package/dist/emitter/normalize-tree.js +99 -0
  28. package/dist/emitter/normalize-tree.js.map +1 -0
  29. package/dist/emitter/project-scaffolder.d.ts.map +1 -1
  30. package/dist/emitter/project-scaffolder.js +47 -1
  31. package/dist/emitter/project-scaffolder.js.map +1 -1
  32. package/dist/emitter/python-template-loader.d.ts.map +1 -1
  33. package/dist/emitter/python-template-loader.js +6 -1
  34. package/dist/emitter/python-template-loader.js.map +1 -1
  35. package/dist/emitter/templates/server-main-http.ts.hbs +48 -0
  36. package/dist/emitter/templates/server-main.ts.hbs +38 -0
  37. package/dist/emitter/templates/tsconfig.json.hbs +3 -2
  38. package/dist/index.d.ts +8 -0
  39. package/dist/index.d.ts.map +1 -1
  40. package/dist/index.js +4 -0
  41. package/dist/index.js.map +1 -1
  42. package/dist/parser/overlay-loader.js +5 -1
  43. package/dist/parser/overlay-loader.js.map +1 -1
  44. package/dist/parser/postman-loader.js +7 -0
  45. package/dist/parser/postman-loader.js.map +1 -1
  46. package/dist/pricing.js +2 -2
  47. package/dist/pricing.js.map +1 -1
  48. package/dist/rescan/rescan-scheduler.js +14 -5
  49. package/dist/rescan/rescan-scheduler.js.map +1 -1
  50. package/dist/site-transformer/selector-healer.d.ts.map +1 -1
  51. package/dist/site-transformer/selector-healer.js +8 -0
  52. package/dist/site-transformer/selector-healer.js.map +1 -1
  53. package/dist/transformer/har-to-operations.d.ts.map +1 -1
  54. package/dist/transformer/har-to-operations.js +17 -6
  55. package/dist/transformer/har-to-operations.js.map +1 -1
  56. package/dist/transformer/resource-builder.d.ts.map +1 -1
  57. package/dist/transformer/resource-builder.js +15 -2
  58. package/dist/transformer/resource-builder.js.map +1 -1
  59. package/dist/types/index.d.ts +12 -0
  60. package/dist/types/index.d.ts.map +1 -1
  61. package/package.json +1 -1
@@ -0,0 +1,391 @@
1
+ /**
2
+ * Composite tools (`compositeTools:` in `.mcpmake.yaml`): one MCP tool that
3
+ * orchestrates several EXISTING generated tools in sequence, threading data
4
+ * between them. Opt-in — absent config emits nothing.
5
+ *
6
+ * A composite is declared as an ordered list of steps. Each step names an
7
+ * existing generated tool (by its MCP tool name) and an argument map (`with`)
8
+ * whose values are either:
9
+ * • a literal (string / number / boolean),
10
+ * • `{ $input: <name> }` — a value the composite tool takes as its OWN input,
11
+ * • `{ $step: [i] }` — the whole JSON result of an earlier step i, or
12
+ * • `{ $step: [i, field] }` — a top-level `field` of an earlier step i's result.
13
+ * The composite's `returns` (default: the last step) selects which step result
14
+ * is returned. The composite's inputSchema is the set of distinct `$input` names
15
+ * referenced across every step — each a `z.string()` for v1 (documented limit).
16
+ *
17
+ * The generated handler runs the steps IN ORDER. It invokes each step's
18
+ * underlying request by calling that step's existing generated tool through an
19
+ * in-process MCP loopback client (InMemoryTransport + Client.callTool) — the
20
+ * SAME public-SDK pattern `a2a.ts` uses. This reuses each tool's real request
21
+ * logic verbatim (method, path template, param mapping, auth, jq filtering); no
22
+ * HTTP is reinvented here. Each step's parsed JSON result is stored so later
23
+ * steps and `returns` can reference it.
24
+ *
25
+ * PURE: a deterministic function of the inputs. Every interpolated value (tool
26
+ * names, input names, field names, literals) is JSON.stringify'd into the
27
+ * generated source, so no character from the (untrusted) config can break out of
28
+ * a string literal. No Date.now()/random — identical input → byte-identical output.
29
+ */
30
+ /** Thrown when a composite-tool declaration is invalid (surfaced at build time). */
31
+ export class CompositeToolError extends Error {
32
+ constructor(message) {
33
+ super(message);
34
+ this.name = 'CompositeToolError';
35
+ }
36
+ }
37
+ function isPlainObject(v) {
38
+ return typeof v === 'object' && v !== null && !Array.isArray(v);
39
+ }
40
+ function isInputRef(v) {
41
+ return isPlainObject(v) && typeof v.$input === 'string';
42
+ }
43
+ function isStepRef(v) {
44
+ if (!isPlainObject(v))
45
+ return false;
46
+ const ref = v.$step;
47
+ if (!Array.isArray(ref) || ref.length < 1 || ref.length > 2)
48
+ return false;
49
+ if (typeof ref[0] !== 'number' || !Number.isInteger(ref[0]))
50
+ return false;
51
+ if (ref.length === 2 && typeof ref[1] !== 'string')
52
+ return false;
53
+ return true;
54
+ }
55
+ function isLiteral(v) {
56
+ return typeof v === 'string' || typeof v === 'number' || typeof v === 'boolean';
57
+ }
58
+ /**
59
+ * Parse + validate the raw `compositeTools` value from `.mcpmake.yaml` into typed
60
+ * specs. Throws a {@link CompositeToolError} (clear, build-time) on any malformed
61
+ * entry. Loosely-typed input (the YAML loader returns `unknown`) is checked here.
62
+ */
63
+ export function parseCompositeToolSpecs(raw) {
64
+ if (raw === undefined || raw === null)
65
+ return [];
66
+ if (!Array.isArray(raw)) {
67
+ throw new CompositeToolError('compositeTools must be a list of composite-tool declarations');
68
+ }
69
+ return raw.map((entry, idx) => parseOne(entry, idx));
70
+ }
71
+ function parseOne(entry, idx) {
72
+ const where = `compositeTools[${idx}]`;
73
+ if (!isPlainObject(entry)) {
74
+ throw new CompositeToolError(`${where} must be a mapping`);
75
+ }
76
+ const name = entry.name;
77
+ if (typeof name !== 'string' || !name.trim()) {
78
+ throw new CompositeToolError(`${where} is missing a non-empty "name"`);
79
+ }
80
+ const description = typeof entry.description === 'string' ? entry.description : undefined;
81
+ const rawSteps = entry.steps;
82
+ if (!Array.isArray(rawSteps) || rawSteps.length === 0) {
83
+ throw new CompositeToolError(`Composite tool "${name}" must declare a non-empty "steps" list`);
84
+ }
85
+ const steps = rawSteps.map((s, sIdx) => {
86
+ if (!isPlainObject(s)) {
87
+ throw new CompositeToolError(`Composite tool "${name}" step ${sIdx} must be a mapping`);
88
+ }
89
+ if (typeof s.tool !== 'string' || !s.tool.trim()) {
90
+ throw new CompositeToolError(`Composite tool "${name}" step ${sIdx} is missing a non-empty "tool"`);
91
+ }
92
+ let withMap;
93
+ if (s.with !== undefined) {
94
+ if (!isPlainObject(s.with)) {
95
+ throw new CompositeToolError(`Composite tool "${name}" step ${sIdx} "with" must be a mapping`);
96
+ }
97
+ withMap = {};
98
+ for (const [argName, value] of Object.entries(s.with)) {
99
+ withMap[argName] = parseValue(value, name, sIdx, argName);
100
+ }
101
+ }
102
+ return { tool: s.tool, with: withMap };
103
+ });
104
+ let returns;
105
+ if (entry.returns !== undefined) {
106
+ if (!isStepRef(entry.returns)) {
107
+ throw new CompositeToolError(`Composite tool "${name}" "returns" must be a { $step: [i] } / { $step: [i, field] } reference`);
108
+ }
109
+ returns = entry.returns;
110
+ }
111
+ return { name, description, steps, returns };
112
+ }
113
+ function parseValue(value, toolName, stepIdx, argName) {
114
+ if (isLiteral(value))
115
+ return value;
116
+ if (isInputRef(value)) {
117
+ if (!value.$input.trim()) {
118
+ throw new CompositeToolError(`Composite tool "${toolName}" step ${stepIdx} arg "${argName}": $input name must be non-empty`);
119
+ }
120
+ return value;
121
+ }
122
+ if (isStepRef(value))
123
+ return value;
124
+ throw new CompositeToolError(`Composite tool "${toolName}" step ${stepIdx} arg "${argName}" must be a literal, ` +
125
+ `{ $input: <name> }, or { $step: [i] } / { $step: [i, field] }`);
126
+ }
127
+ /**
128
+ * Validate a single composite spec against the set of existing tool names and
129
+ * derive its build result (the `$input` names that form its inputSchema). Throws
130
+ * a {@link CompositeToolError} on any invalid reference. Validation rules:
131
+ * • every step's `tool` must be an existing generated tool name;
132
+ * • a `$step: [i]` may reference only an EARLIER step (i < current step index)
133
+ * and a valid step index (0 ≤ i);
134
+ * • `returns` must reference a valid step index (0 ≤ i < steps.length);
135
+ * • the composite name must not collide with an existing tool name.
136
+ */
137
+ export function validateCompositeTool(spec, existingToolNames) {
138
+ if (existingToolNames.has(spec.name)) {
139
+ throw new CompositeToolError(`Composite tool "${spec.name}" collides with an existing generated tool of the same name`);
140
+ }
141
+ const inputNames = new Set();
142
+ spec.steps.forEach((step, stepIdx) => {
143
+ if (!existingToolNames.has(step.tool)) {
144
+ throw new CompositeToolError(`Composite tool "${spec.name}" step ${stepIdx} references unknown tool "${step.tool}". ` +
145
+ `It must name an existing generated tool.`);
146
+ }
147
+ for (const [argName, value] of Object.entries(step.with ?? {})) {
148
+ if (isInputRef(value)) {
149
+ inputNames.add(value.$input);
150
+ }
151
+ else if (isStepRef(value)) {
152
+ const target = value.$step[0];
153
+ if (target < 0 || target >= stepIdx) {
154
+ throw new CompositeToolError(`Composite tool "${spec.name}" step ${stepIdx} arg "${argName}" references step ${target}, ` +
155
+ `but a step may only reference an EARLIER step (0..${stepIdx - 1}).`);
156
+ }
157
+ }
158
+ }
159
+ });
160
+ const returnsTarget = spec.returns ? spec.returns.$step[0] : spec.steps.length - 1;
161
+ if (returnsTarget < 0 || returnsTarget >= spec.steps.length) {
162
+ throw new CompositeToolError(`Composite tool "${spec.name}" "returns" references step ${returnsTarget}, ` +
163
+ `but valid steps are 0..${spec.steps.length - 1}.`);
164
+ }
165
+ return { inputNames: [...inputNames].sort() };
166
+ }
167
+ /**
168
+ * Emit the runtime expression that resolves one composite {@link CompositeValue}
169
+ * at handler runtime. Literals and refs are JSON.stringify'd so no config text
170
+ * can break out of the generated source. `$step` references read from the
171
+ * `steps` result array; `[i, field]` calls a runtime helper that throws a clear
172
+ * error when the result is not an object or the field is missing.
173
+ */
174
+ function emitValueExpr(value) {
175
+ if (isInputRef(value)) {
176
+ // Read from the composite tool's own input object.
177
+ return `input[${JSON.stringify(value.$input)}]`;
178
+ }
179
+ if (isStepRef(value)) {
180
+ const [i, field] = value.$step;
181
+ if (field === undefined) {
182
+ return `steps[${JSON.stringify(i)}]`;
183
+ }
184
+ return `stepField(steps, ${JSON.stringify(i)}, ${JSON.stringify(field)})`;
185
+ }
186
+ // Literal: JSON-encode (covers string/number/boolean inertly).
187
+ return JSON.stringify(value);
188
+ }
189
+ /** Emit the `arguments` object literal for one step's tool call. */
190
+ function emitArgsObject(withMap) {
191
+ const entries = Object.entries(withMap ?? {});
192
+ if (entries.length === 0)
193
+ return '{}';
194
+ const lines = entries.map(([argName, value]) => ` ${JSON.stringify(argName)}: ${emitValueExpr(value)},`);
195
+ return `{\n${lines.join('\n')}\n }`;
196
+ }
197
+ /** Emit the JS for one step inside the handler's sequential run loop. */
198
+ function emitStep(step, stepIdx) {
199
+ return (` // Step ${stepIdx}: ${'invoke an existing generated tool'}\n` +
200
+ ` steps[${stepIdx}] = await callStep(client, ${JSON.stringify(step.tool)}, ${emitArgsObject(step.with)});`);
201
+ }
202
+ /** Emit the registration for one composite tool (its inputSchema + handler). */
203
+ function emitCompositeRegistration(spec, build) {
204
+ const schemaFields = build.inputNames.length === 0
205
+ ? '{}'
206
+ : `{\n${build.inputNames
207
+ .map((n) => ` ${JSON.stringify(n)}: z.string().describe('Input "${escapeForLineComment(n)}" for composite tool ${escapeForLineComment(spec.name)}'),`)
208
+ .join('\n')}\n }`;
209
+ const stepsBody = spec.steps.map((s, i) => emitStep(s, i)).join('\n');
210
+ const returnsTarget = spec.returns ? spec.returns.$step[0] : spec.steps.length - 1;
211
+ const returnsField = spec.returns && spec.returns.$step.length === 2 ? spec.returns.$step[1] : undefined;
212
+ const returnExpr = returnsField === undefined
213
+ ? `steps[${JSON.stringify(returnsTarget)}]`
214
+ : `stepField(steps, ${JSON.stringify(returnsTarget)}, ${JSON.stringify(returnsField)})`;
215
+ return ` server.registerTool(
216
+ ${JSON.stringify(spec.name)},
217
+ {
218
+ title: ${JSON.stringify(spec.name)},
219
+ description: ${JSON.stringify(spec.description ?? `Composite tool: runs ${spec.steps.length} step(s) in order.`)},
220
+ inputSchema: ${schemaFields},
221
+ },
222
+ async (rawInput) => {
223
+ const input = rawInput as Record<string, unknown>;
224
+ const steps: unknown[] = [];
225
+ try {
226
+ const client = await getClient(registerTools);
227
+ ${stepsBody}
228
+ const result = ${returnExpr};
229
+ return {
230
+ content: [{ type: 'text' as const, text: JSON.stringify(result, null, 2) }],
231
+ };
232
+ } catch (error) {
233
+ const message = error instanceof Error ? error.message : String(error);
234
+ return {
235
+ content: [{ type: 'text' as const, text: \`Error: \${message}\` }],
236
+ isError: true,
237
+ };
238
+ }
239
+ },
240
+ );`;
241
+ }
242
+ /**
243
+ * Escape a string for safe inclusion inside a single-quoted JS string that is
244
+ * itself emitted as part of a `.describe('...')` call. Strips quotes/backslashes/
245
+ * newlines so an input/tool name from config can never break the literal.
246
+ */
247
+ function escapeForLineComment(s) {
248
+ return s.replace(/[\\'\r\n]/g, '');
249
+ }
250
+ /**
251
+ * Build the `src/composite-tools.ts` module that registers every composite tool.
252
+ * Validates each spec against the existing tool names first (throws a
253
+ * {@link CompositeToolError} on any invalid reference). Returns the module
254
+ * source.
255
+ *
256
+ * The handler dispatches each step through an in-process MCP loopback client
257
+ * (the same `InMemoryTransport` + `Client.callTool` pattern as `a2a.ts`), so the
258
+ * step's real generated request logic runs — no HTTP is reinvented. The
259
+ * `registerTools` callback (passed by the server entry) populates the dedicated
260
+ * loopback server with the same tool surface the primary server exposes.
261
+ */
262
+ export function buildCompositeToolsModule(specs, tools) {
263
+ const existingToolNames = new Set(tools.map((t) => t.name));
264
+ // Reject a composite whose name duplicates another composite, too — they are
265
+ // all registered on the same server and a dup would crash registration.
266
+ const seenComposite = new Set();
267
+ const registrations = specs.map((spec) => {
268
+ if (seenComposite.has(spec.name)) {
269
+ throw new CompositeToolError(`Duplicate composite tool name "${spec.name}"`);
270
+ }
271
+ seenComposite.add(spec.name);
272
+ const build = validateCompositeTool(spec, existingToolNames);
273
+ return emitCompositeRegistration(spec, build);
274
+ });
275
+ return `import { z } from 'zod';
276
+ import type { McpServer } from '@modelcontextprotocol/sdk/server/mcp.js';
277
+ import { Client } from '@modelcontextprotocol/sdk/client/index.js';
278
+ import { InMemoryTransport } from '@modelcontextprotocol/sdk/inMemory.js';
279
+
280
+ /* Composite tools: each runs several EXISTING generated tools in order, threading
281
+ * data between them. Steps are dispatched through an in-process MCP loopback
282
+ * client connected to a DEDICATED server populated with the same tool surface, so
283
+ * each step reuses that tool's real request logic (method, path, params, auth, jq
284
+ * filtering). Generated by @mcpmake/core — do not edit by hand. */
285
+
286
+ type ToolResult = Awaited<ReturnType<Client['callTool']>>;
287
+
288
+ /* Parse a step tool's CallToolResult into a plain JS value for later steps and
289
+ * the composite's return. Prefers structuredContent (the SDK validates it against
290
+ * the tool's outputSchema); otherwise parses the first text block as JSON, falling
291
+ * back to the raw text. A tool that reported isError fails the whole composite. */
292
+ function parseStepResult(result: ToolResult): unknown {
293
+ if ((result as { isError?: unknown }).isError === true) {
294
+ const content = (result as { content?: unknown }).content;
295
+ const text =
296
+ Array.isArray(content) && content[0] && typeof content[0] === 'object'
297
+ ? String((content[0] as { text?: unknown }).text ?? '')
298
+ : 'step tool reported an error';
299
+ throw new Error(text);
300
+ }
301
+ const structured = (result as { structuredContent?: unknown }).structuredContent;
302
+ if (structured !== undefined) return structured;
303
+ const content = (result as { content?: unknown }).content;
304
+ if (Array.isArray(content)) {
305
+ for (const block of content) {
306
+ if (block && typeof block === 'object' && (block as { type?: unknown }).type === 'text') {
307
+ const text = String((block as { text?: unknown }).text ?? '');
308
+ try {
309
+ return JSON.parse(text);
310
+ } catch {
311
+ return text;
312
+ }
313
+ }
314
+ }
315
+ }
316
+ return undefined;
317
+ }
318
+
319
+ /* Resolve a { $step: [i, field] } reference: read \`field\` off step i's result.
320
+ * Throws a clear error when the result is not an object or the field is missing,
321
+ * so the composite tool call fails with a useful message. */
322
+ function stepField(steps: unknown[], i: number, field: string): unknown {
323
+ const r = steps[i];
324
+ if (r === null || typeof r !== 'object' || Array.isArray(r)) {
325
+ throw new Error(
326
+ \`Cannot read field "\${field}" from step \${i}: its result is not a JSON object\`,
327
+ );
328
+ }
329
+ if (!(field in (r as Record<string, unknown>))) {
330
+ throw new Error(\`Step \${i} result has no field "\${field}"\`);
331
+ }
332
+ return (r as Record<string, unknown>)[field];
333
+ }
334
+
335
+ /* Invoke one step's existing generated tool via the loopback client and return
336
+ * its parsed result. \`args\` values come from the composite's own input or an
337
+ * earlier step's result. */
338
+ async function callStep(
339
+ client: Client,
340
+ toolName: string,
341
+ args: Record<string, unknown>,
342
+ ): Promise<unknown> {
343
+ // Strip args whose resolved value is undefined (an absent optional input) so the
344
+ // step tool sees only the arguments actually supplied.
345
+ const clean: Record<string, unknown> = {};
346
+ for (const [k, v] of Object.entries(args)) {
347
+ if (v !== undefined) clean[k] = v;
348
+ }
349
+ const result = await client.callTool({ name: toolName, arguments: clean });
350
+ return parseStepResult(result);
351
+ }
352
+
353
+ /* Lazily stand up (once) the DEDICATED loopback McpServer + in-process MCP client
354
+ * that composite steps dispatch through. \`registerTools\` populates the loopback
355
+ * server with the same tool surface the primary server exposes, so each step
356
+ * reuses that tool's real request logic. Memoized: the first composite call
357
+ * connects the pair; subsequent calls reuse it. Public SDK API only. */
358
+ let clientPromise: Promise<Client> | undefined;
359
+ function getClient(registerTools: (s: McpServer) => void): Promise<Client> {
360
+ if (!clientPromise) {
361
+ clientPromise = (async () => {
362
+ const { McpServer: McpServerCtor } = await import(
363
+ '@modelcontextprotocol/sdk/server/mcp.js'
364
+ );
365
+ const loopback = new McpServerCtor({ name: 'composite-loopback', version: '0.0.0' });
366
+ registerTools(loopback);
367
+ const client = new Client({ name: 'composite-loopback-client', version: '0.0.0' });
368
+ const [clientTransport, serverTransport] = InMemoryTransport.createLinkedPair();
369
+ await loopback.connect(serverTransport);
370
+ await client.connect(clientTransport);
371
+ return client;
372
+ })();
373
+ }
374
+ return clientPromise;
375
+ }
376
+
377
+ /**
378
+ * Register every composite tool on \`server\`. \`registerTools\` populates the
379
+ * dedicated loopback server (lazily, on the first composite call) with the same
380
+ * tool surface the primary server exposes, so a composite step never contends
381
+ * with the primary transport.
382
+ */
383
+ export function registerCompositeTools(
384
+ server: McpServer,
385
+ registerTools: (s: McpServer) => void,
386
+ ): void {
387
+ ${registrations.join('\n\n')}
388
+ }
389
+ `;
390
+ }
391
+ //# sourceMappingURL=composite-tools.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"composite-tools.js","sourceRoot":"","sources":["../../src/emitter/composite-tools.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,42 @@
1
+ /**
2
+ * MCP Apps output (`mcp-ui`): generate a sandboxed-iframe HTML UI for a generated MCP
3
+ * server, conformant to the MCP-UI standard (MCP-UI-Org/mcp-ui):
4
+ * • the server exposes a UIResource at `ui://<server>/tools`,
5
+ * • mimeType `text/html;profile=mcp-app`,
6
+ * • the HTML runs in the host's sandboxed iframe and asks the host to invoke a tool via
7
+ * `window.parent.postMessage({ type: 'tool', payload: { toolName, params } }, '*')`.
8
+ *
9
+ * The generated UI is a TOOL LAUNCHER: it lists every tool with a JSON-params box and an
10
+ * Invoke button that posts the tool-call message. Everything is inline (no external assets)
11
+ * so it works under a strict iframe sandbox. PURE: a deterministic function of the inputs,
12
+ * with all interpolated values HTML/JS-escaped (tool descriptions come from the source API
13
+ * and must never break out of the markup).
14
+ */
15
+ /** MCP-UI standard MIME type for inline HTML app content. */
16
+ export declare const MCP_UI_MIME = "text/html;profile=mcp-app";
17
+ export interface McpUiTool {
18
+ name: string;
19
+ description: string;
20
+ }
21
+ export interface McpUiResource {
22
+ uri: string;
23
+ mimeType: string;
24
+ text: string;
25
+ }
26
+ /** The `ui://` resource URI for a server's tool launcher. */
27
+ export declare function mcpUiUri(serverName: string): string;
28
+ /**
29
+ * Build the tool-launcher HTML. Each tool gets a JSON-params textarea and an Invoke button
30
+ * that posts the MCP-UI `tool` message to the host. Tool names are JSON-encoded into the
31
+ * script (so a name can never break the string literal); descriptions are HTML-escaped.
32
+ */
33
+ export declare function buildMcpUiHtml(serverName: string, tools: readonly McpUiTool[]): string;
34
+ /** Build the full MCP-UI resource (uri + mimeType + HTML) for a server's tools. */
35
+ export declare function mcpUiResource(serverName: string, tools: readonly McpUiTool[]): McpUiResource;
36
+ /**
37
+ * Generate the `src/mcp-ui.ts` module the server ships when MCP Apps output is enabled.
38
+ * It registers the `ui://` UIResource via the MCP SDK; the HTML is embedded as a JSON-encoded
39
+ * string constant (so any character in it is inert in the generated source).
40
+ */
41
+ export declare function buildMcpUiModule(serverName: string, tools: readonly McpUiTool[]): string;
42
+ //# sourceMappingURL=mcp-ui.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"mcp-ui.d.ts","sourceRoot":"","sources":["../../src/emitter/mcp-ui.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;GAaG;AAEH,6DAA6D;AAC7D,eAAO,MAAM,WAAW,8BAA8B,CAAC;AAEvD,MAAM,WAAW,SAAS;IACxB,IAAI,EAAE,MAAM,CAAC;IACb,WAAW,EAAE,MAAM,CAAC;CACrB;AAED,MAAM,WAAW,aAAa;IAC5B,GAAG,EAAE,MAAM,CAAC;IACZ,QAAQ,EAAE,MAAM,CAAC;IACjB,IAAI,EAAE,MAAM,CAAC;CACd;AAqBD,6DAA6D;AAC7D,wBAAgB,QAAQ,CAAC,UAAU,EAAE,MAAM,GAAG,MAAM,CAEnD;AAED;;;;GAIG;AACH,wBAAgB,cAAc,CAAC,UAAU,EAAE,MAAM,EAAE,KAAK,EAAE,SAAS,SAAS,EAAE,GAAG,MAAM,CA4DtF;AAED,mFAAmF;AACnF,wBAAgB,aAAa,CAAC,UAAU,EAAE,MAAM,EAAE,KAAK,EAAE,SAAS,SAAS,EAAE,GAAG,aAAa,CAM5F;AAED;;;;GAIG;AACH,wBAAgB,gBAAgB,CAAC,UAAU,EAAE,MAAM,EAAE,KAAK,EAAE,SAAS,SAAS,EAAE,GAAG,MAAM,CA+BxF"}
@@ -0,0 +1,146 @@
1
+ /**
2
+ * MCP Apps output (`mcp-ui`): generate a sandboxed-iframe HTML UI for a generated MCP
3
+ * server, conformant to the MCP-UI standard (MCP-UI-Org/mcp-ui):
4
+ * • the server exposes a UIResource at `ui://<server>/tools`,
5
+ * • mimeType `text/html;profile=mcp-app`,
6
+ * • the HTML runs in the host's sandboxed iframe and asks the host to invoke a tool via
7
+ * `window.parent.postMessage({ type: 'tool', payload: { toolName, params } }, '*')`.
8
+ *
9
+ * The generated UI is a TOOL LAUNCHER: it lists every tool with a JSON-params box and an
10
+ * Invoke button that posts the tool-call message. Everything is inline (no external assets)
11
+ * so it works under a strict iframe sandbox. PURE: a deterministic function of the inputs,
12
+ * with all interpolated values HTML/JS-escaped (tool descriptions come from the source API
13
+ * and must never break out of the markup).
14
+ */
15
+ /** MCP-UI standard MIME type for inline HTML app content. */
16
+ export const MCP_UI_MIME = 'text/html;profile=mcp-app';
17
+ /** Escape a string for use in HTML text / double-quoted attribute context. */
18
+ function escapeHtml(s) {
19
+ return s
20
+ .replace(/&/g, '&amp;')
21
+ .replace(/</g, '&lt;')
22
+ .replace(/>/g, '&gt;')
23
+ .replace(/"/g, '&quot;')
24
+ .replace(/'/g, '&#39;');
25
+ }
26
+ /** Slugify a server name for the `ui://` host segment (kebab, alnum + dashes). */
27
+ function uiSlug(serverName) {
28
+ const slug = serverName
29
+ .toLowerCase()
30
+ .replace(/[^a-z0-9]+/g, '-')
31
+ .replace(/^-+|-+$/g, '');
32
+ return slug || 'server';
33
+ }
34
+ /** The `ui://` resource URI for a server's tool launcher. */
35
+ export function mcpUiUri(serverName) {
36
+ return `ui://${uiSlug(serverName)}/tools`;
37
+ }
38
+ /**
39
+ * Build the tool-launcher HTML. Each tool gets a JSON-params textarea and an Invoke button
40
+ * that posts the MCP-UI `tool` message to the host. Tool names are JSON-encoded into the
41
+ * script (so a name can never break the string literal); descriptions are HTML-escaped.
42
+ */
43
+ export function buildMcpUiHtml(serverName, tools) {
44
+ const title = escapeHtml(serverName);
45
+ const items = tools
46
+ .map((t) => {
47
+ const name = escapeHtml(t.name);
48
+ const desc = escapeHtml(t.description || '');
49
+ // data-tool carries the raw (escaped) name; the click handler reads it back.
50
+ return (` <li class="tool">\n` +
51
+ ` <div class="tool-head"><code>${name}</code>${desc ? ` — <span class="desc">${desc}</span>` : ''}</div>\n` +
52
+ ` <details><summary>params (JSON)</summary><textarea data-params="${name}">{}</textarea></details>\n` +
53
+ ` <button type="button" data-tool="${name}">Invoke</button>\n` +
54
+ ` </li>`);
55
+ })
56
+ .join('\n');
57
+ return `<!doctype html>
58
+ <html lang="en">
59
+ <head>
60
+ <meta charset="utf-8">
61
+ <meta name="viewport" content="width=device-width, initial-scale=1">
62
+ <title>${title} — MCP tools</title>
63
+ <style>
64
+ body { font: 14px/1.5 system-ui, sans-serif; margin: 1rem; color: #111; }
65
+ h1 { font-size: 1.2rem; }
66
+ ul { list-style: none; padding: 0; }
67
+ .tool { border: 1px solid #ddd; border-radius: 6px; padding: .6rem .8rem; margin: .5rem 0; }
68
+ .desc { color: #555; }
69
+ textarea { width: 100%; box-sizing: border-box; font: 12px monospace; min-height: 3rem; }
70
+ button { margin-top: .4rem; cursor: pointer; }
71
+ code { background: #f4f4f4; padding: 0 .25rem; border-radius: 3px; }
72
+ </style>
73
+ </head>
74
+ <body>
75
+ <h1>${title}</h1>
76
+ <p>${tools.length} tool${tools.length === 1 ? '' : 's'}. Edit the JSON params and click Invoke — the host runs the tool.</p>
77
+ <ul>
78
+ ${items}
79
+ </ul>
80
+ <script>
81
+ document.querySelectorAll('button[data-tool]').forEach(function (btn) {
82
+ btn.addEventListener('click', function () {
83
+ var name = btn.getAttribute('data-tool');
84
+ var ta = document.querySelector('textarea[data-params="' + name + '"]');
85
+ var params = {};
86
+ try {
87
+ params = ta && ta.value.trim() ? JSON.parse(ta.value) : {};
88
+ } catch (e) {
89
+ alert('Invalid JSON params for ' + name);
90
+ return;
91
+ }
92
+ // MCP-UI host interaction: ask the host to call the tool.
93
+ window.parent.postMessage({ type: 'tool', payload: { toolName: name, params: params } }, '*');
94
+ });
95
+ });
96
+ </script>
97
+ </body>
98
+ </html>
99
+ `;
100
+ }
101
+ /** Build the full MCP-UI resource (uri + mimeType + HTML) for a server's tools. */
102
+ export function mcpUiResource(serverName, tools) {
103
+ return {
104
+ uri: mcpUiUri(serverName),
105
+ mimeType: MCP_UI_MIME,
106
+ text: buildMcpUiHtml(serverName, tools),
107
+ };
108
+ }
109
+ /**
110
+ * Generate the `src/mcp-ui.ts` module the server ships when MCP Apps output is enabled.
111
+ * It registers the `ui://` UIResource via the MCP SDK; the HTML is embedded as a JSON-encoded
112
+ * string constant (so any character in it is inert in the generated source).
113
+ */
114
+ export function buildMcpUiModule(serverName, tools) {
115
+ const res = mcpUiResource(serverName, tools);
116
+ // Mirrors the generated resources.ts registration pattern (McpServer + ResourceTemplate)
117
+ // so it compiles against the same MCP SDK the rest of the server uses.
118
+ return `import { McpServer } from '@modelcontextprotocol/sdk/server/mcp.js';
119
+ import { ResourceTemplate } from '@modelcontextprotocol/sdk/server/mcp.js';
120
+
121
+ const MCP_UI_URI = ${JSON.stringify(res.uri)};
122
+ const MCP_UI_MIME = ${JSON.stringify(res.mimeType)};
123
+ const MCP_UI_HTML = ${JSON.stringify(res.text)};
124
+
125
+ /**
126
+ * Register the MCP Apps (mcp-ui) tool-launcher UI as a ui:// resource. Hosts that support
127
+ * MCP Apps render MCP_UI_HTML in a sandboxed iframe; its Invoke buttons post a
128
+ * { type: 'tool', payload: { toolName, params } } message to the host to call a tool.
129
+ */
130
+ export function registerMcpUi(server: McpServer): void {
131
+ server.registerResource(
132
+ 'mcp-ui',
133
+ new ResourceTemplate(MCP_UI_URI, { list: undefined }),
134
+ {
135
+ title: ${JSON.stringify(`${serverName} UI`)},
136
+ description: 'Interactive tool launcher (MCP Apps / mcp-ui)',
137
+ mimeType: MCP_UI_MIME,
138
+ },
139
+ async (uri) => ({
140
+ contents: [{ uri: uri.href, mimeType: MCP_UI_MIME, text: MCP_UI_HTML }],
141
+ }),
142
+ );
143
+ }
144
+ `;
145
+ }
146
+ //# sourceMappingURL=mcp-ui.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"mcp-ui.js","sourceRoot":"","sources":["../../src/emitter/mcp-ui.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;GAaG;AAEH,6DAA6D;AAC7D,MAAM,CAAC,MAAM,WAAW,GAAG,2BAA2B,CAAC;AAavD,8EAA8E;AAC9E,SAAS,UAAU,CAAC,CAAS;IAC3B,OAAO,CAAC;SACL,OAAO,CAAC,IAAI,EAAE,OAAO,CAAC;SACtB,OAAO,CAAC,IAAI,EAAE,MAAM,CAAC;SACrB,OAAO,CAAC,IAAI,EAAE,MAAM,CAAC;SACrB,OAAO,CAAC,IAAI,EAAE,QAAQ,CAAC;SACvB,OAAO,CAAC,IAAI,EAAE,OAAO,CAAC,CAAC;AAC5B,CAAC;AAED,kFAAkF;AAClF,SAAS,MAAM,CAAC,UAAkB;IAChC,MAAM,IAAI,GAAG,UAAU;SACpB,WAAW,EAAE;SACb,OAAO,CAAC,aAAa,EAAE,GAAG,CAAC;SAC3B,OAAO,CAAC,UAAU,EAAE,EAAE,CAAC,CAAC;IAC3B,OAAO,IAAI,IAAI,QAAQ,CAAC;AAC1B,CAAC;AAED,6DAA6D;AAC7D,MAAM,UAAU,QAAQ,CAAC,UAAkB;IACzC,OAAO,QAAQ,MAAM,CAAC,UAAU,CAAC,QAAQ,CAAC;AAC5C,CAAC;AAED;;;;GAIG;AACH,MAAM,UAAU,cAAc,CAAC,UAAkB,EAAE,KAA2B;IAC5E,MAAM,KAAK,GAAG,UAAU,CAAC,UAAU,CAAC,CAAC;IACrC,MAAM,KAAK,GAAG,KAAK;SAChB,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE;QACT,MAAM,IAAI,GAAG,UAAU,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC;QAChC,MAAM,IAAI,GAAG,UAAU,CAAC,CAAC,CAAC,WAAW,IAAI,EAAE,CAAC,CAAC;QAC7C,6EAA6E;QAC7E,OAAO,CACL,2BAA2B;YAC3B,wCAAwC,IAAI,UAAU,IAAI,CAAC,CAAC,CAAC,yBAAyB,IAAI,SAAS,CAAC,CAAC,CAAC,EAAE,UAAU;YAClH,2EAA2E,IAAI,6BAA6B;YAC5G,4CAA4C,IAAI,qBAAqB;YACrE,aAAa,CACd,CAAC;IACJ,CAAC,CAAC;SACD,IAAI,CAAC,IAAI,CAAC,CAAC;IAEd,OAAO;;;;;WAKE,KAAK;;;;;;;;;;;;;QAaR,KAAK;OACN,KAAK,CAAC,MAAM,QAAQ,KAAK,CAAC,MAAM,KAAK,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,GAAG;;EAEtD,KAAK;;;;;;;;;;;;;;;;;;;;;CAqBN,CAAC;AACF,CAAC;AAED,mFAAmF;AACnF,MAAM,UAAU,aAAa,CAAC,UAAkB,EAAE,KAA2B;IAC3E,OAAO;QACL,GAAG,EAAE,QAAQ,CAAC,UAAU,CAAC;QACzB,QAAQ,EAAE,WAAW;QACrB,IAAI,EAAE,cAAc,CAAC,UAAU,EAAE,KAAK,CAAC;KACxC,CAAC;AACJ,CAAC;AAED;;;;GAIG;AACH,MAAM,UAAU,gBAAgB,CAAC,UAAkB,EAAE,KAA2B;IAC9E,MAAM,GAAG,GAAG,aAAa,CAAC,UAAU,EAAE,KAAK,CAAC,CAAC;IAC7C,yFAAyF;IACzF,uEAAuE;IACvE,OAAO;;;qBAGY,IAAI,CAAC,SAAS,CAAC,GAAG,CAAC,GAAG,CAAC;sBACtB,IAAI,CAAC,SAAS,CAAC,GAAG,CAAC,QAAQ,CAAC;sBAC5B,IAAI,CAAC,SAAS,CAAC,GAAG,CAAC,IAAI,CAAC;;;;;;;;;;;;eAY/B,IAAI,CAAC,SAAS,CAAC,GAAG,UAAU,KAAK,CAAC;;;;;;;;;CAShD,CAAC;AACF,CAAC"}