@unified-product-graph/mcp-server 0.8.15 → 0.8.16

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/README.md CHANGED
@@ -21,7 +21,7 @@ For Claude Code, add to `.mcp.json`:
21
21
  ```json
22
22
  {
23
23
  "mcpServers": {
24
- "upg": {
24
+ "unified-product-graph": {
25
25
  "command": "npx",
26
26
  "args": ["upg-mcp-server"]
27
27
  }
@@ -34,7 +34,7 @@ The server auto-discovers `.upg` files in the current directory. To point at a s
34
34
  ```json
35
35
  {
36
36
  "mcpServers": {
37
- "upg": {
37
+ "unified-product-graph": {
38
38
  "command": "npx",
39
39
  "args": ["upg-mcp-server", "--file", "path/to/product.upg"]
40
40
  }
package/TOOLS.md CHANGED
@@ -1,14 +1,14 @@
1
1
  # UPG MCP Server: Tool Reference
2
2
 
3
- Reference for the 99 tools exposed by `@unified-product-graph/mcp-server`. Generated from JSDoc on `src/tools/*.ts` (do not edit by hand).
3
+ Reference for the 106 tools exposed by `@unified-product-graph/mcp-server`. Generated from JSDoc on `src/tools/*.ts` (do not edit by hand).
4
4
 
5
5
  ## Contents
6
6
 
7
7
  - [Context & Session](#context-session): 5 tools
8
8
  - [Nodes](#nodes): 15 tools
9
9
  - [Edges](#edges): 9 tools
10
- - [Areas & Change Log](#areas-change-log): 6 tools
11
- - [Workspace & Portfolios](#workspace-portfolios): 12 tools
10
+ - [Areas & Change Log](#areas-change-log): 10 tools
11
+ - [Workspace & Portfolios](#workspace-portfolios): 15 tools
12
12
  - [Schema](#schema): 1 tool
13
13
  - [Spec Introspection](#spec-introspection): 45 tools
14
14
  - [Cloud Sync](#cloud-sync): 3 tools
@@ -948,10 +948,14 @@ _Product areas, the `.upg-area.json` cwd scoper, and the session change log._
948
948
 
949
949
  - [`assign_product_to_area`](#assign-product-to-area)
950
950
  - [`create_area`](#create-area)
951
+ - [`delete_area`](#delete-area)
951
952
  - [`get_area_context`](#get-area-context)
952
953
  - [`get_area_graph`](#get-area-graph)
953
954
  - [`get_changes`](#get-changes)
954
955
  - [`list_product_areas`](#list-product-areas)
956
+ - [`move_product_to_area`](#move-product-to-area)
957
+ - [`remove_product_from_area`](#remove-product-from-area)
958
+ - [`update_area`](#update-area)
955
959
 
956
960
  ### `assign_product_to_area`
957
961
 
@@ -1009,6 +1013,31 @@ fails.
1009
1013
  **See also:** `list_product_areas`
1010
1014
 
1011
1015
 
1016
+ ### `delete_area`
1017
+
1018
+ Delete a product area from `.upg/portfolio.upg`. Guarded: refuses while the area still has products unless `force: true`. Child areas are un-nested (their parent link is cleared) so no parent reference dangles.
1019
+
1020
+ **Atomicity:** `atomic (single portfolio.upg flush).`
1021
+
1022
+ **Arguments:**
1023
+
1024
+ | Name | Type | Required | Description |
1025
+ | ---- | ---- | -------- | ----------- |
1026
+ | `area_id` | string | ✓ | Product area id to delete (from list_product_areas) |
1027
+ | `force` | boolean | | Delete even if the area still has products (default false) |
1028
+
1029
+ **Returns:**
1030
+
1031
+ JSON: `{ message, area_id, deleted, unnested_children: string[] }`.
1032
+
1033
+ **Throws:**
1034
+
1035
+ - textError on a missing workspace, unknown area, or a non-empty area without
1036
+ `force`.
1037
+
1038
+ **See also:** `create_area`, `remove_product_from_area`
1039
+
1040
+
1012
1041
  ### `get_area_context`
1013
1042
 
1014
1043
  Check whether the current working directory has a `.upg-area.json` that scopes work to a specific product area.
@@ -1093,13 +1122,96 @@ parent_area_id?, products? }>, total }`.
1093
1122
  **See also:** `create_area`, `get_area_graph`
1094
1123
 
1095
1124
 
1125
+ ### `move_product_to_area`
1126
+
1127
+ Move a product to a different product area: remove it from `from_area_id` (or, when omitted, from every area it currently sits in) and add it to `to_area_id`. Convenience over remove_product_from_area + assign_product_to_area.
1128
+
1129
+ **Atomicity:** `atomic (single portfolio.upg flush).`
1130
+
1131
+ **Arguments:**
1132
+
1133
+ | Name | Type | Required | Description |
1134
+ | ---- | ---- | -------- | ----------- |
1135
+ | `from_area_id` | string | | Source area id to remove from; omit to remove from all areas |
1136
+ | `product_id` | string | ✓ | Product id (from list_local_products) |
1137
+ | `to_area_id` | string | ✓ | Destination product area id (from list_product_areas) |
1138
+
1139
+ **Returns:**
1140
+
1141
+ JSON: `{ product_id, to_area_id, to_area_title?, removed_from: string[], added }`.
1142
+
1143
+ **Throws:**
1144
+
1145
+ - textError on a missing workspace, unknown product, or unknown target area.
1146
+
1147
+ **See also:** `assign_product_to_area`, `remove_product_from_area`
1148
+
1149
+
1150
+ ### `remove_product_from_area`
1151
+
1152
+ Remove a product from a product area's `products[]` in `.upg/portfolio.upg` (the product stays registered on the portfolio and in any other container). The inverse of `assign_product_to_area`.
1153
+
1154
+ **Atomicity:** `atomic (single portfolio.upg flush).`
1155
+
1156
+ **Arguments:**
1157
+
1158
+ | Name | Type | Required | Description |
1159
+ | ---- | ---- | -------- | ----------- |
1160
+ | `area_id` | string | ✓ | Product area id (from list_product_areas) |
1161
+ | `product_id` | string | ✓ | Product id (from list_local_products) |
1162
+
1163
+ **Returns:**
1164
+
1165
+ JSON: `{ product_id, container_id, container_kind: "product_area",
1166
+ container_title?, removed }`. `removed: false` (not an error) when the product
1167
+ was not a member, so retries are idempotent.
1168
+
1169
+ **Throws:**
1170
+
1171
+ - textError on a missing workspace or an unknown area id.
1172
+
1173
+ **See also:** `assign_product_to_area`, `move_product_to_area`
1174
+
1175
+
1176
+ ### `update_area`
1177
+
1178
+ Edit a product area in `.upg/portfolio.upg` (title, description, strategic_priority, owner) and/or re-parent it via `parent_area_id`. The mirror of `update_product` for the organisational axis. `parent_area_id` is tri-state: omit to leave unchanged, pass null to un-nest (top-level), or pass an area id to re-parent (rejected if it would create a cycle).
1179
+
1180
+ **Atomicity:** `atomic (single portfolio.upg flush).`
1181
+
1182
+ **Arguments:**
1183
+
1184
+ | Name | Type | Required | Description |
1185
+ | ---- | ---- | -------- | ----------- |
1186
+ | `area_id` | string | ✓ | Product area id to edit (from list_product_areas) |
1187
+ | `description` | string | | New area description |
1188
+ | `owner` | string | | Person or team that owns this area |
1189
+ | `parent_area_id` | string,null | | Re-parent under this area id; null un-nests (top-level); omit to leave unchanged |
1190
+ | `strategic_priority` | `urgent` \| `high` \| `medium` \| `low` \| `none` | | Strategic priority (canonical Priority scale) |
1191
+ | `title` | string | | New area title |
1192
+
1193
+ **Returns:**
1194
+
1195
+ JSON: `{ message, area, updated: string[] }`.
1196
+
1197
+ **Throws:**
1198
+
1199
+ - textError on a missing workspace, unknown area/parent, a re-parent cycle, or
1200
+ when no editable field is supplied.
1201
+
1202
+ **See also:** `create_area`, `list_product_areas`
1203
+
1204
+
1096
1205
  ## Workspace & Portfolios
1097
1206
 
1098
1207
  _Multi-product discovery, switching, init, cross-product edges._
1099
1208
 
1100
1209
  - [`attach_product_to_portfolio`](#attach-product-to-portfolio)
1210
+ - [`batch_create_cross_product_edges`](#batch-create-cross-product-edges)
1101
1211
  - [`create_cross_product_edge`](#create-cross-product-edge)
1102
1212
  - [`create_product`](#create-product)
1213
+ - [`delete_cross_product_edge`](#delete-cross-product-edge)
1214
+ - [`detach_product_from_portfolio`](#detach-product-from-portfolio)
1103
1215
  - [`get_organization`](#get-organization)
1104
1216
  - [`get_workspace_info`](#get-workspace-info)
1105
1217
  - [`init_workspace`](#init-workspace)
@@ -1136,9 +1248,35 @@ portfolio id (the message points at list_portfolios / list_local_products).
1136
1248
  **See also:** `assign_product_to_area`, `create_product`
1137
1249
 
1138
1250
 
1251
+ ### `batch_create_cross_product_edges`
1252
+
1253
+ Create up to 50 cross-product edges in one atomic write (the portfolio-tier mirror of batch_create_edges). Every edge is validated and qualified before anything is written; if any is invalid the whole batch is rejected. Referenced products are auto-registered.
1254
+
1255
+ **Atomicity:** `atomic. All edges validated first, then a single portfolio.upg flush.`
1256
+
1257
+ **Arguments:**
1258
+
1259
+ | Name | Type | Required | Description |
1260
+ | ---- | ---- | -------- | ----------- |
1261
+ | `auto_create_portfolio` | boolean | | Create an empty portfolio document if none exists (default false) |
1262
+ | `edges` | array | ✓ | Cross-product edges to create (max 50). Each: { source_id, target_id, type, source_product_id?, target_product_id? }. |
1263
+
1264
+ **Returns:**
1265
+
1266
+ JSON: `{ message, created: UPGCrossEdge[], count, portfolio_file,
1267
+ registered_products? }`.
1268
+
1269
+ **Throws:**
1270
+
1271
+ - textError when `edges` is missing/empty/oversized, when any edge is invalid,
1272
+ or when no portfolio document exists (pass `auto_create_portfolio: true` to mint one).
1273
+
1274
+ **See also:** `create_cross_product_edge`, `list_cross_edge_types`
1275
+
1276
+
1139
1277
  ### `create_cross_product_edge`
1140
1278
 
1141
- 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`.
1279
+ 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).
1142
1280
 
1143
1281
  **Atomicity:** `non-atomic. Portfolio file create (if new) + edge append are
1144
1282
  separate filesystem operations.`
@@ -1151,7 +1289,7 @@ separate filesystem operations.`
1151
1289
  | `source_product_id` | string | | Product ID of the source node |
1152
1290
  | `target_id` | string | ✓ | Target node ID |
1153
1291
  | `target_product_id` | string | | Product ID of the target node |
1154
- | `type` | `shares_persona` \| `shares_competitor` \| `shares_metric` \| `depends_on_product` \| `cannibalises` \| `succeeds` | ✓ | Cross-product relationship type |
1292
+ | `type` | `shares_persona` \| `shares_competitor` \| `shares_metric` \| `depends_on_product` \| `cannibalises` \| `succeeds` \| `hosts` | ✓ | Cross-product relationship type |
1155
1293
 
1156
1294
  **Returns:**
1157
1295
 
@@ -1197,6 +1335,56 @@ JSON: `{ message, ...result }`. `result` carries `id`, `title`,
1197
1335
  **See also:** `init_workspace`
1198
1336
 
1199
1337
 
1338
+ ### `delete_cross_product_edge`
1339
+
1340
+ Delete a cross-product edge from `.upg/portfolio.upg` by id. The inverse of `create_cross_product_edge`. Returns `deleted: false` (not an error) when no edge with that id exists.
1341
+
1342
+ **Atomicity:** `atomic (single portfolio.upg flush).`
1343
+
1344
+ **Arguments:**
1345
+
1346
+ | Name | Type | Required | Description |
1347
+ | ---- | ---- | -------- | ----------- |
1348
+ | `edge_id` | string | ✓ | Cross-product edge id (from list_portfolio_cross_edges) |
1349
+
1350
+ **Returns:**
1351
+
1352
+ JSON: `{ edge_id, deleted, edge? }`. `deleted: false` (not an error) when
1353
+ no edge with that id exists, so retries are idempotent.
1354
+
1355
+ **Throws:**
1356
+
1357
+ - textError on a missing workspace.
1358
+
1359
+ **See also:** `create_cross_product_edge`, `list_portfolio_cross_edges`
1360
+
1361
+
1362
+ ### `detach_product_from_portfolio`
1363
+
1364
+ Remove a product from a portfolio's `products[]` in `.upg/portfolio.upg` (the product stays registered and in any other container). The inverse of `attach_product_to_portfolio`.
1365
+
1366
+ **Atomicity:** `atomic (single portfolio.upg flush).`
1367
+
1368
+ **Arguments:**
1369
+
1370
+ | Name | Type | Required | Description |
1371
+ | ---- | ---- | -------- | ----------- |
1372
+ | `portfolio_id` | string | ✓ | Portfolio id (from list_portfolios) |
1373
+ | `product_id` | string | ✓ | Product id (from list_local_products) |
1374
+
1375
+ **Returns:**
1376
+
1377
+ JSON: `{ product_id, container_id, container_kind: "portfolio",
1378
+ container_title?, removed }`. `removed: false` (not an error) when the product was
1379
+ not a member, so retries are idempotent.
1380
+
1381
+ **Throws:**
1382
+
1383
+ - textError on a missing workspace or an unknown portfolio id.
1384
+
1385
+ **See also:** `attach_product_to_portfolio`
1386
+
1387
+
1200
1388
  ### `get_organization`
1201
1389
 
1202
1390
  Get the organisation that owns the current workspace's portfolio. Reads the singleton `portfolio.upg.organization`. Returns `{ organization: null }` when no portfolio document exists yet.
@@ -1971,7 +2159,7 @@ JSON: `{ kind, total, count, benchmarks: ... }`
1971
2159
 
1972
2160
  ### `list_cross_edge_types`
1973
2161
 
1974
- List the canonical cross-product edge types from `UPG_CROSS_EDGE_TYPES`: `shares_persona`, `shares_competitor`, `shares_metric`, `depends_on_product`, `cannibalises`, `succeeds`. Portfolio-level relationships across products. Distinct from the within-product `UPG_EDGE_CATALOG`.
2162
+ 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`.
1975
2163
 
1976
2164
  **Atomicity:** `atomic (read-only)`
1977
2165