@roadmapperai/mcp 0.9.4 → 0.9.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.
Files changed (4) hide show
  1. package/AGENTS.md +71 -37
  2. package/README.md +51 -16
  3. package/package.json +1 -1
  4. package/server.mjs +887 -96
package/AGENTS.md CHANGED
@@ -7,6 +7,23 @@ The roadmap data model is the source of truth — TypeScript types in
7
7
  [`src/types.ts`](https://github.com/vsgro/roadmapper/blob/main/src/types.ts) are the canonical schema. Everything
8
8
  in this doc is downstream of that file.
9
9
 
10
+ ## How to call operations (dispatch surface)
11
+
12
+ The `roadmapper` MCP server advertises **one** action tool: `roadmap({ op, args })`.
13
+ Every operation named in this document — `get_roadmap_snapshot`, `suggest_capability_for`,
14
+ `propose_task`, `propose_tasks`, `propose_capability`, `get_agents_md`, `link_repo`, etc. — is
15
+ an `op` **value**, not a separately-advertised tool. Invoke it as
16
+ `roadmap({ op: "<name>", args: { ... } })`. Two helpers round out the surface:
17
+
18
+ - `roadmap_search({ intent })` — list/rank the available operations by what you're trying to do.
19
+ - `roadmap_describe({ op })` — return one operation's exact input schema (its arguments).
20
+ - `roadmap({ op, args })` — execute the operation. `args` may also be passed flat (top-level), but the documented shape is nested under `args`.
21
+
22
+ So when a section below says "call `propose_tasks`" or shows `suggest_theme_for({ description })`,
23
+ read it as `roadmap({ op: "propose_tasks", args: {...} })` /
24
+ `roadmap({ op: "suggest_theme_for", args: { description } })`. The server enforces the
25
+ rubric/discovery gates and per-op validation identically however you call.
26
+
10
27
  ## TL;DR — what an agent must do
11
28
 
12
29
  - Reference Themes / Capabilities / Tasks / Sprints by **stable ID**,
@@ -114,8 +131,8 @@ you do, every write tool below returns a structured error:
114
131
  ```json
115
132
  {
116
133
  "error": "prerequisite_missing",
117
- "message": "Call get_agents_md first this session, then retry ...",
118
- "fix": "get_agents_md()"
134
+ "message": "Call roadmap({ op: \"get_agents_md\" }) first this session, then retry ...",
135
+ "fix": "roadmap({ op: \"get_agents_md\" })"
119
136
  }
120
137
  ```
121
138
 
@@ -258,15 +275,15 @@ the first such write is **refused** with a structured error:
258
275
  {
259
276
  "error": "repo_unmapped",
260
277
  "message": "\"owner/name\" isn't mapped to a workspace ...",
261
- "fix": "link_repo()",
262
- "alt": "<tool>({ workspaceId: \"<target>\", ... })"
278
+ "fix": "roadmap({ op: \"link_repo\" })",
279
+ "alt": "roadmap({ op: \"<op>\", args: { workspaceId: \"<target>\", ... } })"
263
280
  }
264
281
  ```
265
282
 
266
283
  Resolve it one of two ways, then retry:
267
- - **`link_repo()`** — maps the repo you're in to your key's
268
- workspace, so every future session resolves silently. This is
269
- the right move when the repo *should* feed this workspace.
284
+ - **`roadmap({ op: "link_repo" })`** — maps the repo you're in to
285
+ your key's workspace, so every future session resolves silently.
286
+ This is the right move when the repo *should* feed this workspace.
270
287
  - **Pass `workspaceId` explicitly** on the call — proceeds without
271
288
  mapping the repo. This is the escape hatch when you're working
272
289
  across **several repos in one session** and just want this write
@@ -339,52 +356,69 @@ PRs without submitted acceptance grades; call submit_acceptance_grades
339
356
  for TK-X, TK-Y, TK-Z." Surface these to the user; they're the
340
357
  roadmap's way of asking for the next action.
341
358
 
342
- Three capability tiers, driven by which env vars the operator set:
359
+ Two install shapes:
360
+
361
+ - **Customer (recommended):** `npx -y @roadmapperai/mcp` with
362
+ `ROADMAPPER_BACKEND_URL` + `ROADMAPPER_PUBLISHABLE_KEY` +
363
+ `ROADMAPPER_WORKSPACE_ID`, plus `ROADMAPPER_API_KEY` (an `rmpr_…` key)
364
+ to enable writes. Writes route through the mcp-broker, so no
365
+ service-role key ever lives on the machine. The dashboard's
366
+ Settings → Connect page generates this block pre-filled.
367
+ - **Self-host / operator:** run `node mcp/server.mjs` from a local
368
+ checkout with the `SUPABASE_*` env vars (legacy aliases the server
369
+ still accepts) and the Postgres migrations applied for writes.
370
+
371
+ Capability tiers, by which env vars are set (either shape):
343
372
 
344
373
  | Tier | Required env | What you get |
345
374
  |-------------------|-----------------------------------------------------------------------------------------------------------|-------------------------------------------------------------------------------|
346
375
  | Seed-only | none | Read tools against the static `roadmap.json`. |
347
- | Live read | `SUPABASE_URL` + (`SUPABASE_PUBLISHABLE_KEY` or `SUPABASE_ANON_KEY`) + `SUPABASE_WORKSPACE_ID` | Read tools merged with the workspace's edits. |
348
- | Live read + write | All of the above plus `SUPABASE_SERVICE_ROLE_KEY` (and migrations 0005–0045 applied) | Read tools + propose_* / grade / archive_* / unarchive_* / move_* / update_* tools. |
349
-
350
- If a write tool returns an error result mentioning `SUPABASE_SERVICE_ROLE_KEY`,
351
- the operator is on the live-read tier; don't keep retrying — fall
352
- back to telling the human what you'd do and let them apply it.
353
-
354
- Sanity check the install with `node mcp/server.mjs --selftest` — runs
355
- every tool against the local seed and prints a pass/fail summary.
356
-
357
- If the operator chose project-scoped install (`.mcp.json` in the
358
- roadmapper repo root, which is the default `npm run mcp:setup` path),
359
- the MCP only loads when their client is launched from that repo. If
360
- you're an agent running in another codebase and the `roadmapper`
361
- tools aren't visible, ask the operator to either (a) merge the
362
- `mcpServers.roadmapper` block from `roadmap/.mcp.json` into their
363
- user-level client config or (b) point you at the roadmapper repo so
364
- you can run there instead.
365
-
366
- Wire-up (Claude Code, Claude Desktop, or any MCP client):
376
+ | Live read | `ROADMAPPER_BACKEND_URL` + `ROADMAPPER_PUBLISHABLE_KEY` + `ROADMAPPER_WORKSPACE_ID` (or the `SUPABASE_*` equivalents) | Read merged with the workspace's edits. |
377
+ | Live read + write | the above plus `ROADMAPPER_API_KEY` (`rmpr_…`, broker path) — or, self-hosting, `SUPABASE_SERVICE_ROLE_KEY` with migrations applied | Read + propose_* / grade / archive_* / unarchive_* / move_* / update_* ops. |
378
+
379
+ If a write returns an error about a missing key, you're on the read
380
+ tier; don't keep retrying — tell the human what you'd do and let them
381
+ apply it.
382
+
383
+ Sanity check (repo checkout only): `node mcp/server.mjs --selftest`
384
+ runs every check against the bundled seed and prints a pass/fail
385
+ summary. Run it from the **repo root** — an npm/npx install ships no
386
+ seed file, so ~13 seed-dependent checks fail with `ENOENT` there and
387
+ that is EXPECTED, not a broken install; the server still works over
388
+ the wire (reads fall back to a demo seed; live edits come from the
389
+ backend).
390
+
391
+ If the operator chose project-scoped install (`.mcp.json` in the repo,
392
+ the default `npm run mcp:setup` path), the MCP only loads when their
393
+ client is launched from that repo. If you're an agent in another
394
+ codebase and the `roadmapper` tools aren't visible, ask the operator
395
+ to either (a) merge the `mcpServers.roadmapper` block into their
396
+ user-level client config or (b) point you at the roadmapper repo.
397
+
398
+ Wire-up (Claude Code, Claude Desktop, or any MCP client) — customer path:
367
399
 
368
400
  ```jsonc
369
401
  {
370
402
  "mcpServers": {
371
403
  "roadmapper": {
372
- "command": "node",
373
- "args": ["/absolute/path/to/roadmap/mcp/server.mjs"],
404
+ "command": "npx",
405
+ "args": ["-y", "@roadmapperai/mcp"],
374
406
  "env": {
375
- "SUPABASE_URL": "https://<id>.supabase.co",
376
- "SUPABASE_PUBLISHABLE_KEY": "sb_publishable_...",
377
- "SUPABASE_WORKSPACE_ID": "<workspace id>",
378
- "SUPABASE_SERVICE_ROLE_KEY": "<only if write tools wanted>"
407
+ "ROADMAPPER_BACKEND_URL": "https://<id>.supabase.co",
408
+ "ROADMAPPER_PUBLISHABLE_KEY": "sb_publishable_...",
409
+ "ROADMAPPER_WORKSPACE_ID": "<workspace id>",
410
+ "ROADMAPPER_API_KEY": "<rmpr_… — only if write ops wanted>"
379
411
  }
380
412
  }
381
413
  }
382
414
  }
383
415
  ```
384
416
 
385
- The `env` block is optional drop it to serve the seed only. See
386
- [README.md](/README.md#mcp-server) for the config-file path per
387
- client and the full env-var matrix.
417
+ Self-hosting from a checkout instead? Use `"command": "node"` with the
418
+ absolute path to `mcp/server.mjs`; the `SUPABASE_*` env names are
419
+ accepted as aliases. The `env` block is optional — drop it to serve the
420
+ seed only. See [README.md](/README.md#mcp-server) for the config-file
421
+ path per client and the full env-var matrix.
388
422
 
389
423
  ## The snapshot file in connected repos
390
424
 
package/README.md CHANGED
@@ -57,7 +57,22 @@ JSON config works, dropped into Cursor's `mcp` field.
57
57
 
58
58
  ## What this server exposes
59
59
 
60
- Read tools (always available):
60
+ **The wire surface is three dispatch tools.** As of 0.9.5 the server advertises
61
+ only:
62
+
63
+ - `roadmap_search({ intent })` — list/rank the available operations by intent
64
+ - `roadmap_describe({ op })` — return one operation's exact input schema
65
+ - `roadmap({ op, args })` — execute an operation
66
+
67
+ Everything below is an **`op` value** passed to `roadmap`, e.g.
68
+ `roadmap({ op: "get_roadmap_snapshot" })` or
69
+ `roadmap({ op: "propose_tasks", args: { capabilityId, tasks: [...] } })`. This
70
+ keeps `tools/list` tiny (one schema instead of ~34) while the per-op schemas
71
+ load on demand via `roadmap_describe`. The full planning contract ships in the
72
+ server's `instructions` (sent at connect) and the `get_agents_md` op /
73
+ `roadmapper://rubric` resource.
74
+
75
+ ### Read operations (always available)
61
76
 
62
77
  - `list_themes` — top-level strategic themes
63
78
  - `list_capabilities` — capabilities (optionally filtered by theme)
@@ -86,7 +101,7 @@ Read tools (always available):
86
101
  > for full rows and `limit` (max 200) to raise the cap. This keeps a
87
102
  > cold-start read from blowing the token budget on a large workspace.
88
103
 
89
- Write tools (require workspace-scoped write auth — set `ROADMAPPER_API_KEY`
104
+ ### Write operations (require workspace-scoped write auth — set `ROADMAPPER_API_KEY`
90
105
  to an `rmpr_…` key from the dashboard; writes then route through the
91
106
  mcp-broker so the service-role key never lives on your machine):
92
107
 
@@ -100,25 +115,26 @@ mcp-broker so the service-role key never lives on your machine):
100
115
 
