@linktr.ee/arbor-mcp 0.1.2-rc.db212f55.5824 → 0.2.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +58 -22
- package/dist/index.js +5816 -78
- package/package.json +4 -3
package/README.md
CHANGED
|
@@ -8,39 +8,52 @@ Claude Desktop, Cursor, Zed, etc.).
|
|
|
8
8
|
|
|
9
9
|
Currently registers a single tool:
|
|
10
10
|
|
|
11
|
-
### `
|
|
11
|
+
### `arbor_open_in_playroom`
|
|
12
|
+
|
|
13
|
+
> The legacy name `arbor.open_in_playroom` remains registered as a deprecated
|
|
14
|
+
> alias (it routes to the same handler) and will be removed in the next major.
|
|
15
|
+
> Prefer the snake_case name.
|
|
12
16
|
|
|
13
17
|
Resolves an Arbor PascalCase component name into a Playroom share URL with
|
|
14
18
|
the canonical default snippet pre-loaded.
|
|
15
19
|
|
|
16
|
-
**Input
|
|
20
|
+
**Input** (validated by a strict Zod schema — unknown keys are rejected):
|
|
17
21
|
|
|
18
22
|
```json
|
|
19
23
|
{ "componentName": "Button" }
|
|
20
24
|
```
|
|
21
25
|
|
|
22
|
-
**Output:**
|
|
23
|
-
`
|
|
26
|
+
**Output:** `structuredContent` matching the tool's `outputSchema` (the machine
|
|
27
|
+
payload), plus a concise one-line `text` summary (the human mirror — it does
|
|
28
|
+
**not** duplicate the full JSON):
|
|
24
29
|
|
|
25
30
|
```json
|
|
26
31
|
{
|
|
27
32
|
"coverage": "mapped",
|
|
28
33
|
"arborComponentName": "Button",
|
|
29
34
|
"snippet": "<Button>Save changes</Button>",
|
|
30
|
-
"url": "https://arbor.linktr.ee/playroom
|
|
35
|
+
"url": "https://arbor.linktr.ee/playroom/?slug=flowering-sapling-glen-5",
|
|
36
|
+
"source": "minted",
|
|
37
|
+
"slug": "flowering-sapling-glen-5"
|
|
31
38
|
}
|
|
32
39
|
```
|
|
33
40
|
|
|
34
|
-
`
|
|
41
|
+
A `mapped` result carries the pretty `?slug=` URL when slug minting succeeds
|
|
42
|
+
(`source: "minted"` or `"cached"`). If minting is unavailable it degrades to a
|
|
43
|
+
self-contained lz-string `#?code=…` URL with `degraded: true` and a `reason`,
|
|
44
|
+
and no `slug`.
|
|
45
|
+
|
|
46
|
+
`coverage` (for this by-name tool) is one of:
|
|
35
47
|
|
|
36
48
|
- `mapped` — the component appears in `figma-mappings.ts` AND has a
|
|
37
49
|
canonical entry in `compositions.ts`. High confidence.
|
|
38
|
-
- `fallback` — best-effort name matching (e.g. "Header Bar" → `HeaderBar`).
|
|
39
|
-
Used by the Figma plugin's selection-driven path; the by-name MCP tool
|
|
40
|
-
almost always returns `mapped` or `not_found`.
|
|
41
50
|
- `not_found` — the URL points at the Playroom homepage; agents should
|
|
42
51
|
surface this to the human rather than silently following the link.
|
|
43
52
|
|
|
53
|
+
> A third coverage, `fallback` (best-effort fuzzy name matching), exists only
|
|
54
|
+
> on the Figma plugin's selection-driven node-ID path. This by-name MCP tool
|
|
55
|
+
> never returns it — its `outputSchema` is `mapped | not_found`.
|
|
56
|
+
|
|
44
57
|
## Install
|
|
45
58
|
|
|
46
59
|
The package is published publicly to npm as `@linktr.ee/arbor-mcp`. The
|
|
@@ -48,8 +61,13 @@ expected use is `npx`-style spawning by an MCP client — see the wiring
|
|
|
48
61
|
section below. No global install required.
|
|
49
62
|
|
|
50
63
|
```bash
|
|
51
|
-
# Smoke-check the latest release
|
|
52
|
-
|
|
64
|
+
# Smoke-check the latest release. The server speaks JSON-RPC over stdio (there
|
|
65
|
+
# is no --help flag); pipe a handshake in so stdin closes and the process
|
|
66
|
+
# exits. Expect a tools/list response naming arbor_open_in_playroom.
|
|
67
|
+
printf '%s\n%s\n' \
|
|
68
|
+
'{"jsonrpc":"2.0","id":1,"method":"initialize","params":{"protocolVersion":"2024-11-05","capabilities":{},"clientInfo":{"name":"smoke","version":"0"}}}' \
|
|
69
|
+
'{"jsonrpc":"2.0","id":2,"method":"tools/list"}' \
|
|
70
|
+
| npx -y @linktr.ee/arbor-mcp
|
|
53
71
|
```
|
|
54
72
|
|
|
55
73
|
If you're working inside the Arbor monorepo, build the local source
|
|
@@ -101,7 +119,7 @@ For portability across clients that don't substitute path variables
|
|
|
101
119
|
|
|
102
120
|
### Verify the connection
|
|
103
121
|
|
|
104
|
-
After restarting your MCP client, the `
|
|
122
|
+
After restarting your MCP client, the `arbor_open_in_playroom` tool should
|
|
105
123
|
appear in the available-tools list. Ask the agent something like:
|
|
106
124
|
|
|
107
125
|
> Use the arbor MCP server to open Button in Playroom.
|
|
@@ -115,8 +133,9 @@ The agent will call the tool and return the URL.
|
|
|
115
133
|
# iterating on tool handlers.
|
|
116
134
|
yarn workspace @linktr.ee/arbor-mcp dev
|
|
117
135
|
|
|
118
|
-
# Run the
|
|
119
|
-
#
|
|
136
|
+
# Run the tests: the in-memory Client handshake + protocol contract
|
|
137
|
+
# (server.test.ts) plus tool metadata, input validation, lookup
|
|
138
|
+
# happy/not-found paths, and the figma-mappings coverage gate.
|
|
120
139
|
yarn workspace @linktr.ee/arbor-mcp test
|
|
121
140
|
|
|
122
141
|
# Smoke-test the full JSON-RPC handshake end-to-end.
|
|
@@ -129,20 +148,29 @@ printf '{"jsonrpc":"2.0","id":1,"method":"initialize","params":{"protocolVersion
|
|
|
129
148
|
packages/arbor-mcp/
|
|
130
149
|
├── src/
|
|
131
150
|
│ ├── index.ts # entrypoint: connects stdio transport
|
|
132
|
-
│ ├── server.ts # creates the
|
|
151
|
+
│ ├── server.ts # creates the McpServer + registers ARBOR_TOOLS
|
|
133
152
|
│ └── tools/
|
|
134
|
-
│
|
|
153
|
+
│ ├── registry.ts # ArborTool convention + registerArborTool
|
|
154
|
+
│ └── open-in-playroom.ts # tool: schemas, annotations, handler
|
|
135
155
|
├── tests/
|
|
156
|
+
│ ├── server.test.ts # in-memory Client handshake + contract
|
|
136
157
|
│ └── open-in-playroom.test.ts # node --test, validation + coverage
|
|
137
158
|
├── build.mjs # esbuild bundle to dist/index.js
|
|
138
159
|
└── tsconfig.json # rootDir: ../.. for cross-package imports
|
|
139
160
|
```
|
|
140
161
|
|
|
141
|
-
The `
|
|
162
|
+
The `arbor_open_in_playroom` handler delegates to `lookupByArborName` in
|
|
142
163
|
`apps/playroom/src/canonical-snippet-lookup.ts` — the same module the
|
|
143
164
|
Figma plugin's "Open in Playroom" relaunch button uses. This keeps the
|
|
144
165
|
agent-facing surface and the designer-facing surface in lockstep.
|
|
145
166
|
|
|
167
|
+
The server is built on the SDK's high-level `McpServer` + `registerTool`
|
|
168
|
+
(the modern, non-deprecated API). Every tool is an `ArborTool` registry
|
|
169
|
+
object (`tools/registry.ts`): a `.strict()` Zod `inputSchema`, a Zod
|
|
170
|
+
`outputSchema` (the handler returns matching `structuredContent`),
|
|
171
|
+
annotation hints, and a total handler. Input-validation and handler errors
|
|
172
|
+
surface as `isError: true` results, never protocol rejections.
|
|
173
|
+
|
|
146
174
|
## Why bundle vs. emit `tsc` files?
|
|
147
175
|
|
|
148
176
|
`tsc` would emit one `.js` per `.ts` and preserve cross-package directory
|
|
@@ -155,9 +183,17 @@ runs in the build script for type checking.
|
|
|
155
183
|
|
|
156
184
|
## Future tools
|
|
157
185
|
|
|
158
|
-
When adding a second tool, follow the
|
|
186
|
+
When adding a second tool, follow the registry convention:
|
|
187
|
+
|
|
188
|
+
1. New file under `src/tools/<name>.ts` exporting an `ArborTool` object
|
|
189
|
+
(see `tools/registry.ts`): `name`, optional deprecated `aliases`, a
|
|
190
|
+
`config` with `title` / `description` / `.strict()` Zod `inputSchema` /
|
|
191
|
+
Zod `outputSchema` / `annotations`, and a total `handler` returning
|
|
192
|
+
`{ content, structuredContent }`.
|
|
193
|
+
2. Add it to the `ARBOR_TOOLS` array in `src/server.ts`.
|
|
194
|
+
3. Mirror the test file shape under `tests/` (drive it through the in-memory
|
|
195
|
+
`Client` as in `server.test.ts`, plus pure-handler unit tests).
|
|
159
196
|
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
3. Mirror the test file shape under `tests/`.
|
|
197
|
+
Pass `inputSchema` as a `z.object({...}).strict()` (a ZodObject, **not** a
|
|
198
|
+
raw shape) — the SDK only preserves `.strict()` rejection of unknown keys
|
|
199
|
+
for a ZodObject; a raw shape is rebuilt non-strict and silently strips them.
|