@tangle-network/agent-app 0.12.0 → 0.14.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (41) hide show
  1. package/dist/DesignCanvas-3JEEIT6Y.js +10 -0
  2. package/dist/DesignCanvas-3JEEIT6Y.js.map +1 -0
  3. package/dist/DesignCanvasEditor-37LPJIIR.js +9 -0
  4. package/dist/DesignCanvasEditor-37LPJIIR.js.map +1 -0
  5. package/dist/chunk-2Q73HGDI.js +1743 -0
  6. package/dist/chunk-2Q73HGDI.js.map +1 -0
  7. package/dist/{chunk-3WAJWYKD.js → chunk-6UOE5CTA.js} +9 -92
  8. package/dist/{chunk-3WAJWYKD.js.map → chunk-6UOE5CTA.js.map} +1 -1
  9. package/dist/chunk-7QCIYDGC.js +1119 -0
  10. package/dist/chunk-7QCIYDGC.js.map +1 -0
  11. package/dist/chunk-A76ZHWNF.js +194 -0
  12. package/dist/chunk-A76ZHWNF.js.map +1 -0
  13. package/dist/chunk-F5KTWRO7.js +2276 -0
  14. package/dist/chunk-F5KTWRO7.js.map +1 -0
  15. package/dist/chunk-JZAJE3JL.js +990 -0
  16. package/dist/chunk-JZAJE3JL.js.map +1 -0
  17. package/dist/{chunk-CF5DZELC.js → chunk-SSX2A6XX.js} +39 -2
  18. package/dist/chunk-SSX2A6XX.js.map +1 -0
  19. package/dist/design-canvas/drizzle.d.ts +569 -0
  20. package/dist/design-canvas/drizzle.js +183 -0
  21. package/dist/design-canvas/drizzle.js.map +1 -0
  22. package/dist/design-canvas/index.d.ts +261 -0
  23. package/dist/design-canvas/index.js +96 -0
  24. package/dist/design-canvas/index.js.map +1 -0
  25. package/dist/design-canvas-react/index.d.ts +916 -0
  26. package/dist/design-canvas-react/index.js +423 -0
  27. package/dist/design-canvas-react/index.js.map +1 -0
  28. package/dist/export-presets-Dl5Aa5xj.d.ts +284 -0
  29. package/dist/index.d.ts +6 -1
  30. package/dist/index.js +103 -3
  31. package/dist/mcp-rpc-DLw_r9PQ.d.ts +55 -0
  32. package/dist/model-BHLN208Z.d.ts +183 -0
  33. package/dist/sequences/index.d.ts +4 -0
  34. package/dist/sequences/index.js +2 -2
  35. package/dist/store-CUStmtdH.d.ts +64 -0
  36. package/dist/tools/index.d.ts +64 -2
  37. package/dist/tools/index.js +10 -2
  38. package/package.json +28 -3
  39. package/dist/chunk-CF5DZELC.js.map +0 -1
  40. package/dist/chunk-IJZJWKUK.js +0 -77
  41. package/dist/chunk-IJZJWKUK.js.map +0 -1
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/design-canvas/operations.ts","../src/design-canvas/templates.ts","../src/design-canvas/mcp-tools.ts","../src/design-canvas/mcp-handler.ts","../src/design-canvas/mcp-entry.ts"],"sourcesContent":["/**\n * The design-canvas operation union — the ONE mutation vocabulary shared by\n * the editor's command stack (human edits, undo/redo), the MCP tool\n * dispatcher (agent edits), and programmatic automation (template\n * instantiation, data sync). Every state change the editor can express is an\n * operation here; anything not expressible here does not happen to a\n * document. That closure is the automation contract: replaying a decision\n * log reproduces the document.\n *\n * Attribute patches are validated per element kind in ./validate before\n * ./apply mutates the document; both run server-side on every path.\n */\n\nimport type { NewPageOptions, PageBleed, PageGuides, SceneElement } from './model'\n\n/** Per-kind attribute patch. `kind` is immutable after creation; ids are\n * immutable always. Validation rejects attrs foreign to the target's kind. */\nexport type SceneAttrsPatch = Partial<Omit<SceneElement, 'id' | 'kind' | 'children'>> & {\n text?: string\n width?: number\n height?: number\n points?: number[]\n fill?: string\n stroke?: string\n strokeWidth?: number\n cornerRadius?: number\n dash?: number[]\n fontFamily?: string\n fontSize?: number\n fontStyle?: 'normal' | 'bold' | 'italic' | 'bold italic'\n align?: 'left' | 'center' | 'right'\n lineHeight?: number\n letterSpacing?: number\n src?: string\n posterSrc?: string\n fit?: 'fill' | 'cover' | 'contain'\n}\n\nexport interface AddElementOperation {\n type: 'add_element'\n pageId: string\n /** Complete element including caller-minted id (reconciled like sequences\n * clips when the server re-mints). */\n element: SceneElement\n /** Insertion z-index; omitted → top. */\n index?: number\n /** Parent group; omitted → page root. */\n parentGroupId?: string\n}\n\nexport interface SetAttrsOperation {\n type: 'set_attrs'\n pageId: string\n elementId: string\n attrs: SceneAttrsPatch\n}\n\nexport interface ReorderElementOperation {\n type: 'reorder_element'\n pageId: string\n elementId: string\n /** Target index within the element's CURRENT owner (page root or group). */\n toIndex: number\n}\n\nexport interface DeleteElementOperation {\n type: 'delete_element'\n pageId: string\n elementId: string\n}\n\nexport interface GroupElementsOperation {\n type: 'group_elements'\n pageId: string\n /** ≥ 2 sibling elements (same owner); grouped in their current z-order. */\n elementIds: string[]\n /** Caller-minted id for the new group. */\n groupId: string\n name?: string\n}\n\nexport interface UngroupElementOperation {\n type: 'ungroup_element'\n pageId: string\n groupId: string\n}\n\nexport interface AddPageOperation {\n type: 'add_page'\n /** Caller-minted page id. */\n pageId: string\n options?: NewPageOptions\n /** Position in the page list; omitted → end. */\n index?: number\n}\n\nexport interface DuplicatePageOperation {\n type: 'duplicate_page'\n sourcePageId: string\n /** Caller-minted id for the copy; element ids are re-minted server-side. */\n pageId: string\n}\n\nexport interface DeletePageOperation {\n type: 'delete_page'\n pageId: string\n}\n\nexport interface ReorderPageOperation {\n type: 'reorder_page'\n pageId: string\n toIndex: number\n}\n\nexport interface SetPagePropsOperation {\n type: 'set_page_props'\n pageId: string\n name?: string\n width?: number\n height?: number\n background?: string\n /** null clears bleed; omitted leaves unchanged. */\n bleed?: PageBleed | null\n}\n\nexport interface SetPageGuidesOperation {\n type: 'set_page_guides'\n pageId: string\n guides: PageGuides\n}\n\nexport interface BindSlotOperation {\n type: 'bind_slot'\n pageId: string\n elementId: string\n /** null unbinds. Slot names are unique document-wide. */\n slot: string | null\n}\n\n/** Fill slots with data — text slots take strings, image/video slots take\n * src URLs. Unknown slot names throw; partial application is allowed. */\nexport interface ApplyDataOperation {\n type: 'apply_data'\n bindings: Record<string, string>\n}\n\nexport interface SetDocumentTitleOperation {\n type: 'set_document_title'\n title: string\n}\n\nexport type SceneOperation =\n | AddElementOperation\n | SetAttrsOperation\n | ReorderElementOperation\n | DeleteElementOperation\n | GroupElementsOperation\n | UngroupElementOperation\n | AddPageOperation\n | DuplicatePageOperation\n | DeletePageOperation\n | ReorderPageOperation\n | SetPagePropsOperation\n | SetPageGuidesOperation\n | BindSlotOperation\n | ApplyDataOperation\n | SetDocumentTitleOperation\n\nexport interface ScenePlan {\n summary: string\n operations: SceneOperation[]\n}\n\nexport type SceneOperationType = SceneOperation['type']\n\nexport const SCENE_OPERATION_TYPES: readonly SceneOperationType[] = [\n 'add_element',\n 'set_attrs',\n 'reorder_element',\n 'delete_element',\n 'group_elements',\n 'ungroup_element',\n 'add_page',\n 'duplicate_page',\n 'delete_page',\n 'reorder_page',\n 'set_page_props',\n 'set_page_guides',\n 'bind_slot',\n 'apply_data',\n 'set_document_title',\n] as const\n","/**\n * Template helpers for design-canvas documents. A template is any document\n * whose elements carry `slot` names — those slots define the fillable surface\n * that data sources and agents target. The helpers here are pure (no store,\n * no Konva) so they run server-side, in MCP tools, or in tests without a DOM.\n *\n * Binding semantics (shared with `apply_data` operation):\n * - text elements: binding value replaces `element.text`\n * - image/video elements: binding value replaces `element.src`\n * - rect/ellipse elements with a slot: binding value replaces `element.fill`\n * (color-slot convention — background swatch templates)\n * - line/group slots are reserved; binding them throws a loud error\n * Unknown binding keys (no matching slot) throw — callers must preflight with\n * `validateBindings` or accept that the throw is the signal to fix their data.\n */\n\nimport {\n SCENE_SCHEMA_VERSION,\n type SceneDocument,\n type SceneElement,\n type ScenePage,\n type SceneElementKind,\n collectSlots,\n} from './model'\n\n// ---------------------------------------------------------------------------\n// Slot surface\n// ---------------------------------------------------------------------------\n\nexport type SlotFillKind = 'text' | 'src' | 'color'\n\nexport interface TemplateSlot {\n name: string\n pageId: string\n elementId: string\n elementKind: SceneElementKind\n fillKind: SlotFillKind\n}\n\n/**\n * Wraps `collectSlots` with kind-aware fill typing so callers know WHAT to\n * put in each slot without inspecting the element tree themselves.\n * Throws when duplicate slot names exist (propagated from collectSlots).\n */\nexport function listTemplateSlots(document: SceneDocument): TemplateSlot[] {\n const raw = collectSlots(document)\n const slots: TemplateSlot[] = []\n for (const [name, { pageId, elementId, kind }] of raw) {\n slots.push({ name, pageId, elementId, elementKind: kind, fillKind: fillKindForElementKind(kind) })\n }\n return slots\n}\n\nfunction fillKindForElementKind(kind: SceneElementKind): SlotFillKind {\n switch (kind) {\n case 'text': return 'text'\n case 'image':\n case 'video': return 'src'\n case 'rect':\n case 'ellipse': return 'color'\n case 'line':\n case 'group':\n throw new Error(\n `slot on \"${kind}\" element has no defined fill kind — bind_slot should not target line or group elements`,\n )\n }\n}\n\n// ---------------------------------------------------------------------------\n// Binding validation\n// ---------------------------------------------------------------------------\n\n/**\n * Preflight check: every key in `bindings` must name a slot in the document.\n * Returns a list of problems; an empty array means the bindings are clean.\n * Does NOT throw — designed to run before `instantiateTemplate` so callers\n * can surface a structured error instead of catching.\n */\nexport function validateBindings(\n document: SceneDocument,\n bindings: Record<string, string>,\n): string[] {\n const slots = collectSlots(document)\n const problems: string[] = []\n for (const key of Object.keys(bindings)) {\n if (!slots.has(key)) {\n problems.push(`binding key \"${key}\" does not match any slot in the document`)\n }\n }\n return problems\n}\n\n// ---------------------------------------------------------------------------\n// Template instantiation\n// ---------------------------------------------------------------------------\n\nexport interface InstantiateOptions {\n /** Human-readable title for the new document. */\n title: string\n /** Slot bindings to apply after id re-minting. Partial application allowed. */\n bindings?: Record<string, string>\n /**\n * Caller-supplied id factory — every page/element id in the source document\n * is replaced with a fresh value from this callback. The callback receives\n * the source id so implementations can build stable deterministic ids (e.g.\n * `crypto.randomUUID()` or `nanoid()` from the host).\n */\n mintId(sourceId: string): string\n}\n\n/**\n * Produces a new `SceneDocument` from a template:\n * 1. Re-mints every page and element id via `options.mintId` (slot *names* are\n * preserved so apply_data still targets them by name).\n * 2. Applies `options.bindings` with the same semantics as `apply_data`.\n * 3. Stamps `metadata.templateSourceId` with the source document's title so\n * the lineage is traceable without storing separate template provenance rows.\n *\n * Throws when bindings reference unknown slots (validated via `validateBindings`\n * before mutation so no partial state is possible).\n */\nexport function instantiateTemplate(\n document: SceneDocument,\n options: InstantiateOptions,\n): SceneDocument {\n const bindings = options.bindings ?? {}\n\n // Preflight — throw before touching the document tree\n const problems = validateBindings(document, bindings)\n if (problems.length > 0) {\n throw new Error(`template bindings are invalid:\\n${problems.map((p) => ` - ${p}`).join('\\n')}`)\n }\n\n // Build id mapping: sourceId → mintedId. Walk all page + element ids now so\n // group children can reference their parent's minted id during deep copy.\n const idMap = new Map<string, string>()\n const allocate = (sourceId: string): string => {\n if (idMap.has(sourceId)) return idMap.get(sourceId)!\n const minted = options.mintId(sourceId)\n idMap.set(sourceId, minted)\n return minted\n }\n\n for (const page of document.pages) {\n allocate(page.id)\n collectElementIds(page.elements, allocate)\n }\n\n // Deep-copy pages with re-minted ids\n const newPages: ScenePage[] = document.pages.map((page) => ({\n ...page,\n id: idMap.get(page.id)!,\n elements: copyElements(page.elements, idMap),\n }))\n\n const newDocument: SceneDocument = {\n schemaVersion: SCENE_SCHEMA_VERSION,\n title: options.title,\n pages: newPages,\n settings: { ...document.settings },\n metadata: {\n ...document.metadata,\n templateSourceId: document.title,\n },\n }\n\n // Apply bindings against the copied document (ids are now minted, slots preserved)\n return Object.keys(bindings).length > 0 ? applyBindings(newDocument, bindings) : newDocument\n}\n\n// ---------------------------------------------------------------------------\n// Binding application (shared with apply_data operation semantics)\n// ---------------------------------------------------------------------------\n\n/**\n * Applies slot bindings to a document in place (mutates a deep copy produced\n * by the caller). Unknown slot names throw — the preflight in `instantiateTemplate`\n * guarantees this is unreachable there; exported so the `apply_data` operation\n * handler can reuse it without duplicating the switch.\n */\nexport function applyBindingsToDocument(\n document: SceneDocument,\n bindings: Record<string, string>,\n): SceneDocument {\n const problems = validateBindings(document, bindings)\n if (problems.length > 0) {\n throw new Error(`apply_data bindings are invalid:\\n${problems.map((p) => ` - ${p}`).join('\\n')}`)\n }\n return applyBindings(document, bindings)\n}\n\n// Internal — called only after validateBindings passes\nfunction applyBindings(document: SceneDocument, bindings: Record<string, string>): SceneDocument {\n const slots = collectSlots(document)\n // Build a lookup: elementId → { slot, value } so the walk is O(elements)\n const targetMap = new Map<string, { slotName: string; value: string }>()\n for (const [slotName, { elementId }] of slots) {\n const value = bindings[slotName]\n if (value !== undefined) {\n targetMap.set(elementId, { slotName, value })\n }\n }\n\n const newPages: ScenePage[] = document.pages.map((page) => ({\n ...page,\n elements: applyBindingsToElements(page.elements, targetMap),\n }))\n\n return { ...document, pages: newPages }\n}\n\nfunction applyBindingsToElements(\n elements: SceneElement[],\n targetMap: Map<string, { slotName: string; value: string }>,\n): SceneElement[] {\n return elements.map((element) => {\n const target = targetMap.get(element.id)\n let updated = element\n\n if (target !== undefined) {\n updated = applyBindingToElement(element, target.value, target.slotName)\n }\n\n if (updated.kind === 'group') {\n return { ...updated, children: applyBindingsToElements(updated.children, targetMap) }\n }\n return updated\n })\n}\n\nfunction applyBindingToElement(element: SceneElement, value: string, slotName: string): SceneElement {\n switch (element.kind) {\n case 'text': return { ...element, text: value }\n case 'image': return { ...element, src: value }\n case 'video': return { ...element, src: value }\n case 'rect': return { ...element, fill: value }\n case 'ellipse': return { ...element, fill: value }\n case 'line':\n case 'group':\n throw new Error(\n `slot \"${slotName}\" on \"${element.kind}\" element cannot accept a binding — remove the slot or use a supported element kind`,\n )\n }\n}\n\n// ---------------------------------------------------------------------------\n// Deep copy helpers\n// ---------------------------------------------------------------------------\n\nfunction collectElementIds(elements: SceneElement[], allocate: (id: string) => string): void {\n for (const element of elements) {\n allocate(element.id)\n if (element.kind === 'group') collectElementIds(element.children, allocate)\n }\n}\n\nfunction copyElements(elements: SceneElement[], idMap: Map<string, string>): SceneElement[] {\n return elements.map((element) => copyElement(element, idMap))\n}\n\nfunction copyElement(element: SceneElement, idMap: Map<string, string>): SceneElement {\n const newId = idMap.get(element.id)\n if (newId === undefined) throw new Error(`element ${element.id} was not pre-allocated in the id map — this is a bug in instantiateTemplate`)\n const base = { ...element, id: newId }\n if (base.kind === 'group') {\n return { ...base, children: copyElements(base.children, idMap) }\n }\n return base\n}\n","/**\n * Design-canvas MCP tool registry — what the in-sandbox agent sees over the\n * live agent→canvas channel. Each entry carries an LLM-facing description, a\n * JSON Schema for the arguments, and the typed dispatch that validates the\n * resulting operations, applies them through the store, and records ONE\n * decision row per mutating call.\n *\n * Every mutation: validate → apply via storeApplyScenePlan → recordDecision.\n * Throws anywhere become isError results the model reads to correct its call.\n *\n * Convenience sugar tools (add_text, move_element, etc.) expand to the\n * underlying operation primitives before reaching the kernel — no separate\n * code path to drift.\n */\n\nimport { elementAabb, requirePage, SCENE_ELEMENT_KINDS } from './model'\nimport type {\n RectElement,\n EllipseElement,\n LineElement,\n TextElement,\n ImageElement,\n VideoElement,\n SceneDocument,\n SceneElement,\n ScenePage,\n} from './model'\nimport type { SceneOperation, ScenePlan } from './operations'\nimport type { SceneStore } from './store'\nimport { storeApplyScenePlan } from './apply'\nimport type { McpToolDefinition } from '../tools/mcp-rpc'\n\n// ---------------------------------------------------------------------------\n// Tool env\n// ---------------------------------------------------------------------------\n\nexport interface DesignCanvasMcpToolEnv {\n store: SceneStore\n mintId: () => string\n}\n\n// ---------------------------------------------------------------------------\n// Argument readers — fail loud with name + expected type\n// ---------------------------------------------------------------------------\n\nfunction isRecord(value: unknown): value is Record<string, unknown> {\n return typeof value === 'object' && value !== null && !Array.isArray(value)\n}\n\nfunction requireString(args: Record<string, unknown>, name: string): string {\n const value = args[name]\n if (typeof value !== 'string' || value.trim().length === 0) {\n throw new Error(`${name} is required and must be a non-empty string`)\n }\n return value\n}\n\nfunction optionalString(args: Record<string, unknown>, name: string): string | undefined {\n const value = args[name]\n if (value === undefined || value === null) return undefined\n if (typeof value !== 'string') throw new Error(`${name} must be a string when provided`)\n return value\n}\n\nfunction requireNumber(args: Record<string, unknown>, name: string): number {\n const value = args[name]\n if (typeof value !== 'number' || !Number.isFinite(value)) {\n throw new Error(`${name} is required and must be a finite number`)\n }\n return value\n}\n\nfunction optionalNumber(args: Record<string, unknown>, name: string): number | undefined {\n const value = args[name]\n if (value === undefined || value === null) return undefined\n if (typeof value !== 'number' || !Number.isFinite(value)) {\n throw new Error(`${name} must be a finite number when provided`)\n }\n return value\n}\n\nfunction optionalBoolean(args: Record<string, unknown>, name: string): boolean | undefined {\n const value = args[name]\n if (value === undefined || value === null) return undefined\n if (typeof value !== 'boolean') throw new Error(`${name} must be a boolean when provided`)\n return value\n}\n\nfunction optionalNonNegativeInteger(args: Record<string, unknown>, name: string): number | undefined {\n const value = args[name]\n if (value === undefined || value === null) return undefined\n if (typeof value !== 'number' || !Number.isInteger(value) || value < 0) {\n throw new Error(`${name} must be a non-negative integer when provided`)\n }\n return value\n}\n\nfunction requireStringArray(args: Record<string, unknown>, name: string): string[] {\n const value = args[name]\n if (!Array.isArray(value) || value.length === 0 || value.some((v) => typeof v !== 'string')) {\n throw new Error(`${name} is required and must be a non-empty array of strings`)\n }\n return value as string[]\n}\n\nfunction optionalRecord(args: Record<string, unknown>, name: string): Record<string, string> | undefined {\n const value = args[name]\n if (value === undefined || value === null) return undefined\n if (!isRecord(value) || Object.values(value).some((v) => typeof v !== 'string')) {\n throw new Error(`${name} must be an object mapping string keys to string values when provided`)\n }\n return value as Record<string, string>\n}\n\nfunction requireEnum<T extends string>(args: Record<string, unknown>, name: string, values: readonly T[]): T {\n const value = args[name]\n if (typeof value !== 'string' || !(values as readonly string[]).includes(value)) {\n throw new Error(`${name} must be one of: ${values.join(', ')}`)\n }\n return value as T\n}\n\nfunction optionalEnum<T extends string>(args: Record<string, unknown>, name: string, values: readonly T[]): T | undefined {\n const value = args[name]\n if (value === undefined || value === null) return undefined\n return requireEnum(args, name, values)\n}\n\n// ---------------------------------------------------------------------------\n// Shared helpers\n// ---------------------------------------------------------------------------\n\n/** Pick the first page id when the caller omits page_id. */\nfunction resolvePageId(document: SceneDocument, args: Record<string, unknown>): string {\n const pageId = optionalString(args, 'page_id')\n if (pageId) {\n requirePage(document, pageId)\n return pageId\n }\n const first = document.pages[0]\n if (!first) throw new Error('document has no pages')\n return first.id\n}\n\nfunction elementAabbRecord(el: SceneElement) {\n const aabb = elementAabb(el)\n return { x: aabb.x, y: aabb.y, width: aabb.width, height: aabb.height }\n}\n\nfunction pageSnapshot(page: ScenePage) {\n return {\n id: page.id,\n name: page.name,\n width: page.width,\n height: page.height,\n background: page.background,\n bleed: page.bleed,\n element_count: page.elements.length,\n elements: page.elements.map((el) => ({\n id: el.id,\n kind: el.kind,\n name: el.name,\n aabb: elementAabbRecord(el),\n rotation: el.rotation,\n opacity: el.opacity,\n locked: el.locked,\n visible: el.visible,\n ...(el.slot ? { slot: el.slot } : {}),\n })),\n }\n}\n\nasync function applyPlan(\n store: SceneStore,\n mintId: () => string,\n summary: string,\n operations: SceneOperation[],\n): Promise<{ rev: number; operation_count: number }> {\n const plan: ScenePlan = { summary, operations }\n const { record } = await storeApplyScenePlan(store, plan, { actorKind: 'agent_edit', mintId })\n return { rev: record.rev, operation_count: operations.length }\n}\n\n/** Collect slot→elementId mapping for a SINGLE page (no cross-page slot walk,\n * so duplicate slot names across different pages don't cause an error). */\nfunction collectPageSlotAttrs(page: ScenePage): Map<string, { elementId: string; kind: SceneElement['kind'] }> {\n const slots = new Map<string, { elementId: string; kind: SceneElement['kind'] }>()\n const stack = [...page.elements]\n while (stack.length > 0) {\n const el = stack.pop()!\n if (el.slot) {\n if (slots.has(el.slot)) {\n throw new Error(`duplicate slot name \"${el.slot}\" on page ${page.id}`)\n }\n slots.set(el.slot, { elementId: el.id, kind: el.kind })\n }\n if (el.kind === 'group') stack.push(...el.children)\n }\n return slots\n}\n\n\n// ---------------------------------------------------------------------------\n// JSON Schema helpers\n// ---------------------------------------------------------------------------\n\nfunction objectSchema(properties: Record<string, unknown>, required: string[]): Record<string, unknown> {\n return { type: 'object', properties, required, additionalProperties: false }\n}\n\nconst pageIdProp = { type: 'string', description: 'Page id to target. Omit to target the first page.' }\nconst elementIdProp = { type: 'string', description: 'Element id to target.' }\nconst xProp = { type: 'number', description: 'X position in page coordinates (px).' }\nconst yProp = { type: 'number', description: 'Y position in page coordinates (px).' }\nconst widthProp = { type: 'number', description: 'Width in px (must be > 0).' }\nconst heightProp = { type: 'number', description: 'Height in px (must be > 0).' }\nconst colorProp = (label: string) => ({ type: 'string', description: `${label} — hex (#rrggbb), rgb(), rgba(), or \"transparent\".` })\n\n// ---------------------------------------------------------------------------\n// Tool implementations\n// ---------------------------------------------------------------------------\n\nconst CANVAS_MCP_TOOLS: McpToolDefinition<DesignCanvasMcpToolEnv>[] = [\n\n // ─── read ────────────────────────────────────────────────────────────────\n\n {\n name: 'get_scene_state',\n description:\n 'Read the full scene document: title, settings, all pages with dimensions and background, and every element with its axis-aligned bounding box (so you can reason about layout and overlap without rendering). Call this before editing to get real page and element ids.',\n inputSchema: objectSchema({}, []),\n async run(_args, env) {\n const { document, rev } = await env.store.getDocument()\n return {\n rev,\n title: document.title,\n schema_version: document.schemaVersion,\n settings: document.settings,\n pages: document.pages.map(pageSnapshot),\n }\n },\n },\n\n {\n name: 'describe_page',\n description:\n 'Read one page in detail: name, dimensions, background, bleed, guides, and every element with geometry, attributes, and slot bindings. Use this when you need attribute values (fill, font, src) the compact get_scene_state summary omits.',\n inputSchema: objectSchema(\n { page_id: pageIdProp },\n ['page_id'],\n ),\n async run(args, env) {\n const pageId = requireString(args, 'page_id')\n const { document, rev } = await env.store.getDocument()\n const page = requirePage(document, pageId)\n return {\n rev,\n id: page.id,\n name: page.name,\n width: page.width,\n height: page.height,\n background: page.background,\n bleed: page.bleed,\n guides: page.guides,\n elements: page.elements.map((el) => ({ ...el, aabb: elementAabbRecord(el) })),\n }\n },\n },\n\n {\n name: 'list_decisions',\n description: 'List recent agent decisions recorded against this document. Useful to audit what the agent has already done this session.',\n inputSchema: objectSchema(\n { limit: { type: 'number', description: 'Max decisions to return (default 20, max 100).' } },\n [],\n ),\n async run(args, env) {\n const limitRaw = optionalNumber(args, 'limit') ?? 20\n const limit = Math.min(100, Math.max(1, Math.round(limitRaw)))\n const decisions = await env.store.listDecisions(limit)\n return { decisions }\n },\n },\n\n // ─── add convenience wrappers ─────────────────────────────────────────────\n\n {\n name: 'add_text',\n description:\n 'Place a text element on a page. The element id is minted server-side and returned. x/y are the top-left in page coordinates (px). width sets the wrap column; height derives from content at render time.',\n inputSchema: objectSchema(\n {\n page_id: pageIdProp,\n text: { type: 'string', description: 'Initial text content.' },\n x: xProp,\n y: yProp,\n width: widthProp,\n font_size: { type: 'number', description: 'Font size in px (must be > 0). Default 24.' },\n font_family: { type: 'string', description: 'CSS font family. Default \"Inter\".' },\n font_style: { type: 'string', enum: ['normal', 'bold', 'italic', 'bold italic'], description: 'Default \"normal\".' },\n fill: colorProp('Text color. Default \"#000000\".'),\n align: { type: 'string', enum: ['left', 'center', 'right'], description: 'Default \"left\".' },\n line_height: { type: 'number', description: 'Line height multiplier. Default 1.2.' },\n letter_spacing: { type: 'number', description: 'Letter spacing in px. Default 0.' },\n name: { type: 'string', description: 'Layer name. Defaults to the first 32 chars of text.' },\n slot: { type: 'string', description: 'Template slot name — allows apply_data to replace this text programmatically.' },\n },\n ['text', 'x', 'y', 'width'],\n ),\n async run(args, env) {\n const { document } = await env.store.getDocument()\n const pageId = resolvePageId(document, args)\n const id = env.mintId()\n const text = requireString(args, 'text')\n const element: TextElement = {\n id,\n kind: 'text',\n name: optionalString(args, 'name') ?? text.slice(0, 32),\n x: requireNumber(args, 'x'),\n y: requireNumber(args, 'y'),\n width: requireNumber(args, 'width'),\n text,\n fontFamily: optionalString(args, 'font_family') ?? 'Inter',\n fontSize: optionalNumber(args, 'font_size') ?? 24,\n fontStyle: optionalEnum(args, 'font_style', ['normal', 'bold', 'italic', 'bold italic'] as const) ?? 'normal',\n fill: optionalString(args, 'fill') ?? '#000000',\n align: optionalEnum(args, 'align', ['left', 'center', 'right'] as const) ?? 'left',\n lineHeight: optionalNumber(args, 'line_height') ?? 1.2,\n letterSpacing: optionalNumber(args, 'letter_spacing') ?? 0,\n rotation: 0,\n opacity: 1,\n locked: false,\n visible: true,\n ...(() => { const s = optionalString(args, 'slot'); return s ? { slot: s } : {} })(),\n }\n const result = await applyPlan(env.store, env.mintId, `add text \"${text.slice(0, 40)}\"`, [\n { type: 'add_element', pageId, element },\n ])\n return { element_id: id, ...result }\n },\n },\n\n {\n name: 'add_image',\n description:\n 'Place an image element on a page. src must be an http(s) URL or a rooted /api/ path — never a data: blob. The element id is minted server-side and returned.',\n inputSchema: objectSchema(\n {\n page_id: pageIdProp,\n src: { type: 'string', description: 'Image URL (https://...) or /api/ path.' },\n x: xProp,\n y: yProp,\n width: widthProp,\n height: heightProp,\n fit: { type: 'string', enum: ['fill', 'cover', 'contain'], description: 'How the source maps into the frame. Default \"cover\".' },\n name: { type: 'string', description: 'Layer name. Default \"Image\".' },\n slot: { type: 'string', description: 'Template slot name — allows apply_data to swap this image\\'s src.' },\n },\n ['src', 'x', 'y', 'width', 'height'],\n ),\n async run(args, env) {\n const { document } = await env.store.getDocument()\n const pageId = resolvePageId(document, args)\n const id = env.mintId()\n const element: ImageElement = {\n id,\n kind: 'image',\n name: optionalString(args, 'name') ?? 'Image',\n x: requireNumber(args, 'x'),\n y: requireNumber(args, 'y'),\n width: requireNumber(args, 'width'),\n height: requireNumber(args, 'height'),\n src: requireString(args, 'src'),\n fit: optionalEnum(args, 'fit', ['fill', 'cover', 'contain'] as const) ?? 'cover',\n rotation: 0,\n opacity: 1,\n locked: false,\n visible: true,\n ...(() => { const s = optionalString(args, 'slot'); return s ? { slot: s } : {} })(),\n }\n const result = await applyPlan(env.store, env.mintId, 'add image element', [\n { type: 'add_element', pageId, element },\n ])\n return { element_id: id, ...result }\n },\n },\n\n {\n name: 'add_shape',\n description:\n 'Place a geometric shape on a page. kind must be \"rect\", \"ellipse\", or \"line\". For line: provide points as a flat [x0,y0,x1,y1,...] array (relative to x,y); for rect/ellipse: provide width and height.',\n inputSchema: objectSchema(\n {\n page_id: pageIdProp,\n kind: { type: 'string', enum: ['rect', 'ellipse', 'line'], description: 'Shape type.' },\n x: xProp,\n y: yProp,\n width: { type: 'number', description: 'Width in px (required for rect and ellipse).' },\n height: { type: 'number', description: 'Height in px (required for rect and ellipse).' },\n fill: colorProp('Fill color (rect/ellipse). Default \"#cccccc\".'),\n stroke: colorProp('Stroke/line color.'),\n stroke_width: { type: 'number', description: 'Stroke width in px.' },\n corner_radius: { type: 'number', description: 'Corner radius in px (rect only).' },\n points: {\n type: 'array',\n items: { type: 'number' },\n description: 'Flat [x0,y0,x1,y1,...] array for lines, relative to (x,y). Required for kind=\"line\".',\n },\n name: { type: 'string', description: 'Layer name.' },\n },\n ['kind', 'x', 'y'],\n ),\n async run(args, env) {\n const { document } = await env.store.getDocument()\n const pageId = resolvePageId(document, args)\n const id = env.mintId()\n const kind = requireEnum(args, 'kind', ['rect', 'ellipse', 'line'] as const)\n const x = requireNumber(args, 'x')\n const y = requireNumber(args, 'y')\n let element: SceneElement\n if (kind === 'rect') {\n const rect: RectElement = {\n id, kind, x, y,\n name: optionalString(args, 'name') ?? 'Rectangle',\n width: requireNumber(args, 'width'),\n height: requireNumber(args, 'height'),\n fill: optionalString(args, 'fill') ?? '#cccccc',\n rotation: 0, opacity: 1, locked: false, visible: true,\n ...(optionalString(args, 'stroke') ? { stroke: optionalString(args, 'stroke') } : {}),\n ...(optionalNumber(args, 'stroke_width') !== undefined ? { strokeWidth: optionalNumber(args, 'stroke_width') } : {}),\n ...(optionalNumber(args, 'corner_radius') !== undefined ? { cornerRadius: optionalNumber(args, 'corner_radius') } : {}),\n }\n element = rect\n } else if (kind === 'ellipse') {\n const ellipse: EllipseElement = {\n id, kind, x, y,\n name: optionalString(args, 'name') ?? 'Ellipse',\n width: requireNumber(args, 'width'),\n height: requireNumber(args, 'height'),\n fill: optionalString(args, 'fill') ?? '#cccccc',\n rotation: 0, opacity: 1, locked: false, visible: true,\n ...(optionalString(args, 'stroke') ? { stroke: optionalString(args, 'stroke') } : {}),\n ...(optionalNumber(args, 'stroke_width') !== undefined ? { strokeWidth: optionalNumber(args, 'stroke_width') } : {}),\n }\n element = ellipse\n } else {\n const rawPoints = args['points']\n if (!Array.isArray(rawPoints) || rawPoints.length < 4 || rawPoints.length % 2 !== 0) {\n throw new Error('points is required for kind=\"line\" and must be a flat [x0,y0,...] array with ≥ 2 points')\n }\n const points = rawPoints as number[]\n const line: LineElement = {\n id, kind, x, y, points,\n name: optionalString(args, 'name') ?? 'Line',\n stroke: optionalString(args, 'stroke') ?? '#000000',\n strokeWidth: optionalNumber(args, 'stroke_width') ?? 2,\n rotation: 0, opacity: 1, locked: false, visible: true,\n }\n element = line\n }\n const result = await applyPlan(env.store, env.mintId, `add ${kind} shape`, [\n { type: 'add_element', pageId, element },\n ])\n return { element_id: id, ...result }\n },\n },\n\n {\n name: 'add_video',\n description:\n 'Place a video element on a page. Video renders and exports as its poster frame — motion belongs to the sequences surface. src must be an http(s) URL or /api/ path.',\n inputSchema: objectSchema(\n {\n page_id: pageIdProp,\n src: { type: 'string', description: 'Video URL (https://...) or /api/ path.' },\n x: xProp,\n y: yProp,\n width: widthProp,\n height: heightProp,\n poster_src: { type: 'string', description: 'Poster frame URL shown before render. Optional.' },\n name: { type: 'string', description: 'Layer name. Default \"Video\".' },\n },\n ['src', 'x', 'y', 'width', 'height'],\n ),\n async run(args, env) {\n const { document } = await env.store.getDocument()\n const pageId = resolvePageId(document, args)\n const id = env.mintId()\n const element: VideoElement = {\n id,\n kind: 'video',\n name: optionalString(args, 'name') ?? 'Video',\n x: requireNumber(args, 'x'),\n y: requireNumber(args, 'y'),\n width: requireNumber(args, 'width'),\n height: requireNumber(args, 'height'),\n src: requireString(args, 'src'),\n rotation: 0,\n opacity: 1,\n locked: false,\n visible: true,\n ...(() => { const s = optionalString(args, 'poster_src'); return s ? { posterSrc: s } : {} })(),\n }\n const result = await applyPlan(env.store, env.mintId, 'add video element', [\n { type: 'add_element', pageId, element },\n ])\n return { element_id: id, ...result }\n },\n },\n\n // ─── mutations ────────────────────────────────────────────────────────────\n\n {\n name: 'set_attrs',\n description:\n 'Set one or more attributes on an existing element. Only provide the attrs you want to change — omitted attributes are unchanged. Attempting to change kind or id is an error. For convenience transforms (x/y/width/height/rotation) prefer move_element, resize_element, or rotate_element.',\n inputSchema: objectSchema(\n {\n page_id: pageIdProp,\n element_id: elementIdProp,\n attrs: {\n type: 'object',\n description: 'Attribute patch — any subset of the element\\'s mutable fields.',\n additionalProperties: true,\n },\n },\n ['page_id', 'element_id', 'attrs'],\n ),\n async run(args, env) {\n const pageId = requireString(args, 'page_id')\n const elementId = requireString(args, 'element_id')\n if (!isRecord(args['attrs'])) throw new Error('attrs must be an object')\n const attrs = args['attrs'] as Record<string, unknown>\n const result = await applyPlan(env.store, env.mintId, `set attrs on ${elementId}`, [\n { type: 'set_attrs', pageId, elementId, attrs: attrs as import('./operations').SceneAttrsPatch },\n ])\n return result\n },\n },\n\n {\n name: 'move_element',\n description: 'Move an element to a new (x, y) position in page coordinates. Sugar for set_attrs({x, y}).',\n inputSchema: objectSchema(\n { page_id: pageIdProp, element_id: elementIdProp, x: xProp, y: yProp },\n ['page_id', 'element_id', 'x', 'y'],\n ),\n async run(args, env) {\n const pageId = requireString(args, 'page_id')\n const elementId = requireString(args, 'element_id')\n const x = requireNumber(args, 'x')\n const y = requireNumber(args, 'y')\n const result = await applyPlan(env.store, env.mintId, `move element ${elementId} to (${x}, ${y})`, [\n { type: 'set_attrs', pageId, elementId, attrs: { x, y } },\n ])\n return result\n },\n },\n\n {\n name: 'resize_element',\n description: 'Resize an element by setting its width and height. Sugar for set_attrs({width, height}). Not valid on lines (use set_attrs with points instead).',\n inputSchema: objectSchema(\n { page_id: pageIdProp, element_id: elementIdProp, width: widthProp, height: heightProp },\n ['page_id', 'element_id', 'width', 'height'],\n ),\n async run(args, env) {\n const pageId = requireString(args, 'page_id')\n const elementId = requireString(args, 'element_id')\n const width = requireNumber(args, 'width')\n const height = requireNumber(args, 'height')\n const result = await applyPlan(env.store, env.mintId, `resize element ${elementId} to ${width}×${height}`, [\n { type: 'set_attrs', pageId, elementId, attrs: { width, height } },\n ])\n return result\n },\n },\n\n {\n name: 'rotate_element',\n description: 'Set an element\\'s rotation in degrees (clockwise, about the element\\'s top-left origin). Sugar for set_attrs({rotation}).',\n inputSchema: objectSchema(\n {\n page_id: pageIdProp,\n element_id: elementIdProp,\n degrees: { type: 'number', description: 'Rotation in degrees (clockwise, 0–360 or negative).' },\n },\n ['page_id', 'element_id', 'degrees'],\n ),\n async run(args, env) {\n const pageId = requireString(args, 'page_id')\n const elementId = requireString(args, 'element_id')\n const rotation = requireNumber(args, 'degrees')\n const result = await applyPlan(env.store, env.mintId, `rotate element ${elementId} to ${rotation}°`, [\n { type: 'set_attrs', pageId, elementId, attrs: { rotation } },\n ])\n return result\n },\n },\n\n {\n name: 'reorder_element',\n description:\n 'Change an element\\'s z-order within its owner (page root or parent group). toIndex is 0-based within the owner\\'s element list: 0 = bottom, length-1 = top.',\n inputSchema: objectSchema(\n {\n page_id: pageIdProp,\n element_id: elementIdProp,\n to_index: { type: 'number', description: '0-based target z-index within the element\\'s owner.' },\n },\n ['page_id', 'element_id', 'to_index'],\n ),\n async run(args, env) {\n const pageId = requireString(args, 'page_id')\n const elementId = requireString(args, 'element_id')\n const toIndex = optionalNonNegativeInteger(args, 'to_index') ?? 0\n const result = await applyPlan(env.store, env.mintId, `reorder element ${elementId} to index ${toIndex}`, [\n { type: 'reorder_element', pageId, elementId, toIndex },\n ])\n return result\n },\n },\n\n {\n name: 'delete_element',\n description: 'Permanently delete an element (and all its children if it is a group) from a page.',\n inputSchema: objectSchema(\n { page_id: pageIdProp, element_id: elementIdProp },\n ['page_id', 'element_id'],\n ),\n async run(args, env) {\n const pageId = requireString(args, 'page_id')\n const elementId = requireString(args, 'element_id')\n const result = await applyPlan(env.store, env.mintId, `delete element ${elementId}`, [\n { type: 'delete_element', pageId, elementId },\n ])\n return result\n },\n },\n\n {\n name: 'group_elements',\n description:\n 'Group 2+ sibling elements into a new group. Elements must share the same owner (page root or the same parent group). The group\\'s origin is set to the minimum bounding box of the members; children are rebased to group-local coordinates.',\n inputSchema: objectSchema(\n {\n page_id: pageIdProp,\n element_ids: { type: 'array', items: { type: 'string' }, minItems: 2, description: '≥2 sibling element ids to group.' },\n name: { type: 'string', description: 'Layer name for the new group. Default \"Group\".' },\n },\n ['page_id', 'element_ids'],\n ),\n async run(args, env) {\n const pageId = requireString(args, 'page_id')\n const elementIds = requireStringArray(args, 'element_ids')\n const groupId = env.mintId()\n const result = await applyPlan(env.store, env.mintId, `group ${elementIds.length} elements`, [\n { type: 'group_elements', pageId, elementIds, groupId, name: optionalString(args, 'name') },\n ])\n return { group_id: groupId, ...result }\n },\n },\n\n {\n name: 'ungroup_element',\n description: 'Dissolve a group, promoting its children to the group\\'s parent owner at page coordinates. The group element is removed.',\n inputSchema: objectSchema(\n { page_id: pageIdProp, group_id: { type: 'string', description: 'Id of the group element to ungroup.' } },\n ['page_id', 'group_id'],\n ),\n async run(args, env) {\n const pageId = requireString(args, 'page_id')\n const groupId = requireString(args, 'group_id')\n const result = await applyPlan(env.store, env.mintId, `ungroup ${groupId}`, [\n { type: 'ungroup_element', pageId, groupId },\n ])\n return result\n },\n },\n\n // ─── page management ──────────────────────────────────────────────────────\n\n {\n name: 'add_page',\n description: 'Add a new blank page to the document. Returns the new page\\'s id.',\n inputSchema: objectSchema(\n {\n name: { type: 'string', description: 'Page name.' },\n width: { type: 'number', description: 'Width in px. Default 1080.' },\n height: { type: 'number', description: 'Height in px. Default 1080.' },\n background: colorProp('Page background. Default \"#ffffff\".'),\n index: { type: 'number', description: 'Position in the page list (0-based). Omit to append.' },\n },\n [],\n ),\n async run(args, env) {\n const pageId = env.mintId()\n const result = await applyPlan(env.store, env.mintId, 'add page', [\n {\n type: 'add_page',\n pageId,\n options: {\n name: optionalString(args, 'name'),\n width: optionalNumber(args, 'width'),\n height: optionalNumber(args, 'height'),\n background: optionalString(args, 'background'),\n },\n index: optionalNonNegativeInteger(args, 'index'),\n },\n ])\n return { page_id: pageId, ...result }\n },\n },\n\n {\n name: 'duplicate_page',\n description:\n 'Duplicate an existing page including all its elements. Element ids are re-minted server-side to avoid conflicts. Returns the new page\\'s id.',\n inputSchema: objectSchema(\n {\n source_page_id: { type: 'string', description: 'Page id to copy.' },\n },\n ['source_page_id'],\n ),\n async run(args, env) {\n const sourcePageId = requireString(args, 'source_page_id')\n const pageId = env.mintId()\n const result = await applyPlan(env.store, env.mintId, `duplicate page ${sourcePageId}`, [\n { type: 'duplicate_page', sourcePageId, pageId },\n ])\n return { page_id: pageId, ...result }\n },\n },\n\n {\n name: 'delete_page',\n description: 'Delete a page. Fails if the document has only one page.',\n inputSchema: objectSchema(\n { page_id: { type: 'string', description: 'Page id to delete.' } },\n ['page_id'],\n ),\n async run(args, env) {\n const pageId = requireString(args, 'page_id')\n const result = await applyPlan(env.store, env.mintId, `delete page ${pageId}`, [\n { type: 'delete_page', pageId },\n ])\n return result\n },\n },\n\n {\n name: 'set_page_props',\n description: 'Update a page\\'s name, dimensions, background color, or bleed. Pass null for bleed to clear it. Omit fields you don\\'t want to change.',\n inputSchema: objectSchema(\n {\n page_id: { type: 'string', description: 'Page id to update.' },\n name: { type: 'string', description: 'New page name.' },\n width: { type: 'number', description: 'New width in px.' },\n height: { type: 'number', description: 'New height in px.' },\n background: colorProp('New background color.'),\n bleed: {\n type: 'object',\n description: 'Bleed extents in px drawn OUTSIDE the page trim edge. Pass null to clear bleed.',\n properties: {\n top: { type: 'number' },\n right: { type: 'number' },\n bottom: { type: 'number' },\n left: { type: 'number' },\n },\n required: ['top', 'right', 'bottom', 'left'],\n nullable: true,\n },\n },\n ['page_id'],\n ),\n async run(args, env) {\n const pageId = requireString(args, 'page_id')\n let bleed: { top: number; right: number; bottom: number; left: number } | null | undefined\n if ('bleed' in args) {\n if (args['bleed'] === null) {\n bleed = null\n } else if (isRecord(args['bleed'])) {\n const b = args['bleed']\n bleed = {\n top: requireNumber(b, 'top'),\n right: requireNumber(b, 'right'),\n bottom: requireNumber(b, 'bottom'),\n left: requireNumber(b, 'left'),\n }\n } else {\n throw new Error('bleed must be an object with top/right/bottom/left or null to clear')\n }\n }\n const result = await applyPlan(env.store, env.mintId, `set props on page ${pageId}`, [\n {\n type: 'set_page_props',\n pageId,\n name: optionalString(args, 'name'),\n width: optionalNumber(args, 'width'),\n height: optionalNumber(args, 'height'),\n background: optionalString(args, 'background'),\n ...(bleed !== undefined ? { bleed } : {}),\n },\n ])\n return result\n },\n },\n\n {\n name: 'set_page_guides',\n description: 'Set ruler guides on a page. Replaces ALL existing guides for that axis — pass the full updated arrays.',\n inputSchema: objectSchema(\n {\n page_id: { type: 'string', description: 'Page id to update.' },\n vertical: { type: 'array', items: { type: 'number' }, description: 'Vertical guide positions in page-coordinate px.' },\n horizontal: { type: 'array', items: { type: 'number' }, description: 'Horizontal guide positions in page-coordinate px.' },\n },\n ['page_id', 'vertical', 'horizontal'],\n ),\n async run(args, env) {\n const pageId = requireString(args, 'page_id')\n if (!Array.isArray(args['vertical'])) throw new Error('vertical must be an array of numbers')\n if (!Array.isArray(args['horizontal'])) throw new Error('horizontal must be an array of numbers')\n const vertical = args['vertical'] as number[]\n const horizontal = args['horizontal'] as number[]\n const result = await applyPlan(env.store, env.mintId, `set guides on page ${pageId}`, [\n { type: 'set_page_guides', pageId, guides: { vertical, horizontal } },\n ])\n return result\n },\n },\n\n // ─── template / data binding ──────────────────────────────────────────────\n\n {\n name: 'bind_slot',\n description:\n 'Bind or unbind a template slot name to an element. Slot names are unique document-wide. Text elements accept string data; image/video elements accept src URLs. Pass null for slot to unbind.',\n inputSchema: objectSchema(\n {\n page_id: pageIdProp,\n element_id: elementIdProp,\n slot: { type: ['string', 'null'], description: 'Slot name to bind, or null to unbind.' },\n },\n ['page_id', 'element_id', 'slot'],\n ),\n async run(args, env) {\n const pageId = requireString(args, 'page_id')\n const elementId = requireString(args, 'element_id')\n const slot = args['slot'] === null ? null : requireString(args, 'slot')\n const result = await applyPlan(env.store, env.mintId, `bind slot \"${slot}\" to ${elementId}`, [\n { type: 'bind_slot', pageId, elementId, slot },\n ])\n return result\n },\n },\n\n {\n name: 'apply_data',\n description:\n 'Fill template slots with data. bindings is a {slot_name: value} map. Text slots accept any string; image/video slots accept http(s) URLs or /api/ paths; unknown slot names throw. Partial application is allowed.',\n inputSchema: objectSchema(\n {\n bindings: {\n type: 'object',\n description: 'Map of slot name → value. Text slots: string. Image/video slots: URL.',\n additionalProperties: { type: 'string' },\n },\n },\n ['bindings'],\n ),\n async run(args, env) {\n if (!isRecord(args['bindings'])) throw new Error('bindings must be an object')\n const bindings = args['bindings'] as Record<string, string>\n const result = await applyPlan(env.store, env.mintId, `apply data to ${Object.keys(bindings).length} slots`, [\n { type: 'apply_data', bindings },\n ])\n return result\n },\n },\n\n {\n name: 'instantiate_template',\n description:\n 'Clone this document\\'s page(s) with freshly minted element ids and fill the declared slots with the provided data bindings in one atomic call. Use this to produce personalized copies of a template document without modifying the original. Returns the new page ids in order. Note: this mutates the SAME document by appending copies of the requested pages with re-minted ids and applying data — it does NOT create a separate document. After calling, the document contains both the original pages and the new copies.',\n inputSchema: objectSchema(\n {\n source_page_ids: {\n type: 'array',\n items: { type: 'string' },\n description: 'Page ids to clone. Omit to clone all pages.',\n },\n bindings: {\n type: 'object',\n description: 'Slot name → value map applied after cloning.',\n additionalProperties: { type: 'string' },\n },\n },\n [],\n ),\n async run(args, env) {\n const { document } = await env.store.getDocument()\n const rawSourceIds = Array.isArray(args['source_page_ids'])\n ? (args['source_page_ids'] as string[])\n : document.pages.map((p) => p.id)\n const bindings = optionalRecord(args, 'bindings') ?? {}\n if (rawSourceIds.length === 0) throw new Error('source_page_ids must not be empty')\n\n // Phase 1: for each source page, collect any slots to temporarily unbind\n // from the source before duplicating. apply_data's collectSlots() walks ALL\n // pages, so it throws on duplicate slot names when source and copy share the\n // same slot attribute. The strategy: unbind source slots → duplicate →\n // apply_data (only copy pages carry slots now) → re-bind source slots. All\n // four phases are one atomic applyPlan call.\n const unbindOps: SceneOperation[] = []\n const rebindOps: SceneOperation[] = []\n const dupOps: SceneOperation[] = []\n const newPageIds: string[] = []\n\n for (const sourcePageId of rawSourceIds) {\n const sourcePage = requirePage(document, sourcePageId)\n // Collect slots on the source page (single-page walk, no collision check).\n const sourceSlots = collectPageSlotAttrs(sourcePage)\n for (const [slotName, { elementId }] of sourceSlots) {\n unbindOps.push({ type: 'bind_slot', pageId: sourcePageId, elementId, slot: null })\n rebindOps.push({ type: 'bind_slot', pageId: sourcePageId, elementId, slot: slotName })\n }\n const pageId = env.mintId()\n newPageIds.push(pageId)\n dupOps.push({ type: 'duplicate_page', sourcePageId, pageId })\n }\n\n const applyDataOps: SceneOperation[] = Object.keys(bindings).length > 0\n ? [{ type: 'apply_data', bindings }]\n : []\n\n // Op ordering is critical: duplicate FIRST (copies inherit source slots),\n // then unbind source slots (sources now have no slots, copies still do),\n // then apply_data (only copy pages carry slots — no duplicate names),\n // then re-bind source slots (restore original state of source pages).\n const allOps: SceneOperation[] = [\n ...dupOps,\n ...unbindOps,\n ...applyDataOps,\n ...rebindOps,\n ]\n\n const result = await applyPlan(\n env.store,\n env.mintId,\n `instantiate template (${rawSourceIds.length} pages)`,\n allOps,\n )\n return { new_page_ids: newPageIds, ...result }\n },\n },\n\n // ─── exports ──────────────────────────────────────────────────────────────\n\n {\n name: 'create_export',\n description:\n 'Queue a document export. For \"png\" and \"jpeg\", a render job is queued and status starts as \"queued\" — the host renders the Konva canvas and uploads the result. For \"json\", the export completes immediately with the full document JSON in metadata. Returns the export record id and initial status.',\n inputSchema: objectSchema(\n {\n format: { type: 'string', enum: ['png', 'jpeg', 'json'], description: 'Export format.' },\n page_id: { type: 'string', description: 'Page to export. Omit to export all pages (first page for images).' },\n pixel_ratio: { type: 'number', description: 'Device pixel ratio for raster exports. Default 1.' },\n },\n ['format'],\n ),\n async run(args, env) {\n const format = requireEnum(args, 'format', ['png', 'jpeg', 'json'] as const)\n const pageId = optionalString(args, 'page_id')\n const pixelRatio = optionalNumber(args, 'pixel_ratio') ?? 1\n\n let metadata: Record<string, unknown> = {\n pageId: pageId ?? null,\n pixelRatio,\n }\n\n if (format === 'json') {\n const { document, rev } = await env.store.getDocument()\n metadata = { ...metadata, document, rev }\n }\n\n const exportRecord = await env.store.createExport(format, metadata)\n await env.store.recordDecision({\n kind: 'export',\n instruction: `create ${format} export${pageId ? ` for page ${pageId}` : ''}`,\n metadata: { tool: 'create_export', export_id: exportRecord.id, format },\n })\n return {\n export_id: exportRecord.id,\n format: exportRecord.format,\n status: exportRecord.status,\n metadata: exportRecord.metadata,\n created_at: exportRecord.createdAt,\n }\n },\n },\n]\n\nexport { CANVAS_MCP_TOOLS }\n\nexport function findCanvasMcpTool(\n name: string,\n): McpToolDefinition<DesignCanvasMcpToolEnv> | undefined {\n return CANVAS_MCP_TOOLS.find((tool) => tool.name === name)\n}\n\nexport const CANVAS_MCP_TOOL_NAMES = CANVAS_MCP_TOOLS.map((t) => t.name)\nexport const CANVAS_ELEMENT_KINDS: readonly string[] = SCENE_ELEMENT_KINDS\n","/**\n * Streamable-HTTP MCP server for one design-canvas document — the live\n * agent→canvas channel. JSON-RPC 2.0 over POST, stateless per request\n * (Workers-compatible: no session table, no SSE).\n *\n * Trust boundary: the product authenticates the request (capability token,\n * workspace RBAC) BEFORE constructing the scoped {@link SceneStore} and\n * calling this handler — the handler trusts its store completely. Tool\n * execution failures (argument shape, validation, stale rev) become `isError`\n * tool results carrying the thrown message verbatim so the model can read WHY\n * and retry.\n *\n * The JSON-RPC envelope (initialize/ping/tools/list/tools/call, -32601) lives\n * in {@link createMcpToolHandler}; this module wires the canvas tool list +\n * the caller-supplied id-minting function.\n */\n\nimport type { SceneStore } from './store'\nimport { CANVAS_MCP_TOOLS } from './mcp-tools'\nimport type { DesignCanvasMcpToolEnv } from './mcp-tools'\nimport { createMcpToolHandler } from '../tools/mcp-rpc'\n\nexport interface DesignCanvasMcpServerInfo {\n name: string\n version: string\n}\n\nexport interface CreateDesignCanvasMcpHandlerOptions {\n /** Already scoped + authorized for one (workspace, document, actor). */\n store: SceneStore\n /** Id-minting function threaded into every mutating tool. Must return\n * a string unique within the document scope — use crypto.randomUUID()\n * in production; a deterministic counter in tests. */\n mintId: () => string\n serverInfo?: DesignCanvasMcpServerInfo\n}\n\nexport function createDesignCanvasMcpHandler(\n opts: CreateDesignCanvasMcpHandlerOptions,\n): (request: Request) => Promise<Response> {\n const serverInfo = opts.serverInfo ?? { name: 'design-canvas', version: '1.0.0' }\n\n return createMcpToolHandler<DesignCanvasMcpToolEnv>({\n serverInfo,\n tools: CANVAS_MCP_TOOLS,\n buildEnv: (_request) => ({ store: opts.store, mintId: opts.mintId }),\n })\n}\n","/**\n * Profile entry for the design-canvas MCP server — what a product spreads\n * into its sandbox `AgentProfile.mcp` map so the in-sandbox agent gets the\n * live canvas channel. Same shape and conventions as the sequences entry in\n * ../sequences/mcp-entry: transport 'http', capability token in the\n * Authorization header (server-set, never a tool argument).\n */\n\nimport { DEFAULT_HEADER_NAMES } from '../tools/auth'\nimport type { ToolHeaderNames } from '../tools/auth'\nimport { buildHttpMcpServer } from '../tools/mcp'\nimport type { AppToolMcpServer } from '../tools/mcp'\nimport type { AppToolContext } from '../tools/types'\n\nexport const DEFAULT_DESIGN_CANVAS_MCP_DESCRIPTION =\n 'Live visual asset editor for the current design document: read scene state, add/move/resize/delete elements, manage pages, bind template slots, apply data, and queue exports. All coordinates are CSS pixels.'\n\nexport interface BuildDesignCanvasMcpServerEntryOptions {\n /** App base URL the sandbox reaches back to (trailing slash tolerated). */\n baseUrl: string\n /** Product route serving `createDesignCanvasMcpHandler` for ONE document —\n * the document id is part of the path, never a tool argument. */\n path: string\n /** Capability token the product minted for this (user, document) scope.\n * With no token there is no entry to build — omit the server instead. */\n token: string\n description?: string\n /** Identity headers for products whose route recovers the user via\n * `authenticateToolRequest`. Omit when the bearer token is self-contained. */\n ctx?: AppToolContext\n headerNames?: ToolHeaderNames\n}\n\n/** Build the `AgentProfileMcpServer`-shaped entry for the design-canvas channel. */\nexport function buildDesignCanvasMcpServerEntry(\n opts: BuildDesignCanvasMcpServerEntryOptions,\n): AppToolMcpServer {\n if (opts.token.trim().length === 0) {\n throw new Error(\n 'buildDesignCanvasMcpServerEntry requires a capability token — omit the design-canvas MCP server when none is available',\n )\n }\n if (!opts.path.startsWith('/')) {\n throw new Error(\n `buildDesignCanvasMcpServerEntry path must start with \"/\" (got \"${opts.path}\")`,\n )\n }\n const description = opts.description ?? DEFAULT_DESIGN_CANVAS_MCP_DESCRIPTION\n\n if (opts.ctx) {\n return buildHttpMcpServer({\n path: opts.path,\n baseUrl: opts.baseUrl,\n token: opts.token,\n ctx: opts.ctx,\n description,\n headerNames: opts.headerNames ?? DEFAULT_HEADER_NAMES,\n })\n }\n\n return {\n transport: 'http',\n url: `${opts.baseUrl.replace(/\\/+$/, '')}${opts.path}`,\n headers: {\n Authorization: `Bearer ${opts.token}`,\n 'Content-Type': 'application/json',\n },\n enabled: true,\n metadata: { description },\n }\n}\n"],"mappings":"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","names":[]}
@@ -0,0 +1,194 @@
1
+ // src/tools/auth.ts
2
+ var DEFAULT_HEADER_NAMES = {
3
+ userId: "X-Agent-App-User-Id",
4
+ workspaceId: "X-Agent-App-Workspace-Id",
5
+ threadId: "X-Agent-App-Thread-Id"
6
+ };
7
+ async function authenticateToolRequest(request, opts) {
8
+ const h = opts.headerNames ?? DEFAULT_HEADER_NAMES;
9
+ const userId = request.headers.get(h.userId)?.trim();
10
+ const workspaceId = request.headers.get(h.workspaceId)?.trim();
11
+ const threadId = request.headers.get(h.threadId)?.trim() || null;
12
+ const bearer = request.headers.get("authorization")?.match(/^Bearer\s+(.+)$/i)?.[1];
13
+ if (!userId || !bearer) {
14
+ return { ok: false, response: Response.json({ error: "Missing capability credentials" }, { status: 401 }) };
15
+ }
16
+ if (!await opts.verifyToken(userId, bearer)) {
17
+ return { ok: false, response: Response.json({ error: "Invalid capability token" }, { status: 401 }) };
18
+ }
19
+ if (!workspaceId) {
20
+ return { ok: false, response: Response.json({ error: "Missing workspace context" }, { status: 400 }) };
21
+ }
22
+ return { ok: true, ctx: { userId, workspaceId, threadId } };
23
+ }
24
+ async function readToolArgs(request) {
25
+ let body;
26
+ try {
27
+ body = await request.json();
28
+ } catch {
29
+ return null;
30
+ }
31
+ return body.args ?? body.arguments ?? body;
32
+ }
33
+
34
+ // src/tools/mcp.ts
35
+ var DEFAULT_APP_TOOL_PATHS = {
36
+ submit_proposal: "/api/tools/propose",
37
+ schedule_followup: "/api/tools/followup",
38
+ render_ui: "/api/tools/render-ui",
39
+ add_citation: "/api/tools/citation"
40
+ };
41
+ function buildHttpMcpServer(opts) {
42
+ const base = opts.baseUrl.replace(/\/+$/, "");
43
+ const h = opts.headerNames ?? DEFAULT_HEADER_NAMES;
44
+ return {
45
+ transport: "http",
46
+ url: `${base}${opts.path}`,
47
+ headers: {
48
+ Authorization: `Bearer ${opts.token}`,
49
+ [h.userId]: opts.ctx.userId,
50
+ ...opts.ctx.workspaceId ? { [h.workspaceId]: opts.ctx.workspaceId } : {},
51
+ ...opts.ctx.threadId ? { [h.threadId]: opts.ctx.threadId } : {},
52
+ "Content-Type": "application/json"
53
+ },
54
+ enabled: true,
55
+ metadata: { description: opts.description }
56
+ };
57
+ }
58
+ function buildAppToolMcpServer(opts) {
59
+ return buildHttpMcpServer({
60
+ path: opts.paths?.[opts.tool] ?? DEFAULT_APP_TOOL_PATHS[opts.tool],
61
+ baseUrl: opts.baseUrl,
62
+ token: opts.token,
63
+ ctx: opts.ctx,
64
+ description: opts.description,
65
+ headerNames: opts.headerNames
66
+ });
67
+ }
68
+
69
+ // src/tools/mcp-rpc.ts
70
+ var MCP_PROTOCOL_VERSIONS = ["2025-06-18", "2025-03-26", "2024-11-05"];
71
+ var LATEST_PROTOCOL_VERSION = MCP_PROTOCOL_VERSIONS[0];
72
+ function isRecord(value) {
73
+ return typeof value === "object" && value !== null && !Array.isArray(value);
74
+ }
75
+ function rpcResult(id, result) {
76
+ return Response.json({ jsonrpc: "2.0", id, result });
77
+ }
78
+ function rpcError(id, code, message, status = 200) {
79
+ return Response.json({ jsonrpc: "2.0", id, error: { code, message } }, { status });
80
+ }
81
+ function createMcpToolHandler(opts) {
82
+ const toolMap = /* @__PURE__ */ new Map();
83
+ for (const tool of opts.tools) {
84
+ if (toolMap.has(tool.name)) throw new Error(`duplicate MCP tool name: ${tool.name}`);
85
+ toolMap.set(tool.name, tool);
86
+ }
87
+ return async (request) => {
88
+ if (request.method !== "POST") {
89
+ return new Response("MCP server accepts JSON-RPC 2.0 over POST only", {
90
+ status: 405,
91
+ headers: { Allow: "POST" }
92
+ });
93
+ }
94
+ let body;
95
+ try {
96
+ body = await request.json();
97
+ } catch {
98
+ return rpcError(null, -32700, "Parse error: request body is not valid JSON", 400);
99
+ }
100
+ if (Array.isArray(body)) {
101
+ return rpcError(null, -32600, "Invalid request: JSON-RPC batching is not supported", 400);
102
+ }
103
+ if (!isRecord(body) || body.jsonrpc !== "2.0" || typeof body.method !== "string") {
104
+ return rpcError(
105
+ null,
106
+ -32600,
107
+ 'Invalid request: expected a JSON-RPC 2.0 object with jsonrpc "2.0" and a string method',
108
+ 400
109
+ );
110
+ }
111
+ const method = body.method;
112
+ const params = isRecord(body.params) ? body.params : {};
113
+ if (!("id" in body) || body.id === void 0) {
114
+ return new Response(null, { status: 202 });
115
+ }
116
+ const id = body.id;
117
+ switch (method) {
118
+ case "initialize": {
119
+ const requested = typeof params.protocolVersion === "string" ? params.protocolVersion : void 0;
120
+ const protocolVersion = requested !== void 0 && MCP_PROTOCOL_VERSIONS.includes(requested) ? requested : LATEST_PROTOCOL_VERSION;
121
+ return rpcResult(id, {
122
+ protocolVersion,
123
+ capabilities: { tools: { listChanged: false } },
124
+ serverInfo: opts.serverInfo
125
+ });
126
+ }
127
+ case "ping":
128
+ return rpcResult(id, {});
129
+ case "tools/list":
130
+ return rpcResult(id, {
131
+ tools: opts.tools.map((tool) => ({
132
+ name: tool.name,
133
+ description: tool.description,
134
+ inputSchema: tool.inputSchema
135
+ }))
136
+ });
137
+ case "tools/call": {
138
+ const name = params.name;
139
+ if (typeof name !== "string" || name.length === 0) {
140
+ return rpcError(id, -32602, "tools/call requires params.name (string)");
141
+ }
142
+ const tool = toolMap.get(name);
143
+ if (!tool) {
144
+ return rpcError(
145
+ id,
146
+ -32602,
147
+ `Unknown tool: ${name}. Available tools: ${opts.tools.map((t) => t.name).join(", ")}`
148
+ );
149
+ }
150
+ if (params.arguments !== void 0 && !isRecord(params.arguments)) {
151
+ return rpcError(id, -32602, "tools/call params.arguments must be an object when provided");
152
+ }
153
+ const args = isRecord(params.arguments) ? params.arguments : {};
154
+ let env;
155
+ try {
156
+ env = await opts.buildEnv(request);
157
+ } catch (err) {
158
+ const message = err instanceof Error ? err.message : String(err);
159
+ const payload = {
160
+ content: [{ type: "text", text: `${name} failed to build env: ${message}` }],
161
+ isError: true
162
+ };
163
+ return rpcResult(id, payload);
164
+ }
165
+ try {
166
+ const result = await tool.run(args, env);
167
+ const payload = { content: [{ type: "text", text: JSON.stringify(result) }] };
168
+ return rpcResult(id, payload);
169
+ } catch (err) {
170
+ const message = err instanceof Error ? err.message : String(err);
171
+ const payload = {
172
+ content: [{ type: "text", text: `${name} failed: ${message}` }],
173
+ isError: true
174
+ };
175
+ return rpcResult(id, payload);
176
+ }
177
+ }
178
+ default:
179
+ return rpcError(id, -32601, `Method not found: ${method}`);
180
+ }
181
+ };
182
+ }
183
+
184
+ export {
185
+ DEFAULT_HEADER_NAMES,
186
+ authenticateToolRequest,
187
+ readToolArgs,
188
+ DEFAULT_APP_TOOL_PATHS,
189
+ buildHttpMcpServer,
190
+ buildAppToolMcpServer,
191
+ MCP_PROTOCOL_VERSIONS,
192
+ createMcpToolHandler
193
+ };
194
+ //# sourceMappingURL=chunk-A76ZHWNF.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/tools/auth.ts","../src/tools/mcp.ts","../src/tools/mcp-rpc.ts"],"sourcesContent":["import type { AppToolContext } from './types'\n\n/**\n * Header names carrying the server-set per-turn context + the capability token.\n * Defaults are product-neutral (`X-Agent-App-*`); a product that already ships\n * a header convention (e.g. `X-Acme-User-Id`) passes its own.\n */\nexport interface ToolHeaderNames {\n userId: string\n workspaceId: string\n threadId: string\n}\n\nexport const DEFAULT_HEADER_NAMES: ToolHeaderNames = {\n userId: 'X-Agent-App-User-Id',\n workspaceId: 'X-Agent-App-Workspace-Id',\n threadId: 'X-Agent-App-Thread-Id',\n}\n\nexport interface AuthenticateOptions {\n /** Verify the bearer capability token belongs to `userId`. The product's\n * HMAC/JWT impl — the seam that keeps token crypto out of this package. */\n verifyToken: (userId: string, bearer: string) => Promise<boolean>\n headerNames?: ToolHeaderNames\n}\n\nexport type ToolAuthResult =\n | { ok: true; ctx: AppToolContext }\n | { ok: false; response: Response }\n\n/**\n * Recover + verify the trusted context for a tool request. The user comes from\n * a server-set header and the bearer token MUST verify against THAT user; the\n * workspace comes from a header too — never from tool args — so the model can\n * neither forge identity nor target another workspace. Fail-closed: any missing\n * credential or a token minted for another user yields a 401/400 Response.\n */\nexport async function authenticateToolRequest(request: Request, opts: AuthenticateOptions): Promise<ToolAuthResult> {\n const h = opts.headerNames ?? DEFAULT_HEADER_NAMES\n const userId = request.headers.get(h.userId)?.trim()\n const workspaceId = request.headers.get(h.workspaceId)?.trim()\n const threadId = request.headers.get(h.threadId)?.trim() || null\n const bearer = request.headers.get('authorization')?.match(/^Bearer\\s+(.+)$/i)?.[1]\n\n if (!userId || !bearer) {\n return { ok: false, response: Response.json({ error: 'Missing capability credentials' }, { status: 401 }) }\n }\n if (!(await opts.verifyToken(userId, bearer))) {\n return { ok: false, response: Response.json({ error: 'Invalid capability token' }, { status: 401 }) }\n }\n if (!workspaceId) {\n return { ok: false, response: Response.json({ error: 'Missing workspace context' }, { status: 400 }) }\n }\n return { ok: true, ctx: { userId, workspaceId, threadId } }\n}\n\n/** Read a tool's argument object from the request body, tolerant of MCP host\n * aliases (`args` / `arguments`) or a bare body. Returns null on non-JSON. */\nexport async function readToolArgs<T>(request: Request): Promise<T | null> {\n let body: { args?: T; arguments?: T }\n try {\n body = (await request.json()) as typeof body\n } catch {\n return null\n }\n return (body.args ?? body.arguments ?? (body as T)) as T\n}\n","import type { AppToolContext } from './types'\nimport type { AppToolName } from './openai'\nimport type { ToolHeaderNames } from './auth'\nimport { DEFAULT_HEADER_NAMES } from './auth'\n\n/** Default route path each app tool is served at. A product mounts its routes\n * at these paths (or supplies its own via {@link BuildMcpServerOptions.paths}). */\nexport const DEFAULT_APP_TOOL_PATHS: Record<AppToolName, string> = {\n submit_proposal: '/api/tools/propose',\n schedule_followup: '/api/tools/followup',\n render_ui: '/api/tools/render-ui',\n add_citation: '/api/tools/citation',\n}\n\n/** The portable MCP server entry the sandbox SDK accepts (transport + url +\n * headers). Matches `AgentProfileMcpServer` structurally without importing the\n * sandbox SDK — products spread it into their profile's `mcp` map. */\nexport interface AppToolMcpServer {\n transport: 'http'\n url: string\n headers: Record<string, string>\n enabled: true\n metadata: { description: string }\n}\n\nexport interface BuildHttpMcpServerOptions {\n /** Route path on the app the sandbox POSTs to (e.g. `/api/tools/propose`). */\n path: string\n /** App base URL the sandbox reaches back to (no trailing slash required). */\n baseUrl: string\n /** Per-user capability token, baked into the Authorization header. */\n token: string\n ctx: AppToolContext\n /** Tool description the model sees. */\n description: string\n headerNames?: ToolHeaderNames\n}\n\n/**\n * Build ONE HTTP MCP server entry — the generic agent→app bridge. The\n * capability token + the user/workspace/thread ids ride in server-set headers\n * (never tool args), so the model can't forge identity or target another\n * workspace. Workspace/thread headers are omitted when their `ctx` value is\n * empty/null (e.g. an integration-invoke bridge that's user-scoped only). Used\n * directly for non-app-tool bridges (integration_invoke) and via\n * {@link buildAppToolMcpServer} for the four app tools.\n */\nexport function buildHttpMcpServer(opts: BuildHttpMcpServerOptions): AppToolMcpServer {\n const base = opts.baseUrl.replace(/\\/+$/, '')\n const h = opts.headerNames ?? DEFAULT_HEADER_NAMES\n return {\n transport: 'http',\n url: `${base}${opts.path}`,\n headers: {\n Authorization: `Bearer ${opts.token}`,\n [h.userId]: opts.ctx.userId,\n ...(opts.ctx.workspaceId ? { [h.workspaceId]: opts.ctx.workspaceId } : {}),\n ...(opts.ctx.threadId ? { [h.threadId]: opts.ctx.threadId } : {}),\n 'Content-Type': 'application/json',\n },\n enabled: true,\n metadata: { description: opts.description },\n }\n}\n\nexport interface BuildMcpServerOptions {\n tool: AppToolName\n baseUrl: string\n token: string\n ctx: AppToolContext\n description: string\n headerNames?: ToolHeaderNames\n paths?: Partial<Record<AppToolName, string>>\n}\n\n/** Build one of the four app-tool MCP servers — a thin wrapper over\n * {@link buildHttpMcpServer} that maps the tool name to its route path. */\nexport function buildAppToolMcpServer(opts: BuildMcpServerOptions): AppToolMcpServer {\n return buildHttpMcpServer({\n path: opts.paths?.[opts.tool] ?? DEFAULT_APP_TOOL_PATHS[opts.tool],\n baseUrl: opts.baseUrl,\n token: opts.token,\n ctx: opts.ctx,\n description: opts.description,\n headerNames: opts.headerNames,\n })\n}\n","/**\n * Generic streamable-HTTP JSON-RPC 2.0 envelope for a tools-only MCP server.\n * Stateless, Workers-compatible: no session table, no SSE — every request gets\n * a single `application/json` response, which the streamable-HTTP transport\n * explicitly permits for tools-only servers.\n *\n * Protocol surface:\n * initialize → echo client's protocolVersion if supported, else latest\n * ping → empty result {}\n * notifications/* (no `id`) → 202 with no body\n * tools/list → tool manifest\n * tools/call → run + surface execution failures as isError text results\n * anything else → -32601\n *\n * Execution failures (argument shape, validation, store throws) become `isError`\n * tool results carrying the thrown message verbatim — the model reads WHY and\n * retries. Protocol misuse becomes a JSON-RPC error object.\n */\n\nexport const MCP_PROTOCOL_VERSIONS = ['2025-06-18', '2025-03-26', '2024-11-05'] as const\nexport type McpProtocolVersion = (typeof MCP_PROTOCOL_VERSIONS)[number]\n\nconst LATEST_PROTOCOL_VERSION: McpProtocolVersion = MCP_PROTOCOL_VERSIONS[0]\n\nexport interface McpServerInfo {\n name: string\n version: string\n}\n\n/** One tool entry in the registry the handler owns. */\nexport interface McpToolDefinition<TEnv = Record<string, never>> {\n name: string\n description: string\n /** JSON Schema for the `params.arguments` object. */\n inputSchema: Record<string, unknown>\n /** Receive validated (Record) args + the env the handler threaded; throw to\n * surface an isError result — never throw for protocol/framing issues. */\n run(args: Record<string, unknown>, env: TEnv): Promise<unknown>\n}\n\nexport interface CreateMcpToolHandlerOptions<TEnv = Record<string, never>> {\n serverInfo: McpServerInfo\n /** Full tool list; order IS the tools/list order. */\n tools: McpToolDefinition<TEnv>[]\n /** Per-request environment threaded into every `run` call. If your tools are\n * stateless (or carry state through closure) pass an empty builder:\n * `() => ({} as TEnv)`. */\n buildEnv(request: Request): TEnv | Promise<TEnv>\n}\n\n// ---------------------------------------------------------------------------\n// Internal helpers\n// ---------------------------------------------------------------------------\n\ntype JsonRpcId = string | number | null\n\ninterface ToolCallContent {\n content: Array<{ type: 'text'; text: string }>\n isError?: true\n}\n\nfunction isRecord(value: unknown): value is Record<string, unknown> {\n return typeof value === 'object' && value !== null && !Array.isArray(value)\n}\n\nfunction rpcResult(id: JsonRpcId, result: unknown): Response {\n return Response.json({ jsonrpc: '2.0', id, result })\n}\n\nfunction rpcError(id: JsonRpcId, code: number, message: string, status = 200): Response {\n return Response.json({ jsonrpc: '2.0', id, error: { code, message } }, { status })\n}\n\n// ---------------------------------------------------------------------------\n// Factory\n// ---------------------------------------------------------------------------\n\n/**\n * Build a request handler for a tools-only MCP server. The returned function\n * accepts a standard `Request` and resolves to a `Response` — mount it on any\n * Cloudflare Worker route or Remix `loader`.\n *\n * The handler calls `buildEnv` exactly ONCE per `tools/call` request (after\n * the tool is found, before `run`) — non-`tools/call` paths skip it entirely\n * so metadata requests do not pay env-build cost.\n */\nexport function createMcpToolHandler<TEnv = Record<string, never>>(\n opts: CreateMcpToolHandlerOptions<TEnv>,\n): (request: Request) => Promise<Response> {\n const toolMap = new Map<string, McpToolDefinition<TEnv>>()\n for (const tool of opts.tools) {\n if (toolMap.has(tool.name)) throw new Error(`duplicate MCP tool name: ${tool.name}`)\n toolMap.set(tool.name, tool)\n }\n\n return async (request: Request): Promise<Response> => {\n if (request.method !== 'POST') {\n return new Response('MCP server accepts JSON-RPC 2.0 over POST only', {\n status: 405,\n headers: { Allow: 'POST' },\n })\n }\n\n let body: unknown\n try {\n body = await request.json()\n } catch {\n return rpcError(null, -32700, 'Parse error: request body is not valid JSON', 400)\n }\n\n if (Array.isArray(body)) {\n return rpcError(null, -32600, 'Invalid request: JSON-RPC batching is not supported', 400)\n }\n if (!isRecord(body) || body.jsonrpc !== '2.0' || typeof body.method !== 'string') {\n return rpcError(\n null,\n -32600,\n 'Invalid request: expected a JSON-RPC 2.0 object with jsonrpc \"2.0\" and a string method',\n 400,\n )\n }\n\n const method = body.method\n const params = isRecord(body.params) ? body.params : {}\n\n // Notifications have no `id` — acknowledge without a JSON-RPC body.\n if (!('id' in body) || body.id === undefined) {\n return new Response(null, { status: 202 })\n }\n const id = body.id as JsonRpcId\n\n switch (method) {\n case 'initialize': {\n const requested = typeof params.protocolVersion === 'string' ? params.protocolVersion : undefined\n const protocolVersion =\n requested !== undefined && (MCP_PROTOCOL_VERSIONS as readonly string[]).includes(requested)\n ? requested\n : LATEST_PROTOCOL_VERSION\n return rpcResult(id, {\n protocolVersion,\n capabilities: { tools: { listChanged: false } },\n serverInfo: opts.serverInfo,\n })\n }\n\n case 'ping':\n return rpcResult(id, {})\n\n case 'tools/list':\n return rpcResult(id, {\n tools: opts.tools.map((tool) => ({\n name: tool.name,\n description: tool.description,\n inputSchema: tool.inputSchema,\n })),\n })\n\n case 'tools/call': {\n const name = params.name\n if (typeof name !== 'string' || name.length === 0) {\n return rpcError(id, -32602, 'tools/call requires params.name (string)')\n }\n const tool = toolMap.get(name)\n if (!tool) {\n return rpcError(\n id,\n -32602,\n `Unknown tool: ${name}. Available tools: ${opts.tools.map((t) => t.name).join(', ')}`,\n )\n }\n if (params.arguments !== undefined && !isRecord(params.arguments)) {\n return rpcError(id, -32602, 'tools/call params.arguments must be an object when provided')\n }\n const args = isRecord(params.arguments) ? params.arguments : {}\n let env: TEnv\n try {\n env = await opts.buildEnv(request)\n } catch (err) {\n const message = err instanceof Error ? err.message : String(err)\n const payload: ToolCallContent = {\n content: [{ type: 'text', text: `${name} failed to build env: ${message}` }],\n isError: true,\n }\n return rpcResult(id, payload)\n }\n try {\n const result = await tool.run(args, env)\n const payload: ToolCallContent = { content: [{ type: 'text', text: JSON.stringify(result) }] }\n return rpcResult(id, payload)\n } catch (err) {\n const message = err instanceof Error ? err.message : String(err)\n const payload: ToolCallContent = {\n content: [{ type: 'text', text: `${name} failed: ${message}` }],\n isError: true,\n }\n return rpcResult(id, payload)\n }\n }\n\n default:\n return rpcError(id, -32601, `Method not found: ${method}`)\n }\n }\n}\n"],"mappings":"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","names":[]}