@pascal-app/mcp 0.3.0 → 0.3.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +71 -0
- package/dist/bin/pascal-mcp.js +0 -0
- package/dist/bridge/scene-bridge.d.ts.map +1 -1
- package/dist/bridge/scene-bridge.js +6 -0
- package/dist/operations/scene-operations.js +1 -0
- package/dist/resources/constraints.js +1 -1
- package/dist/tools/construction-tools.d.ts +21 -21
- package/dist/tools/construction-tools.d.ts.map +1 -1
- package/dist/tools/construction-tools.js +45 -19
- package/dist/tools/create-level.d.ts +1 -1
- package/dist/tools/create-level.d.ts.map +1 -1
- package/dist/tools/create-level.js +5 -1
- package/dist/tools/create-wall.d.ts +2 -2
- package/dist/tools/create-wall.d.ts.map +1 -1
- package/dist/tools/create-wall.js +6 -2
- package/dist/tools/cut-opening.d.ts +3 -3
- package/dist/tools/cut-opening.d.ts.map +1 -1
- package/dist/tools/cut-opening.js +3 -2
- package/dist/tools/find-nodes.d.ts +2 -2
- package/dist/tools/find-nodes.js +1 -1
- package/dist/tools/measurement.d.ts +37 -0
- package/dist/tools/measurement.d.ts.map +1 -0
- package/dist/tools/measurement.js +94 -0
- package/dist/tools/photo-to-scene/photo-to-scene.d.ts +2 -2
- package/dist/tools/photo-to-scene/photo-to-scene.d.ts.map +1 -1
- package/dist/tools/photo-to-scene/photo-to-scene.js +9 -2
- package/dist/tools/place-item.d.ts +1 -1
- package/dist/tools/place-item.d.ts.map +1 -1
- package/dist/tools/place-item.js +2 -1
- package/dist/tools/room-tools.d.ts +8 -8
- package/dist/tools/room-tools.d.ts.map +1 -1
- package/dist/tools/room-tools.js +17 -7
- package/dist/tools/scene-query.js +2 -2
- package/examples/coordinate-conventions-demo.json +968 -0
- package/examples/coordinate-conventions-demo.md +68 -0
- package/examples/embed-in-agent.ts +82 -0
- package/examples/generate-apartment.md +242 -0
- package/examples/photo-to-scene.md +119 -0
- package/examples/renovate-from-photos.md +202 -0
- package/package.json +8 -6
|
@@ -0,0 +1,202 @@
|
|
|
1
|
+
# Renovate an existing flat from photos
|
|
2
|
+
|
|
3
|
+
This example shows how an agent can combine the `renovation_from_photos`
|
|
4
|
+
prompt with the `analyze_floorplan_image` and `analyze_room_photo` vision
|
|
5
|
+
tools to propose a renovation plan grounded in real photos.
|
|
6
|
+
|
|
7
|
+
> **Note:** the vision tools use MCP sampling (`createMessage`), which
|
|
8
|
+
> Claude Desktop supports today. Hosts without sampling support will get a
|
|
9
|
+
> structured `sampling_unavailable` error; fall back to the text-only
|
|
10
|
+
> `from_brief` prompt in that case.
|
|
11
|
+
|
|
12
|
+
## The brief
|
|
13
|
+
|
|
14
|
+
The user drops four photos into the chat:
|
|
15
|
+
|
|
16
|
+
1. A floorplan PDF page (exported as PNG).
|
|
17
|
+
2. A photo of the current living room.
|
|
18
|
+
3. A photo of the current kitchen.
|
|
19
|
+
4. An inspirational photo from a magazine — a minimal Scandinavian loft.
|
|
20
|
+
|
|
21
|
+
And types:
|
|
22
|
+
|
|
23
|
+
> **User:** Claude, help me plan a renovation. Here's the current plan and
|
|
24
|
+
> two room photos. I want something like this Scandinavian reference —
|
|
25
|
+
> open-plan, neutral tones, keep the footprint.
|
|
26
|
+
|
|
27
|
+
## What the agent does
|
|
28
|
+
|
|
29
|
+
The host loads the **`renovation_from_photos`** prompt:
|
|
30
|
+
|
|
31
|
+
```text
|
|
32
|
+
currentPhotos: ["data:image/png;base64,...", "data:image/jpeg;base64,..."]
|
|
33
|
+
referencePhotos: ["data:image/jpeg;base64,..."]
|
|
34
|
+
goals: "Open-plan living/kitchen, neutral tones, keep the footprint."
|
|
35
|
+
```
|
|
36
|
+
|
|
37
|
+
The prompt tells the agent to (1) analyze the floorplan, (2) analyze each
|
|
38
|
+
room photo, (3) seed a scene from the floorplan, (4) compare against the
|
|
39
|
+
reference, and (5) propose patches.
|
|
40
|
+
|
|
41
|
+
### 1. Extract the floorplan
|
|
42
|
+
|
|
43
|
+
```jsonc
|
|
44
|
+
// tool: analyze_floorplan_image
|
|
45
|
+
{
|
|
46
|
+
"name": "analyze_floorplan_image",
|
|
47
|
+
"arguments": {
|
|
48
|
+
"image": "data:image/png;base64,iVBORw0KGgoAAAANS...",
|
|
49
|
+
"scaleHint": "1 m grid, total footprint ~9.5 m × 7 m"
|
|
50
|
+
}
|
|
51
|
+
}
|
|
52
|
+
```
|
|
53
|
+
|
|
54
|
+
Under the hood, the tool issues an MCP sampling request to the host with
|
|
55
|
+
the image and a structured prompt asking for walls, rooms, and
|
|
56
|
+
approximate dimensions. The response is validated against the tool's
|
|
57
|
+
output schema:
|
|
58
|
+
|
|
59
|
+
```jsonc
|
|
60
|
+
{
|
|
61
|
+
"walls": [
|
|
62
|
+
{ "start": [0, 0], "end": [9.5, 0], "thickness": 0.25 },
|
|
63
|
+
{ "start": [9.5, 0], "end": [9.5, 7], "thickness": 0.25 },
|
|
64
|
+
{ "start": [9.5, 7], "end": [0, 7], "thickness": 0.25 },
|
|
65
|
+
{ "start": [0, 7], "end": [0, 0], "thickness": 0.25 },
|
|
66
|
+
{ "start": [4.5, 0], "end": [4.5, 7], "thickness": 0.15 },
|
|
67
|
+
{ "start": [4.5, 3.5], "end": [9.5, 3.5], "thickness": 0.15 }
|
|
68
|
+
],
|
|
69
|
+
"rooms": [
|
|
70
|
+
{ "label": "Living", "polygon": [[0, 0], [4.5, 0], [4.5, 7], [0, 7]] },
|
|
71
|
+
{ "label": "Kitchen", "polygon": [[4.5, 0], [9.5, 0], [9.5, 3.5], [4.5, 3.5]] },
|
|
72
|
+
{ "label": "Bedroom", "polygon": [[4.5, 3.5], [9.5, 3.5], [9.5, 7], [4.5, 7]] }
|
|
73
|
+
],
|
|
74
|
+
"approximateDimensions": { "widthMeters": 9.5, "depthMeters": 7, "areaSqMeters": 66.5 },
|
|
75
|
+
"confidence": 0.82
|
|
76
|
+
}
|
|
77
|
+
```
|
|
78
|
+
|
|
79
|
+
### 2. Analyze the room photos
|
|
80
|
+
|
|
81
|
+
```jsonc
|
|
82
|
+
// tool: analyze_room_photo
|
|
83
|
+
{
|
|
84
|
+
"name": "analyze_room_photo",
|
|
85
|
+
"arguments": { "image": "data:image/jpeg;base64,/9j/4AAQ..." }
|
|
86
|
+
}
|
|
87
|
+
```
|
|
88
|
+
|
|
89
|
+
Response:
|
|
90
|
+
|
|
91
|
+
```jsonc
|
|
92
|
+
{
|
|
93
|
+
"approximateDimensions": { "widthMeters": 4.4, "depthMeters": 5.8, "heightMeters": 2.5 },
|
|
94
|
+
"identifiedFixtures": [
|
|
95
|
+
{ "kind": "sofa", "approximatePosition": [2.2, 3.5] },
|
|
96
|
+
{ "kind": "coffee-table", "approximatePosition": [2.2, 2.4] },
|
|
97
|
+
{ "kind": "tv-unit", "approximatePosition": [0.3, 2.0] }
|
|
98
|
+
],
|
|
99
|
+
"identifiedWindows": [
|
|
100
|
+
{ "wallHint": "south", "approximateWidth": 1.4, "approximateHeight": 1.5 }
|
|
101
|
+
]
|
|
102
|
+
}
|
|
103
|
+
```
|
|
104
|
+
|
|
105
|
+
The kitchen photo is analyzed the same way.
|
|
106
|
+
|
|
107
|
+
### 3. Seed the scene
|
|
108
|
+
|
|
109
|
+
The agent reads `get_scene`, confirms the default empty Site → Building →
|
|
110
|
+
Level is present, and then batch-creates walls matching the floorplan:
|
|
111
|
+
|
|
112
|
+
```jsonc
|
|
113
|
+
// tool: apply_patch
|
|
114
|
+
{
|
|
115
|
+
"name": "apply_patch",
|
|
116
|
+
"arguments": {
|
|
117
|
+
"patches": [
|
|
118
|
+
{ "op": "create", "parentId": "level-1",
|
|
119
|
+
"node": { "type": "wall", "start": [0, 0], "end": [9.5, 0],
|
|
120
|
+
"thickness": 0.25, "height": 2.5 } },
|
|
121
|
+
/* ...remaining perimeter + partition walls from the vision result... */
|
|
122
|
+
]
|
|
123
|
+
}
|
|
124
|
+
}
|
|
125
|
+
```
|
|
126
|
+
|
|
127
|
+
The agent then calls `set_zone` three times to seed the Living / Kitchen /
|
|
128
|
+
Bedroom polygons from the floorplan rooms.
|
|
129
|
+
|
|
130
|
+
### 4. Cut the identified openings
|
|
131
|
+
|
|
132
|
+
For each window the vision tool reported, the agent calls `cut_opening`
|
|
133
|
+
against the corresponding perimeter wall:
|
|
134
|
+
|
|
135
|
+
```jsonc
|
|
136
|
+
{
|
|
137
|
+
"name": "cut_opening",
|
|
138
|
+
"arguments": {
|
|
139
|
+
"wallId": "wall-south",
|
|
140
|
+
"type": "window",
|
|
141
|
+
"position": 0.5,
|
|
142
|
+
"width": 1.4,
|
|
143
|
+
"height": 1.5
|
|
144
|
+
}
|
|
145
|
+
}
|
|
146
|
+
```
|
|
147
|
+
|
|
148
|
+
### 5. Propose the renovation
|
|
149
|
+
|
|
150
|
+
Guided by the reference photo's analysis (bright neutrals, open plan,
|
|
151
|
+
minimal furnishing), the agent proposes a single logical patch:
|
|
152
|
+
|
|
153
|
+
- Remove the partition wall between Living and Kitchen.
|
|
154
|
+
- Relocate the kitchen island further west.
|
|
155
|
+
- Delete the bulky TV unit item; leave the sofa and coffee table.
|
|
156
|
+
- Re-label the merged zone `"Open-Plan Living / Kitchen"`.
|
|
157
|
+
|
|
158
|
+
All of that goes into one `apply_patch`:
|
|
159
|
+
|
|
160
|
+
```jsonc
|
|
161
|
+
{
|
|
162
|
+
"name": "apply_patch",
|
|
163
|
+
"arguments": {
|
|
164
|
+
"patches": [
|
|
165
|
+
{ "op": "delete", "id": "wall-partition-living-kitchen", "cascade": false },
|
|
166
|
+
{ "op": "update", "id": "zone-living", "data": { "label": "Open-Plan Living / Kitchen",
|
|
167
|
+
"polygon": [[0, 0], [9.5, 0],
|
|
168
|
+
[9.5, 3.5], [0, 3.5]] } },
|
|
169
|
+
{ "op": "delete", "id": "zone-kitchen", "cascade": false }
|
|
170
|
+
/* + item moves / deletes for the TV unit etc. */
|
|
171
|
+
]
|
|
172
|
+
}
|
|
173
|
+
}
|
|
174
|
+
```
|
|
175
|
+
|
|
176
|
+
The user can walk back with `undo`; `redo` returns them to the proposal.
|
|
177
|
+
|
|
178
|
+
### 6. Sanity-check
|
|
179
|
+
|
|
180
|
+
```jsonc
|
|
181
|
+
// tool: validate_scene
|
|
182
|
+
{ "name": "validate_scene", "arguments": {} }
|
|
183
|
+
// → { "valid": true, "errors": [] }
|
|
184
|
+
|
|
185
|
+
// tool: check_collisions
|
|
186
|
+
{ "name": "check_collisions", "arguments": { "levelId": "level-1" } }
|
|
187
|
+
// → { "collisions": [] }
|
|
188
|
+
```
|
|
189
|
+
|
|
190
|
+
The agent reports a summary of the changes plus the approximate new
|
|
191
|
+
usable area (from the summary resource), and the user opens the scene in
|
|
192
|
+
`@pascal-app/viewer` to see the renovated 3D layout.
|
|
193
|
+
|
|
194
|
+
## Takeaways
|
|
195
|
+
|
|
196
|
+
- The vision tools only return **data**. They don't mutate the scene —
|
|
197
|
+
the agent is explicit about every structural change via `apply_patch`.
|
|
198
|
+
- Photos supply priors (approximate dimensions, fixture types) that a
|
|
199
|
+
brief-only workflow can't. Combine them with `from_brief`-style
|
|
200
|
+
prompts when the user has both a reference and concrete text goals.
|
|
201
|
+
- All renovation steps are a single temporal step per patch, so the user
|
|
202
|
+
can compare before/after with `undo` / `redo`.
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@pascal-app/mcp",
|
|
3
|
-
"version": "0.3.
|
|
3
|
+
"version": "0.3.2",
|
|
4
4
|
"description": "Model Context Protocol server for Pascal 3D editor",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "./dist/index.js",
|
|
@@ -42,29 +42,31 @@
|
|
|
42
42
|
},
|
|
43
43
|
"files": [
|
|
44
44
|
"dist",
|
|
45
|
+
"examples",
|
|
45
46
|
"README.md",
|
|
46
47
|
"CHANGELOG.md"
|
|
47
48
|
],
|
|
48
49
|
"scripts": {
|
|
49
50
|
"build": "tsc --build",
|
|
50
|
-
"dev": "
|
|
51
|
+
"dev": "tsgo --build --watch",
|
|
51
52
|
"start": "bun dist/bin/pascal-mcp.js",
|
|
52
53
|
"test": "bun test",
|
|
53
54
|
"smoke": "bun run scripts/smoke.ts",
|
|
54
55
|
"prepublishOnly": "bun run build && bun test"
|
|
55
56
|
},
|
|
56
57
|
"peerDependencies": {
|
|
57
|
-
"@pascal-app/core": "^0.
|
|
58
|
+
"@pascal-app/core": "^0.9.2"
|
|
58
59
|
},
|
|
59
60
|
"dependencies": {
|
|
60
61
|
"@modelcontextprotocol/sdk": "^1.29.0",
|
|
62
|
+
"@pascal-app/lingo": "^0.2.0",
|
|
61
63
|
"zod": "^4.3.5"
|
|
62
64
|
},
|
|
63
65
|
"devDependencies": {
|
|
64
|
-
"@pascal-app/core": "^0.
|
|
66
|
+
"@pascal-app/core": "^0.9.2",
|
|
65
67
|
"@pascal/typescript-config": "*",
|
|
66
|
-
"@types/node": "^
|
|
67
|
-
"typescript": "
|
|
68
|
+
"@types/node": "^22.19.20",
|
|
69
|
+
"typescript": "6.0.3"
|
|
68
70
|
},
|
|
69
71
|
"keywords": [
|
|
70
72
|
"mcp",
|