@roadmapperai/mcp
v0.9.26
Published
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.
Maintainers
Readme
@roadmapperai/mcp
The MCP (Model Context Protocol) server for Roadmapper AI.
Lets your coding agent (Claude Code, Claude Desktop, Cursor, etc.) read your roadmap and — once write auth is enabled — propose themes, capabilities, and tasks against your live rubric.
Install
You need a Roadmapper AI workspace. Sign up free at dashboard.roadmapperai.com.
Then add the server to your MCP client. The dashboard's Settings → Connect to your agent page generates a copy-pasteable config block with your workspace ID pre-filled — that's the fastest path.
Manual config
If you'd rather wire it up by hand:
Claude Code / Claude Desktop
Add to your ~/.config/claude-code/config.json (or the equivalent
claude_desktop_config.json for the desktop app):
{
"mcpServers": {
"roadmapper": {
"command": "npx",
"args": ["-y", "@roadmapperai/mcp"],
"env": {
"ROADMAPPER_BACKEND_URL": "https://api.roadmapperai.com",
"ROADMAPPER_PUBLISHABLE_KEY": "sb_publishable_...",
"ROADMAPPER_WORKSPACE_ID": "<your workspace id>",
"ROADMAPPER_API_KEY": "<rmpr_... — optional, enables writes>"
}
}
}
}The ROADMAPPER_API_KEY env var is optional. Without it, the install runs
read-only (list/get/suggest tools). Mint a key in the dashboard at Settings →
MCP activity → API keys and add it to the env block to unlock write tools
(propose / link / grade).
Get your workspace ID from the dashboard's URL bar
(dashboard.roadmapperai.com/settings → workspace section) or from the
generated config block in Settings → Connect.
Cursor
Cursor's MCP settings live under Settings → Features → MCP. The same
JSON config works, dropped into Cursor's mcp field.
HTTP transport (one shared server for every chat)
The default install is stdio — the MCP client spawns one npx
@roadmapperai/mcp subprocess per session. Each chat gets its own Node
process, each independently connecting to the backend. With several concurrent
sessions that piles up (roughly two processes per session) and the repeated
npx cold-start + handshake makes the server appear to flap
(disconnect/reconnect as sessions come and go). The roadmap state lives in the
backend — the shared source of truth — so the per-session process buys nothing.
HTTP mode runs one shared server that every chat talks to over localhost HTTP. Start it once:
ROADMAPPER_WORKSPACE_ID="<your workspace id>" \
ROADMAPPER_API_KEY="<rmpr_... — optional, enables writes>" \
node /ABSOLUTE/PATH/TO/mcp/server.mjs --http
# → http ready on http://127.0.0.1:4025/mcp(ROADMAPPER_HTTP=1 is equivalent to --http. Port defaults to 4025,
override with ROADMAPPER_HTTP_PORT. It binds 127.0.0.1 only; set
ROADMAPPER_HTTP_HOST to expose it elsewhere.) Then point the MCP client at
the running server instead of spawning a subprocess:
{
"mcpServers": {
"roadmapper": {
"type": "http",
"url": "http://127.0.0.1:4025/mcp"
}
}
}Every chat now shares the one process — no per-session npx, no flapping.
GET /healthz returns a liveness snapshot (resolved workspace + roadmap
shape).
Workspace per request. HTTP can't do the stdio server→client roots/list
handshake that auto-detects a repo's workspace, so the HTTP server resolves the
workspace from the ROADMAPPER_WORKSPACE_ID env default. To target a different
workspace on a single request, send an X-Roadmapper-Workspace: <id> header
(or pass workspaceId in the call args, which always wins). This is the same
per-op override the tools already honor.
Stdio remains the default — running server.mjs with no flag is unchanged.
What this server exposes
The wire surface is three dispatch tools. As of 0.9.5 the server advertises only:
roadmap_search({ intent })— list/rank the available operations by intentroadmap_describe({ op })— return one operation's exact input schemaroadmap({ op, args })— execute an operation
Everything below is an op value passed to roadmap, e.g.
roadmap({ op: "get_roadmap_snapshot" }) or
roadmap({ op: "propose_tasks", args: { capabilityId, tasks: [...] } }). This
keeps tools/list tiny (one schema instead of ~34) while the per-op schemas
load on demand via roadmap_describe. The full planning contract ships in the
server's instructions (sent at connect) and the get_agents_md op /
roadmapper://rubric resource.
Read operations (always available)
list_themes— top-level strategic themeslist_capabilities— capabilities (optionally filtered by theme)list_tasks— tasks (optionally filtered by capability or status)list_uncategorized_tasks— tasks with no parent capability (orphans the webhook created from PRs with noRoadmapper-Capability:trailer); triage entry pointget_task— full task detail including acceptance criteria + depsget_capability— full capability detail (outcome, RICE, rollup, closeState)get_records— fetch a mixed batch of ids (TH-/CAP-/TK-) in one call, full rows tagged withrecordType, with anotFoundlist; the spot-check op for ids of unknown/mixed type, and the only way to read a single theme by idget_agents_md— the planning rubric (the contract for proposals)get_roadmap_snapshot— current state of the whole roadmapget_active_workspace— which workspace this server is pointed at and how it resolved (arg / snapshot / env); confirm before writingsuggest_capability_for— find the existing capability matching a free-text description or an existingtaskId(synthesizes the query from the task's title + summary)suggest_theme_for— find existing theme that matches a descriptiondetect_capability_gaps— cluster orphaned tasks that fit no existing capability and flag where a new bet is likely missinglist_stale_outcomes— capabilities whose outcome metric hasn't been re-read recently
Output is light by default. The collection reads (
get_roadmap_snapshot,list_tasks,list_capabilities,list_uncategorized_tasks) return light rows and are capped (50), wrapped in a{ total, returned, truncated, items }envelope. Passdetail: truefor full rows andlimit(max 200) to raise the cap. This keeps a cold-start read from blowing the token budget on a large workspace.
Write operations (require workspace-scoped write auth — set ROADMAPPER_API_KEY
to an rmpr_… key from the dashboard; writes then route through the
mcp-broker so the service-role key never lives on your machine):
propose_theme,propose_capability,propose_task— file new workupdate_theme,update_capability,update_task— patch existing rowsarchive_*/unarchive_*— soft deletemove_task,move_capability— reparentlink_pr— attach a merged PR to a taskrecord_outcome_reading— log an outcome metric measurementsubmit_acceptance_grades— self-grade after delivery
How agents are meant to use this
The intended loop (every step is roadmap({ op, args })):
roadmap({ op: "get_agents_md" })to load the rubric.- Read the current roadmap state:
roadmap({ op: "get_roadmap_snapshot" })(orlist_themes/list_capabilities/list_tasksops). - Before proposing anything new,
roadmap({ op: "suggest_capability_for", args: { description } })(orsuggest_theme_for) to check if a matching parent already exists. Skipping is allowed forpropose_taskbut the response carries a warn-on-skip nudge;propose_capabilityhard-requires it. - Propose new rows via
roadmap({ op: "propose_tasks", args })/roadmap({ op: "propose_capability", args }), including all the rubric-required fields (RICE, acceptance criteria, etc.). - Once a PR is merged,
roadmap({ op: "link_pr", args })to attach it; the roadmap delivery stats update automatically. - After delivery, self-grade against the acceptance criteria with
roadmap({ op: "submit_acceptance_grades", args }).
The server enforces the rubric: proposals filed without first fetching
get_agents_md are rejected with a structured remediation hint whose fix
field names the exact dispatch call to make next.
Versioning
This package follows semver. Breaking changes to tool shapes get a
major-version bump and a deprecation window. Add --package=@roadmapperai/[email protected]
to your npx invocation if you want to pin.
Because the install is version-pinned (the dashboard hands you a config
pinned to an exact version), the server checks the npm registry at boot
and logs a one-line nudge to stderr if a newer version is published —
re-copy the install command from Settings → MCP to upgrade. Disable
the check with ROADMAPPER_DISABLE_UPDATE_CHECK=1.
Recent changes
- 0.9.12 — new
get_recordsread op: fetch a mixed batch of ids (TH-/CAP-/TK-, 1–50 per call) in one round trip, returning full rows tagged withrecordTypeplus anotFoundlist. The spot-check / verify-by-id op for ids of unknown or mixed type, and the only way to read a single theme by id (there is noget_theme). Complements the existing single-recordget_task/get_capability; not for discovery (use snapshot/list_*/search). - 0.9.6 — hardening pass on top of the 0.9.5 collapse.
submit_acceptance_gradesnow rejects a negative/non-integer/out-of-rangeindex, a non-arraygrades, and a status that isn'tpass/fail(the per-op schema is no longer on the wire for clients to enforce, so the handler validates). A task can no longer be moved toin_progresswith an empty acceptance list on the MCP write path.propose_themewithdryRunnow previews a near-duplicate (with a warning) instead of hard-blocking. Server instructions no longer tell agents to proceed only onstatus:"resolved"(the normal env install resolves toenv_default). Docs reconciled to the dispatch surface + customer (npx) install path. - 0.9.5 — tool-surface collapse for token efficiency.
tools/listnow advertises three dispatch tools (roadmap_search/roadmap_describe/roadmap) instead of ~34, cutting the always-loaded tool definitions ~97% (~15k → ~0.5k tokens) and the per-session planning footprint ~95%. The ~34 operations are unchanged — they're reached asroadmap({ op, args }), with schemas served on demand viaroadmap_describe. Per-tool methodology moved into the serverinstructions(now correctly top-level) plus theroadmapper://rubricresource. Already-linked repos should re-runnpm run mcp:setup -- --link <path>to refresh the permission allow-list and the CLAUDE.md block for the dispatch surface. - 0.9.3 — new
link_repotool: whenget_active_workspacereportsenv_default/unresolvedand you're in a git repo, one call persists the repo → workspace mapping so future sessions resolve silently (the repo slug is derived server-side; your API key pins the workspace). - 0.9.2 —
get_active_workspacereturns an explicit status envelope (resolved/ambiguous/env_default/unresolved) with anextaction, instead of prose; surfaces multi-repo ambiguity. - 0.9.1 — the server now self-reports its real version (was a stale
hardcoded string in
serverInfoand audit logs) and warns at boot when a newer package is published. - 0.9.0 — entity reads on the customer path now route through the broker, fixing an empty roadmap for every customer; new triage + gap tools; light-by-default reads.
Support
- Bugs / feature requests: [email protected]
- Dashboard: https://dashboard.roadmapperai.com
- Docs: https://roadmapperai.com
License
MIT.
