@roadmapperai/mcp 0.9.3 → 0.9.5
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/AGENTS.md +112 -16
- package/README.md +42 -16
- package/package.json +1 -1
- package/server.mjs +1647 -125
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**,
|
|
@@ -85,6 +102,13 @@ that's almost always what you actually want.
|
|
|
85
102
|
CANDIDATE for `propose_capability` (human-confirmed) followed by
|
|
86
103
|
`move_tasks`. Tune `minClusterSize` (default 3) / `fitThreshold`
|
|
87
104
|
(default 0.2) to control sensitivity.
|
|
105
|
+
- `detect_theme_sprawl` — the theme-level companion. Scores every
|
|
106
|
+
active theme against every other and flags pairs that overlap enough
|
|
107
|
+
to be consolidation candidates, each with a suggested merge
|
|
108
|
+
(`move_capabilities` the lighter theme's bets into the heavier, then
|
|
109
|
+
`archive_theme`). This is how you keep theme count in check now that
|
|
110
|
+
agents create themes autonomously (see `propose_theme`). Run it at
|
|
111
|
+
quarterly review. Tune `threshold` (default 0.34).
|
|
88
112
|
- `get_agents_md` — re-read this contract on demand.
|
|
89
113
|
|
|
90
114
|
**Multi-workspace addressing.** A single MCP install can talk to any
|
|
@@ -137,18 +161,37 @@ to "tell the human what I'd do"):
|
|
|
137
161
|
succeeds (this is a nudge, not a gate — unlike `propose_capability`,
|
|
138
162
|
which hard-blocks until you've done discovery). Surface the warning
|
|
139
163
|
to the user.
|
|
164
|
+
- `propose_tasks` — **bulk** create many tasks under ONE capability in
|
|
165
|
+
a single call. **This is the token-efficient path: prefer it over N
|
|
166
|
+
separate `propose_task` calls when filing a plan** — one request, one
|
|
167
|
+
compact `{id,title}` array back. Each task spec needs `title` +
|
|
168
|
+
`effort`; intra-batch dependencies work by giving a task a `ref` and
|
|
169
|
+
listing that ref in a sibling's `dependsOn` (refs are rewritten to
|
|
170
|
+
real ids after minting). A validation error fails the whole batch
|
|
171
|
+
before writing; once valid, per-row RPC failures are reported in
|
|
172
|
+
`tasks[].error` without sinking the rest.
|
|
140
173
|
- `propose_capability` — create a new capability under an **existing**
|
|
141
174
|
theme. Required: `name`, `pillarId`. Sensible defaults are applied
|
|
142
175
|
(`reach: 100`, `impact: 1`, `confidence: 70`). Pass `outcome` and
|
|
143
176
|
`specRef` whenever you have them — capabilities without an outcome
|
|
144
177
|
rarely survive review. Pass `idempotencyKey`.
|
|
145
|
-
- `propose_theme` — create a new theme. **
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
178
|
+
- `propose_theme` — create a new theme. **Theme-autonomy is ON by
|
|
179
|
+
default**, so you MAY create a theme without human confirmation when
|
|
180
|
+
the work genuinely needs a new years-stable pillar. You don't police
|
|
181
|
+
sprawl by asking a human every time — the server does it for you:
|
|
182
|
+
`propose_theme` returns `error: "too_similar"` (naming the match) if
|
|
183
|
+
your theme overlaps an existing one above the block bar, so you reuse
|
|
184
|
+
or `update_theme` that one instead. Still prefer the deepest existing
|
|
185
|
+
parent (new task > new capability > new theme); a theme is the rare
|
|
186
|
+
case. If a workspace turned autonomy OFF (Settings → Agent
|
|
187
|
+
automation), `propose_theme` returns `error: "confirmation_required"`
|
|
188
|
+
until you surface the new theme to the user and retry with
|
|
189
|
+
`confirm: true`. Use `force: true` only to override a `too_similar`
|
|
190
|
+
block that's a genuine false positive. Run `detect_theme_sprawl`
|
|
191
|
+
periodically to catch themes that have drifted into overlap.
|
|
192
|
+
- `submit_acceptance_grades` — stamp `{ status: pass | fail, note? }`
|
|
193
|
+
per criterion index, after you've actually verified the work. The
|
|
194
|
+
server stamps `gradedAt` and `gradedBy: "mcp:agent"`.
|
|
152
195
|
- `submit_acceptance_grades` — stamp `{ status: pass | fail, note? }`
|
|
153
196
|
per criterion index, after you've actually verified the work. The
|
|
154
197
|
server stamps `gradedAt` and `gradedBy: "mcp:agent"`.
|
|
@@ -223,6 +266,45 @@ disagrees with the cwd snapshot are refused — set
|
|
|
223
266
|
`ROADMAPPER_ALLOW_CROSS_WORKSPACE=1` in the env to override.
|
|
224
267
|
Reads can target any workspace freely.
|
|
225
268
|
|
|
269
|
+
**Repo-link gate (write path).** If you're in a git repo that
|
|
270
|
+
isn't mapped to a workspace, a mutator would silently land on the
|
|
271
|
+
install's env-default workspace — almost never what you want. So
|
|
272
|
+
the first such write is **refused** with a structured error:
|
|
273
|
+
|
|
274
|
+
```json
|
|
275
|
+
{
|
|
276
|
+
"error": "repo_unmapped",
|
|
277
|
+
"message": "\"owner/name\" isn't mapped to a workspace ...",
|
|
278
|
+
"fix": "link_repo()",
|
|
279
|
+
"alt": "<tool>({ workspaceId: \"<target>\", ... })"
|
|
280
|
+
}
|
|
281
|
+
```
|
|
282
|
+
|
|
283
|
+
Resolve it one of two ways, then retry:
|
|
284
|
+
- **`link_repo()`** — maps the repo you're in to your key's
|
|
285
|
+
workspace, so every future session resolves silently. This is
|
|
286
|
+
the right move when the repo *should* feed this workspace.
|
|
287
|
+
- **Pass `workspaceId` explicitly** on the call — proceeds without
|
|
288
|
+
mapping the repo. This is the escape hatch when you're working
|
|
289
|
+
across **several repos in one session** and just want this write
|
|
290
|
+
to land on a specific existing workspace.
|
|
291
|
+
|
|
292
|
+
The gate is repo-aware and only fires for a genuinely unmapped
|
|
293
|
+
repo: an explicit `workspaceId`, an already-mapped repo (resolves
|
|
294
|
+
via `repo_workspace_map`), or not being in a git repo at all
|
|
295
|
+
pass straight through — a multi-repo chat is never bricked.
|
|
296
|
+
Operators can disable the gate entirely with
|
|
297
|
+
`ROADMAPPER_ALLOW_UNMAPPED_REPO=1`.
|
|
298
|
+
|
|
299
|
+
This gate and the **seed-workspace guard** below are complementary,
|
|
300
|
+
not redundant: the repo-link gate covers the *in a git repo but
|
|
301
|
+
unmapped* case (and gives the more actionable `link_repo` fix),
|
|
302
|
+
while the seed-workspace guard still catches a write that fell
|
|
303
|
+
through to the bundled `"default"` workspace when you're **not** in
|
|
304
|
+
any repo (nothing to link). A write can be refused by at most one of
|
|
305
|
+
them; both protect the same env-default footgun from different
|
|
306
|
+
angles.
|
|
307
|
+
|
|
226
308
|
Authoring discipline:
|
|
227
309
|
- Read first (`list_themes`, `list_capabilities`, `list_tasks`) before
|
|
228
310
|
proposing anything, so you don't invent a new theme/capability that
|
|
@@ -402,12 +484,17 @@ Before writing anything:
|
|
|
402
484
|
- **Top score 0.2–0.4**: weak overlap. The top match is still
|
|
403
485
|
usually the right home; re-using a "close-enough" theme is
|
|
404
486
|
almost always better than creating a duplicate.
|
|
405
|
-
- **Empty matches or top < 0.2**: no existing theme fits.
|
|
406
|
-
|
|
407
|
-
|
|
408
|
-
|
|
409
|
-
|
|
410
|
-
|
|
487
|
+
- **Empty matches or top < 0.2**: no existing theme fits. With
|
|
488
|
+
theme-autonomy ON (the default), you may call `propose_theme`
|
|
489
|
+
directly when this is a genuinely new years-stable pillar — you
|
|
490
|
+
don't need to stop and ask. The server is the sprawl guard: it
|
|
491
|
+
refuses a near-duplicate (`error: "too_similar"`), so a theme that
|
|
492
|
+
gets created is one that doesn't already exist. With autonomy OFF,
|
|
493
|
+
`propose_theme` returns `error: "confirmation_required"` — surface
|
|
494
|
+
the theme to the user and retry with `confirm: true`. Either way,
|
|
495
|
+
prefer a capability under the closest theme when one is even
|
|
496
|
+
plausibly a fit; a new theme is the rare case.
|
|
497
|
+
The propose_theme tool enforces discovery: skipping
|
|
411
498
|
`suggest_theme_for` (or `list_themes` / `get_roadmap_snapshot`)
|
|
412
499
|
returns a `discovery_missing` error.
|
|
413
500
|
2. **Decompose into Capabilities.** A Capability is "a quarterly
|
|
@@ -427,9 +514,18 @@ Before writing anything:
|
|
|
427
514
|
|
|
428
515
|
### What to emit (template)
|
|
429
516
|
|
|
430
|
-
|
|
431
|
-
|
|
432
|
-
|
|
517
|
+
**If the write tools are live (you can call `propose_capability` /
|
|
518
|
+
`propose_tasks`), FILE DIRECTLY — do not also emit this JSON block.**
|
|
519
|
+
Dumping the full plan as JSON *and* filing it via tools pays for the
|
|
520
|
+
plan twice in tokens, and the tools are the canonical path anyway. Use
|
|
521
|
+
`propose_capability` for the bet, then ONE `propose_tasks` call for all
|
|
522
|
+
its tasks (not N `propose_task` calls), and report back a short summary
|
|
523
|
+
with the returned ids — not the whole record set. The JSON block below
|
|
524
|
+
is only for the **no-write-tools** case (seed/live-read tier), where
|
|
525
|
+
the user pastes it into Roadmapper's import manually.
|
|
526
|
+
|
|
527
|
+
When you do emit it: return a single JSON block. The field names must
|
|
528
|
+
match exactly. IDs use the `__NEW__` placeholder prefix when you're
|
|
433
529
|
proposing a new record — Roadmapper assigns the real `TH-NNNNNN` /
|
|
434
530
|
`CAP-NNN` / `TK-NNNNNN` ID at import time.
|
|
435
531
|
|
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
|
-
|
|
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
|
|
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.
|
|
106
|
-
2.
|
|
107
|
-
`list_capabilities` / `list_tasks
|
|
108
|
-
3. Before proposing anything new,
|
|
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
|
|
111
|
-
|
|
112
|
-
4.
|
|
113
|
-
|
|
114
|
-
|
|
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,
|
|
117
|
-
|
|
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
|
|
121
|
-
|
|
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,16 @@ the check with `ROADMAPPER_DISABLE_UPDATE_CHECK=1`.
|
|
|
134
150
|
|
|
135
151
|
### Recent changes
|
|
136
152
|
|
|
153
|
+
- **0.9.5** — **tool-surface collapse for token efficiency.** `tools/list` now
|
|
154
|
+
advertises three dispatch tools (`roadmap_search` / `roadmap_describe` /
|
|
155
|
+
`roadmap`) instead of ~34, cutting the always-loaded tool definitions ~97%
|
|
156
|
+
(~15k → ~0.5k tokens) and the per-session planning footprint ~95%. The ~34
|
|
157
|
+
operations are unchanged — they're reached as `roadmap({ op, args })`, with
|
|
158
|
+
schemas served on demand via `roadmap_describe`. Per-tool methodology moved
|
|
159
|
+
into the server `instructions` (now correctly top-level) plus the
|
|
160
|
+
`roadmapper://rubric` resource. Already-linked repos should re-run
|
|
161
|
+
`npm run mcp:setup -- --link <path>` to refresh the permission allow-list and
|
|
162
|
+
the CLAUDE.md block for the dispatch surface.
|
|
137
163
|
- **0.9.3** — new `link_repo` tool: when `get_active_workspace` reports
|
|
138
164
|
`env_default`/`unresolved` and you're in a git repo, one call persists
|
|
139
165
|
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.
|
|
3
|
+
"version": "0.9.5",
|
|
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",
|