@pascal-app/mcp 1.0.4 → 1.0.5

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 (244) hide show
  1. package/CHANGELOG.md +76 -0
  2. package/README.md +166 -62
  3. package/dist/bin/pascal-mcp.js +1 -1
  4. package/dist/bridge/agent-session.d.ts +18 -0
  5. package/dist/bridge/agent-session.d.ts.map +1 -0
  6. package/dist/bridge/agent-session.js +15 -0
  7. package/dist/bridge/index.d.ts +1 -1
  8. package/dist/bridge/index.d.ts.map +1 -1
  9. package/dist/bridge/scene-bridge.d.ts +3 -0
  10. package/dist/bridge/scene-bridge.d.ts.map +1 -1
  11. package/dist/bridge/scene-bridge.js +7 -0
  12. package/dist/lib/safe-fetch.d.ts +22 -4
  13. package/dist/lib/safe-fetch.d.ts.map +1 -1
  14. package/dist/lib/safe-fetch.js +233 -134
  15. package/dist/operations/scene-operations.d.ts +18 -0
  16. package/dist/operations/scene-operations.d.ts.map +1 -1
  17. package/dist/operations/scene-operations.js +11 -0
  18. package/dist/prompts/from-brief.d.ts +1 -1
  19. package/dist/prompts/from-brief.d.ts.map +1 -1
  20. package/dist/prompts/from-brief.js +3 -3
  21. package/dist/prompts/index.d.ts +1 -1
  22. package/dist/prompts/index.d.ts.map +1 -1
  23. package/dist/prompts/iterate-on-feedback.d.ts +1 -1
  24. package/dist/prompts/iterate-on-feedback.d.ts.map +1 -1
  25. package/dist/prompts/iterate-on-feedback.js +2 -2
  26. package/dist/prompts/renovation-from-photos.d.ts +1 -1
  27. package/dist/prompts/renovation-from-photos.d.ts.map +1 -1
  28. package/dist/prompts/renovation-from-photos.js +2 -2
  29. package/dist/prompts/scene-guidance.d.ts.map +1 -1
  30. package/dist/prompts/scene-guidance.js +10 -3
  31. package/dist/resources/agent-guide.d.ts +1 -1
  32. package/dist/resources/agent-guide.d.ts.map +1 -1
  33. package/dist/resources/agent-guide.js +52 -44
  34. package/dist/resources/catalog-items.d.ts +1 -1
  35. package/dist/resources/catalog-items.d.ts.map +1 -1
  36. package/dist/resources/constraints.d.ts +1 -1
  37. package/dist/resources/constraints.d.ts.map +1 -1
  38. package/dist/resources/constraints.js +1 -1
  39. package/dist/resources/design-schema.d.ts +1 -1
  40. package/dist/resources/design-schema.d.ts.map +1 -1
  41. package/dist/resources/index.d.ts +1 -1
  42. package/dist/resources/index.d.ts.map +1 -1
  43. package/dist/resources/scene-current.d.ts +1 -1
  44. package/dist/resources/scene-current.d.ts.map +1 -1
  45. package/dist/resources/scene-summary.d.ts +1 -1
  46. package/dist/resources/scene-summary.d.ts.map +1 -1
  47. package/dist/server.d.ts +7 -2
  48. package/dist/server.d.ts.map +1 -1
  49. package/dist/server.js +59 -21
  50. package/dist/storage/disk-artifact-store.d.ts.map +1 -1
  51. package/dist/storage/sqlite-scene-store.d.ts +1 -1
  52. package/dist/storage/sqlite-scene-store.d.ts.map +1 -1
  53. package/dist/storage/types.d.ts +4 -4
  54. package/dist/storage/types.d.ts.map +1 -1
  55. package/dist/templates/empty-studio.d.ts +3 -3
  56. package/dist/templates/empty-studio.d.ts.map +1 -1
  57. package/dist/templates/garden-house.d.ts +3 -3
  58. package/dist/templates/garden-house.d.ts.map +1 -1
  59. package/dist/templates/index.d.ts.map +1 -1
  60. package/dist/templates/two-bedroom.d.ts +3 -3
  61. package/dist/templates/two-bedroom.d.ts.map +1 -1
  62. package/dist/tools/add-column.d.ts +1 -1
  63. package/dist/tools/add-column.d.ts.map +1 -1
  64. package/dist/tools/add-column.js +3 -2
  65. package/dist/tools/add-object.d.ts +19 -3
  66. package/dist/tools/add-object.d.ts.map +1 -1
  67. package/dist/tools/add-object.js +66 -35
  68. package/dist/tools/annotations.d.ts.map +1 -1
  69. package/dist/tools/apply-patch.d.ts +6 -2
  70. package/dist/tools/apply-patch.d.ts.map +1 -1
  71. package/dist/tools/apply-patch.js +13 -8
  72. package/dist/tools/asset-catalog.d.ts.map +1 -1
  73. package/dist/tools/asset-catalog.js +23 -0
  74. package/dist/tools/author-scene.d.ts +10 -0
  75. package/dist/tools/author-scene.d.ts.map +1 -0
  76. package/dist/tools/author-scene.js +140 -0
  77. package/dist/tools/check-collisions.d.ts +6 -6
  78. package/dist/tools/check-collisions.d.ts.map +1 -1
  79. package/dist/tools/check-collisions.js +6 -6
  80. package/dist/tools/clear-scene.d.ts +1 -1
  81. package/dist/tools/clear-scene.d.ts.map +1 -1
  82. package/dist/tools/clear-scene.js +3 -3
  83. package/dist/tools/collections.d.ts +1 -1
  84. package/dist/tools/collections.d.ts.map +1 -1
  85. package/dist/tools/collections.js +3 -2
  86. package/dist/tools/construction-tools.d.ts +6 -49
  87. package/dist/tools/construction-tools.d.ts.map +1 -1
  88. package/dist/tools/construction-tools.js +9 -158
  89. package/dist/tools/create-unit.d.ts +3 -3
  90. package/dist/tools/create-unit.d.ts.map +1 -1
  91. package/dist/tools/create-unit.js +2 -2
  92. package/dist/tools/errors.d.ts +5 -5
  93. package/dist/tools/errors.d.ts.map +1 -1
  94. package/dist/tools/errors.js +4 -4
  95. package/dist/tools/export-glb.d.ts +1 -1
  96. package/dist/tools/export-glb.d.ts.map +1 -1
  97. package/dist/tools/export-glb.js +2 -2
  98. package/dist/tools/export-json.d.ts +1 -1
  99. package/dist/tools/export-json.d.ts.map +1 -1
  100. package/dist/tools/export-json.js +2 -2
  101. package/dist/tools/get-scene.d.ts +1 -1
  102. package/dist/tools/get-scene.d.ts.map +1 -1
  103. package/dist/tools/get-scene.js +2 -2
  104. package/dist/tools/hosted-services.d.ts +1 -1
  105. package/dist/tools/hosted-services.d.ts.map +1 -1
  106. package/dist/tools/hosted-services.js +13 -3
  107. package/dist/tools/index.d.ts +4 -3
  108. package/dist/tools/index.d.ts.map +1 -1
  109. package/dist/tools/index.js +8 -13
  110. package/dist/tools/level-height-guard.d.ts +2 -0
  111. package/dist/tools/level-height-guard.d.ts.map +1 -0
  112. package/dist/tools/level-height-guard.js +11 -0
  113. package/dist/tools/list-units.d.ts +2 -2
  114. package/dist/tools/list-units.d.ts.map +1 -1
  115. package/dist/tools/list-units.js +2 -2
  116. package/dist/tools/live-sync.d.ts +1 -1
  117. package/dist/tools/live-sync.d.ts.map +1 -1
  118. package/dist/tools/live-sync.js +4 -4
  119. package/dist/tools/measure.d.ts +1 -1
  120. package/dist/tools/measure.d.ts.map +1 -1
  121. package/dist/tools/measure.js +7 -7
  122. package/dist/tools/node-world-point.d.ts +1 -1
  123. package/dist/tools/node-world-point.d.ts.map +1 -1
  124. package/dist/tools/normalize-schema-dialect.d.ts +1 -1
  125. package/dist/tools/normalize-schema-dialect.d.ts.map +1 -1
  126. package/dist/tools/normalize-schema-dialect.js +2 -3
  127. package/dist/tools/patch-guards.d.ts +6 -4
  128. package/dist/tools/patch-guards.d.ts.map +1 -1
  129. package/dist/tools/patch-guards.js +5 -2
  130. package/dist/tools/photo-to-scene/index.d.ts +1 -1
  131. package/dist/tools/photo-to-scene/index.d.ts.map +1 -1
  132. package/dist/tools/photo-to-scene/photo-to-scene.d.ts +3 -3
  133. package/dist/tools/photo-to-scene/photo-to-scene.d.ts.map +1 -1
  134. package/dist/tools/photo-to-scene/photo-to-scene.js +7 -7
  135. package/dist/tools/project-files.d.ts +4 -0
  136. package/dist/tools/project-files.d.ts.map +1 -0
  137. package/dist/tools/project-files.js +30 -0
  138. package/dist/tools/redo.d.ts +2 -2
  139. package/dist/tools/redo.d.ts.map +1 -1
  140. package/dist/tools/redo.js +2 -2
  141. package/dist/tools/retired-tools.d.ts +10 -0
  142. package/dist/tools/retired-tools.d.ts.map +1 -0
  143. package/dist/tools/retired-tools.js +22 -0
  144. package/dist/tools/roof-level-guard.d.ts +2 -0
  145. package/dist/tools/roof-level-guard.d.ts.map +1 -0
  146. package/dist/tools/roof-level-guard.js +22 -0
  147. package/dist/tools/room-tools.d.ts +47 -46
  148. package/dist/tools/room-tools.d.ts.map +1 -1
  149. package/dist/tools/room-tools.js +6 -5
  150. package/dist/tools/scene-lifecycle/create-project.d.ts +1 -1
  151. package/dist/tools/scene-lifecycle/create-project.d.ts.map +1 -1
  152. package/dist/tools/scene-lifecycle/create-project.js +5 -5
  153. package/dist/tools/scene-lifecycle/delete-scene.d.ts +1 -1
  154. package/dist/tools/scene-lifecycle/delete-scene.d.ts.map +1 -1
  155. package/dist/tools/scene-lifecycle/delete-scene.js +6 -6
  156. package/dist/tools/scene-lifecycle/get-project-status.d.ts +1 -1
  157. package/dist/tools/scene-lifecycle/get-project-status.d.ts.map +1 -1
  158. package/dist/tools/scene-lifecycle/get-project-status.js +6 -6
  159. package/dist/tools/scene-lifecycle/index.d.ts +1 -1
  160. package/dist/tools/scene-lifecycle/index.d.ts.map +1 -1
  161. package/dist/tools/scene-lifecycle/list-scenes.d.ts +1 -1
  162. package/dist/tools/scene-lifecycle/list-scenes.d.ts.map +1 -1
  163. package/dist/tools/scene-lifecycle/list-scenes.js +4 -4
  164. package/dist/tools/scene-lifecycle/load-scene.d.ts +2 -2
  165. package/dist/tools/scene-lifecycle/load-scene.d.ts.map +1 -1
  166. package/dist/tools/scene-lifecycle/load-scene.js +5 -5
  167. package/dist/tools/scene-lifecycle/metadata.d.ts +1 -1
  168. package/dist/tools/scene-lifecycle/rename-scene.d.ts +1 -1
  169. package/dist/tools/scene-lifecycle/rename-scene.d.ts.map +1 -1
  170. package/dist/tools/scene-lifecycle/rename-scene.js +6 -6
  171. package/dist/tools/scene-lifecycle/save-scene.d.ts +5 -3
  172. package/dist/tools/scene-lifecycle/save-scene.d.ts.map +1 -1
  173. package/dist/tools/scene-lifecycle/save-scene.js +80 -12
  174. package/dist/tools/scene-lifecycle/test-utils.d.ts +1 -1
  175. package/dist/tools/scene-lifecycle/test-utils.d.ts.map +1 -1
  176. package/dist/tools/set-unit-members.d.ts +2 -2
  177. package/dist/tools/set-unit-members.d.ts.map +1 -1
  178. package/dist/tools/set-unit-members.js +6 -6
  179. package/dist/tools/set-zone.d.ts +2 -2
  180. package/dist/tools/set-zone.d.ts.map +1 -1
  181. package/dist/tools/set-zone.js +30 -18
  182. package/dist/tools/shared-tools.d.ts +15 -5
  183. package/dist/tools/shared-tools.d.ts.map +1 -1
  184. package/dist/tools/shared-tools.js +242 -29
  185. package/dist/tools/structure-tools.d.ts +3 -3
  186. package/dist/tools/templates/create-from-template.d.ts +2 -2
  187. package/dist/tools/templates/create-from-template.d.ts.map +1 -1
  188. package/dist/tools/templates/create-from-template.js +6 -6
  189. package/dist/tools/templates/create-house-from-brief.d.ts +1 -1
  190. package/dist/tools/templates/create-house-from-brief.d.ts.map +1 -1
  191. package/dist/tools/templates/create-house-from-brief.js +6 -6
  192. package/dist/tools/templates/index.d.ts +1 -1
  193. package/dist/tools/templates/index.d.ts.map +1 -1
  194. package/dist/tools/templates/list-templates.d.ts +1 -1
  195. package/dist/tools/templates/list-templates.d.ts.map +1 -1
  196. package/dist/tools/templates/list-templates.js +2 -2
  197. package/dist/tools/undo.d.ts +2 -2
  198. package/dist/tools/undo.d.ts.map +1 -1
  199. package/dist/tools/undo.js +2 -2
  200. package/dist/tools/unit-members.d.ts.map +1 -1
  201. package/dist/tools/unit-members.js +6 -6
  202. package/dist/tools/variants/generate-variants.d.ts +6 -6
  203. package/dist/tools/variants/generate-variants.d.ts.map +1 -1
  204. package/dist/tools/variants/generate-variants.js +6 -6
  205. package/dist/tools/variants/index.d.ts +1 -1
  206. package/dist/tools/variants/index.d.ts.map +1 -1
  207. package/dist/tools/view-scene.d.ts +8 -2
  208. package/dist/tools/view-scene.d.ts.map +1 -1
  209. package/dist/tools/view-scene.js +17 -5
  210. package/dist/tools/vision/analyze-floorplan-image.d.ts +1 -1
  211. package/dist/tools/vision/analyze-floorplan-image.d.ts.map +1 -1
  212. package/dist/tools/vision/analyze-floorplan-image.js +7 -7
  213. package/dist/tools/vision/analyze-room-photo.d.ts +1 -1
  214. package/dist/tools/vision/analyze-room-photo.d.ts.map +1 -1
  215. package/dist/tools/vision/analyze-room-photo.js +7 -7
  216. package/dist/tools/vision/index.d.ts +1 -1
  217. package/dist/tools/vision/index.d.ts.map +1 -1
  218. package/dist/transports/http.d.ts +8 -2
  219. package/dist/transports/http.d.ts.map +1 -1
  220. package/dist/transports/http.js +9 -3
  221. package/dist/transports/stdio.d.ts +15 -9
  222. package/dist/transports/stdio.d.ts.map +1 -1
  223. package/dist/transports/stdio.js +18 -11
  224. package/examples/coordinate-conventions-demo.md +12 -13
  225. package/examples/embed-in-agent.ts +5 -6
  226. package/examples/generate-apartment.md +4 -4
  227. package/examples/photo-to-scene.md +2 -3
  228. package/examples/renovate-from-photos.md +3 -5
  229. package/package.json +13 -9
  230. package/dist/tools/describe-node.d.ts +0 -17
  231. package/dist/tools/describe-node.d.ts.map +0 -1
  232. package/dist/tools/describe-node.js +0 -99
  233. package/dist/tools/find-nodes.d.ts +0 -16
  234. package/dist/tools/find-nodes.d.ts.map +0 -1
  235. package/dist/tools/find-nodes.js +0 -204
  236. package/dist/tools/place-design.d.ts +0 -34
  237. package/dist/tools/place-design.d.ts.map +0 -1
  238. package/dist/tools/place-design.js +0 -91
  239. package/dist/tools/validate-design.d.ts +0 -136
  240. package/dist/tools/validate-design.d.ts.map +0 -1
  241. package/dist/tools/validate-design.js +0 -28
  242. package/dist/tools/validate-scene.d.ts +0 -19
  243. package/dist/tools/validate-scene.d.ts.map +0 -1
  244. package/dist/tools/validate-scene.js +0 -28