101
116
  ## How agents are meant to use this
102
117
 
103
- The intended loop:
118
+ The intended loop (every step is `roadmap({ op, args })`):
104
119
 
105
- 1. Agent calls `get_agents_md` to load the rubric.
106
- 2. Agent reads the current roadmap state via `list_themes` /
107
- `list_capabilities` / `list_tasks`.
108
- 3. Before proposing anything new, agent calls `suggest_capability_for`
120
+ 1. `roadmap({ op: "get_agents_md" })` to load the rubric.
121
+ 2. Read the current roadmap state: `roadmap({ op: "get_roadmap_snapshot" })`
122
+ (or `list_themes` / `list_capabilities` / `list_tasks` ops).
123
+ 3. Before proposing anything new, `roadmap({ op: "suggest_capability_for", args: { description } })`
109
124
  (or `suggest_theme_for`) to check if a matching parent already exists.
110
- Skipping this is allowed for `propose_task` but the response will carry
111
- a warn-on-skip nudge; `propose_capability` hard-requires it.
112
- 4. Agent proposes new rows through the `propose_*` tools, including all
113
- the rubric-required fields (RICE, acceptance criteria, etc.).
114
- 5. Once a PR is merged, the agent calls `link_pr` to attach it; the
125
+ Skipping is allowed for `propose_task` but the response carries a
126
+ warn-on-skip nudge; `propose_capability` hard-requires it.
127
+ 4. Propose new rows via `roadmap({ op: "propose_tasks", args })` /
128
+ `roadmap({ op: "propose_capability", args })`, including all the
129
+ rubric-required fields (RICE, acceptance criteria, etc.).
130
+ 5. Once a PR is merged, `roadmap({ op: "link_pr", args })` to attach it; the
115
131
  roadmap delivery stats update automatically.
