@linktr.ee/arbor-mcp 0.1.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 +163 -0
- package/dist/index.js +1208 -0
- package/package.json +52 -0
package/README.md
ADDED
|
@@ -0,0 +1,163 @@
|
|
|
1
|
+
# @linktr.ee/arbor-mcp
|
|
2
|
+
|
|
3
|
+
A [Model Context Protocol](https://modelcontextprotocol.io) server that
|
|
4
|
+
exposes Arbor design system tools to MCP-connected AI agents (Claude Code,
|
|
5
|
+
Claude Desktop, Cursor, Zed, etc.).
|
|
6
|
+
|
|
7
|
+
## What it does
|
|
8
|
+
|
|
9
|
+
Currently registers a single tool:
|
|
10
|
+
|
|
11
|
+
### `arbor.open_in_playroom`
|
|
12
|
+
|
|
13
|
+
Resolves an Arbor PascalCase component name into a Playroom share URL with
|
|
14
|
+
the canonical default snippet pre-loaded.
|
|
15
|
+
|
|
16
|
+
**Input:**
|
|
17
|
+
|
|
18
|
+
```json
|
|
19
|
+
{ "componentName": "Button" }
|
|
20
|
+
```
|
|
21
|
+
|
|
22
|
+
**Output:** a `text` content item containing a JSON-stringified
|
|
23
|
+
`CanonicalLookupResult`:
|
|
24
|
+
|
|
25
|
+
```json
|
|
26
|
+
{
|
|
27
|
+
"coverage": "mapped",
|
|
28
|
+
"arborComponentName": "Button",
|
|
29
|
+
"snippet": "<Button>Save changes</Button>",
|
|
30
|
+
"url": "https://arbor.linktr.ee/playroom/#?code=PEJ1dHRvbj5TYXZlIGNoYW5nZXM8L0J1dHRvbj4="
|
|
31
|
+
}
|
|
32
|
+
```
|
|
33
|
+
|
|
34
|
+
`coverage` is one of:
|
|
35
|
+
|
|
36
|
+
- `mapped` — the component appears in `figma-mappings.ts` AND has a
|
|
37
|
+
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
|
+
- `not_found` — the URL points at the Playroom homepage; agents should
|
|
42
|
+
surface this to the human rather than silently following the link.
|
|
43
|
+
|
|
44
|
+
## Install
|
|
45
|
+
|
|
46
|
+
The package is published publicly to npm as `@linktr.ee/arbor-mcp`. The
|
|
47
|
+
expected use is `npx`-style spawning by an MCP client — see the wiring
|
|
48
|
+
section below. No global install required.
|
|
49
|
+
|
|
50
|
+
```bash
|
|
51
|
+
# Smoke-check the latest release
|
|
52
|
+
npx -y @linktr.ee/arbor-mcp --help 2>&1 | head -5
|
|
53
|
+
```
|
|
54
|
+
|
|
55
|
+
If you're working inside the Arbor monorepo, build the local source
|
|
56
|
+
instead so you're testing your changes:
|
|
57
|
+
|
|
58
|
+
```bash
|
|
59
|
+
yarn install
|
|
60
|
+
yarn workspace @linktr.ee/arbor-mcp build
|
|
61
|
+
```
|
|
62
|
+
|
|
63
|
+
That produces a single bundled ESM file at
|
|
64
|
+
`packages/arbor-mcp/dist/index.js` (with shebang) ready to be spawned by
|
|
65
|
+
any MCP client.
|
|
66
|
+
|
|
67
|
+
## Wire it into an MCP client
|
|
68
|
+
|
|
69
|
+
### Claude Code / Claude Desktop / Cursor (`.mcp.json` or equivalent)
|
|
70
|
+
|
|
71
|
+
The recommended setup uses the public npm package — no clone required:
|
|
72
|
+
|
|
73
|
+
```jsonc
|
|
74
|
+
{
|
|
75
|
+
"mcpServers": {
|
|
76
|
+
"arbor": {
|
|
77
|
+
"command": "npx",
|
|
78
|
+
"args": ["-y", "@linktr.ee/arbor-mcp"]
|
|
79
|
+
}
|
|
80
|
+
}
|
|
81
|
+
}
|
|
82
|
+
```
|
|
83
|
+
|
|
84
|
+
If you're hacking on the server inside the Arbor workspace, point at the
|
|
85
|
+
local build instead so changes pick up without republishing:
|
|
86
|
+
|
|
87
|
+
```jsonc
|
|
88
|
+
{
|
|
89
|
+
"mcpServers": {
|
|
90
|
+
"arbor": {
|
|
91
|
+
"command": "node",
|
|
92
|
+
"args": ["./packages/arbor-mcp/dist/index.js"]
|
|
93
|
+
}
|
|
94
|
+
}
|
|
95
|
+
}
|
|
96
|
+
```
|
|
97
|
+
|
|
98
|
+
For portability across clients that don't substitute path variables
|
|
99
|
+
(Claude Desktop, most CLI MCP clients), prefer absolute paths over
|
|
100
|
+
`${workspaceFolder}`.
|
|
101
|
+
|
|
102
|
+
### Verify the connection
|
|
103
|
+
|
|
104
|
+
After restarting your MCP client, the `arbor.open_in_playroom` tool should
|
|
105
|
+
appear in the available-tools list. Ask the agent something like:
|
|
106
|
+
|
|
107
|
+
> Use the arbor MCP server to open Button in Playroom.
|
|
108
|
+
|
|
109
|
+
The agent will call the tool and return the URL.
|
|
110
|
+
|
|
111
|
+
## Develop
|
|
112
|
+
|
|
113
|
+
```bash
|
|
114
|
+
# Run the server against tsx directly (no build step) — useful for
|
|
115
|
+
# iterating on tool handlers.
|
|
116
|
+
yarn workspace @linktr.ee/arbor-mcp dev
|
|
117
|
+
|
|
118
|
+
# Run the unit tests (covers tool metadata, input validation, lookup
|
|
119
|
+
# happy/not-found paths, and the 9-of-9 figma-mappings coverage gate).
|
|
120
|
+
yarn workspace @linktr.ee/arbor-mcp test
|
|
121
|
+
|
|
122
|
+
# Smoke-test the full JSON-RPC handshake end-to-end.
|
|
123
|
+
printf '{"jsonrpc":"2.0","id":1,"method":"initialize","params":{"protocolVersion":"2024-11-05","capabilities":{},"clientInfo":{"name":"manual","version":"0.0.0"}}}\n{"jsonrpc":"2.0","id":2,"method":"tools/list"}\n' | node dist/index.js
|
|
124
|
+
```
|
|
125
|
+
|
|
126
|
+
## Architecture
|
|
127
|
+
|
|
128
|
+
```
|
|
129
|
+
packages/arbor-mcp/
|
|
130
|
+
├── src/
|
|
131
|
+
│ ├── index.ts # entrypoint: connects stdio transport
|
|
132
|
+
│ ├── server.ts # creates the Server + registers handlers
|
|
133
|
+
│ └── tools/
|
|
134
|
+
│ └── open-in-playroom.ts # tool metadata + dispatch function
|
|
135
|
+
├── tests/
|
|
136
|
+
│ └── open-in-playroom.test.ts # node --test, validation + coverage
|
|
137
|
+
├── build.mjs # esbuild bundle to dist/index.js
|
|
138
|
+
└── tsconfig.json # rootDir: ../.. for cross-package imports
|
|
139
|
+
```
|
|
140
|
+
|
|
141
|
+
The `arbor.open_in_playroom` handler delegates to `lookupByArborName` in
|
|
142
|
+
`apps/playroom/src/canonical-snippet-lookup.ts` — the same module the
|
|
143
|
+
Figma plugin's "Open in Playroom" relaunch button uses. This keeps the
|
|
144
|
+
agent-facing surface and the designer-facing surface in lockstep.
|
|
145
|
+
|
|
146
|
+
## Why bundle vs. emit `tsc` files?
|
|
147
|
+
|
|
148
|
+
`tsc` would emit one `.js` per `.ts` and preserve cross-package directory
|
|
149
|
+
structure under `dist/`. Node's ESM resolver doesn't add `.js` extensions
|
|
150
|
+
to extensionless imports (the workspace TS source uses extensionless
|
|
151
|
+
imports because `moduleResolution: bundler`), so the multi-file output
|
|
152
|
+
fails to resolve at runtime. Bundling with esbuild flattens the
|
|
153
|
+
dependency graph into a single self-contained file. `tsc --noEmit` still
|
|
154
|
+
runs in the build script for type checking.
|
|
155
|
+
|
|
156
|
+
## Future tools
|
|
157
|
+
|
|
158
|
+
When adding a second tool, follow the existing pattern:
|
|
159
|
+
|
|
160
|
+
1. New file under `src/tools/<name>.ts` exporting `TOOL_NAME`,
|
|
161
|
+
`TOOL_DESCRIPTION`, `TOOL_INPUT_SCHEMA`, and a `run<Name>` handler.
|
|
162
|
+
2. Register it in `src/server.ts` alongside the existing entry.
|
|
163
|
+
3. Mirror the test file shape under `tests/`.
|