@@ -1,8 +1,10 @@
1
1
  import { isAgentRefusal } from '@pascal-app/core/agent-tools';
2
2
  import { z } from 'zod';
3
3
  import { DESTRUCTIVE_TOOL_ANNOTATIONS } from './annotations.js';
4
- import { ErrorCode, McpError, refusalResult, throwMcpError } from './errors.js';
4
+ import { ProtocolError, ProtocolErrorCode, refusalResult, throwMcpError } from './errors.js';
5
5
  import './honest-patch-guard.js';
6
+ import './level-height-guard.js';
7
+ import './roof-level-guard.js';
6
8
  import { liveSyncOutput, persistencePayload, publishLiveSceneSnapshot } from './live-sync.js';
7
9
  import { assertPatchKeepsIdentity, PatchRefusedError, runPatchGuards } from './patch-guards.js';
8
10
  import { PatchSchema } from './schemas.js';
@@ -13,14 +15,16 @@ export const applyPatchOutput = {
13
15
  appliedOps: z.number(),
14
16
  deletedIds: z.array(z.string()),
15
17
  createdIds: z.array(z.string()),
18
+ /** What the server changed in the patch before writing it, one line each. */
19
+ notes: z.array(z.string()).optional(),
16
20
  ...liveSyncOutput,
17
21
  };
