@unified-product-graph/mcp-server 0.8.16 → 0.9.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.
@@ -1,8 +1,8 @@
1
1
  {
2
2
  "schema_version": "2",
3
3
  "package": "@unified-product-graph/mcp-server",
4
- "package_version": "0.8.16",
5
- "tool_count": 106,
4
+ "package_version": "0.9.1",
5
+ "tool_count": 108,
6
6
  "domains": [
7
7
  "context",
8
8
  "nodes",
@@ -1952,7 +1952,7 @@
1952
1952
  "assign_product_to_area",
1953
1953
  "create_product"
1954
1954
  ],
1955
- "source": "src/tools/workspace.ts:777",
1955
+ "source": "src/tools/workspace.ts:816",
1956
1956
  "symbol": "attachProductToPortfolioTool",
1957
1957
  "returns": "JSON: `{ product_id, container_id, container_kind: \"portfolio\",\ncontainer_title?, already_member, registered }`.",
1958
1958
  "return_shape": "{ product_id, container_id, container_kind: \"portfolio\", container_title?, already_member, registered }",
@@ -1988,7 +1988,8 @@
1988
1988
  "depends_on_product",
1989
1989
  "cannibalises",
1990
1990
  "succeeds",
1991
- "hosts"
1991
+ "hosts",
1992
+ "contributes_to"
1992
1993
  ],
1993
1994
  "description": "Cross-product relationship type"
1994
1995
  },
@@ -2026,7 +2027,7 @@
2026
2027
  "create_cross_product_edge",
2027
2028
  "list_cross_edge_types"
2028
2029
  ],
2029
- "source": "src/tools/workspace.ts:860",
2030
+ "source": "src/tools/workspace.ts:899",
2030
2031
  "symbol": "batchCreateCrossProductEdges",
2031
2032
  "returns": "JSON: `{ message, created: UPGCrossEdge[], count, portfolio_file,\nregistered_products? }`.",
2032
2033
  "return_shape": "{ message, created: UPGCrossEdge[], count, portfolio_file, registered_products? }",
@@ -2034,7 +2035,7 @@
2034
2035
  },
2035
2036
  {
2036
2037
  "name": "create_cross_product_edge",
2037
- "description": "Create a cross-product relationship between two entities in different products within a portfolio graph. Types: `shares_persona`, `shares_competitor`, `shares_metric`, `depends_on_product`, `cannibalises`, `succeeds`, `hosts` (host product runs the hosted product inside itself, directed host to hosted).",
2038
+ "description": "Create a cross-product relationship between two entities in different products within a portfolio graph. Types: `shares_persona`, `shares_competitor`, `shares_metric`, `depends_on_product`, `cannibalises`, `succeeds`, `hosts` (host product runs the hosted product inside itself, directed host to hosted), `contributes_to` (a product strategy entity rolls up to a higher-level one, e.g. product objective → company objective, product key_result → company key_result; directed subordinate to superior).",
2038
2039
  "domain": "workspace",
2039
2040
  "inputSchema": {
2040
2041
  "type": "object",
@@ -2056,7 +2057,8 @@
2056
2057
  "depends_on_product",
2057
2058
  "cannibalises",
2058
2059
  "succeeds",
2059
- "hosts"
2060
+ "hosts",
2061
+ "contributes_to"
2060
2062
  ],
2061
2063
  "description": "Cross-product relationship type"
2062
2064
  },
@@ -2085,7 +2087,7 @@
2085
2087
  "list_portfolio_cross_edges",
2086
2088
  "migrate_cross_edges"
2087
2089
  ],
2088
- "source": "src/tools/workspace.ts:494",
2090
+ "source": "src/tools/workspace.ts:533",
2089
2091
  "symbol": "createCrossProductEdge",
2090
2092
  "returns": "JSON: `{ edge, portfolio_file }`.",
2091
2093
  "return_shape": "{ edge, portfolio_file }",
@@ -2141,7 +2143,7 @@
2141
2143
  "see": [
2142
2144
  "init_workspace"
2143
2145
  ],
2144
- "source": "src/tools/workspace.ts:335",
2146
+ "source": "src/tools/workspace.ts:374",
2145
2147
  "symbol": "createProductTool",
2146
2148
  "returns": "JSON: `{ message, ...result }`. `result` carries `id`, `title`,\n`slug`, `file_path`, and the optional portfolio edge.",
2147
2149
  "return_shape": "{ message,...result }",
@@ -2175,7 +2177,7 @@
2175
2177
  "create_cross_product_edge",
2176
2178
  "list_portfolio_cross_edges"
2177
2179
  ],
2178
- "source": "src/tools/workspace.ts:831",
2180
+ "source": "src/tools/workspace.ts:870",
2179
2181
  "symbol": "deleteCrossProductEdgeTool",