116
- 6. After delivery, the agent self-grades against the acceptance criteria
117
- with `submit_acceptance_grades`.
132
+ 6. After delivery, self-grade against the acceptance criteria with
133
+ `roadmap({ op: "submit_acceptance_grades", args })`.
118
134
 
119
135
  The server enforces the rubric: proposals filed without first fetching
120
- `get_agents_md` are rejected with a remediation hint pointing the agent
121
- back to the rubric.
136
+ `get_agents_md` are rejected with a structured remediation hint whose `fix`
137
+ field names the exact dispatch call to make next.
122
138
 
123
139
  ## Versioning
124
140
 
@@ -134,6 +150,25 @@ the check with `ROADMAPPER_DISABLE_UPDATE_CHECK=1`.
134
150
 
135
151
  ### Recent changes
136
152
 
153
+ - **0.9.6** — hardening pass on top of the 0.9.5 collapse. `submit_acceptance_grades`
154
+ now rejects a negative/non-integer/out-of-range `index`, a non-array `grades`,
155
+ and a status that isn't `pass`/`fail` (the per-op schema is no longer on the
156
+ wire for clients to enforce, so the handler validates). A task can no longer be
157
+ moved to `in_progress` with an empty acceptance list on the MCP write path.
158
+ `propose_theme` with `dryRun` now previews a near-duplicate (with a warning)
159
+ instead of hard-blocking. Server instructions no longer tell agents to proceed
160
+ only on `status:"resolved"` (the normal env install resolves to `env_default`).
161
+ Docs reconciled to the dispatch surface + customer (npx) install path.
162
+ - **0.9.5** — **tool-surface collapse for token efficiency.** `tools/list` now
163
+ advertises three dispatch tools (`roadmap_search` / `roadmap_describe` /
164
+ `roadmap`) instead of ~34, cutting the always-loaded tool definitions ~97%
165
+ (~15k → ~0.5k tokens) and the per-session planning footprint ~95%. The ~34
166
+ operations are unchanged — they're reached as `roadmap({ op, args })`, with
167
+ schemas served on demand via `roadmap_describe`. Per-tool methodology moved
168
+ into the server `instructions` (now correctly top-level) plus the
169
+ `roadmapper://rubric` resource. Already-linked repos should re-run
170
+ `npm run mcp:setup -- --link <path>` to refresh the permission allow-list and
171
+ the CLAUDE.md block for the dispatch surface.
137
172
  - **0.9.3** — new `link_repo` tool: when `get_active_workspace` reports
138
173
  `env_default`/`unresolved` and you're in a git repo, one call persists
139
174
  the repo → workspace mapping so future sessions resolve silently (the
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@roadmapperai/mcp",
3
- "version": "0.9.4",
3
+ "version": "0.9.6",
4
4
  "description": "Roadmapper AI MCP server — exposes a planning surface (themes, capabilities, tasks, sprints, PRs) to coding agents via stdio JSON-RPC. Pairs with the Roadmapper AI workspace at dashboard.roadmapperai.com.",
5
5
  "keywords": [
6
6
  "mcp",