@unified-product-graph/mcp-server 0.8.6 → 0.8.7

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/CHANGELOG.md CHANGED
@@ -2,6 +2,10 @@
2
2
 
3
3
  All notable changes to `@unified-product-graph/mcp-server` are documented in this file. Format follows [Keep a Changelog](https://keepachangelog.com/en/1.1.0/).
4
4
 
5
+ ## [0.8.7] - 2026-06-03
6
+
7
+ `list_frameworks` now returns a lightweight summary per framework (the full four-layer record was overflowing the tool-result token cap on the default call); `get_framework` returns the full record. `apply_framework` shares one cross-surface envelope with the CLI (`{ exercise_id, exercise, included, warnings }`). `get_framework` gives a helpful error on an unknown id. Last-writer provenance is stamped on writes. The `upg-prioritise` skill teaches the apply/score exercise flow. Co-versions the @unified-product-graph/* 0.8.7 train.
8
+
5
9
  ## [0.8.5] - 2026-06-02
6
10
 
7
11
  Field-report fast-follow (tester report on 0.8.4).
package/TOOLS.md CHANGED
@@ -1413,11 +1413,13 @@ Apply a framework (MoSCoW, RICE, Kano, ...) to a set of entities: creates a fram
1413
1413
 
1414
1414
  **Returns:**
1415
1415
 
1416
- JSON: `{ exercise_id, exercise, included: [{ edge_id, entity_id }], warnings }`.
1416
+ JSON: `{ exercise_id, exercise, included: [{ edge_id, entity_id, edge_type }], warnings }`
1417
+ (the shared cross-surface envelope; identical to CLI `apply --json`).
1417
1418
 
1418
1419
  **Throws:**
1419
1420
 
1420
- - textError on a missing/unknown framework_id.
1421
+ - textError on a missing/unknown framework_id, or when no requested
1422
+ entity resolves (no dangling exercise is left behind).
1421
1423
 
1422
1424
  **See also:** `score_entity`
1423
1425
 
@@ -2021,7 +2023,7 @@ JSON: `{ patterns: string[], total: number }`
2021
2023
 
2022
2024
  ### `list_frameworks`
2023
2025
 
2024
- List the canonical `UPGFramework` definitions; the 34 curated, famous product frameworks that anchor the public catalog (spanning strategy, discovery, prioritisation, design, growth, engineering, and reflection classics). Paginated (default 50, max 200). Cursor is opaque: pass `next_cursor` from a previous response. Optional `category` is exact-match against `UPGFramework.category` and applies before pagination.
2026
+ List the canonical `UPGFramework` definitions: the curated, famous product frameworks that anchor the public catalog (spanning strategy, discovery, prioritisation, design, growth, engineering, and reflection classics). Returns a lightweight summary per framework (id, name, category, description, tags, approach_ids, structure_pattern); call `get_framework(id)` for the full record. Paginated (default 50, max 200). Cursor is opaque: pass `next_cursor` from a previous response. Optional `category` is exact-match against `UPGFramework.category` and applies before pagination.
2025
2027
 
2026
2028
  **Atomicity:** `atomic (read-only)`
2027
2029
 
@@ -2035,7 +2037,7 @@ List the canonical `UPGFramework` definitions; the 34 curated, famous product fr
2035
2037
 
2036
2038
  **Returns:**
2037
2039
 
2038
- JSON: `{ total, count, next_cursor?, frameworks: UPGFramework[] }`
2040
+ JSON: `{ total, count, next_cursor?, frameworks: Array<{ id, name, category, description, tags, approach_ids, structure_pattern }> }`
2039
2041
 
2040
2042
  **See also:** `get_framework`, `list_framework_categories`, `list_framework_structure_patterns`, `prioritise`, `list_approaches`
2041
2043
 
package/dist/index.js CHANGED
@@ -7923,7 +7923,6 @@ function migrateStatusValue(entityType, currentStatus) {
7923
7923
  if (!typeMap) return null;
7924
7924
  return typeMap[currentStatus] ?? null;
7925
7925
  }
7926
- var crossProductEdgeTypeSet = new Set(UPG_CROSS_EDGE_TYPES);
7927
7926
  var UPG_PROPERTY_SCHEMA = {
7928
7927
  // A11yAnnotationProperties: Accessibility annotation.
7929
7928
  a11y_annotation: {
@@ -11080,6 +11079,7 @@ var UPG_PROPERTY_SCHEMA = {
11080
11079
  function getPropertySchema(entityType) {
11081
11080
  return UPG_PROPERTY_SCHEMA[entityType];
11082
11081
  }
11082
+ var crossProductEdgeTypeSet = new Set(UPG_CROSS_EDGE_TYPES);
11083
11083
  var UPG_FRAMEWORKS = [
11084
11084
  {
11085
11085
  "id": "opportunity-solution-tree",
@@ -12315,7 +12315,7 @@ var UPG_FRAMEWORKS = [
12315
12315
  ],
12316
12316
  "name": "RICE Scoring",
12317
12317
  "version": "1.0.0",
12318
- "description": "Score features and opportunities by Reach, Impact, Confidence, and Effort to produce a ranked priority list.",
12318
+ "description": "Score features, opportunities, and needs by Reach, Impact, Confidence, and Effort to produce a ranked priority list.",
12319
12319
  "category": "prioritization",
12320
12320
  "origin": {
12321
12321
  "type": "practitioner",
@@ -12333,7 +12333,7 @@ var UPG_FRAMEWORKS = [
12333
12333
  {
12334
12334
  "label": "Items to score",
12335
12335
  "entityTypeId": "feature",
12336
- "description": "Features, opportunities, or solutions being evaluated"
12336
+ "description": "Features, opportunities, or needs being evaluated"
12337
12337
  },
12338
12338
  {
12339
12339
  "label": "Opportunities to score",
@@ -12499,7 +12499,60 @@ var UPG_FRAMEWORKS = [
12499
12499
  "label": "RICE Score",
12500
12500
  "format": "number"
12501
12501
  }
12502
- ]
12502
+ ],
12503
+ "scoring_lens": {
12504
+ "applies_to": [
12505
+ "feature",
12506
+ "opportunity",
12507
+ "need"
12508
+ ],
12509
+ "inputs": [
12510
+ {
12511
+ "property": "reach",
12512
+ "type": "assessment",
12513
+ "scale_id": "reach_5",
12514
+ "required": true,
12515
+ "scope": "framework",
12516
+ "label": "Reach",
12517
+ "description": "How many users will this impact per quarter?"
12518
+ },
12519
+ {
12520
+ "property": "impact",
12521
+ "type": "assessment",
12522
+ "scale_id": "impact_5",
12523
+ "required": true,
12524
+ "scope": "framework",
12525
+ "label": "Impact",
12526
+ "description": "How much will this impact each user, on the impact scale?"
12527
+ },
12528
+ {
12529
+ "property": "confidence",
12530
+ "type": "assessment",
12531
+ "scale_id": "confidence_5",
12532
+ "required": true,
12533
+ "scope": "framework",
12534
+ "label": "Confidence",
12535
+ "description": "How confident are you in the reach, impact, and effort estimates?"
12536
+ },
12537
+ {
12538
+ "property": "effort",
12539
+ "type": "assessment",
12540
+ "scale_id": "effort_5",
12541
+ "required": true,
12542
+ "scope": "framework",
12543
+ "label": "Effort",
12544
+ "description": "How much work is required to build and ship this, on the effort scale?"
12545
+ }
12546
+ ],
12547
+ "computed": [
12548
+ {
12549
+ "property": "rice_score",
12550
+ "expression": "(reach * impact * confidence) / effort",
12551
+ "label": "RICE Score",
12552
+ "format": "number"
12553
+ }
12554
+ ]
12555
+ }
12503
12556
  },
12504
12557
  "structure": {
12505
12558
  "pattern": "table"
@@ -14624,7 +14677,7 @@ var UPG_FRAMEWORKS = [
14624
14677
  "entity_types": [
14625
14678
  {
14626
14679
  "type": "team",
14627
- "role": "scored_item"
14680
+ "role": "item"
14628
14681
  },
14629
14682
  {
14630
14683
  "type": "retrospective",
@@ -15018,7 +15071,48 @@ var UPG_FRAMEWORKS = [
15018
15071
  "label": "ICE Score",
15019
15072
  "format": "number"
15020
15073
  }
15021
- ]
15074
+ ],
15075
+ "scoring_lens": {
15076
+ "applies_to": [
15077
+ "feature",
15078
+ "opportunity",
15079
+ "need"
15080
+ ],
15081
+ "inputs": [
15082
+ {
15083
+ "property": "impact",
15084
+ "type": "number",
15085
+ "required": true,
15086
+ "scope": "framework",
15087
+ "label": "Impact",
15088
+ "description": "Expected impact on the target metric (1-10)"
15089
+ },
15090
+ {
15091
+ "property": "confidence",
15092
+ "type": "number",
15093
+ "required": true,
15094
+ "scope": "framework",
15095
+ "label": "Confidence",
15096
+ "description": "Confidence in the impact estimate (1-10)"
15097
+ },
15098
+ {
15099
+ "property": "ease",
15100
+ "type": "number",
15101
+ "required": true,
15102
+ "scope": "framework",
15103
+ "label": "Ease",
15104
+ "description": "Ease of implementation (1-10)"
15105
+ }
15106
+ ],
15107
+ "computed": [
15108
+ {
15109
+ "property": "ice_score",
15110
+ "expression": "impact * confidence * ease",
15111
+ "label": "ICE Score",
15112
+ "format": "number"
15113
+ }
15114
+ ]
15115
+ }
15022
15116
  },
15023
15117
  "structure": {
15024
15118
  "pattern": "table"
@@ -15227,7 +15321,55 @@ var UPG_FRAMEWORKS = [
15227
15321
  "label": "WSJF Score",
15228
15322
  "format": "number"
15229
15323
  }
15230
- ]
15324
+ ],
15325
+ "scoring_lens": {
15326
+ "applies_to": [
15327
+ "feature",
15328
+ "opportunity"
15329
+ ],
15330
+ "inputs": [
15331
+ {
15332
+ "property": "user_value",
15333
+ "type": "number",
15334
+ "required": true,
15335
+ "scope": "framework",
15336
+ "label": "User/Business Value",
15337
+ "description": "Relative value to users and the business if delivered"
15338
+ },
15339
+ {
15340
+ "property": "time_criticality",
15341
+ "type": "number",
15342
+ "required": true,
15343
+ "scope": "framework",
15344
+ "label": "Time Criticality",
15345
+ "description": "How much value decays if delivery is delayed (deadlines, competition, seasonal windows)"
15346
+ },
15347
+ {
15348
+ "property": "risk_reduction",
15349
+ "type": "number",
15350
+ "required": true,
15351
+ "scope": "framework",
15352
+ "label": "Risk Reduction / Opportunity Enablement",
15353
+ "description": "Value from reducing risk or enabling future opportunities"
15354
+ },
15355
+ {
15356
+ "property": "job_size",
15357
+ "type": "number",
15358
+ "required": true,
15359
+ "scope": "framework",
15360
+ "label": "Job Size",
15361
+ "description": "Estimated effort (story points, t-shirt size, or person-weeks)"
15362
+ }
15363
+ ],
15364
+ "computed": [
15365
+ {
15366
+ "property": "wsjf_score",
15367
+ "expression": "(user_value + time_criticality + risk_reduction) / job_size",
15368
+ "label": "WSJF Score",
15369
+ "format": "number"
15370
+ }
15371
+ ]
15372
+ }
15231
15373
  },
15232
15374
  "structure": {
15233
15375
  "pattern": "table"
@@ -15300,7 +15442,7 @@ var UPG_FRAMEWORKS = [
15300
15442
  ],
15301
15443
  "name": "Cost of Delay",
15302
15444
  "version": "1.0.0",
15303
- "description": "Quantify the economic cost of not shipping a feature to drive priority decisions. Combines urgency with value.",
15445
+ "description": "Quantify the economic cost of not shipping a feature or opportunity to drive priority decisions. Combines urgency with value.",
15304
15446
  "category": "prioritization",
15305
15447
  "origin": {
15306
15448
  "type": "practitioner",
@@ -15416,7 +15558,39 @@ var UPG_FRAMEWORKS = [
15416
15558
  "label": "WSJF Score",
15417
15559
  "format": "number"
15418
15560
  }
15419
- ]
15561
+ ],
15562
+ "scoring_lens": {
15563
+ "applies_to": [
15564
+ "feature",
15565
+ "opportunity"
15566
+ ],
15567
+ "inputs": [
15568
+ {
15569
+ "property": "cost_of_delay",
15570
+ "type": "number",
15571
+ "required": true,
15572
+ "scope": "framework",
15573
+ "label": "Cost of Delay",
15574
+ "description": "Weekly revenue impact of not shipping"
15575
+ },
15576
+ {
15577
+ "property": "job_size",
15578
+ "type": "number",
15579
+ "required": true,
15580
+ "scope": "framework",
15581
+ "label": "Job Size",
15582
+ "description": "Weeks of development effort"
15583
+ }
15584
+ ],
15585
+ "computed": [
15586
+ {
15587
+ "property": "wsjf_score",
15588
+ "expression": "cost_of_delay / job_size",
15589
+ "label": "WSJF Score",
15590
+ "format": "number"
15591
+ }
15592
+ ]
15593
+ }
15420
15594
  },
15421
15595
  "structure": {
15422
15596
  "pattern": "table"
@@ -24004,7 +24178,7 @@ function serializePortfolioWithHeader(doc, opts) {
24004
24178
  header.integrity = { algorithm: INTEGRITY_ALGORITHM, body: computeBodyChecksum(doc) };
24005
24179
  return JSON.stringify({ $upg: header, ...body }, null, 2) + "\n";
24006
24180
  }
24007
- var UPG_VERSION = "0.8.6";
24181
+ var UPG_VERSION = "0.8.7";
24008
24182
  var MARKDOWN_FORMAT_VERSION = "0.1";
24009
24183
  var UPG_TYPES = getTypes();
24010
24184
  var UPG_TYPES_SET = new Set(UPG_TYPES);
@@ -26513,6 +26687,7 @@ var getEntitySchema = (args, _ctx) => {
26513
26687
  // src/tools/frameworks.ts
26514
26688
  import {
26515
26689
  applyFramework as applyFrameworkLib,
26690
+ applyFrameworkEnvelope,
26516
26691
  scoreEntity as scoreEntityLib
26517
26692
  } from "@unified-product-graph/sdk";
26518
26693
  var applyFramework = (args, ctx) => {
@@ -26528,18 +26703,7 @@ var applyFramework = (args, ctx) => {
26528
26703
  entity_ids: args.entity_ids ?? [],
26529
26704
  status: args.status
26530
26705
  });
26531
- return text(
26532
- JSON.stringify(
26533
- {
26534
- exercise_id: result.exercise.id,
26535
- exercise: result.exercise,
26536
- included: result.edges.map((e) => ({ edge_id: e.id, entity_id: e.target })),
26537
- warnings: result.warnings
26538
- },
26539
- null,
26540
- 2
26541
- )
26542
- );
26706
+ return text(JSON.stringify(applyFrameworkEnvelope(result), null, 2));
26543
26707
  } catch (err) {
26544
26708
  return textError(err.message);
26545
26709
  }
@@ -27286,10 +27450,19 @@ var listFrameworks = (args) => {
27286
27450
  const slice = pool.slice(cursorOffset, cursorOffset + limit);
27287
27451
  const nextOffset = cursorOffset + slice.length;
27288
27452
  const nextCursor = nextOffset < total ? encodeCursor(nextOffset) : void 0;
27453
+ const frameworks = slice.map((f) => ({
27454
+ id: f.id,
27455
+ name: f.name,
27456
+ category: f.category,
27457
+ description: f.description,
27458
+ tags: f.tags,
27459
+ approach_ids: f.approach_ids,
27460
+ structure_pattern: f.structure?.pattern
27461
+ }));
27289
27462
  const body = {
27290
27463
  total,
27291
27464
  count: slice.length,
27292
- frameworks: slice
27465
+ frameworks
27293
27466
  };
27294
27467
  if (nextCursor) body.next_cursor = nextCursor;
27295
27468
  return text(JSON.stringify(body, null, 2));
@@ -27298,7 +27471,10 @@ var getFramework = (args) => {
27298
27471
  const id = args.id;
27299
27472
  if (!id) return textError("Missing required parameter: id");
27300
27473
  const framework = UPG_FRAMEWORKS_BY_ID[id];
27301
- if (!framework) return textError(`Unknown framework id: ${id}`);
27474
+ if (!framework)
27475
+ return textError(
27476
+ `Unknown framework id: "${id}". Pass a framework id from the catalog (e.g. 'moscow', 'rice-scoring', 'kano-model'). See list_frameworks for the full list.`
27477
+ );
27302
27478
  return text(JSON.stringify(framework, null, 2));
27303
27479
  };
27304
27480
  function buildEdgeEntries(filterSource, filterTarget) {
@@ -28989,7 +29165,7 @@ var TOOL_DEFINITIONS = [
28989
29165
  },
28990
29166
  {
28991
29167
  name: "list_frameworks",
28992
- description: "List the canonical `UPGFramework` definitions; the 34 curated, famous product frameworks that anchor the public catalog (spanning strategy, discovery, prioritisation, design, growth, engineering, and reflection classics). Paginated (default 50, max 200). Cursor is opaque: pass `next_cursor` from a previous response. Optional `category` is exact-match against `UPGFramework.category` and applies before pagination.",
29168
+ description: "List the canonical `UPGFramework` definitions: the curated, famous product frameworks that anchor the public catalog (spanning strategy, discovery, prioritisation, design, growth, engineering, and reflection classics). Returns a lightweight summary per framework (id, name, category, description, tags, approach_ids, structure_pattern); call `get_framework(id)` for the full record. Paginated (default 50, max 200). Cursor is opaque: pass `next_cursor` from a previous response. Optional `category` is exact-match against `UPGFramework.category` and applies before pagination.",
28993
29169
  inputSchema: {
28994
29170
  type: "object",
28995
29171
  properties: {
@@ -29918,6 +30094,7 @@ async function runMcpServer() {
29918
30094
  }
29919
30095
  }
29920
30096
  const store = new UPGFileStore();
30097
+ store.setWriter("upg-mcp-local", SERVER_VERSION);
29921
30098
  await store.load(resolvedPath);
29922
30099
  const deprecated = getDeprecatedTypes();
29923
30100
  const nodes = store.getAllNodes();