2180
2182
  "returns": "JSON: `{ edge_id, deleted, edge? }`. `deleted: false` (not an error) when\nno edge with that id exists, so retries are idempotent.",
2181
2183
  "return_shape": "{ edge_id, deleted, edge? }",
@@ -2213,7 +2215,7 @@
2213
2215
  "see": [
2214
2216
  "attach_product_to_portfolio"
2215
2217
  ],
2216
- "source": "src/tools/workspace.ts:804",
2218
+ "source": "src/tools/workspace.ts:843",
2217
2219
  "symbol": "detachProductFromPortfolioTool",
2218
2220
  "returns": "JSON: `{ product_id, container_id, container_kind: \"portfolio\",\ncontainer_title?, removed }`. `removed: false` (not an error) when the product was\nnot a member, so retries are idempotent.",
2219
2221
  "return_shape": "{ product_id, container_id, container_kind: \"portfolio\", container_title?, removed }",
@@ -2242,7 +2244,7 @@
2242
2244
  "see": [
2243
2245
  "list_portfolios"
2244
2246
  ],
2245
- "source": "src/tools/workspace.ts:443",
2247
+ "source": "src/tools/workspace.ts:482",
2246
2248
  "symbol": "getOrganization",
2247
2249
  "returns": "JSON: `{ organization: UPGOrganization | null, portfolio_file? }`.\nReturns `{ organization: null }` when no portfolio document exists yet.",
2248
2250
  "return_shape": "{ organization: UPGOrganization | null, portfolio_file? }",
@@ -2271,7 +2273,7 @@
2271
2273
  "see": [
2272
2274
  "init_workspace"
2273
2275
  ],
2274
- "source": "src/tools/workspace.ts:223",
2276
+ "source": "src/tools/workspace.ts:262",
2275
2277
  "symbol": "getWorkspaceInfo",
2276
2278
  "returns": "JSON: `{ mode, workspace_path?, current_product?, current_file?,\nproducts }`. The shape depends on whether `.upg/workspace.json` exists.",
2277
2279
  "return_shape": "{ mode, workspace_path?, current_product?, current_file?, products }",
@@ -2311,7 +2313,7 @@
2311
2313
  "switch_product",
2312
2314
  "get_workspace_info"
2313
2315
  ],
2314
- "source": "src/tools/workspace.ts:299",
2316
+ "source": "src/tools/workspace.ts:338",
2315
2317
  "symbol": "initWorkspaceTool",
2316
2318
  "returns": "JSON: `{ message, ...result }`. `result` carries the workspace\npath and the moved file's new location.",
2317
2319
  "return_shape": "{ message,...result }",
@@ -2341,7 +2343,7 @@
2341
2343
  "switch_product",
2342
2344
  "get_workspace_info"
2343
2345
  ],
2344
- "source": "src/tools/workspace.ts:48",
2346
+ "source": "src/tools/workspace.ts:98",
2345
2347
  "symbol": "listLocalProducts",
2346
2348
  "returns": "JSON: `{ products: Array<{ file, title, stage, nodes, edges }> }`.\n`stage` is the CANONICAL UPGProductStage (legacy values like `idea` are\ncoerced to `concept`), or `null` when unset — matching what\n`get_product_context` reports for the same product (UPG-611 / DT-MCP-3).",
2347
2349
  "return_shape": "{ products: Array<{ file, title, stage, nodes, edges }> }",
@@ -2364,7 +2366,7 @@
2364
2366
  "see": [
2365
2367
  "create_cross_product_edge"
2366
2368
  ],
2367
- "source": "src/tools/workspace.ts:633",
2369
+ "source": "src/tools/workspace.ts:672",
2368
2370
  "symbol": "listPortfolioCrossEdges",
2369
2371
  "returns": "JSON: `{ cross_edges: UPGCrossEdge[], total, portfolio_file? }`.",
2370
2372
  "return_shape": "{ cross_edges: UPGCrossEdge[], total, portfolio_file? }",
@@ -2391,7 +2393,7 @@
2391
2393
  "create_cross_product_edge",
2392
2394
  "get_organization"
2393
2395
  ],
2394
- "source": "src/tools/workspace.ts:416",
2396
+ "source": "src/tools/workspace.ts:455",
2395
2397
  "symbol": "listPortfolios",
2396
2398
  "returns": "JSON: `{ portfolios: Array<{ id, title, description?,\nparent_portfolio_id?, hierarchy_model?, products? }>, total }`.",
2397
2399
  "return_shape": "{ portfolios: Array<{ id, title, description?, parent_portfolio_id?, hierarchy_model?, products? }>, total }",
@@ -2434,12 +2436,122 @@
2434
2436
  "list_cross_edge_types",
