wayfinder-mcp 0.1.0 → 0.1.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 +11 -9
- package/package.json +1 -1
- package/server.js +17 -1
package/README.md
CHANGED
|
@@ -29,7 +29,10 @@ the plan lives in `~/.wayfinder/wayfinder-plan.json`, the bridge binds
|
|
|
29
29
|
JSON-RPC over stdin/stdout. No network, no auth dance.
|
|
30
30
|
- **Tools** are named functions with a JSON schema: `get_summary`,
|
|
31
31
|
`get_plan`, `add_node`, `update_node`, `remove_node`, `connect`,
|
|
32
|
-
`disconnect`, `complete_node`, `set_text`, `replace_plan`.
|
|
32
|
+
`disconnect`, `complete_node`, `set_text`, `replace_plan`, `layout`.
|
|
33
|
+
New nodes are auto-placed (after their prerequisites, nudged until free,
|
|
34
|
+
so siblings never stack), and `layout` arranges the whole map by depth —
|
|
35
|
+
agents should call it after building a fresh map.
|
|
33
36
|
- **Validation is shared** with the site: `graph.js` is a byte-identical copy
|
|
34
37
|
of `wayfinder/dist/graph.js` (enforced by `npm run check`), so agent edits
|
|
35
38
|
obey the same rules as the UI (version 1, ≤2000 nodes, ≤10000 edges,
|
|
@@ -40,17 +43,16 @@ the plan lives in `~/.wayfinder/wayfinder-plan.json`, the bridge binds
|
|
|
40
43
|
(`WAYFINDER_NO_BRIDGE=1` disables it). It answers Chrome's private-network
|
|
41
44
|
preflight so the **deployed site** can reach each visitor's own bridge.
|
|
42
45
|
|
|
43
|
-
## For the site owner:
|
|
46
|
+
## For the site owner: releasing a new version
|
|
44
47
|
|
|
45
|
-
|
|
48
|
+
Releases are manual (two commands, ~2 minutes). From `mcp/`:
|
|
46
49
|
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
npm publish --access public
|
|
50
|
-
|
|
50
|
+
1. Bump `version` in `mcp/package.json`.
|
|
51
|
+
2. Create a short-lived granular token: npmjs.com → Access Tokens → Generate New Token → Granular, scoped to `wayfinder-mcp`, Read + Write.
|
|
52
|
+
3. `npm config set //registry.npmjs.org/:_authToken 'paste-token-here' && npm publish --access public`
|
|
53
|
+
4. Revoke the token on the website and clear it locally: `npm config delete //registry.npmjs.org/:_authToken`
|
|
51
54
|
|
|
52
|
-
|
|
53
|
-
Bump `version` in `mcp/package.json` for later releases (`0.1.0` now).
|
|
55
|
+
(Browser `npm login` tokens cannot publish — always use a granular token.)
|
|
54
56
|
|
|
55
57
|
## For developers (repo clone)
|
|
56
58
|
|
package/package.json
CHANGED
package/server.js
CHANGED
|
@@ -19,7 +19,7 @@ import {
|
|
|
19
19
|
CallToolRequestSchema,
|
|
20
20
|
ListToolsRequestSchema,
|
|
21
21
|
} from '@modelcontextprotocol/sdk/types.js';
|
|
22
|
-
import { validatePlan, canConnect } from './graph.js';
|
|
22
|
+
import { validatePlan, canConnect, layoutNodes } from './graph.js';
|
|
23
23
|
import { resolvePlanPath } from './paths.js';
|
|
24
24
|
import { loadPlan, startBridge } from './bridge.js';
|
|
25
25
|
|
|
@@ -141,6 +141,11 @@ const TOOLS = [
|
|
|
141
141
|
properties: { plan: { type: 'object', description: 'Full version-1 plan JSON' } },
|
|
142
142
|
},
|
|
143
143
|
},
|
|
144
|
+
{
|
|
145
|
+
name: 'layout',
|
|
146
|
+
description: 'Auto-arrange every node by graph depth (same as the site Arrange button). Call after building or importing a fresh map so nothing overlaps.',
|
|
147
|
+
inputSchema: { type: 'object', properties: {} },
|
|
148
|
+
},
|
|
144
149
|
];
|
|
145
150
|
|
|
146
151
|
const server = new Server({ name: 'wayfinder', version: '1.0.0' }, { capabilities: { tools: {} } });
|
|
@@ -180,7 +185,12 @@ server.setRequestHandler(CallToolRequestSchema, async (req) => {
|
|
|
180
185
|
const ps = nodes.filter((n) => parents.includes(n.id));
|
|
181
186
|
node.x = Math.max(...ps.map((p) => p.x)) + 270;
|
|
182
187
|
node.y = ps.reduce((t, p) => t + p.y, 0) / ps.length;
|
|
188
|
+
} else {
|
|
189
|
+
// First free grid slot, so parentless nodes never stack on each other.
|
|
190
|
+
node.x = 55; node.y = 55;
|
|
183
191
|
}
|
|
192
|
+
// Nudge down until free: siblings sharing parents would otherwise overlap exactly.
|
|
193
|
+
while (nodes.some((n) => Math.abs(n.x - node.x) < 235 && Math.abs(n.y - node.y) < 165)) node.y += 184;
|
|
184
194
|
return text({ ok: true, node: savePlan({ ...plan, nodes, edges }).nodes.find((n) => n.id === id) });
|
|
185
195
|
}
|
|
186
196
|
|
|
@@ -252,6 +262,12 @@ server.setRequestHandler(CallToolRequestSchema, async (req) => {
|
|
|
252
262
|
return text({ ok: true, plan: savePlan(args.plan) });
|
|
253
263
|
}
|
|
254
264
|
|
|
265
|
+
if (name === 'layout') {
|
|
266
|
+
layoutNodes(plan.nodes, plan.edges);
|
|
267
|
+
savePlan(plan);
|
|
268
|
+
return text({ ok: true, nodes: plan.nodes.length });
|
|
269
|
+
}
|
|
270
|
+
|
|
255
271
|
throw new Error(`unknown tool ${name}`);
|
|
256
272
|
} catch (err) {
|
|
257
273
|
return { content: [{ type: 'text', text: `Error: ${err.message}` }], isError: true };
|