@roadmapperai/mcp 0.6.0 → 0.7.1
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/package.json +1 -1
- package/server.mjs +42 -4
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@roadmapperai/mcp",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.7.1",
|
|
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
|
@@ -1902,7 +1902,14 @@ async function callTool(name, args) {
|
|
|
1902
1902
|
session.themesListedAt = Date.now();
|
|
1903
1903
|
return suggestThemeFor(args, projected);
|
|
1904
1904
|
case "link_pr":
|
|
1905
|
-
|
|
1905
|
+
// Pass null as the seed reference. linkPR's only use of seed
|
|
1906
|
+
// is to look up legacy seed-bundled PR entries on a task; in
|
|
1907
|
+
// the live path the canonical PRs live on the projected task,
|
|
1908
|
+
// so seed is never the source of truth. Passing the previously-
|
|
1909
|
+
// undefined identifier `seed` raised "seed is not defined" at
|
|
1910
|
+
// runtime for every link_pr call — caught by the live test
|
|
1911
|
+
// drive that exposed bug #5.
|
|
1912
|
+
return linkPR(args, projected, null, wsId);
|
|
1906
1913
|
case "archive_task":
|
|
1907
1914
|
return archiveLifecycle("task", "archive", args, wsId);
|
|
1908
1915
|
case "archive_capability":
|
|
@@ -1943,7 +1950,16 @@ async function proposeTask(args, projected, wsId) {
|
|
|
1943
1950
|
if (!cap) return errorResult(`Capability ${args.capabilityId} not found.`);
|
|
1944
1951
|
const titleErr = validateName(args.title, 5);
|
|
1945
1952
|
if (titleErr) return errorResult(titleErr);
|
|
1946
|
-
|
|
1953
|
+
// Effort is required end-to-end: the schema flags it, and the
|
|
1954
|
+
// Postgres RPC refuses without it. We also raise here so older
|
|
1955
|
+
// clients that ignore the schema get a clear error message before
|
|
1956
|
+
// a round-trip.
|
|
1957
|
+
if (!args.effort) {
|
|
1958
|
+
return errorResult(
|
|
1959
|
+
"effort is required (one of XS, S, M, L, XL). Always size the task — XS (≤2h), S (≤1d), M (~1-3d), L (~1-2w), XL (>2w)."
|
|
1960
|
+
);
|
|
1961
|
+
}
|
|
1962
|
+
if (!VALID_EFFORTS.has(args.effort))
|
|
1947
1963
|
return errorResult(`Invalid effort ${args.effort}.`);
|
|
1948
1964
|
if (args.priority && !VALID_PRIORITIES.has(args.priority))
|
|
1949
1965
|
return errorResult(`Invalid priority ${args.priority}.`);
|
|
@@ -1960,7 +1976,7 @@ async function proposeTask(args, projected, wsId) {
|
|
|
1960
1976
|
)
|
|
1961
1977
|
return errorResult(`expectedScope must be a positive number, got ${args.expectedScope}.`);
|
|
1962
1978
|
|
|
1963
|
-
const effort = args.effort
|
|
1979
|
+
const effort = args.effort;
|
|
1964
1980
|
const start = todayISO();
|
|
1965
1981
|
// Target dates are day-resolution; round up so sub-day estimates
|
|
1966
1982
|
// (XS=0.25, S=0.5) still nudge the target at least one day out.
|
|
@@ -2269,10 +2285,32 @@ function suggestCapabilityFor(args, projected) {
|
|
|
2269
2285
|
(c) => effectiveCapabilityStatus(c, projected.tasks) !== "delivered"
|
|
2270
2286
|
);
|
|
2271
2287
|
const query = tokenize(desc);
|
|
2288
|
+
// Build a richer haystack per capability: include the parent
|
|
2289
|
+
// theme's name+description (vocabulary often overlaps with the
|
|
2290
|
+
// query) and the titles of attached tasks (the *implementation*
|
|
2291
|
+
// language, which is closer to how engineers describe new work
|
|
2292
|
+
// than the bet-style capability outcome statement). This makes
|
|
2293
|
+
// matches that previously scored near zero hit the 0.2+ band
|
|
2294
|
+
// where the model takes them seriously.
|
|
2295
|
+
const themeById = new Map(
|
|
2296
|
+
(projected.themes ?? []).map((t) => [t.id, t])
|
|
2297
|
+
);
|
|
2272
2298
|
const ranked = activeCaps
|
|
2273
2299
|
.map((c) => {
|
|
2300
|
+
const theme = themeById.get(c.pillarId);
|
|
2301
|
+
const taskTitles = (projected.tasks ?? [])
|
|
2302
|
+
.filter((t) => t.capabilityId === c.id)
|
|
2303
|
+
.map((t) => t.title)
|
|
2304
|
+
.join(" ");
|
|
2274
2305
|
const hay = tokenize(
|
|
2275
|
-
|
|
2306
|
+
[
|
|
2307
|
+
c.name,
|
|
2308
|
+
c.description ?? "",
|
|
2309
|
+
c.outcome ?? "",
|
|
2310
|
+
theme?.name ?? "",
|
|
2311
|
+
theme?.description ?? "",
|
|
2312
|
+
taskTitles,
|
|
2313
|
+
].join(" ")
|
|
2276
2314
|
);
|
|
2277
2315
|
return { capability: c, score: jaccardScore(query, hay) };
|
|
2278
2316
|
})
|