2435
2437
  "init_workspace"
2436
2438
  ],
2437
- "source": "src/tools/workspace.ts:702",
2439
+ "source": "src/tools/workspace.ts:741",
2438
2440
  "symbol": "migrateCrossEdges",
2439
2441
  "returns": "JSON: `{ migrated, skipped, dry_run, portfolio_file? }`.",
2440
2442
  "return_shape": "{ migrated, skipped, dry_run, portfolio_file? }",
2441
2443
  "atomicity": "non-atomic. Portfolio write + product file save are separate."
2442
2444
  },
2445
+ {
2446
+ "name": "portfolio_digest",
2447
+ "description": "Roll up every product's counts, health, and stage-coverage in one call (the multi-product `get_graph_digest`). The strategic-surface read that otherwise required `switch_product` + `get_graph_digest` per graph. Returns per-product summaries plus a portfolio rollup (totals, products-by-stage). Read-only; never mutates active-product state.",
2448
+ "domain": "workspace",
2449
+ "inputSchema": {
2450
+ "type": "object",
2451
+ "properties": {
2452
+ "scope": {
2453
+ "type": "array",
2454
+ "items": {
2455
+ "type": "string"
2456
+ },
2457
+ "description": "Product IDs (or files) to summarise. Omit to summarise ALL products in the workspace."
2458
+ }
2459
+ }
2460
+ },
2461
+ "throws": [],
2462
+ "examples": [],
2463
+ "warnings": [],
2464
+ "see": [
2465
+ "get_graph_digest",
2466
+ "portfolio_query"
2467
+ ],
2468
+ "source": "src/tools/portfolio-read.ts:243",
2469
+ "symbol": "portfolioDigest",
2470
+ "returns": "JSON: `{ products: Array<{ product_id, file, title, stage,\ntotal_nodes, total_edges, health, coverage_pct, top_types }>, rollup:\n{ products, total_nodes, total_edges, by_stage }, errored_products?,\nunmatched_scope? }`. `health`/`coverage_pct` come from `computeGraphDigest`,\nidentical to what `get_graph_digest` reports per product.",
2471
+ "return_shape": "{ products: Array<{ product_id, file, title, stage, total_nodes, total_edges, health, coverage_pct, top_types }>, rollup: { products, total_nodes, total_edges, by_stage }, errored_products?, unmatched_scope? }",
2472
+ "return_notes": [
2473
+ "`health`/`coverage_pct` come from `computeGraphDigest`, identical to what `get_graph_digest` reports per product."
2474
+ ],
2475
+ "atomicity": "atomic (read-only). Never mutates active-product state."
2476
+ },
2477
+ {
2478
+ "name": "portfolio_query",
2479
+ "description": "Traverse the graph ACROSS products in one call (the multi-product `query`). Runs the same BFS (typed-edge traversal + field projection) against every product in scope and tags each subgraph with its source `product_id`, without `switch_product` (the active product is read live; others are read-only). Use for portfolio-level questions (\"every product's strategy region\", \"which products have a persona\"). `from_id` only matches in its owning product. Read-only.",
2480
+ "domain": "workspace",
2481
+ "inputSchema": {
2482
+ "type": "object",
2483
+ "properties": {
2484
+ "from": {
2485
+ "type": "string",
2486
+ "description": "Start from all nodes of this type (in each product)"
2487
+ },
2488
+ "from_id": {
2489
+ "type": "string",
2490
+ "description": "Start from a specific node ID. Node IDs are product-local; only the owning product returns results."
2491
+ },
2492
+ "traverse": {
2493
+ "type": "array",
2494
+ "items": {
2495
+ "type": "string"
2496
+ },
2497
+ "description": "Edge types to follow at each level (in order). If omitted, follows all edges. Prefix with ! to exclude."
2498
+ },
2499
+ "depth": {
2500
+ "type": "number",
2501
+ "description": "Max traversal depth (default 3, max 10)"
2502
+ },
2503
+ "include": {
2504
+ "type": "array",
2505
+ "items": {
2506
+ "type": "string"
2507
+ },
2508
+ "description": "Fields per node: \"title\", \"status\", \"tags\", \"description\", \"properties\" (default: title, status, type)"
2509
+ },
2510
+ "limit": {
2511
+ "type": "number",
2512
+ "description": "Max nodes per product (default 100, max 1000)"
2513
+ },
2514
+ "edge_include": {
2515
+ "type": "array",
2516
+ "items": {
2517
+ "type": "string"
2518
+ },
2519
+ "description": "Edge fields to return: \"id\", \"type\", \"source\", \"target\". Empty array = no edges. Default: all fields."
2520
+ },
2521
+ "property_include": {
2522
+ "type": "array",
2523
+ "items": {
2524
+ "type": "string"
2525
+ },
2526
+ "description": "When \"properties\" is in include, only return these property keys."
2527
+ },
2528
+ "scope": {
2529
+ "type": "array",
2530
+ "items": {
2531
+ "type": "string"
2532
+ },
2533
+ "description": "Product IDs (or files) to query. Omit to query ALL products in the workspace. Match by product id, relative file, or basename."
2534
+ }
2535
+ }
2536
+ },
2537
+ "throws": [],
2538
+ "examples": [],
2539
+ "warnings": [],
2540
+ "see": [
2541
+ "query",
2542
+ "portfolio_digest",
2543
+ "list_local_products"
2544
+ ],
2545
+ "source": "src/tools/portfolio-read.ts:119",
2546
+ "symbol": "portfolioQuery",
2547
+ "returns": "JSON: `{ products: Array<{ product_id, file, title, total_nodes,\ntotal_edges, nodes, edges, truncated? }>, products_searched,\nproducts_with_matches, empty_products, unmatched_scope? }`. Products that\nmatched zero nodes are summarised in `empty_products`, not expanded, to\nkeep the payload lean. `from_id` only matches in its owning product; the\nrest report empty.",
2548
+ "return_shape": "{ products: Array<{ product_id, file, title, total_nodes, total_edges, nodes, edges, truncated? }>, products_searched, products_with_matches, empty_products, unmatched_scope? }",
2549
+ "return_notes": [
2550
+ "Products that matched zero nodes are summarised in `empty_products`, not expanded, to keep the payload lean.",
2551
+ "`from_id` only matches in its owning product; the rest report empty."
2552
+ ],
2553
+ "atomicity": "atomic (read-only). Never mutates active-product state."
2554
+ },
2443
2555
  {
2444
2556
  "name": "switch_product",
2445
2557
  "description": "Switch to a different .upg file without restarting the server. In workspace mode, accepts just a filename (e.g. \"client-project\" or \"client-project.upg\").",
@@ -2472,7 +2584,7 @@
2472
2584
  "list_local_products",
2473
2585
  "init_workspace"
2474
2586
  ],
