@roadmapperai/mcp 0.6.0 → 0.7.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.
- package/package.json +1 -1
- package/server.mjs +34 -3
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@roadmapperai/mcp",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.7.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
|
@@ -1943,7 +1943,16 @@ async function proposeTask(args, projected, wsId) {
|
|
|
1943
1943
|
if (!cap) return errorResult(`Capability ${args.capabilityId} not found.`);
|
|
1944
1944
|
const titleErr = validateName(args.title, 5);
|
|
1945
1945
|
if (titleErr) return errorResult(titleErr);
|
|
1946
|
-
|
|
1946
|
+
// Effort is required end-to-end: the schema flags it, and the
|
|
1947
|
+
// Postgres RPC refuses without it. We also raise here so older
|
|
1948
|
+
// clients that ignore the schema get a clear error message before
|
|
1949
|
+
// a round-trip.
|
|
1950
|
+
if (!args.effort) {
|
|
1951
|
+
return errorResult(
|
|
1952
|
+
"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)."
|
|
1953
|
+
);
|
|
1954
|
+
}
|
|
1955
|
+
if (!VALID_EFFORTS.has(args.effort))
|
|
1947
1956
|
return errorResult(`Invalid effort ${args.effort}.`);
|
|
1948
1957
|
if (args.priority && !VALID_PRIORITIES.has(args.priority))
|
|
1949
1958
|
return errorResult(`Invalid priority ${args.priority}.`);
|
|
@@ -1960,7 +1969,7 @@ async function proposeTask(args, projected, wsId) {
|
|
|
1960
1969
|
)
|
|
1961
1970
|
return errorResult(`expectedScope must be a positive number, got ${args.expectedScope}.`);
|
|
1962
1971
|
|
|
1963
|
-
const effort = args.effort
|
|
1972
|
+
const effort = args.effort;
|
|
1964
1973
|
const start = todayISO();
|
|
1965
1974
|
// Target dates are day-resolution; round up so sub-day estimates
|
|
1966
1975
|
// (XS=0.25, S=0.5) still nudge the target at least one day out.
|
|
@@ -2269,10 +2278,32 @@ function suggestCapabilityFor(args, projected) {
|
|
|
2269
2278
|
(c) => effectiveCapabilityStatus(c, projected.tasks) !== "delivered"
|
|
2270
2279
|
);
|
|
2271
2280
|
const query = tokenize(desc);
|
|
2281
|
+
// Build a richer haystack per capability: include the parent
|
|
2282
|
+
// theme's name+description (vocabulary often overlaps with the
|
|
2283
|
+
// query) and the titles of attached tasks (the *implementation*
|
|
2284
|
+
// language, which is closer to how engineers describe new work
|
|
2285
|
+
// than the bet-style capability outcome statement). This makes
|
|
2286
|
+
// matches that previously scored near zero hit the 0.2+ band
|
|
2287
|
+
// where the model takes them seriously.
|
|
2288
|
+
const themeById = new Map(
|
|
2289
|
+
(projected.themes ?? []).map((t) => [t.id, t])
|
|
2290
|
+
);
|
|
2272
2291
|
const ranked = activeCaps
|
|
2273
2292
|
.map((c) => {
|
|
2293
|
+
const theme = themeById.get(c.pillarId);
|
|
2294
|
+
const taskTitles = (projected.tasks ?? [])
|
|
2295
|
+
.filter((t) => t.capabilityId === c.id)
|
|
2296
|
+
.map((t) => t.title)
|
|
2297
|
+
.join(" ");
|
|
2274
2298
|
const hay = tokenize(
|
|
2275
|
-
|
|
2299
|
+
[
|
|
2300
|
+
c.name,
|
|
2301
|
+
c.description ?? "",
|
|
2302
|
+
c.outcome ?? "",
|
|
2303
|
+
theme?.name ?? "",
|
|
2304
|
+
theme?.description ?? "",
|
|
2305
|
+
taskTitles,
|
|
2306
|
+
].join(" ")
|
|
2276
2307
|
);
|
|
2277
2308
|
return { capability: c, score: jaccardScore(query, hay) };
|
|
2278
2309
|
})
|