@pascal-app/mcp 1.0.4 → 1.0.6
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +76 -0
- package/README.md +166 -62
- package/dist/bin/pascal-mcp.js +1 -1
- package/dist/bridge/agent-session.d.ts +18 -0
- package/dist/bridge/agent-session.d.ts.map +1 -0
- package/dist/bridge/agent-session.js +15 -0
- package/dist/bridge/index.d.ts +1 -1
- package/dist/bridge/index.d.ts.map +1 -1
- package/dist/bridge/scene-bridge.d.ts +3 -0
- package/dist/bridge/scene-bridge.d.ts.map +1 -1
- package/dist/bridge/scene-bridge.js +7 -0
- package/dist/lib/safe-fetch.d.ts +22 -4
- package/dist/lib/safe-fetch.d.ts.map +1 -1
- package/dist/lib/safe-fetch.js +233 -134
- package/dist/operations/scene-operations.d.ts +18 -0
- package/dist/operations/scene-operations.d.ts.map +1 -1
- package/dist/operations/scene-operations.js +11 -0
- package/dist/prompts/from-brief.d.ts +1 -1
- package/dist/prompts/from-brief.d.ts.map +1 -1
- package/dist/prompts/from-brief.js +3 -3
- package/dist/prompts/index.d.ts +1 -1
- package/dist/prompts/index.d.ts.map +1 -1
- package/dist/prompts/iterate-on-feedback.d.ts +1 -1
- package/dist/prompts/iterate-on-feedback.d.ts.map +1 -1
- package/dist/prompts/iterate-on-feedback.js +2 -2
- package/dist/prompts/renovation-from-photos.d.ts +1 -1
- package/dist/prompts/renovation-from-photos.d.ts.map +1 -1
- package/dist/prompts/renovation-from-photos.js +2 -2
- package/dist/prompts/scene-guidance.d.ts.map +1 -1
- package/dist/prompts/scene-guidance.js +10 -3
- package/dist/resources/agent-guide.d.ts +1 -1
- package/dist/resources/agent-guide.d.ts.map +1 -1
- package/dist/resources/agent-guide.js +52 -44
- package/dist/resources/catalog-items.d.ts +1 -1
- package/dist/resources/catalog-items.d.ts.map +1 -1
- package/dist/resources/constraints.d.ts +1 -1
- package/dist/resources/constraints.d.ts.map +1 -1
- package/dist/resources/constraints.js +1 -1
- package/dist/resources/design-schema.d.ts +1 -1
- package/dist/resources/design-schema.d.ts.map +1 -1
- package/dist/resources/index.d.ts +1 -1
- package/dist/resources/index.d.ts.map +1 -1
- package/dist/resources/scene-current.d.ts +1 -1
- package/dist/resources/scene-current.d.ts.map +1 -1
- package/dist/resources/scene-summary.d.ts +1 -1
- package/dist/resources/scene-summary.d.ts.map +1 -1
- package/dist/server.d.ts +7 -2
- package/dist/server.d.ts.map +1 -1
- package/dist/server.js +59 -21
- package/dist/storage/disk-artifact-store.d.ts.map +1 -1
- package/dist/storage/sqlite-scene-store.d.ts +1 -1
- package/dist/storage/sqlite-scene-store.d.ts.map +1 -1
- package/dist/storage/types.d.ts +4 -4
- package/dist/storage/types.d.ts.map +1 -1
- package/dist/templates/empty-studio.d.ts +3 -3
- package/dist/templates/empty-studio.d.ts.map +1 -1
- package/dist/templates/garden-house.d.ts +3 -3
- package/dist/templates/garden-house.d.ts.map +1 -1
- package/dist/templates/index.d.ts.map +1 -1
- package/dist/templates/two-bedroom.d.ts +3 -3
- package/dist/templates/two-bedroom.d.ts.map +1 -1
- package/dist/tools/add-column.d.ts +1 -1
- package/dist/tools/add-column.d.ts.map +1 -1
- package/dist/tools/add-column.js +3 -2
- package/dist/tools/add-object.d.ts +19 -3
- package/dist/tools/add-object.d.ts.map +1 -1
- package/dist/tools/add-object.js +66 -35
- package/dist/tools/annotations.d.ts.map +1 -1
- package/dist/tools/apply-patch.d.ts +6 -2
- package/dist/tools/apply-patch.d.ts.map +1 -1
- package/dist/tools/apply-patch.js +13 -8
- package/dist/tools/asset-catalog.d.ts.map +1 -1
- package/dist/tools/asset-catalog.js +23 -0
- package/dist/tools/author-scene.d.ts +10 -0
- package/dist/tools/author-scene.d.ts.map +1 -0
- package/dist/tools/author-scene.js +140 -0
- package/dist/tools/check-collisions.d.ts +6 -6
- package/dist/tools/check-collisions.d.ts.map +1 -1
- package/dist/tools/check-collisions.js +6 -6
- package/dist/tools/clear-scene.d.ts +1 -1
- package/dist/tools/clear-scene.d.ts.map +1 -1
- package/dist/tools/clear-scene.js +3 -3
- package/dist/tools/collections.d.ts +1 -1
- package/dist/tools/collections.d.ts.map +1 -1
- package/dist/tools/collections.js +3 -2
- package/dist/tools/construction-tools.d.ts +6 -49
- package/dist/tools/construction-tools.d.ts.map +1 -1
- package/dist/tools/construction-tools.js +9 -158
- package/dist/tools/create-unit.d.ts +3 -3
- package/dist/tools/create-unit.d.ts.map +1 -1
- package/dist/tools/create-unit.js +2 -2
- package/dist/tools/errors.d.ts +5 -5
- package/dist/tools/errors.d.ts.map +1 -1
- package/dist/tools/errors.js +4 -4
- package/dist/tools/export-glb.d.ts +1 -1
- package/dist/tools/export-glb.d.ts.map +1 -1
- package/dist/tools/export-glb.js +2 -2
- package/dist/tools/export-json.d.ts +1 -1
- package/dist/tools/export-json.d.ts.map +1 -1
- package/dist/tools/export-json.js +2 -2
- package/dist/tools/get-scene.d.ts +1 -1
- package/dist/tools/get-scene.d.ts.map +1 -1
- package/dist/tools/get-scene.js +2 -2
- package/dist/tools/hosted-services.d.ts +1 -1
- package/dist/tools/hosted-services.d.ts.map +1 -1
- package/dist/tools/hosted-services.js +13 -3
- package/dist/tools/index.d.ts +4 -3
- package/dist/tools/index.d.ts.map +1 -1
- package/dist/tools/index.js +8 -13
- package/dist/tools/level-height-guard.d.ts +2 -0
- package/dist/tools/level-height-guard.d.ts.map +1 -0
- package/dist/tools/level-height-guard.js +11 -0
- package/dist/tools/list-units.d.ts +2 -2
- package/dist/tools/list-units.d.ts.map +1 -1
- package/dist/tools/list-units.js +2 -2
- package/dist/tools/live-sync.d.ts +1 -1
- package/dist/tools/live-sync.d.ts.map +1 -1
- package/dist/tools/live-sync.js +4 -4
- package/dist/tools/measure.d.ts +1 -1
- package/dist/tools/measure.d.ts.map +1 -1
- package/dist/tools/measure.js +7 -7
- package/dist/tools/node-world-point.d.ts +1 -1
- package/dist/tools/node-world-point.d.ts.map +1 -1
- package/dist/tools/normalize-schema-dialect.d.ts +1 -1
- package/dist/tools/normalize-schema-dialect.d.ts.map +1 -1
- package/dist/tools/normalize-schema-dialect.js +2 -3
- package/dist/tools/patch-guards.d.ts +6 -4
- package/dist/tools/patch-guards.d.ts.map +1 -1
- package/dist/tools/patch-guards.js +5 -2
- package/dist/tools/photo-to-scene/index.d.ts +1 -1
- package/dist/tools/photo-to-scene/index.d.ts.map +1 -1
- package/dist/tools/photo-to-scene/photo-to-scene.d.ts +3 -3
- package/dist/tools/photo-to-scene/photo-to-scene.d.ts.map +1 -1
- package/dist/tools/photo-to-scene/photo-to-scene.js +7 -7
- package/dist/tools/project-files.d.ts +4 -0
- package/dist/tools/project-files.d.ts.map +1 -0
- package/dist/tools/project-files.js +30 -0
- package/dist/tools/redo.d.ts +2 -2
- package/dist/tools/redo.d.ts.map +1 -1
- package/dist/tools/redo.js +2 -2
- package/dist/tools/retired-tools.d.ts +10 -0
- package/dist/tools/retired-tools.d.ts.map +1 -0
- package/dist/tools/retired-tools.js +22 -0
- package/dist/tools/roof-level-guard.d.ts +2 -0
- package/dist/tools/roof-level-guard.d.ts.map +1 -0
- package/dist/tools/roof-level-guard.js +22 -0
- package/dist/tools/room-tools.d.ts +47 -46
- package/dist/tools/room-tools.d.ts.map +1 -1
- package/dist/tools/room-tools.js +6 -5
- package/dist/tools/scene-lifecycle/create-project.d.ts +1 -1
- package/dist/tools/scene-lifecycle/create-project.d.ts.map +1 -1
- package/dist/tools/scene-lifecycle/create-project.js +5 -5
- package/dist/tools/scene-lifecycle/delete-scene.d.ts +1 -1
- package/dist/tools/scene-lifecycle/delete-scene.d.ts.map +1 -1
- package/dist/tools/scene-lifecycle/delete-scene.js +6 -6
- package/dist/tools/scene-lifecycle/get-project-status.d.ts +1 -1
- package/dist/tools/scene-lifecycle/get-project-status.d.ts.map +1 -1
- package/dist/tools/scene-lifecycle/get-project-status.js +6 -6
- package/dist/tools/scene-lifecycle/index.d.ts +1 -1
- package/dist/tools/scene-lifecycle/index.d.ts.map +1 -1
- package/dist/tools/scene-lifecycle/list-scenes.d.ts +1 -1
- package/dist/tools/scene-lifecycle/list-scenes.d.ts.map +1 -1
- package/dist/tools/scene-lifecycle/list-scenes.js +4 -4
- package/dist/tools/scene-lifecycle/load-scene.d.ts +2 -2
- package/dist/tools/scene-lifecycle/load-scene.d.ts.map +1 -1
- package/dist/tools/scene-lifecycle/load-scene.js +5 -5
- package/dist/tools/scene-lifecycle/metadata.d.ts +1 -1
- package/dist/tools/scene-lifecycle/rename-scene.d.ts +1 -1
- package/dist/tools/scene-lifecycle/rename-scene.d.ts.map +1 -1
- package/dist/tools/scene-lifecycle/rename-scene.js +6 -6
- package/dist/tools/scene-lifecycle/save-scene.d.ts +5 -3
- package/dist/tools/scene-lifecycle/save-scene.d.ts.map +1 -1
- package/dist/tools/scene-lifecycle/save-scene.js +80 -12
- package/dist/tools/scene-lifecycle/test-utils.d.ts +1 -1
- package/dist/tools/scene-lifecycle/test-utils.d.ts.map +1 -1
- package/dist/tools/set-unit-members.d.ts +2 -2
- package/dist/tools/set-unit-members.d.ts.map +1 -1
- package/dist/tools/set-unit-members.js +6 -6
- package/dist/tools/set-zone.d.ts +2 -2
- package/dist/tools/set-zone.d.ts.map +1 -1
- package/dist/tools/set-zone.js +30 -18
- package/dist/tools/shared-tools.d.ts +15 -5
- package/dist/tools/shared-tools.d.ts.map +1 -1
- package/dist/tools/shared-tools.js +242 -29
- package/dist/tools/structure-tools.d.ts +3 -3
- package/dist/tools/templates/create-from-template.d.ts +2 -2
- package/dist/tools/templates/create-from-template.d.ts.map +1 -1
- package/dist/tools/templates/create-from-template.js +6 -6
- package/dist/tools/templates/create-house-from-brief.d.ts +1 -1
- package/dist/tools/templates/create-house-from-brief.d.ts.map +1 -1
- package/dist/tools/templates/create-house-from-brief.js +6 -6
- package/dist/tools/templates/index.d.ts +1 -1
- package/dist/tools/templates/index.d.ts.map +1 -1
- package/dist/tools/templates/list-templates.d.ts +1 -1
- package/dist/tools/templates/list-templates.d.ts.map +1 -1
- package/dist/tools/templates/list-templates.js +2 -2
- package/dist/tools/undo.d.ts +2 -2
- package/dist/tools/undo.d.ts.map +1 -1
- package/dist/tools/undo.js +2 -2
- package/dist/tools/unit-members.d.ts.map +1 -1
- package/dist/tools/unit-members.js +6 -6
- package/dist/tools/variants/generate-variants.d.ts +6 -6
- package/dist/tools/variants/generate-variants.d.ts.map +1 -1
- package/dist/tools/variants/generate-variants.js +6 -6
- package/dist/tools/variants/index.d.ts +1 -1
- package/dist/tools/variants/index.d.ts.map +1 -1
- package/dist/tools/view-scene.d.ts +8 -2
- package/dist/tools/view-scene.d.ts.map +1 -1
- package/dist/tools/view-scene.js +17 -5
- package/dist/tools/vision/analyze-floorplan-image.d.ts +1 -1
- package/dist/tools/vision/analyze-floorplan-image.d.ts.map +1 -1
- package/dist/tools/vision/analyze-floorplan-image.js +7 -7
- package/dist/tools/vision/analyze-room-photo.d.ts +1 -1
- package/dist/tools/vision/analyze-room-photo.d.ts.map +1 -1
- package/dist/tools/vision/analyze-room-photo.js +7 -7
- package/dist/tools/vision/index.d.ts +1 -1
- package/dist/tools/vision/index.d.ts.map +1 -1
- package/dist/transports/http.d.ts +8 -2
- package/dist/transports/http.d.ts.map +1 -1
- package/dist/transports/http.js +9 -3
- package/dist/transports/stdio.d.ts +15 -9
- package/dist/transports/stdio.d.ts.map +1 -1
- package/dist/transports/stdio.js +18 -11
- package/examples/coordinate-conventions-demo.md +12 -13
- package/examples/embed-in-agent.ts +5 -6
- package/examples/generate-apartment.md +4 -4
- package/examples/photo-to-scene.md +2 -3
- package/examples/renovate-from-photos.md +3 -5
- package/package.json +13 -9
- package/dist/tools/describe-node.d.ts +0 -17
- package/dist/tools/describe-node.d.ts.map +0 -1
- package/dist/tools/describe-node.js +0 -99
- package/dist/tools/find-nodes.d.ts +0 -16
- package/dist/tools/find-nodes.d.ts.map +0 -1
- package/dist/tools/find-nodes.js +0 -204
- package/dist/tools/place-design.d.ts +0 -34
- package/dist/tools/place-design.d.ts.map +0 -1
- package/dist/tools/place-design.js +0 -91
- package/dist/tools/validate-design.d.ts +0 -136
- package/dist/tools/validate-design.d.ts.map +0 -1
- package/dist/tools/validate-design.js +0 -28
- package/dist/tools/validate-scene.d.ts +0 -19
- package/dist/tools/validate-scene.d.ts.map +0 -1
- package/dist/tools/validate-scene.js +0 -28
|
@@ -3,7 +3,7 @@ import { z } from 'zod';
|
|
|
3
3
|
import { rehydrateSiteChildren } from '../../lib/rehydrate-site-children.js';
|
|
4
4
|
import { isTemplateId, TEMPLATES } from '../../templates/index.js';
|
|
5
5
|
import { DESTRUCTIVE_TOOL_ANNOTATIONS } from '../annotations.js';
|
|
6
|
-
import {
|
|
6
|
+
import { ProtocolErrorCode, throwMcpError } from '../errors.js';
|
|
7
7
|
import { appendLiveSceneEvent } from '../live-sync.js';
|
|
8
8
|
import { currentLevelContext, sceneMetaPayload } from '../scene-lifecycle/metadata.js';
|
|
9
9
|
export const createHouseFromBriefInput = {
|
|
@@ -65,8 +65,8 @@ export function registerCreateHouseFromBrief(server, bridge) {
|
|
|
65
65
|
server.registerTool('create_house_from_brief', {
|
|
66
66
|
title: 'Create house from brief',
|
|
67
67
|
description: 'High-level hosted workflow for external agents: choose a starter house from a brief, create/save/publish it, and return the editor URL. Use semantic tools afterward for exact customization.',
|
|
68
|
-
inputSchema: createHouseFromBriefInput,
|
|
69
|
-
outputSchema: createHouseFromBriefOutput,
|
|
68
|
+
inputSchema: z.object(createHouseFromBriefInput),
|
|
69
|
+
outputSchema: z.object(createHouseFromBriefOutput),
|
|
70
70
|
annotations: DESTRUCTIVE_TOOL_ANNOTATIONS,
|
|
71
71
|
}, async ({ brief, projectId, projectName, bedroomCount, rooms, style, landscaping, constraints, }) => {
|
|
72
72
|
const templateId = chooseTemplate({
|
|
@@ -75,7 +75,7 @@ export function registerCreateHouseFromBrief(server, bridge) {
|
|
|
75
75
|
...(landscaping !== undefined ? { landscaping } : {}),
|
|
76
76
|
});
|
|
77
77
|
if (!isTemplateId(templateId)) {
|
|
78
|
-
throwMcpError(
|
|
78
|
+
throwMcpError(ProtocolErrorCode.InternalError, `unknown_template: ${templateId}`);
|
|
79
79
|
}
|
|
80
80
|
const entry = TEMPLATES[templateId];
|
|
81
81
|
const cloned = rehydrateSiteChildren(cloneSceneGraph(entry.template));
|
|
@@ -87,7 +87,7 @@ export function registerCreateHouseFromBrief(server, bridge) {
|
|
|
87
87
|
}
|
|
88
88
|
catch (err) {
|
|
89
89
|
const msg = err instanceof Error ? err.message : String(err);
|
|
90
|
-
throwMcpError(
|
|
90
|
+
throwMcpError(ProtocolErrorCode.InternalError, `apply_failed: ${msg}`);
|
|
91
91
|
}
|
|
92
92
|
const rawValidation = bridge.validateScene();
|
|
93
93
|
const validation = {
|
|
@@ -166,7 +166,7 @@ export function registerCreateHouseFromBrief(server, bridge) {
|
|
|
166
166
|
}
|
|
167
167
|
catch (err) {
|
|
168
168
|
const msg = err instanceof Error ? err.message : String(err);
|
|
169
|
-
throwMcpError(
|
|
169
|
+
throwMcpError(ProtocolErrorCode.InternalError, `save_failed: ${msg}`);
|
|
170
170
|
}
|
|
171
171
|
});
|
|
172
172
|
}
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import type { McpServer } from '@modelcontextprotocol/
|
|
1
|
+
import type { McpServer } from '@modelcontextprotocol/server';
|
|
2
2
|
import type { SceneOperations } from '../../operations/index.js';
|
|
3
3
|
/**
|
|
4
4
|
* Register the template MCP tools (`list_templates`, `create_from_template`)
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/tools/templates/index.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/tools/templates/index.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,8BAA8B,CAAA;AAC7D,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,kBAAkB,CAAA;AAKvD;;;;;;GAMG;AACH,wBAAgB,qBAAqB,CAAC,MAAM,EAAE,SAAS,EAAE,MAAM,EAAE,eAAe,GAAG,IAAI,CAItF;AAED,OAAO,EACL,uBAAuB,EACvB,wBAAwB,EACxB,0BAA0B,GAC3B,MAAM,wBAAwB,CAAA;AAC/B,OAAO,EACL,yBAAyB,EACzB,0BAA0B,EAC1B,4BAA4B,GAC7B,MAAM,2BAA2B,CAAA;AAClC,OAAO,EACL,kBAAkB,EAClB,mBAAmB,EACnB,qBAAqB,GACtB,MAAM,kBAAkB,CAAA"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"list-templates.d.ts","sourceRoot":"","sources":["../../../src/tools/templates/list-templates.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,
|
|
1
|
+
{"version":3,"file":"list-templates.d.ts","sourceRoot":"","sources":["../../../src/tools/templates/list-templates.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,8BAA8B,CAAA;AAC7D,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAA;AAIvB,eAAO,MAAM,kBAAkB,IAAc,CAAA;AAE7C,eAAO,MAAM,mBAAmB;IAC9B,SAAS;;;;;;CAQV,CAAA;AAED;;;;GAIG;AACH,wBAAgB,qBAAqB,CAAC,MAAM,EAAE,SAAS,GAAG,IAAI,CAyB7D"}
|
|
@@ -19,8 +19,8 @@ export function registerListTemplates(server) {
|
|
|
19
19
|
server.registerTool('list_templates', {
|
|
20
20
|
title: 'List scene templates',
|
|
21
21
|
description: 'List the seed Pascal scene templates available to `create_from_template`. Returns the id, display name, one-line description and node count for each.',
|
|
22
|
-
inputSchema: listTemplatesInput,
|
|
23
|
-
outputSchema: listTemplatesOutput,
|
|
22
|
+
inputSchema: z.object(listTemplatesInput),
|
|
23
|
+
outputSchema: z.object(listTemplatesOutput),
|
|
24
24
|
annotations: READ_ONLY_TOOL_ANNOTATIONS,
|
|
25
25
|
}, async () => {
|
|
26
26
|
const templates = Object.values(TEMPLATES).map((entry) => ({
|
package/dist/tools/undo.d.ts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import type { McpServer } from '@modelcontextprotocol/
|
|
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 undoInput: {
|
|
@@ -9,8 +9,8 @@ export declare const undoOutput: {
|
|
|
9
9
|
unsaved: z.ZodOptional<z.ZodString>;
|
|
10
10
|
persistence: z.ZodOptional<z.ZodObject<{
|
|
11
11
|
status: z.ZodEnum<{
|
|
12
|
-
unbound: "unbound";
|
|
13
12
|
events_unsupported: "events_unsupported";
|
|
13
|
+
unbound: "unbound";
|
|
14
14
|
}>;
|
|
15
15
|
warning: z.ZodString;
|
|
16
16
|
}, z.core.$strip>>;
|
package/dist/tools/undo.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"undo.d.ts","sourceRoot":"","sources":["../../src/tools/undo.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,
|
|
1
|
+
{"version":3,"file":"undo.d.ts","sourceRoot":"","sources":["../../src/tools/undo.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,8BAA8B,CAAA;AAC7D,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAA;AACvB,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,eAAe,CAAA;AASpD,eAAO,MAAM,SAAS;IACpB,KAAK;CACN,CAAA;AAED,eAAO,MAAM,UAAU;;;;;;;;;;;CAGtB,CAAA;AAED,wBAAgB,YAAY,CAAC,MAAM,EAAE,SAAS,EAAE,MAAM,EAAE,eAAe,GAAG,IAAI,CAsB7E"}
|
package/dist/tools/undo.js
CHANGED
|
@@ -12,8 +12,8 @@ export function registerUndo(server, bridge) {
|
|
|
12
12
|
server.registerTool('undo', {
|
|
13
13
|
title: 'Undo',
|
|
14
14
|
description: 'Undo the most recent N steps in the scene history (default 1). Returns the number of steps actually undone.',
|
|
15
|
-
inputSchema: undoInput,
|
|
16
|
-
outputSchema: undoOutput,
|
|
15
|
+
inputSchema: z.object(undoInput),
|
|
16
|
+
outputSchema: z.object(undoOutput),
|
|
17
17
|
annotations: DESTRUCTIVE_TOOL_ANNOTATIONS,
|
|
18
18
|
}, async ({ steps }) => {
|
|
19
19
|
const undone = bridge.undo(steps ?? 1);
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"unit-members.d.ts","sourceRoot":"","sources":["../../src/tools/unit-members.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAa,QAAQ,EAAE,MAAM,yBAAyB,CAAA;AAClE,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,eAAe,CAAA;AAGpD,wBAAgB,mBAAmB,CACjC,MAAM,EAAE,eAAe,EACvB,UAAU,EAAE,MAAM,EAClB,aAAa,EAAE,MAAM,EAAE,GACtB,QAAQ,CAAC,IAAI,CAAC,EAAE,
|
|
1
|
+
{"version":3,"file":"unit-members.d.ts","sourceRoot":"","sources":["../../src/tools/unit-members.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAa,QAAQ,EAAE,MAAM,yBAAyB,CAAA;AAClE,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,eAAe,CAAA;AAGpD,wBAAgB,mBAAmB,CACjC,MAAM,EAAE,eAAe,EACvB,UAAU,EAAE,MAAM,EAClB,aAAa,EAAE,MAAM,EAAE,GACtB,QAAQ,CAAC,IAAI,CAAC,EAAE,CAgClB"}
|
|
@@ -1,23 +1,23 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { ProtocolErrorCode, throwMcpError } from './errors.js';
|
|
2
2
|
export function validateUnitMembers(bridge, buildingId, memberZoneIds) {
|
|
3
3
|
const building = bridge.getNode(buildingId);
|
|
4
4
|
if (!building) {
|
|
5
|
-
throwMcpError(
|
|
5
|
+
throwMcpError(ProtocolErrorCode.InvalidParams, `Building not found: ${buildingId}`);
|
|
6
6
|
}
|
|
7
7
|
if (building.type !== 'building') {
|
|
8
|
-
throwMcpError(
|
|
8
|
+
throwMcpError(ProtocolErrorCode.InvalidParams, `Node ${buildingId} is a ${building.type}, expected building`);
|
|
9
9
|
}
|
|
10
10
|
return memberZoneIds.map((zoneId) => {
|
|
11
11
|
const zone = bridge.getNode(zoneId);
|
|
12
12
|
if (!zone) {
|
|
13
|
-
throwMcpError(
|
|
13
|
+
throwMcpError(ProtocolErrorCode.InvalidParams, `Zone not found: ${zoneId}`);
|
|
14
14
|
}
|
|
15
15
|
if (zone.type !== 'zone') {
|
|
16
|
-
throwMcpError(
|
|
16
|
+
throwMcpError(ProtocolErrorCode.InvalidParams, `Node ${zoneId} is a ${zone.type}, expected zone`);
|
|
17
17
|
}
|
|
18
18
|
const [, level, parent] = bridge.getAncestry(zone.id);
|
|
19
19
|
if (level?.type !== 'level' || parent?.id !== building.id) {
|
|
20
|
-
throwMcpError(
|
|
20
|
+
throwMcpError(ProtocolErrorCode.InvalidParams, `Zone ${zoneId} must belong to a level in building ${buildingId}`);
|
|
21
21
|
}
|
|
22
22
|
return zone.id;
|
|
23
23
|
});
|
|
@@ -1,17 +1,17 @@
|
|
|
1
|
-
import type { McpServer } from '@modelcontextprotocol/
|
|
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 generateVariantsInput: {
|
|
5
5
|
baseSceneId: z.ZodOptional<z.ZodString>;
|
|
6
6
|
count: z.ZodDefault<z.ZodNumber>;
|
|
7
7
|
vary: z.ZodDefault<z.ZodArray<z.ZodEnum<{
|
|
8
|
-
"wall-thickness": "wall-thickness";
|
|
9
|
-
"wall-height": "wall-height";
|
|
10
|
-
"zone-labels": "zone-labels";
|
|
11
|
-
"room-proportions": "room-proportions";
|
|
12
|
-
"open-plan": "open-plan";
|
|
13
8
|
"door-positions": "door-positions";
|
|
14
9
|
"fence-style": "fence-style";
|
|
10
|
+
"open-plan": "open-plan";
|
|
11
|
+
"room-proportions": "room-proportions";
|
|
12
|
+
"wall-height": "wall-height";
|
|
13
|
+
"wall-thickness": "wall-thickness";
|
|
14
|
+
"zone-labels": "zone-labels";
|
|
15
15
|
}>>>;
|
|
16
16
|
seed: z.ZodOptional<z.ZodNumber>;
|
|
17
17
|
save: z.ZodDefault<z.ZodBoolean>;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"generate-variants.d.ts","sourceRoot":"","sources":["../../../src/tools/variants/generate-variants.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,
|
|
1
|
+
{"version":3,"file":"generate-variants.d.ts","sourceRoot":"","sources":["../../../src/tools/variants/generate-variants.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,8BAA8B,CAAA;AAG7D,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAA;AACvB,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,kBAAkB,CAAA;AAevD,eAAO,MAAM,qBAAqB;IAChC,WAAW;IAIX,KAAK;IACL,IAAI;;;;;;;;;IACJ,IAAI;IACJ,IAAI;CAIL,CAAA;AAED,eAAO,MAAM,sBAAsB;IACjC,QAAQ;;;;;;;;CAUT,CAAA;AAcD,wBAAgB,wBAAwB,CAAC,MAAM,EAAE,SAAS,EAAE,MAAM,EAAE,eAAe,GAAG,IAAI,CA2FzF"}
|
|
@@ -2,7 +2,7 @@ import { forkSceneGraph } from '@pascal-app/core/clone-scene-graph';
|
|
|
2
2
|
import { AnyNode as AnyNodeSchema } from '@pascal-app/core/schema';
|
|
3
3
|
import { z } from 'zod';
|
|
4
4
|
import { ADDITIVE_TOOL_ANNOTATIONS } from '../annotations.js';
|
|
5
|
-
import {
|
|
5
|
+
import { ProtocolErrorCode, throwMcpError } from '../errors.js';
|
|
6
6
|
import { applyMutation, describeVariant, mulberry32 } from './mutations.js';
|
|
7
7
|
const MUTATION_KINDS = [
|
|
8
8
|
'wall-thickness',
|
|
@@ -52,8 +52,8 @@ export function registerGenerateVariants(server, bridge) {
|
|
|
52
52
|
server.registerTool('generate_variants', {
|
|
53
53
|
title: 'Generate variants',
|
|
54
54
|
description: 'Generate N variations of a base scene by forking and applying seeded mutations. Example: "give me 5 variations of this kitchen". If `save=true`, each variant is persisted via scene operations and returned with an id + URL; otherwise the graph is returned inline.',
|
|
55
|
-
inputSchema: generateVariantsInput,
|
|
56
|
-
outputSchema: generateVariantsOutput,
|
|
55
|
+
inputSchema: z.object(generateVariantsInput),
|
|
56
|
+
outputSchema: z.object(generateVariantsOutput),
|
|
57
57
|
annotations: ADDITIVE_TOOL_ANNOTATIONS,
|
|
58
58
|
}, async ({ baseSceneId, count, vary, seed, save }) => {
|
|
59
59
|
// 1. Obtain the base SceneGraph.
|
|
@@ -62,7 +62,7 @@ export function registerGenerateVariants(server, bridge) {
|
|
|
62
62
|
if (baseSceneId) {
|
|
63
63
|
const loaded = await bridge.loadStoredScene(baseSceneId);
|
|
64
64
|
if (!loaded) {
|
|
65
|
-
throwMcpError(
|
|
65
|
+
throwMcpError(ProtocolErrorCode.InvalidParams, 'scene_not_found', { id: baseSceneId });
|
|
66
66
|
}
|
|
67
67
|
base = loaded.graph;
|
|
68
68
|
baseName = loaded.name;
|
|
@@ -85,7 +85,7 @@ export function registerGenerateVariants(server, bridge) {
|
|
|
85
85
|
}
|
|
86
86
|
const invalidCount = countInvalidNodes(forked);
|
|
87
87
|
if (invalidCount > 0) {
|
|
88
|
-
throwMcpError(
|
|
88
|
+
throwMcpError(ProtocolErrorCode.InternalError, `variant_invalid: variant ${i} produced ${invalidCount} invalid node(s)`, { index: i });
|
|
89
89
|
}
|
|
90
90
|
const nodeCount = Object.keys(forked.nodes).length;
|
|
91
91
|
const description = describeVariant(forked, mutations);
|
|
@@ -105,7 +105,7 @@ export function registerGenerateVariants(server, bridge) {
|
|
|
105
105
|
}
|
|
106
106
|
catch (err) {
|
|
107
107
|
const msg = err instanceof Error ? err.message : String(err);
|
|
108
|
-
throwMcpError(
|
|
108
|
+
throwMcpError(ProtocolErrorCode.InternalError, `save_failed: ${msg}`, { index: i });
|
|
109
109
|
}
|
|
110
110
|
}
|
|
111
111
|
else {
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import type { McpServer } from '@modelcontextprotocol/
|
|
1
|
+
import type { McpServer } from '@modelcontextprotocol/server';
|
|
2
2
|
import type { SceneOperations } from '../../operations/index.js';
|
|
3
3
|
/**
|
|
4
4
|
* Register the variant-generation MCP tools against shared scene operations.
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/tools/variants/index.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/tools/variants/index.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,8BAA8B,CAAA;AAC7D,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,kBAAkB,CAAA;AAGvD;;GAEG;AACH,wBAAgB,oBAAoB,CAAC,MAAM,EAAE,SAAS,EAAE,MAAM,EAAE,eAAe,GAAG,IAAI,CAErF;AAED,OAAO,EACL,qBAAqB,EACrB,sBAAsB,EACtB,wBAAwB,GACzB,MAAM,qBAAqB,CAAA;AAC5B,OAAO,EACL,aAAa,EACb,eAAe,EACf,KAAK,YAAY,EACjB,UAAU,EACV,KAAK,GAAG,GACT,MAAM,aAAa,CAAA"}
|
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import type { McpServer } from '@modelcontextprotocol/
|
|
2
|
-
import { type SceneViewCrop, type SceneViewInterior, type SceneViewPose } from '@pascal-app/core/agent-operations';
|
|
1
|
+
import type { McpServer } from '@modelcontextprotocol/server';
|
|
2
|
+
import { type SceneViewCrop, type SceneViewInterior, type SceneViewLighting, type SceneViewPose, type SceneViewPresentation } from '@pascal-app/core/agent-operations';
|
|
3
3
|
import type { SceneOperations } from '../operations/index.js';
|
|
4
4
|
/** A picture of the scene, rendered by an editor tab open on the project. */
|
|
5
5
|
export type SceneViewCapture = {
|
|
@@ -10,6 +10,9 @@ export type SceneViewCapture = {
|
|
|
10
10
|
/** Which tab rendered it, and when: the scene as that tab showed it then. */
|
|
11
11
|
tab: string;
|
|
12
12
|
capturedAt: string;
|
|
13
|
+
presentation?: SceneViewPresentation;
|
|
14
|
+
/** The host's id of the picture it kept, these exact pixels: a later call can name the frame. */
|
|
15
|
+
viewId?: string;
|
|
13
16
|
};
|
|
14
17
|
/**
|
|
15
18
|
* Asks an editor open on the project for a picture, the MCP having no renderer of its own. Refuses
|
|
@@ -25,6 +28,9 @@ export type SceneViewHost = {
|
|
|
25
28
|
};
|
|
26
29
|
/** A look inside this floor: the editor leaves the rest out and cuts everything on it. */
|
|
27
30
|
interior?: SceneViewInterior;
|
|
31
|
+
presentation?: SceneViewPresentation;
|
|
32
|
+
/** The light to render it in; the scene's own when absent. */
|
|
33
|
+
lighting?: SceneViewLighting;
|
|
28
34
|
}): Promise<SceneViewCapture>;
|
|
29
35
|
/** Crops the reference photo to a region; without it a view with a photo is refused. */
|
|
30
36
|
crop?(request: SceneViewCrop): Promise<{
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"view-scene.d.ts","sourceRoot":"","sources":["../../src/tools/view-scene.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,
|
|
1
|
+
{"version":3,"file":"view-scene.d.ts","sourceRoot":"","sources":["../../src/tools/view-scene.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,8BAA8B,CAAA;AAC7D,OAAO,EAEL,KAAK,aAAa,EAClB,KAAK,iBAAiB,EACtB,KAAK,iBAAiB,EACtB,KAAK,aAAa,EAClB,KAAK,qBAAqB,EAG3B,MAAM,mCAAmC,CAAA;AAI1C,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,eAAe,CAAA;AAIpD,6EAA6E;AAC7E,MAAM,MAAM,gBAAgB,GAAG;IAC7B,KAAK,EAAE,UAAU,CAAA;IACjB,QAAQ,EAAE,MAAM,CAAA;IAChB,KAAK,EAAE,MAAM,CAAA;IACb,MAAM,EAAE,MAAM,CAAA;IACd,6EAA6E;IAC7E,GAAG,EAAE,MAAM,CAAA;IACX,UAAU,EAAE,MAAM,CAAA;IAClB,YAAY,CAAC,EAAE,qBAAqB,CAAA;IACpC,iGAAiG;IACjG,MAAM,CAAC,EAAE,MAAM,CAAA;CAChB,CAAA;AAED;;;GAGG;AACH,MAAM,MAAM,aAAa,GAAG;IAC1B,OAAO,CAAC,OAAO,EAAE;QACf,SAAS,EAAE,MAAM,CAAA;QACjB,IAAI,EAAE,aAAa,CAAA;QACnB,IAAI,EAAE;YAAE,CAAC,EAAE,MAAM,CAAC;YAAC,CAAC,EAAE,MAAM,CAAA;SAAE,CAAA;QAC9B,0FAA0F;QAC1F,QAAQ,CAAC,EAAE,iBAAiB,CAAA;QAC5B,YAAY,CAAC,EAAE,qBAAqB,CAAA;QACpC,8DAA8D;QAC9D,QAAQ,CAAC,EAAE,iBAAiB,CAAA;KAC7B,GAAG,OAAO,CAAC,gBAAgB,CAAC,CAAA;IAC7B,wFAAwF;IACxF,IAAI,CAAC,CACH,OAAO,EAAE,aAAa,GACrB,OAAO,CAAC;QAAE,KAAK,EAAE,UAAU,CAAC;QAAC,QAAQ,EAAE,MAAM,CAAC;QAAC,KAAK,EAAE,MAAM,CAAC;QAAC,MAAM,EAAE,MAAM,CAAA;KAAE,CAAC,CAAA;CACnF,CAAA;AAED,wBAAgB,iBAAiB,CAC/B,MAAM,EAAE,SAAS,EACjB,UAAU,EAAE,eAAe,EAC3B,KAAK,CAAC,EAAE,aAAa,QAkFtB"}
|
package/dist/tools/view-scene.js
CHANGED
|
@@ -1,12 +1,13 @@
|
|
|
1
|
-
import { sceneViewNote, sceneViewPlan, } from '@pascal-app/core/agent-operations';
|
|
1
|
+
import { confirmSceneViewPresentation, sceneViewNote, sceneViewPlan, } from '@pascal-app/core/agent-operations';
|
|
2
2
|
import { refuse, viewSceneTool } from '@pascal-app/core/agent-tools';
|
|
3
|
+
import { z } from 'zod';
|
|
3
4
|
import { READ_ONLY_TOOL_ANNOTATIONS } from './annotations.js';
|
|
4
5
|
import { refusalResult } from './errors.js';
|
|
5
6
|
export function registerViewScene(server, operations, views) {
|
|
6
7
|
server.registerTool(viewSceneTool.name, {
|
|
7
8
|
title: viewSceneTool.title,
|
|
8
9
|
description: viewSceneTool.description,
|
|
9
|
-
inputSchema: viewSceneTool.input,
|
|
10
|
+
inputSchema: z.object(viewSceneTool.input),
|
|
10
11
|
annotations: READ_ONLY_TOOL_ANNOTATIONS,
|
|
11
12
|
}, async (input) => {
|
|
12
13
|
try {
|
|
@@ -15,20 +16,31 @@ export function registerViewScene(server, operations, views) {
|
|
|
15
16
|
const projectId = operations.getActiveScene()?.projectId;
|
|
16
17
|
if (!projectId)
|
|
17
18
|
refuse('no_project', 'This session has no project open to look at: load or create one.');
|
|
18
|
-
|
|
19
|
+
// No view of the person's here: core refuses camera 'current' without one.
|
|
20
|
+
const { pose, size, crop, interior, presentation, lighting } = sceneViewPlan(operations.getNodes(), input);
|
|
19
21
|
if (crop && !views.crop)
|
|
20
22
|
refuse('photo_crop_unavailable', 'This Pascal server cannot crop a photo: crop the region yourself and lay it beside the view.');
|
|
21
23
|
const [shot, cropped] = await Promise.all([
|
|
22
|
-
views.capture({
|
|
24
|
+
views.capture({
|
|
25
|
+
projectId: projectId,
|
|
26
|
+
pose,
|
|
27
|
+
size,
|
|
28
|
+
...(interior ? { interior } : {}),
|
|
29
|
+
...(presentation ? { presentation } : {}),
|
|
30
|
+
...(lighting ? { lighting } : {}),
|
|
31
|
+
}),
|
|
23
32
|
crop ? views.crop(crop) : undefined,
|
|
24
33
|
]);
|
|
34
|
+
confirmSceneViewPresentation(presentation, shot.presentation);
|
|
25
35
|
const payload = {
|
|
26
36
|
status: 'viewed',
|
|
27
37
|
camera: pose,
|
|
28
38
|
size: { width: shot.width, height: shot.height },
|
|
29
39
|
tab: shot.tab,
|
|
30
40
|
capturedAt: shot.capturedAt,
|
|
31
|
-
|
|
41
|
+
...(shot.viewId ? { viewId: shot.viewId } : {}),
|
|
42
|
+
...(shot.presentation ? { presentation: shot.presentation } : {}),
|
|
43
|
+
note: sceneViewNote(operations.getNodes(), interior, pose),
|
|
32
44
|
...(crop && cropped
|
|
33
45
|
? {
|
|
34
46
|
photoRegion: crop.region,
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"analyze-floorplan-image.d.ts","sourceRoot":"","sources":["../../../src/tools/vision/analyze-floorplan-image.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,
|
|
1
|
+
{"version":3,"file":"analyze-floorplan-image.d.ts","sourceRoot":"","sources":["../../../src/tools/vision/analyze-floorplan-image.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,8BAA8B,CAAA;AAE7D,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAA;AACvB,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,kBAAkB,CAAA;AAGvD;;;;;;GAMG;AACH,eAAO,MAAM,0BAA0B;IACrC,KAAK;IACL,SAAS;CAIV,CAAA;AAED,eAAO,MAAM,2BAA2B;IACtC,KAAK;;;;;IAOL,KAAK;;;;;IAOL,qBAAqB;;;;IAIrB,UAAU;CACX,CAAA;AAgFD,wBAAgB,6BAA6B,CAAC,MAAM,EAAE,SAAS,EAAE,OAAO,EAAE,eAAe,GAAG,IAAI,CAkE/F"}
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { ProtocolError, ProtocolErrorCode } from '@modelcontextprotocol/server';
|
|
2
2
|
import { z } from 'zod';
|
|
3
3
|
import { READ_ONLY_OPEN_WORLD_TOOL_ANNOTATIONS } from '../annotations.js';
|
|
4
4
|
/**
|
|
@@ -93,13 +93,13 @@ export function registerAnalyzeFloorplanImage(server, _bridge) {
|
|
|
93
93
|
server.registerTool('analyze_floorplan_image', {
|
|
94
94
|
title: 'Analyze floor-plan image',
|
|
95
95
|
description: 'Defer to the MCP host (via sampling) to extract walls, rooms, and approximate dimensions from a floor-plan image. Requires host support for sampling.',
|
|
96
|
-
inputSchema: analyzeFloorplanImageInput,
|
|
97
|
-
outputSchema: analyzeFloorplanImageOutput,
|
|
96
|
+
inputSchema: z.object(analyzeFloorplanImageInput),
|
|
97
|
+
outputSchema: z.object(analyzeFloorplanImageOutput),
|
|
98
98
|
annotations: READ_ONLY_OPEN_WORLD_TOOL_ANNOTATIONS,
|
|
99
99
|
}, async ({ image, scaleHint }) => {
|
|
100
100
|
const caps = server.server.getClientCapabilities();
|
|
101
101
|
if (!caps?.sampling) {
|
|
102
|
-
throw new
|
|
102
|
+
throw new ProtocolError(ProtocolErrorCode.InvalidRequest, 'sampling_unavailable');
|
|
103
103
|
}
|
|
104
104
|
const imageBlock = await resolveImageBlock(image);
|
|
105
105
|
const instruction = scaleHint
|
|
@@ -118,7 +118,7 @@ export function registerAnalyzeFloorplanImage(server, _bridge) {
|
|
|
118
118
|
});
|
|
119
119
|
const text = extractText(response.content);
|
|
120
120
|
if (!text) {
|
|
121
|
-
throw new
|
|
121
|
+
throw new ProtocolError(ProtocolErrorCode.InternalError, 'sampling_response_unparseable', {
|
|
122
122
|
reason: 'no text content returned by host',
|
|
123
123
|
});
|
|
124
124
|
}
|
|
@@ -127,14 +127,14 @@ export function registerAnalyzeFloorplanImage(server, _bridge) {
|
|
|
127
127
|
parsed = JSON.parse(text);
|
|
128
128
|
}
|
|
129
129
|
catch (err) {
|
|
130
|
-
throw new
|
|
130
|
+
throw new ProtocolError(ProtocolErrorCode.InternalError, 'sampling_response_unparseable', {
|
|
131
131
|
raw: text,
|
|
132
132
|
reason: err instanceof Error ? err.message : String(err),
|
|
133
133
|
});
|
|
134
134
|
}
|
|
135
135
|
const validation = OutputSchema.safeParse(parsed);
|
|
136
136
|
if (!validation.success) {
|
|
137
|
-
throw new
|
|
137
|
+
throw new ProtocolError(ProtocolErrorCode.InternalError, 'sampling_response_invalid', {
|
|
138
138
|
raw: text,
|
|
139
139
|
errors: validation.error.issues,
|
|
140
140
|
});
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"analyze-room-photo.d.ts","sourceRoot":"","sources":["../../../src/tools/vision/analyze-room-photo.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,
|
|
1
|
+
{"version":3,"file":"analyze-room-photo.d.ts","sourceRoot":"","sources":["../../../src/tools/vision/analyze-room-photo.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,8BAA8B,CAAA;AAE7D,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAA;AACvB,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,kBAAkB,CAAA;AAGvD;;;;GAIG;AACH,eAAO,MAAM,qBAAqB;IAChC,KAAK;CACN,CAAA;AAED,eAAO,MAAM,sBAAsB;IACjC,qBAAqB;;;;;IAKrB,kBAAkB;;;;IAMlB,iBAAiB;;;;;CAOlB,CAAA;AAoED,wBAAgB,wBAAwB,CAAC,MAAM,EAAE,SAAS,EAAE,OAAO,EAAE,eAAe,GAAG,IAAI,CAqE1F"}
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { ProtocolError, ProtocolErrorCode } from '@modelcontextprotocol/server';
|
|
2
2
|
import { z } from 'zod';
|
|
3
3
|
import { READ_ONLY_OPEN_WORLD_TOOL_ANNOTATIONS } from '../annotations.js';
|
|
4
4
|
/**
|
|
@@ -74,13 +74,13 @@ export function registerAnalyzeRoomPhoto(server, _bridge) {
|
|
|
74
74
|
server.registerTool('analyze_room_photo', {
|
|
75
75
|
title: 'Analyze room photo',
|
|
76
76
|
description: 'Defer to the MCP host (via sampling) to extract approximate dimensions, fixtures, and windows from a single-room photograph. Requires host support for sampling.',
|
|
77
|
-
inputSchema: analyzeRoomPhotoInput,
|
|
78
|
-
outputSchema: analyzeRoomPhotoOutput,
|
|
77
|
+
inputSchema: z.object(analyzeRoomPhotoInput),
|
|
78
|
+
outputSchema: z.object(analyzeRoomPhotoOutput),
|
|
79
79
|
annotations: READ_ONLY_OPEN_WORLD_TOOL_ANNOTATIONS,
|
|
80
80
|
}, async ({ image }) => {
|
|
81
81
|
const caps = server.server.getClientCapabilities();
|
|
82
82
|
if (!caps?.sampling) {
|
|
83
|
-
throw new
|
|
83
|
+
throw new ProtocolError(ProtocolErrorCode.InvalidRequest, 'sampling_unavailable');
|
|
84
84
|
}
|
|
85
85
|
const imageBlock = await resolveImageBlock(image);
|
|
86
86
|
const response = await server.server.createMessage({
|
|
@@ -102,7 +102,7 @@ export function registerAnalyzeRoomPhoto(server, _bridge) {
|
|
|
102
102
|
});
|
|
103
103
|
const text = extractText(response.content);
|
|
104
104
|
if (!text) {
|
|
105
|
-
throw new
|
|
105
|
+
throw new ProtocolError(ProtocolErrorCode.InternalError, 'sampling_response_unparseable', {
|
|
106
106
|
reason: 'no text content returned by host',
|
|
107
107
|
});
|
|
108
108
|
}
|
|
@@ -111,14 +111,14 @@ export function registerAnalyzeRoomPhoto(server, _bridge) {
|
|
|
111
111
|
parsed = JSON.parse(text);
|
|
112
112
|
}
|
|
113
113
|
catch (err) {
|
|
114
|
-
throw new
|
|
114
|
+
throw new ProtocolError(ProtocolErrorCode.InternalError, 'sampling_response_unparseable', {
|
|
115
115
|
raw: text,
|
|
116
116
|
reason: err instanceof Error ? err.message : String(err),
|
|
117
117
|
});
|
|
118
118
|
}
|
|
119
119
|
const validation = OutputSchema.safeParse(parsed);
|
|
120
120
|
if (!validation.success) {
|
|
121
|
-
throw new
|
|
121
|
+
throw new ProtocolError(ProtocolErrorCode.InternalError, 'sampling_response_invalid', {
|
|
122
122
|
raw: text,
|
|
123
123
|
errors: validation.error.issues,
|
|
124
124
|
});
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import type { McpServer } from '@modelcontextprotocol/
|
|
1
|
+
import type { McpServer } from '@modelcontextprotocol/server';
|
|
2
2
|
import type { SceneOperations } from '../../operations/index.js';
|
|
3
3
|
/**
|
|
4
4
|
* Register the vision-input tools that defer to the MCP host's sampling
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/tools/vision/index.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/tools/vision/index.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,8BAA8B,CAAA;AAC7D,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,kBAAkB,CAAA;AAIvD;;;;;GAKG;AACH,wBAAgB,mBAAmB,CAAC,MAAM,EAAE,SAAS,EAAE,UAAU,EAAE,eAAe,GAAG,IAAI,CAGxF;AAED,OAAO,EACL,0BAA0B,EAC1B,2BAA2B,EAC3B,6BAA6B,GAC9B,MAAM,2BAA2B,CAAA;AAClC,OAAO,EACL,qBAAqB,EACrB,sBAAsB,EACtB,wBAAwB,GACzB,MAAM,sBAAsB,CAAA"}
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import type { McpServer } from '@modelcontextprotocol/
|
|
1
|
+
import type { McpServer } from '@modelcontextprotocol/server';
|
|
2
2
|
export type HttpTransportHandle = {
|
|
3
3
|
/** Host interface the server is listening on. */
|
|
4
4
|
host: string;
|
|
@@ -28,10 +28,16 @@ export type HttpTransportOptions = {
|
|
|
28
28
|
/**
|
|
29
29
|
* Attach an `McpServer` to a Streamable HTTP transport bound to a local port.
|
|
30
30
|
*
|
|
31
|
-
* Uses the SDK's
|
|
31
|
+
* Uses the SDK's `NodeStreamableHTTPServerTransport`, which accepts
|
|
32
32
|
* `IncomingMessage`/`ServerResponse` directly via `handleRequest(req, res)`.
|
|
33
33
|
* A new session ID is generated per connection (stateful mode).
|
|
34
34
|
*
|
|
35
|
+
* Serves the 2025 sessionful protocol only: a negotiating client falls back
|
|
36
|
+
* to it, and a client pinned to 2026-07-28 is refused. The SDK serves
|
|
37
|
+
* 2026-07-28 over HTTP per request (`createMcpHandler`), with a fresh server
|
|
38
|
+
* from the factory each time, and every server here owns its own scene, so a
|
|
39
|
+
* session is what keeps one client's scene between calls.
|
|
40
|
+
*
|
|
35
41
|
* Listens on `127.0.0.1:<port>` (pass `0` for an ephemeral port in tests). The
|
|
36
42
|
* returned handle exposes the actual bound port and a `close()` that stops
|
|
37
43
|
* the underlying Node HTTP server. To bind a public interface, pass `host` and
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"http.d.ts","sourceRoot":"","sources":["../../src/transports/http.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"http.d.ts","sourceRoot":"","sources":["../../src/transports/http.ts"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,8BAA8B,CAAA;AAS7D,MAAM,MAAM,mBAAmB,GAAG;IAChC,iDAAiD;IACjD,IAAI,EAAE,MAAM,CAAA;IACZ,8EAA8E;IAC9E,IAAI,EAAE,MAAM,CAAA;IACZ,8DAA8D;IAC9D,KAAK,IAAI,OAAO,CAAC,IAAI,CAAC,CAAA;CACvB,CAAA;AAED,MAAM,MAAM,oBAAoB,GAAG;IACjC;;;OAGG;IACH,IAAI,CAAC,EAAE,MAAM,CAAA;IACb,0EAA0E;IAC1E,SAAS,CAAC,EAAE,MAAM,CAAA;IAClB,uFAAuF;IACvF,cAAc,CAAC,EAAE,MAAM,EAAE,CAAA;IACzB,8DAA8D;IAC9D,kBAAkB,CAAC,EAAE,MAAM,CAAA;IAC3B,8EAA8E;IAC9E,MAAM,CAAC,EAAE;QAAE,OAAO,EAAE,MAAM,CAAC;QAAC,UAAU,EAAE,MAAM,CAAA;KAAE,CAAA;CACjD,CAAA;AAED;;;;;;;;;;;;;;;;;GAiBG;AACH,wBAAsB,WAAW,CAC/B,eAAe,EAAE,MAAM,SAAS,EAChC,IAAI,EAAE,MAAM,EACZ,OAAO,GAAE,oBAAyB,GACjC,OAAO,CAAC,mBAAmB,CAAC,CA2G9B"}
|
package/dist/transports/http.js
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { randomUUID, timingSafeEqual } from 'node:crypto';
|
|
2
2
|
import { createServer } from 'node:http';
|
|
3
|
-
import {
|
|
3
|
+
import { NodeStreamableHTTPServerTransport } from '@modelcontextprotocol/node';
|
|
4
4
|
const DEFAULT_HOST = '127.0.0.1';
|
|
5
5
|
const DEFAULT_RATE_LIMIT_PER_MINUTE = 120;
|
|
6
6
|
const WINDOW_MS = 60_000;
|
|
@@ -9,10 +9,16 @@ const ALLOWED_HEADERS = 'authorization, content-type, mcp-session-id, mcp-protoc
|
|
|
9
9
|
/**
|
|
10
10
|
* Attach an `McpServer` to a Streamable HTTP transport bound to a local port.
|
|
11
11
|
*
|
|
12
|
-
* Uses the SDK's
|
|
12
|
+
* Uses the SDK's `NodeStreamableHTTPServerTransport`, which accepts
|
|
13
13
|
* `IncomingMessage`/`ServerResponse` directly via `handleRequest(req, res)`.
|
|
14
14
|
* A new session ID is generated per connection (stateful mode).
|
|
15
15
|
*
|
|
16
|
+
* Serves the 2025 sessionful protocol only: a negotiating client falls back
|
|
17
|
+
* to it, and a client pinned to 2026-07-28 is refused. The SDK serves
|
|
18
|
+
* 2026-07-28 over HTTP per request (`createMcpHandler`), with a fresh server
|
|
19
|
+
* from the factory each time, and every server here owns its own scene, so a
|
|
20
|
+
* session is what keeps one client's scene between calls.
|
|
21
|
+
*
|
|
16
22
|
* Listens on `127.0.0.1:<port>` (pass `0` for an ephemeral port in tests). The
|
|
17
23
|
* returned handle exposes the actual bound port and a `close()` that stops
|
|
18
24
|
* the underlying Node HTTP server. To bind a public interface, pass `host` and
|
|
@@ -66,7 +72,7 @@ export async function connectHttp(createMcpServer, port, options = {}) {
|
|
|
66
72
|
let transport = sessionId ? transports.get(sessionId) : undefined;
|
|
67
73
|
if (!transport && req.method === 'POST' && !sessionId) {
|
|
68
74
|
let createdTransport;
|
|
69
|
-
createdTransport = new
|
|
75
|
+
createdTransport = new NodeStreamableHTTPServerTransport({
|
|
70
76
|
sessionIdGenerator: () => randomUUID(),
|
|
71
77
|
onsessioninitialized: (id) => {
|
|
72
78
|
transports.set(id, createdTransport);
|
|
@@ -1,14 +1,20 @@
|
|
|
1
|
-
import type { McpServer } from '@modelcontextprotocol/
|
|
1
|
+
import type { McpServer } from '@modelcontextprotocol/server';
|
|
2
|
+
import { type ServeStdioOptions, type StdioServerHandle } from '@modelcontextprotocol/server/stdio';
|
|
2
3
|
/**
|
|
3
|
-
*
|
|
4
|
+
* Serve Pascal over stdio from a server factory.
|
|
4
5
|
*
|
|
5
|
-
* The
|
|
6
|
-
*
|
|
7
|
-
*
|
|
6
|
+
* The SDK negotiates the protocol era per connection: a client that opens with
|
|
7
|
+
* the 2025 `initialize` handshake and one that opens with the 2026-07-28
|
|
8
|
+
* `server/discover` probe are both served. A server handed to
|
|
9
|
+
* `StdioServerTransport` directly would answer only the first. The factory can
|
|
10
|
+
* be called twice on one connection (a discarded probe instance, then the
|
|
11
|
+
* instance that serves it), so it must build a fresh, unconnected server each
|
|
12
|
+
* time.
|
|
8
13
|
*
|
|
9
|
-
*
|
|
10
|
-
*
|
|
11
|
-
*
|
|
14
|
+
* The connection owns stdin/stdout for JSON-RPC messaging. Callers must send
|
|
15
|
+
* any operator logging to stderr (not stdout) to avoid corrupting the protocol
|
|
16
|
+
* stream. The process stays alive while stdin is open; the connection tears
|
|
17
|
+
* itself down when stdin reaches end-of-file.
|
|
12
18
|
*/
|
|
13
|
-
export declare function connectStdio(
|
|
19
|
+
export declare function connectStdio(createServer: () => McpServer, options?: Pick<ServeStdioOptions, 'transport' | 'onerror'>): StdioServerHandle;
|
|
14
20
|
//# sourceMappingURL=stdio.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"stdio.d.ts","sourceRoot":"","sources":["../../src/transports/stdio.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,
|
|
1
|
+
{"version":3,"file":"stdio.d.ts","sourceRoot":"","sources":["../../src/transports/stdio.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,8BAA8B,CAAA;AAC7D,OAAO,EACL,KAAK,iBAAiB,EACtB,KAAK,iBAAiB,EAEvB,MAAM,oCAAoC,CAAA;AAE3C;;;;;;;;;;;;;;;GAeG;AACH,wBAAgB,YAAY,CAC1B,YAAY,EAAE,MAAM,SAAS,EAC7B,OAAO,GAAE,IAAI,CAAC,iBAAiB,EAAE,WAAW,GAAG,SAAS,CAAM,GAC7D,iBAAiB,CAKnB"}
|