2475
- "source": "src/tools/workspace.ts:160",
2587
+ "source": "src/tools/workspace.ts:190",
2476
2588
  "symbol": "switchProduct",
2477
2589
  "returns": "JSON: `{ message, file, product: { title, stage }, entities }`.",
2478
2590
  "return_shape": "{ message, file, product: { title, stage }, entities }",
@@ -2515,7 +2627,7 @@
2515
2627
  "see": [
2516
2628
  "create_product"
2517
2629
  ],
2518
- "source": "src/tools/workspace.ts:376",
2630
+ "source": "src/tools/workspace.ts:415",
2519
2631
  "symbol": "updateProductTool",
2520
2632
  "returns": "JSON: `{ product, updated: string[] }` (the fields changed).",
2521
2633
  "return_shape": "{ product, updated: string[] }",
@@ -3464,7 +3576,7 @@
3464
3576
  },
3465
3577
  {
3466
3578
  "name": "list_cross_edge_types",
3467
- "description": "List the canonical cross-product edge types from `UPG_CROSS_EDGE_TYPES`: `shares_persona`, `shares_competitor`, `shares_metric`, `depends_on_product`, `cannibalises`, `succeeds`, `hosts`. Portfolio-level relationships across products. Distinct from the within-product `UPG_EDGE_CATALOG`.",
3579
+ "description": "List the canonical cross-product edge types from `UPG_CROSS_EDGE_TYPES`: `shares_persona`, `shares_competitor`, `shares_metric`, `depends_on_product`, `cannibalises`, `succeeds`, `hosts`, `contributes_to`. Portfolio-level relationships across products. Distinct from the within-product `UPG_EDGE_CATALOG`.",
3468
3580
  "domain": "spec",
3469
3581
  "inputSchema": {
3470
3582
  "type": "object",
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@unified-product-graph/mcp-server",
3
- "version": "0.8.16",
3
+ "version": "0.9.1",
4
4
  "description": "Local MCP server for .upg files. Read and write product knowledge graphs offline.",
5
5
  "license": "MIT",
6
6
  "author": "The Product Creator <hello@theproductcreator.com>",
@@ -52,8 +52,8 @@
52
52
  },
53
53
  "dependencies": {
54
54
  "@modelcontextprotocol/sdk": "^1.27.0",
55
- "@unified-product-graph/core": "0.8.16",
56
- "@unified-product-graph/sdk": "0.8.16",
55
+ "@unified-product-graph/core": "0.9.1",
56
+ "@unified-product-graph/sdk": "0.9.1",
57
57
  "chokidar": "^4.0.0",
58
58
  "nanoid": "^5.1.0"
59
59
  },