18
22
  export function registerApplyPatch(server, bridge) {
19
23
  server.registerTool('apply_patch', {
20
24
  title: 'Apply patch',
21
- description: "Apply a batch of create/update/delete operations atomically. All patches are validated before any are applied; the entire batch forms a single undo step. Batch-first is the default: prefer one apply_patch call containing all create/update/delete ops for a build step, in stable order so later ops can reference ids created by earlier ops. A single call is atomic (all or nothing) and pays the snapshot and save cost once; do not loop one-op calls. A create whose id already exists fails the whole patch with node_exists; to replace a node, delete it earlier in the same patch. An update cannot change id or type (identity_change) or object or children (immutable_field); restating the current value is fine. A parentId change must name an existing node that holds children (invalid_parent). An update cannot add schema issues to a node (invalid_update). After a delete or a roof update that regenerates a roof's default gutters, those gutters and their downspouts are addressable only in a later call (regenerated_default). Refusals come back as a tool error whose text is JSON {code, patchIndex, id, message}.",
22
- inputSchema: applyPatchInput,
23
- outputSchema: applyPatchOutput,
25
+ description: "Apply a batch of create/update/delete operations atomically. All patches are validated before any are applied; the entire batch forms a single undo step. Batch-first is the default: prefer one apply_patch call containing all create/update/delete ops for a build step, in stable order so later ops can reference ids created by earlier ops. A single call is atomic (all or nothing) and pays the snapshot and save cost once; do not loop one-op calls. A create whose id already exists fails the whole patch with node_exists; to replace a node, delete it earlier in the same patch. An update cannot change id or type (identity_change) or object or children (immutable_field); restating the current value is fine. A parentId change must name an existing node that holds children (invalid_parent). An update cannot add schema issues to a node (invalid_update). After a delete or a roof update that regenerates a roof's default gutters, those gutters and their downspouts are addressable only in a later call (regenerated_default). A roof created or moved onto the storey whose walls carry it goes to the level above them (the roof level over a top storey), said in notes; storey content (walls, zones, slabs, ceilings, items, stairs) on a roof level (roof_level), a walled level declared the roof level (roof_level_holds_storey) and floor indexes putting a roof level under a storey (roof_level_on_top) are refused. Refusals come back as a tool error whose text is JSON {code, patchIndex, id, message}.",
26
+ inputSchema: z.object(applyPatchInput),
27
+ outputSchema: z.object(applyPatchOutput),
24
28
  annotations: DESTRUCTIVE_TOOL_ANNOTATIONS,
25
29
  }, async ({ patches }) => {
26
30
  const bridgePatches = patches.map((p) => {
@@ -45,7 +49,7 @@ export function registerApplyPatch(server, bridge) {
45
49
  };
46
50
  });
47
51
  try {
48
- runPatchGuards(bridgePatches, bridge.getNodes());
52
+ const notes = runPatchGuards(bridgePatches, bridge.getNodes());
49
53
  const planDeletion = bridge
50
54
  .planDeletion;
51
55
  assertPatchKeepsIdentity(bridgePatches, bridge.getNodes(), bridge.getRootNodeIds(), typeof planDeletion === 'function' ? planDeletion.bind(bridge) : undefined);
@@ -55,6 +59,7 @@ export function registerApplyPatch(server, bridge) {
55
59
  appliedOps: result.appliedOps,
56
60
  deletedIds: result.deletedIds,
57
61
  createdIds: result.createdIds,
62
+ ...(notes.length ? { notes } : {}),
58
63
  ...persistencePayload(persistence),
59
64
  };
60
65
  return {
@@ -64,7 +69,7 @@ export function registerApplyPatch(server, bridge) {
64
69
  }
65
70
  catch (err) {
66
71
  if (err instanceof PatchRefusedError) {
67
- // A tool error, not an McpError: the SDK keeps only an McpError's
72
+ // A tool error, not an ProtocolError: the SDK keeps only an ProtocolError's
68
73
  // message, and clients need the code, index and id to act on it.
69
74
  const refusal = {
70
75
  code: err.code,
@@ -80,10 +85,10 @@ export function registerApplyPatch(server, bridge) {
80
85
  // A refusal the store made (an accidental wipe) answers with its code, as the shared tools'.
81
86
  if (isAgentRefusal(err))
82
87
  return refusalResult(err);
83
- if (err instanceof McpError)
88
+ if (err instanceof ProtocolError)
84
89
  throw err;
85
90
  const msg = err instanceof Error ? err.message : String(err);
86
- throwMcpError(ErrorCode.InvalidParams, msg);
91
+ throwMcpError(ProtocolErrorCode.InvalidParams, msg);
87
92
  }
88
93
  });
89
94
  }
@@ -1 +1 @@
1
- {"version":3,"file":"asset-catalog.d.ts","sourceRoot":"","sources":["../../src/tools/asset-catalog.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,yBAAyB,CAAA;AAEzD;;;;;;;GAOG;AACH,eAAO,MAAM,iBAAiB,EAAE,UAAU,EA6RzC,CAAA;AAED;;;GAGG;AACH,MAAM,MAAM,YAAY,GAAG,MAAM,OAAO,CAAC,SAAS,UAAU,EAAE,CAAC,CAAA;AAE/D,eAAO,MAAM,cAAc,EAAE,YAA4C,CAAA;AAEzE,iGAAiG;AACjG,wBAAgB,aAAa,CAAC,IAAI,EAAE,YAAY,GAAG,YAAY,CAO9D;AAED,wBAAgB,eAAe,CAAC,KAAK,EAAE,SAAS,UAAU,EAAE,EAAE,EAAE,EAAE,MAAM,GAAG,UAAU,GAAG,SAAS,CAEhG"}
1
+ {"version":3,"file":"asset-catalog.d.ts","sourceRoot":"","sources":["../../src/tools/asset-catalog.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,yBAAyB,CAAA;AAEzD;;;;;;;GAOG;AACH,eAAO,MAAM,iBAAiB,EAAE,UAAU,EAoTzC,CAAA;AAED;;;GAGG;AACH,MAAM,MAAM,YAAY,GAAG,MAAM,OAAO,CAAC,SAAS,UAAU,EAAE,CAAC,CAAA;AAE/D,eAAO,MAAM,cAAc,EAAE,YAA4C,CAAA;AAEzE,iGAAiG;AACjG,wBAAgB,aAAa,CAAC,IAAI,EAAE,YAAY,GAAG,YAAY,CAO9D;AAED,wBAAgB,eAAe,CAAC,KAAK,EAAE,SAAS,UAAU,EAAE,EAAE,EAAE,EAAE,MAAM,GAAG,UAAU,GAAG,SAAS,CAEhG"}
@@ -10,6 +10,7 @@ export const MCP_CATALOG_ITEMS = [
10
10
  {
11
11
  id: 'double-bed',
12
12
  category: 'furniture',
13
+ functionTags: ['double-beds'],
13
14
  tags: ['floor', 'bedroom'],
14
15
  name: 'Double Bed',
15
16
  thumbnail: '/items/double-bed/thumbnail.webp',
@@ -22,6 +23,7 @@ export const MCP_CATALOG_ITEMS = [
22
23
  {
23
24
  id: 'single-bed',
24
25
  category: 'furniture',
26
+ functionTags: ['single-beds'],
25
27
  tags: ['floor', 'bedroom'],
26
28
  name: 'Single Bed',
27
29
  thumbnail: '/items/single-bed/thumbnail.webp',
@@ -34,6 +36,7 @@ export const MCP_CATALOG_ITEMS = [
34
36
  {
35
37
  id: 'bedside-table',
36
38
  category: 'furniture',
39
+ functionTags: ['coffee-tables'],
37
40
  tags: ['floor', 'bedroom'],
38
41
  name: 'Bedside Table',
39
42
  thumbnail: '/items/bedside-table/thumbnail.webp',
@@ -47,6 +50,7 @@ export const MCP_CATALOG_ITEMS = [
47
50
  {
48
51
  id: 'dresser',
49
52
  category: 'furniture',
53
+ functionTags: ['dressers'],
50
54
  tags: ['floor', 'storage', 'bedroom'],
51
55
  name: 'Dresser',
52
56
  thumbnail: '/items/dresser/thumbnail.webp',
@@ -60,6 +64,7 @@ export const MCP_CATALOG_ITEMS = [
60
64
  {
61
65
  id: 'closet',
62
66
  category: 'furniture',
67
+ functionTags: ['wardrobes'],
63
68
  tags: ['floor', 'storage', 'bedroom'],
64
69
  name: 'Closet',
65
70
  thumbnail: '/items/closet/thumbnail.webp',
@@ -72,6 +77,7 @@ export const MCP_CATALOG_ITEMS = [
72
77
  {
73
78
  id: 'sofa',
74
79
  category: 'furniture',
80
+ functionTags: ['sofas'],
75
81
  tags: ['floor', 'seating', 'living'],
76
82
  name: 'Sofa',
77
83
  thumbnail: '/items/sofa/thumbnail.webp',
@@ -84,6 +90,7 @@ export const MCP_CATALOG_ITEMS = [
84
90
  {
85
91
  id: 'livingroom-chair',
86
92
  category: 'furniture',
93
+ functionTags: ['armchairs'],
87
94
  tags: ['floor', 'seating', 'living'],
88
95
  name: 'Livingroom Chair',
89
96
  thumbnail: '/items/livingroom-chair/thumbnail.webp',
@@ -96,6 +103,7 @@ export const MCP_CATALOG_ITEMS = [
96
103
  {
97
104
  id: 'coffee-table',
98
105
  category: 'furniture',
106
+ functionTags: ['coffee-tables'],
99
107
  tags: ['floor', 'table', 'living'],
100
108
  name: 'Coffee Table',
101
109
  thumbnail: '/items/coffee-table/thumbnail.webp',
@@ -109,6 +117,7 @@ export const MCP_CATALOG_ITEMS = [
109
117
  {
110
118
  id: 'tv-stand',
111
119
  category: 'furniture',
120
+ functionTags: ['cabinets'],
112
121
  tags: ['floor', 'storage', 'living'],
113
122
  name: 'TV Stand',
114
123
  thumbnail: '/items/tv-stand/thumbnail.webp',
@@ -122,6 +131,7 @@ export const MCP_CATALOG_ITEMS = [
122
131
  {
123
132
  id: 'shelf',
124
133
  category: 'furniture',
134
+ functionTags: ['shelves'],
125
135
  tags: ['wall', 'storage'],
126
136
  name: 'Shelf',
127
137
  thumbnail: '/items/shelf/thumbnail.webp',
@@ -136,6 +146,7 @@ export const MCP_CATALOG_ITEMS = [
136
146
  {
137
147
  id: 'dining-table',
138
148
  category: 'furniture',
149
+ functionTags: ['dining-tables'],
139
150
  tags: ['floor', 'table', 'dining'],
140
151
  name: 'Dining Table',
141
152
  thumbnail: '/items/dining-table/thumbnail.webp',
@@ -149,6 +160,7 @@ export const MCP_CATALOG_ITEMS = [
149
160
  {
150
161
  id: 'dining-chair',
151
162
  category: 'furniture',
163
+ functionTags: ['dining-chairs'],
152
164
  tags: ['floor', 'seating', 'dining'],
153
165
  name: 'Dining Chair',
154
166
  thumbnail: '/items/dining-chair/thumbnail.webp',
@@ -161,6 +173,7 @@ export const MCP_CATALOG_ITEMS = [
161
173
  {
162
174
  id: 'kitchen',
163
175
  category: 'kitchen',
176
+ functionTags: ['cabinets'],
164
177
  tags: ['floor', 'large', 'kitchen'],
165
178
  name: 'Kitchen',
166
179
  thumbnail: '/items/kitchen/thumbnail.webp',
@@ -173,6 +186,7 @@ export const MCP_CATALOG_ITEMS = [
173
186
  {
174
187
  id: 'kitchen-counter',
175
188
  category: 'kitchen',
189
+ functionTags: ['counters'],
176
190
  tags: ['floor', 'large', 'storage', 'kitchen'],
177
191
  name: 'Kitchen Counter',
178
192
  thumbnail: '/items/kitchen-counter/thumbnail.webp',
@@ -186,6 +200,7 @@ export const MCP_CATALOG_ITEMS = [
186
200
  {
187
201
  id: 'stove',
188
202
  category: 'kitchen',
203
+ functionTags: ['kitchen-appliances'],
189
204
  tags: ['floor', 'large', 'kitchen'],
190
205
  name: 'Stove',
191
206
  thumbnail: '/items/stove/thumbnail.webp',
@@ -198,6 +213,7 @@ export const MCP_CATALOG_ITEMS = [
198
213
  {
199
214
  id: 'fridge',
200
215
  category: 'kitchen',
216
+ functionTags: ['kitchen-appliances'],
201
217
  tags: ['floor', 'large', 'kitchen'],
202
218
  name: 'Fridge',
203
219
  thumbnail: '/items/fridge/thumbnail.webp',
@@ -210,6 +226,7 @@ export const MCP_CATALOG_ITEMS = [
210
226
  {
211
227
  id: 'toilet',
212
228
  category: 'bathroom',
229
+ functionTags: ['toilets'],
213
230
  tags: ['floor', 'large', 'bathroom'],
214
231
  name: 'Toilet',
215
232
  thumbnail: '/items/toilet/thumbnail.webp',
@@ -222,6 +239,7 @@ export const MCP_CATALOG_ITEMS = [
222
239
  {
223
240
  id: 'bathroom-sink',
224
241
  category: 'bathroom',
242
+ functionTags: ['sinks'],
225
243
  tags: ['floor', 'large', 'bathroom'],
226
244
  name: 'Bathroom Sink',
227
245
  thumbnail: '/items/bathroom-sink/thumbnail.webp',
@@ -234,6 +252,7 @@ export const MCP_CATALOG_ITEMS = [
234
252
  {
235
253
  id: 'shower-square',
236
254
  category: 'bathroom',
255
+ functionTags: ['showers'],
237
256
  tags: ['floor', 'large', 'bathroom'],
238
257
  name: 'Squared Shower',
239
258
  thumbnail: '/items/shower-square/thumbnail.webp',
@@ -246,6 +265,7 @@ export const MCP_CATALOG_ITEMS = [
246
265
  {
247
266
  id: 'bathtub',
248
267
  category: 'bathroom',
268
+ functionTags: ['bathtubs'],
249
269
  tags: ['floor', 'large', 'bathroom'],
250
270
  name: 'Bathtub',
251
271
  thumbnail: '/items/bathtub/thumbnail.webp',
@@ -258,6 +278,7 @@ export const MCP_CATALOG_ITEMS = [
258
278
  {
259
279
  id: 'washing-machine',
260
280
  category: 'bathroom',
281
+ functionTags: ['laundry-appliances'],
261
282
  tags: ['floor', 'large', 'electronics', 'laundry'],
262
283
  name: 'Washing Machine',
263
284
  thumbnail: '/items/washing-machine/thumbnail.webp',
@@ -270,6 +291,7 @@ export const MCP_CATALOG_ITEMS = [
270
291
  {
271
292
  id: 'drying-rack',
272
293
  category: 'bathroom',
294
+ functionTags: ['laundry-appliances'],
273
295
  tags: ['floor', 'laundry'],
274
296
  name: 'Drying Rack',
275
297
  thumbnail: '/items/drying-rack/thumbnail.webp',
@@ -282,6 +304,7 @@ export const MCP_CATALOG_ITEMS = [
282
304
  {
283
305
  id: 'coat-rack',
284
306
  category: 'furniture',
307
+ functionTags: ['racks'],
285
308
  tags: ['floor', 'storage', 'entry'],
286
309
  name: 'Coat Rack',
287
310
  thumbnail: '/items/coat-rack/thumbnail.webp',
@@ -0,0 +1,10 @@
1
+ import type { McpServer } from '@modelcontextprotocol/server';
2
+ import type { SceneOperations } from '../operations/index.js';
3
+ import { type GeometryScriptHost } from './add-object.js';
4
+ /**
5
+ * `author_scene` on the MCP: every item's module compiled and stored through the host, the
6
+ * module and the adapter kept as the scene's provenance, the operation applied, Pascal's checks
7
+ * run, and the gate report answered. Replay is the same payload through the same operation.
8
+ */
9
+ export declare function registerAuthorScene(server: McpServer, bridge: SceneOperations, host: GeometryScriptHost | undefined): void;
10
+ //# sourceMappingURL=author-scene.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"author-scene.d.ts","sourceRoot":"","sources":["../../src/tools/author-scene.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,8BAA8B,CAAA;AAe7D,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,eAAe,CAAA;AACpD,OAAO,EAAmB,KAAK,kBAAkB,EAAE,MAAM,cAAc,CAAA;AAevE;;;;GAIG;AACH,wBAAgB,mBAAmB,CACjC,MAAM,EAAE,SAAS,EACjB,MAAM,EAAE,eAAe,EACvB,IAAI,EAAE,kBAAkB,GAAG,SAAS,GACnC,IAAI,CA0HN"}
@@ -0,0 +1,140 @@
1
+ import { achievedChanges, verifyScene, } from '@pascal-app/core/agent-operations';
2
+ import { authorSceneTool, isAgentRefusal, } from '@pascal-app/core/agent-tools';
3
+ import { GEOMETRY_SCRIPT_MIME_TYPES } from '@pascal-app/core/schema';
4
+ import { compileAuthorScene } from '@pascal-app/geometry-script/author-scene';
5
+ import { z } from 'zod';
6
+ import { compileAndStore } from './add-object.js';
7
+ import { DESTRUCTIVE_TOOL_ANNOTATIONS } from './annotations.js';
8
+ import { refusalResult, toolError } from './errors.js';
9
+ import { persistencePayload, publishLiveSceneSnapshot } from './live-sync.js';
10
+ import { toPatches } from './shared-tools.js';
11
+ /**
12
+ * `author_scene` on the MCP: every item's module compiled and stored through the host, the
13
+ * module and the adapter kept as the scene's provenance, the operation applied, Pascal's checks
14
+ * run, and the gate report answered. Replay is the same payload through the same operation.
15
+ */
16
+ export function registerAuthorScene(server, bridge, host) {
17
+ server.registerTool(authorSceneTool.name, {
18
+ title: authorSceneTool.title,
19
+ description: authorSceneTool.description,
20
+ inputSchema: z.object(authorSceneTool.input),
21
+ annotations: DESTRUCTIVE_TOOL_ANNOTATIONS,
22
+ }, async (input) => {
23
+ if (!host) {
24
+ return toolError('This Pascal server cannot run geometry scripts.', {
25
+ code: 'scripts_unavailable',
26
+ });
27
+ }
28
+ const args = input;
29
+ const scene = bridge.getActiveScene();
30
+ if (!scene) {
31
+ return toolError('Open or save a scene first: a conversion is stored with a scene.', {
32
+ code: 'no_active_scene',
33
+ });
34
+ }
35
+ if (args.sceneId && args.sceneId !== scene.id) {
36
+ return toolError('Open the requested scene before converting it.', {
37
+ code: 'scene_mismatch',
38
+ mutationApplied: false,
39
+ });
40
+ }
41
+ const before = bridge.getNodes();
42
+ const beforeJson = JSON.stringify(before);
43
+ const context = {
44
+ activeLevelId: bridge.activeLevelId?.() ?? null,
45
+ ...(bridge.supportsMaterialUpserts && bridge.getMaterials
46
+ ? { materials: bridge.getMaterials() }
47
+ : {}),
48
+ };
49
+ let outcome;
50
+ try {
51
+ outcome = await compileAuthorScene(before, args, context, ({ code, kind, inputs, nodeId }) => compileAndStore(host, scene.id, { code, language: 'three', params: undefined, inputs }, kind, { nodeId }), host.signal);
52
+ }
53
+ catch (error) {
54
+ if (isAgentRefusal(error))
55
+ return refusalResult(error);
56
+ return toolError(error instanceof Error ? error.message : String(error), {
57
+ code: 'conversion_failed',
58
+ });
59
+ }
60
+ // Provenance: the design's module and the program that read it, kept as scripts of the scene.
61
+ const provenance = {};
62
+ for (const [kind, text] of [
63
+ ['module', args.module],
64
+ ['adapter', args.adapter],
65
+ ]) {
66
+ if (!text)
67
+ continue;
68
+ provenance[kind] = await host.storeArtifact({
69
+ sceneId: scene.id,
70
+ sha256: await sha256(text),
71
+ bytes: new TextEncoder().encode(text),
72
+ mimeType: GEOMETRY_SCRIPT_MIME_TYPES.three,
73
+ metadata: { kind: 'item' },
74
+ });
75
+ }
76
+ host.signal?.throwIfAborted();
77
+ await host.assertActive?.();
78
+ if (JSON.stringify(bridge.getNodes()) !== beforeJson) {
79
+ return toolError('The scene changed while its candidate was compiling. Read the current scene and retry the conversion.', { code: 'scene_changed', mutationApplied: false });
80
+ }
81
+ const buildingUpdate = outcome.changes.update.find((change) => change.id === outcome.buildingId);
82
+ buildingUpdate.data.metadata = {
83
+ ...buildingUpdate.data.metadata,
84
+ authorScene: {
85
+ ...provenance,
86
+ payload: withoutCode(args.payload),
87
+ report: outcome.result,
88
+ at: new Date().toISOString(),
89
+ },
90
+ };
91
+ const patches = toPatches(outcome.changes);
92
+ if (patches.length)
93
+ bridge.applyPatch(patches);
94
+ const checks = verifyScene(bridge.getNodes(), undefined, {
95
+ activeLevelId: null,
96
+ }).result;
97
+ const byType = new Map();
98
+ for (const issue of checks.issues)
99
+ byType.set(issue.type ?? 'unknown', (byType.get(issue.type ?? 'unknown') ?? 0) + 1);
100
+ const payload = {
101
+ ...outcome.result,
102
+ itemTriangles: outcome.itemTriangles,
103
+ itemsCompiled: outcome.itemsCompiled,
104
+ green: outcome.result.defects.length === 0,
105
+ verify: {
106
+ valid: checks.valid,
107
+ issues: checks.issues.length,
108
+ byType: Object.fromEntries(byType),
109
+ first: checks.issues.slice(0, 40).map((i) => i.message),
110
+ },
111
+ achieved: achievedChanges(before, outcome.changes ?? {}),
112
+ ...persistencePayload(await publishLiveSceneSnapshot(bridge, authorSceneTool.name)),
113
+ };
114
+ return {
115
+ content: [{ type: 'text', text: JSON.stringify(payload) }],
116
+ structuredContent: payload,
117
+ };
118
+ });
119
+ }
120
+ /** The payload as kept with the scene: every module is already its own artifact. */
121
+ function withoutCode(payload) {
122
+ return {
123
+ ...payload,
124
+ levels: payload.levels.map((level) => ({
125
+ ...level,
126
+ walls: (level.walls ?? []).map(({ faceLeft, faceRight, ...wall }) => ({
127
+ ...wall,
128
+ openings: (wall.openings ?? []).map(({ code: _, ...opening }) => opening),
129
+ ...(faceLeft ? { faceLeft: { toHeight: faceLeft.toHeight } } : {}),
130
+ ...(faceRight ? { faceRight: { toHeight: faceRight.toHeight } } : {}),
131
+ })),
132
+ items: (level.items ?? []).map(({ code: _, ...item }) => item),
133
+ rooms: level.rooms.map(({ floorCode: _, wallCode: _w, ...room }) => room),
134
+ })),
135
+ };
136
+ }
137
+ async function sha256(text) {
138
+ const digest = await crypto.subtle.digest('SHA-256', new TextEncoder().encode(text));
139
+ return [...new Uint8Array(digest)].map((b) => b.toString(16).padStart(2, '0')).join('');
140
+ }
@@ -1,17 +1,17 @@
1
- import type { McpServer } from '@modelcontextprotocol/sdk/server/mcp.js';
1
+ import type { McpServer } from '@modelcontextprotocol/server';
2
2
  import { z } from 'zod';
3
3
  import type { SceneOperations } from '../operations/index.js';
4
4
  export declare const checkCollisionsInput: {
5
5
  levelId: z.ZodOptional<z.ZodString>;
6
- minimumClearance: z.ZodDefault<z.ZodPipe<z.ZodUnion<readonly [z.ZodNumber, z.ZodString]>, z.ZodTransform<number, string | number>>>;
6
+ minimumClearance: z.ZodDefault<z.ZodPipe<z.ZodUnion<[z.ZodNumber, z.ZodString]>, z.ZodTransform<number, string | number>>>;
7
7
  floorOnly: z.ZodDefault<z.ZodBoolean>;
8
8
  candidate: z.ZodOptional<z.ZodObject<{
9
9
  id: z.ZodDefault<z.ZodString>;
10
10
  name: z.ZodDefault<z.ZodString>;
11
11
  levelId: z.ZodString;
12
- position: z.ZodPipe<z.ZodArray<z.ZodPipe<z.ZodUnion<readonly [z.ZodNumber, z.ZodString]>, z.ZodTransform<number, string | number>>>, z.ZodTransform<[number, number, number], number[]>>;
13
- dimensions: z.ZodPipe<z.ZodArray<z.ZodPipe<z.ZodUnion<readonly [z.ZodNumber, z.ZodString]>, z.ZodTransform<number, string | number>>>, z.ZodTransform<[number, number, number], number[]>>;
14
- rotationY: z.ZodDefault<z.ZodPipe<z.ZodUnion<readonly [z.ZodNumber, z.ZodString]>, z.ZodTransform<number, string | number>>>;
12
+ position: z.ZodPipe<z.ZodArray<z.ZodPipe<z.ZodUnion<[z.ZodNumber, z.ZodString]>, z.ZodTransform<number, string | number>> | z.ZodDefault<z.ZodPipe<z.ZodUnion<[z.ZodNumber, z.ZodString]>, z.ZodTransform<number, string | number>>>>, z.ZodTransform<[number, number, number], number[]>>;
13
+ dimensions: z.ZodPipe<z.ZodArray<z.ZodPipe<z.ZodUnion<[z.ZodNumber, z.ZodString]>, z.ZodTransform<number, string | number>> | z.ZodDefault<z.ZodPipe<z.ZodUnion<[z.ZodNumber, z.ZodString]>, z.ZodTransform<number, string | number>>>>, z.ZodTransform<[number, number, number], number[]>>;
14
+ rotationY: z.ZodDefault<z.ZodPipe<z.ZodUnion<[z.ZodNumber, z.ZodString]>, z.ZodTransform<number, string | number>>>;
15
15
  source: z.ZodOptional<z.ZodObject<{
16
16
  assetId: z.ZodOptional<z.ZodString>;
17
17
  uri: z.ZodOptional<z.ZodString>;
@@ -21,8 +21,8 @@ export declare const checkCollisionsInput: {
21
21
  export declare const checkCollisionsOutput: {
22
22
  status: z.ZodEnum<{
23
23
  checked: "checked";
24
- partial: "partial";
25
24
  insufficient_evidence: "insufficient_evidence";
25
+ partial: "partial";
26
26
  }>;
27
27
  units: z.ZodLiteral<"meters">;
28
28
  method: z.ZodLiteral<"rotation-aware-plan-aabb">;
@@ -1 +1 @@
1
- {"version":3,"file":"check-collisions.d.ts","sourceRoot":"","sources":["../../src/tools/check-collisions.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,yCAAyC,CAAA;AAOxE,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAA;AACvB,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,eAAe,CAAA;AA4BpD,eAAO,MAAM,oBAAoB;;;;;;;;;;;;;;;;CA+BhC,CAAA;AAED,eAAO,MAAM,qBAAqB;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;CAoDjC,CAAA;AA6BD,wBAAgB,uBAAuB,CAAC,MAAM,EAAE,SAAS,EAAE,MAAM,EAAE,eAAe,GAAG,IAAI,CAyKxF"}
1
+ {"version":3,"file":"check-collisions.d.ts","sourceRoot":"","sources":["../../src/tools/check-collisions.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,8BAA8B,CAAA;AAO7D,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAA;AACvB,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,eAAe,CAAA;AA4BpD,eAAO,MAAM,oBAAoB;IAC/B,OAAO;IACP,gBAAgB;IAIhB,SAAS;IAIT,SAAS;;;;;;;;;;;;CAqBV,CAAA;AAED,eAAO,MAAM,qBAAqB;IAChC,MAAM;;;;;IACN,KAAK;IACL,MAAM;IACN,mBAAmB;IACnB,sBAAsB;IACtB,SAAS;IACT,eAAe;IACf,YAAY;;;;;;;;;;;;;;;;;;;;IAsBZ,YAAY;;;;;IAOZ,iBAAiB;;;;IAMjB,UAAU;;;;;;;;;;CASX,CAAA;AA6BD,wBAAgB,uBAAuB,CAAC,MAAM,EAAE,SAAS,EAAE,MAAM,EAAE,eAAe,GAAG,IAAI,CA4KxF"}
@@ -2,7 +2,7 @@ import { findItemItemCollisions, inspectItemPlanFootprint, resolveNodeLevelId, }
2
2
  import { ItemNode } from '@pascal-app/core/schema';
3
3
  import { z } from 'zod';
4
4
  import { READ_ONLY_TOOL_ANNOTATIONS } from './annotations.js';
5
- import { ErrorCode, throwMcpError } from './errors.js';
5
+ import { ProtocolErrorCode, throwMcpError } from './errors.js';
6
6
  import { measurement } from './measurement.js';
7
7
  import { computeGraphHash } from './scene-lifecycle/metadata.js';
8
8
  import { NodeIdSchema } from './schemas.js';
@@ -130,24 +130,24 @@ export function registerCheckCollisions(server, bridge) {
130
130
  server.registerTool('check_collisions', {
131
131
  title: 'Check collisions',
132
132
  description: 'Assess declared item footprints with a rotation-aware plan AABB test. Supports an explicit minimum clearance and reports units, source dimensions, skipped evidence, and unsupported checks. Optionally scope to one level or floor-standing items.',
133
- inputSchema: checkCollisionsInput,
134
- outputSchema: checkCollisionsOutput,
133
+ inputSchema: z.object(checkCollisionsInput),
134
+ outputSchema: z.object(checkCollisionsOutput),
135
135
  annotations: READ_ONLY_TOOL_ANNOTATIONS,
136
136
  }, async ({ levelId, minimumClearance, floorOnly, candidate }) => {
137
137
  const sceneNodes = Object.values(bridge.getNodes());
138
138
  if (candidate && levelId && candidate.levelId !== levelId) {
139
- throwMcpError(ErrorCode.InvalidParams, 'candidate.levelId must match levelId when both are provided');
139
+ throwMcpError(ProtocolErrorCode.InvalidParams, 'candidate.levelId must match levelId when both are provided');
140
140
  }
141
141
  const scopeLevelId = candidate?.levelId ?? levelId;
142
142
  if (scopeLevelId) {
143
143
  const target = sceneNodes.find((node) => node.id === scopeLevelId);
144
144
  if (target?.type !== 'level') {
145
- throwMcpError(ErrorCode.InvalidParams, `Level not found: ${scopeLevelId}`);
145
+ throwMcpError(ProtocolErrorCode.InvalidParams, `Level not found: ${scopeLevelId}`);
146
146
  }
147
147
  }
148
148
  if (candidate) {
149
149
  if (sceneNodes.some((node) => node.id === candidate.id)) {
150
- throwMcpError(ErrorCode.InvalidParams, `Candidate id already exists: ${candidate.id}`);
150
+ throwMcpError(ProtocolErrorCode.InvalidParams, `Candidate id already exists: ${candidate.id}`);
151
151
  }
152
152
  }
153
153
  const candidateNode = candidate
@@ -1,4 +1,4 @@
1
- import type { McpServer } from '@modelcontextprotocol/sdk/server/mcp.js';
1
+ import type { McpServer } from '@modelcontextprotocol/server';
2
2
  import type { SceneOperations } from '../operations/index.js';
3
3
  /**
4
4
  * `clear_scene`: the scene goes back to the host's default scaffold (a site, a building, a level),
@@ -1 +1 @@
1
- {"version":3,"file":"clear-scene.d.ts","sourceRoot":"","sources":["../../src/tools/clear-scene.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,yCAAyC,CAAA;AAGxE,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,eAAe,CAAA;AAKpD;;;;GAIG;AACH,wBAAgB,kBAAkB,CAAC,MAAM,EAAE,SAAS,EAAE,UAAU,EAAE,eAAe,GAAG,IAAI,CAmDvF"}
1
+ {"version":3,"file":"clear-scene.d.ts","sourceRoot":"","sources":["../../src/tools/clear-scene.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,8BAA8B,CAAA;AAG7D,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,eAAe,CAAA;AAKpD;;;;GAIG;AACH,wBAAgB,kBAAkB,CAAC,MAAM,EAAE,SAAS,EAAE,UAAU,EAAE,eAAe,GAAG,IAAI,CAmDvF"}
@@ -12,13 +12,13 @@ export function registerClearScene(server, operations) {
12
12
  server.registerTool(clearSceneTool.name, {
13
13
  title: clearSceneTool.title,
14
14
  description: clearSceneTool.description,
15
- inputSchema: clearSceneTool.input,
16
- outputSchema: {
15
+ inputSchema: z.object(clearSceneTool.input),
16
+ outputSchema: z.object({
17
17
  cleared: z.object({ removed: z.number() }),
18
18
  version: z.number().nullable(),
19
19
  graphHash: z.string().nullable(),
20
20
  ...liveSyncOutput,
21
- },
21
+ }),
22
22
  annotations: DESTRUCTIVE_TOOL_ANNOTATIONS,
23
23
  }, async () => {
24
24
  try {
@@ -1,4 +1,4 @@
1
- import type { McpServer } from '@modelcontextprotocol/sdk/server/mcp.js';
1
+ import type { McpServer } from '@modelcontextprotocol/server';
2
2
  import type { SceneOperations } from '../operations/index.js';
3
3
  export declare function registerCollectionTools(server: McpServer, bridge: SceneOperations): void;
4
4
  //# sourceMappingURL=collections.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"collections.d.ts","sourceRoot":"","sources":["../../src/tools/collections.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,yCAAyC,CAAA;AAWxE,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,eAAe,CAAA;AAgBpD,wBAAgB,uBAAuB,CAAC,MAAM,EAAE,SAAS,EAAE,MAAM,EAAE,eAAe,GAAG,IAAI,CA+CxF"}
1
+ {"version":3,"file":"collections.d.ts","sourceRoot":"","sources":["../../src/tools/collections.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,8BAA8B,CAAA;AAY7D,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,eAAe,CAAA;AAgBpD,wBAAgB,uBAAuB,CAAC,MAAM,EAAE,SAAS,EAAE,MAAM,EAAE,eAAe,GAAG,IAAI,CA+CxF"}
@@ -1,5 +1,6 @@
1
1
  import { editCollection, listCollections, writeCollections, } from '@pascal-app/core/agent-operations';
2
2
  import { editCollectionTool, listCollectionsTool } from '@pascal-app/core/agent-tools';
3
+ import { z } from 'zod';
3
4
  import { DESTRUCTIVE_TOOL_ANNOTATIONS, READ_ONLY_TOOL_ANNOTATIONS } from './annotations.js';
4
5
  import { refusalResult } from './errors.js';
5
6
  import { persistencePayload, publishLiveSceneSnapshot } from './live-sync.js';
@@ -15,7 +16,7 @@ export function registerCollectionTools(server, bridge) {
15
16
  server.registerTool(listCollectionsTool.name, {
16
17
  title: listCollectionsTool.title,
17
18
  description: listCollectionsTool.description,
18
- inputSchema: listCollectionsTool.input,
19
+ inputSchema: z.object(listCollectionsTool.input),
19
20
  annotations: READ_ONLY_TOOL_ANNOTATIONS,
20
21
  }, async (input) => {
21
22
  try {
@@ -28,7 +29,7 @@ export function registerCollectionTools(server, bridge) {
28
29
  server.registerTool(editCollectionTool.name, {
29
30
  title: editCollectionTool.title,
30
31
  description: editCollectionTool.description,
31
- inputSchema: editCollectionTool.input,
32
+ inputSchema: z.object(editCollectionTool.input),
32
33
  annotations: DESTRUCTIVE_TOOL_ANNOTATIONS,
33
34
  }, async (input) => {
34
35
  let outcome;
@@ -1,15 +1,15 @@
1
- import type { McpServer } from '@modelcontextprotocol/sdk/server/mcp.js';
1
+ import type { McpServer } from '@modelcontextprotocol/server';
2
2
  import { z } from 'zod';
3
3
  import type { SceneOperations } from '../operations/index.js';
4
4
  export declare const createStoryShellInput: {
5
5
  levelId: z.ZodString;
6
6
  footprint: z.ZodArray<z.ZodArray<z.ZodNumber>>;
7
- wallHeight: z.ZodOptional<z.ZodPipe<z.ZodUnion<readonly [z.ZodNumber, z.ZodString]>, z.ZodTransform<number, string | number>>>;
8
- wallThickness: z.ZodDefault<z.ZodPipe<z.ZodUnion<readonly [z.ZodNumber, z.ZodString]>, z.ZodTransform<number, string | number>>>;
7
+ wallHeight: z.ZodOptional<z.ZodPipe<z.ZodUnion<[z.ZodNumber, z.ZodString]>, z.ZodTransform<number, string | number>>>;
8
+ wallThickness: z.ZodDefault<z.ZodPipe<z.ZodUnion<[z.ZodNumber, z.ZodString]>, z.ZodTransform<number, string | number>>>;
9
9
  createSlab: z.ZodDefault<z.ZodBoolean>;
10
10
  createCeiling: z.ZodDefault<z.ZodBoolean>;
11
- slabElevation: z.ZodDefault<z.ZodPipe<z.ZodUnion<readonly [z.ZodNumber, z.ZodString]>, z.ZodTransform<number, string | number>>>;
12
- ceilingHeight: z.ZodOptional<z.ZodPipe<z.ZodUnion<readonly [z.ZodNumber, z.ZodString]>, z.ZodTransform<number, string | number>>>;
11
+ slabElevation: z.ZodDefault<z.ZodPipe<z.ZodUnion<[z.ZodNumber, z.ZodString]>, z.ZodTransform<number, string | number>>>;
12
+ ceilingHeight: z.ZodOptional<z.ZodPipe<z.ZodUnion<[z.ZodNumber, z.ZodString]>, z.ZodTransform<number, string | number>>>;
13
13
  namePrefix: z.ZodOptional<z.ZodString>;
14
14
  wallMaterialPreset: z.ZodOptional<z.ZodString>;
15
15
  slabMaterialPreset: z.ZodOptional<z.ZodString>;
@@ -20,8 +20,8 @@ export declare const createStoryShellOutput: {
20
20
  unsaved: z.ZodOptional<z.ZodString>;
21
21
  persistence: z.ZodOptional<z.ZodObject<{
22
22
  status: z.ZodEnum<{
23
- unbound: "unbound";
24
23
  events_unsupported: "events_unsupported";
24
+ unbound: "unbound";
25
25
  }>;
26
26
  warning: z.ZodString;
27
27
  }, z.core.$strip>>;
@@ -35,48 +35,5 @@ export declare const createStoryShellOutput: {
35
35
  ceilingId: z.ZodNullable<z.ZodString>;
36
36
  createdIds: z.ZodArray<z.ZodString>;
37
37
  };
38
- export declare const createRoofInput: {
39
- levelId: z.ZodString;
40
- roofLevelId: z.ZodOptional<z.ZodString>;
41
- useDedicatedRoofLevel: z.ZodDefault<z.ZodBoolean>;
42
- roofLevelLabel: z.ZodDefault<z.ZodString>;
43
- roofLevelElevation: z.ZodOptional<z.ZodNumber>;
44
- roofLevelHeight: z.ZodOptional<z.ZodPipe<z.ZodUnion<readonly [z.ZodNumber, z.ZodString]>, z.ZodTransform<number, string | number>>>;
45
- center: z.ZodOptional<z.ZodArray<z.ZodNumber>>;
46
- width: z.ZodPipe<z.ZodUnion<readonly [z.ZodNumber, z.ZodString]>, z.ZodTransform<number, string | number>>;
47
- depth: z.ZodPipe<z.ZodUnion<readonly [z.ZodNumber, z.ZodString]>, z.ZodTransform<number, string | number>>;
48
- roofType: z.ZodDefault<z.ZodEnum<{
49
- gable: "gable";
50
- flat: "flat";
51
- hip: "hip";
52
- shed: "shed";
53
- gambrel: "gambrel";
54
- dutch: "dutch";
55
- mansard: "mansard";
56
- conical: "conical";
57
- }>>;
58
- pitch: z.ZodDefault<z.ZodPipe<z.ZodUnion<readonly [z.ZodNumber, z.ZodString]>, z.ZodTransform<number, string | number>>>;
59
- wallHeight: z.ZodDefault<z.ZodPipe<z.ZodUnion<readonly [z.ZodNumber, z.ZodString]>, z.ZodTransform<number, string | number>>>;
60
- wallThickness: z.ZodDefault<z.ZodPipe<z.ZodUnion<readonly [z.ZodNumber, z.ZodString]>, z.ZodTransform<number, string | number>>>;
61
- overhang: z.ZodDefault<z.ZodPipe<z.ZodUnion<readonly [z.ZodNumber, z.ZodString]>, z.ZodTransform<number, string | number>>>;
62
- materialPreset: z.ZodOptional<z.ZodString>;
63
- name: z.ZodOptional<z.ZodString>;
64
- };
65
- export declare const createRoofOutput: {
66
- project: z.ZodOptional<z.ZodNullable<z.ZodString>>;
67
- unsaved: z.ZodOptional<z.ZodString>;
68
- persistence: z.ZodOptional<z.ZodObject<{
69
- status: z.ZodEnum<{
70
- unbound: "unbound";
71
- events_unsupported: "events_unsupported";
72
- }>;
73
- warning: z.ZodString;
74
- }, z.core.$strip>>;
75
- referenceLevelId: z.ZodString;
76
- roofLevelId: z.ZodString;
77
- createdRoofLevelId: z.ZodNullable<z.ZodString>;
78
- roofId: z.ZodString;
79
- roofSegmentId: z.ZodString;
80
- };
81
38
  export declare function registerConstructionTools(server: McpServer, bridge: SceneOperations): void;
82
39
  //# sourceMappingURL=construction-tools.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"construction-tools.d.ts","sourceRoot":"","sources":["../../src/tools/construction-tools.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,yCAAyC,CAAA;AAKxE,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAA;AACvB,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,eAAe,CAAA;AAgBpD,eAAO,MAAM,qBAAqB;;;;;;;;;;;;;CA8BjC,CAAA;AAED,eAAO,MAAM,sBAAsB;;;;;;;;;;;;IAGjC,2DAA2D;;IAE3D,mFAAmF;;IAEnF,iFAAiF;;;CAIlF,CAAA;AAED,eAAO,MAAM,eAAe;;;;;;;;;;;;;;;;;;;;;;;;;;CA0B3B,CAAA;AAED,eAAO,MAAM,gBAAgB;;;;;;;;;;;;;;;CAO5B,CAAA;AAgFD,wBAAgB,yBAAyB,CAAC,MAAM,EAAE,SAAS,EAAE,MAAM,EAAE,eAAe,GAAG,IAAI,CA2O1F"}
1
+ {"version":3,"file":"construction-tools.d.ts","sourceRoot":"","sources":["../../src/tools/construction-tools.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,8BAA8B,CAAA;AAI7D,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAA;AACvB,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,eAAe,CAAA;AAOpD,eAAO,MAAM,qBAAqB;IAChC,OAAO;IACP,SAAS;IACT,UAAU;IAIV,aAAa;IAIb,UAAU;IAIV,aAAa;IAIb,aAAa;IAGb,aAAa;IAIb,UAAU;IACV,kBAAkB;IAClB,kBAAkB;IAClB,qBAAqB;CACtB,CAAA;AAED,eAAO,MAAM,sBAAsB;;;;;;;;;;;;IAGjC,2DAA2D;;IAE3D,mFAAmF;;IAEnF,iFAAiF;;;CAIlF,CAAA;AAgDD,wBAAgB,yBAAyB,CAAC,MAAM,EAAE,SAAS,EAAE,MAAM,EAAE,eAAe,GAAG,IAAI,CA4H1F"}