@roadmapperai/mcp 0.1.0 → 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.
Files changed (2) hide show
  1. package/package.json +1 -1
  2. package/server.mjs +49 -3
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@roadmapperai/mcp",
3
- "version": "0.1.0",
3
+ "version": "0.2.0",
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",
package/server.mjs CHANGED
@@ -129,6 +129,18 @@ function supabaseConfig() {
129
129
  readKey: readKey(),
130
130
  writeKey: process.env.SUPABASE_SERVICE_ROLE_KEY || null,
131
131
  workspaceId: process.env.SUPABASE_WORKSPACE_ID || null,
132
+ // ROADMAPPER_API_KEY is the customer-facing path: a per-workspace
133
+ // token (rmpr_…) minted from the dashboard. When set, write tools
134
+ // route through the mcp-broker Edge Function instead of needing
135
+ // a service-role key on the customer's machine. The broker URL
136
+ // defaults to the public Supabase project's edge endpoint but is
137
+ // overridable for self-hosted deployments / staging.
138
+ apiKey: process.env.ROADMAPPER_API_KEY || null,
139
+ brokerUrl:
140
+ process.env.ROADMAPPER_BROKER_URL ||
141
+ (process.env.SUPABASE_URL
142
+ ? `${process.env.SUPABASE_URL.replace(/\/$/, "")}/functions/v1/mcp-broker`
143
+ : null),
132
144
  };
133
145
  }
134
146
 
@@ -350,12 +362,46 @@ function stripUndefined(o) {
350
362
  * function bodies.
351
363
  */
352
364
  async function rpcCall(fn, body) {
353
- const { url, writeKey } = supabaseConfig();
365
+ const { url, writeKey, apiKey, brokerUrl } = supabaseConfig();
354
366
  // body must already carry p_workspace_id — the per-tool resolver
355
367
  // injects it before calling rpcCall so the override path works.
356
- if (!url || !writeKey || !body?.p_workspace_id) {
368
+ if (!url || !body?.p_workspace_id) {
357
369
  throw new Error(
358
- "Write tools require SUPABASE_URL + SUPABASE_SERVICE_ROLE_KEY in env and a resolvable workspaceId (either SUPABASE_WORKSPACE_ID env or workspaceId arg)."
370
+ "Write tools require SUPABASE_URL in env and a resolvable workspaceId (either SUPABASE_WORKSPACE_ID env or workspaceId arg)."
371
+ );
372
+ }
373
+
374
+ // Customer path: ROADMAPPER_API_KEY routes through the mcp-broker
375
+ // Edge Function, which validates the key, hashes it against
376
+ // workspace_api_keys, and performs the RPC with service-role
377
+ // credentials never leaving the server side. This is what the
378
+ // published @roadmapperai/mcp package uses; customers' machines
379
+ // never see SUPABASE_SERVICE_ROLE_KEY.
380
+ if (apiKey && brokerUrl) {
381
+ const res = await fetch(brokerUrl, {
382
+ method: "POST",
383
+ headers: {
384
+ Authorization: `Bearer ${apiKey}`,
385
+ "content-type": "application/json",
386
+ Accept: "application/json",
387
+ },
388
+ body: JSON.stringify({ rpc: fn, body }),
389
+ });
390
+ if (!res.ok) {
391
+ const txt = await res.text();
392
+ throw new Error(
393
+ `mcp-broker rejected ${fn}: ${res.status} ${txt.slice(0, 300)}`
394
+ );
395
+ }
396
+ return res.json();
397
+ }
398
+
399
+ // Operator / dev path: SUPABASE_SERVICE_ROLE_KEY in env — bypasses
400
+ // RLS and the broker. Used in CI and the maintainer's local
401
+ // workspace; not what customers should ever configure.
402
+ if (!writeKey) {
403
+ throw new Error(
404
+ "Write tools require either ROADMAPPER_API_KEY (customer path) or SUPABASE_SERVICE_ROLE_KEY (operator path)."
359
405
  );
360
406
  }
361
407
  const res = await fetch(`${url}/rest/v1/rpc/${fn}`, {