@miragon/design-iq-mcp 5.0.0-rc.0 → 5.1.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/README.md +8 -6
- package/dist/http.js +1 -1
- package/dist/server.js +1 -1
- package/dist/{tools-V_22sqM1.js → tools-8vgJc4aD.js} +50 -24
- package/package.json +12 -6
package/README.md
CHANGED
|
@@ -1,11 +1,13 @@
|
|
|
1
1
|
# @miragon/design-iq-mcp
|
|
2
2
|
|
|
3
|
-
designIQ's read-only MCP server: it exposes a
|
|
4
|
-
(
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
3
|
+
designIQ's read-only MCP server: it exposes the models of a designIQ content repo — processes
|
|
4
|
+
(BPMN), decisions (DMN), Wardley Maps, Team Topologies, Event Storming boards, Context Maps,
|
|
5
|
+
Value Chains and Markdown — to any MCP client (Claude Code, Claude Desktop, IDEs, ...). A
|
|
6
|
+
content repo is a root `designiq.yml` naming its models folder (`models:`, legacy alias
|
|
7
|
+
`processes:`; the legacy file name `bpmiq.yml` is still read); a model IS a file with a
|
|
8
|
+
registered notation extension there (a process its `.bpmn`). Views are **derived from the
|
|
9
|
+
models** on the fly; BPMN gets the richest one — name, roles (BPMN lanes), steps, gateways,
|
|
10
|
+
flow, and sub-process calls. Tools:
|
|
9
11
|
`list_models`, `list_processes`, `get_process`, `get_view`, `get_model`, `enumerate_paths`,
|
|
10
12
|
`find_cycles`, `who_owns`, `which_processes_use`, `which_models_use`. Read-only by
|
|
11
13
|
construction: the tools only ever read files, and all of them carry `readOnlyHint`.
|
package/dist/http.js
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
|
-
import { n as createMcpServer, r as todosConfigFromEnv, t as DEFAULT_ROOT } from "./tools-
|
|
2
|
+
import { n as createMcpServer, r as todosConfigFromEnv, t as DEFAULT_ROOT } from "./tools-8vgJc4aD.js";
|
|
3
3
|
import { createServer } from "node:http";
|
|
4
4
|
import { timingSafeEqual } from "node:crypto";
|
|
5
5
|
import { NodeStreamableHTTPServerTransport } from "@modelcontextprotocol/node";
|
package/dist/server.js
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
|
-
import { n as createMcpServer, r as todosConfigFromEnv, t as DEFAULT_ROOT } from "./tools-
|
|
2
|
+
import { n as createMcpServer, r as todosConfigFromEnv, t as DEFAULT_ROOT } from "./tools-8vgJc4aD.js";
|
|
3
3
|
import { existsSync } from "node:fs";
|
|
4
4
|
import { resolve } from "node:path";
|
|
5
5
|
import { StdioServerTransport } from "@modelcontextprotocol/server/stdio";
|
|
@@ -93,8 +93,8 @@ const NOTATIONS = [
|
|
|
93
93
|
id: "wardley",
|
|
94
94
|
label: "Wardley Map",
|
|
95
95
|
noun: {
|
|
96
|
-
singular: "
|
|
97
|
-
plural: "
|
|
96
|
+
singular: "Wardley Map",
|
|
97
|
+
plural: "Wardley Maps"
|
|
98
98
|
},
|
|
99
99
|
extensions: [".owm", ".wmap"],
|
|
100
100
|
mediaKind: "dsl",
|
|
@@ -109,8 +109,8 @@ const NOTATIONS = [
|
|
|
109
109
|
id: "team-topology",
|
|
110
110
|
label: "Team Topology",
|
|
111
111
|
noun: {
|
|
112
|
-
singular: "
|
|
113
|
-
plural: "
|
|
112
|
+
singular: "Team Topology",
|
|
113
|
+
plural: "Team Topologies"
|
|
114
114
|
},
|
|
115
115
|
extensions: [".tt", ".ttm.json"],
|
|
116
116
|
mediaKind: "json",
|
|
@@ -121,8 +121,8 @@ const NOTATIONS = [
|
|
|
121
121
|
id: "event-storming",
|
|
122
122
|
label: "Event Storming",
|
|
123
123
|
noun: {
|
|
124
|
-
singular: "
|
|
125
|
-
plural: "
|
|
124
|
+
singular: "Event Storming board",
|
|
125
|
+
plural: "Event Storming boards"
|
|
126
126
|
},
|
|
127
127
|
extensions: [".storm"],
|
|
128
128
|
mediaKind: "dsl",
|
|
@@ -137,8 +137,8 @@ const NOTATIONS = [
|
|
|
137
137
|
id: "context-map",
|
|
138
138
|
label: "Context Map",
|
|
139
139
|
noun: {
|
|
140
|
-
singular: "
|
|
141
|
-
plural: "
|
|
140
|
+
singular: "Context Map",
|
|
141
|
+
plural: "Context Maps"
|
|
142
142
|
},
|
|
143
143
|
extensions: [".cm.json"],
|
|
144
144
|
mediaKind: "json",
|
|
@@ -159,8 +159,8 @@ const NOTATIONS = [
|
|
|
159
159
|
id: "value-chain",
|
|
160
160
|
label: "Value Chain",
|
|
161
161
|
noun: {
|
|
162
|
-
singular: "
|
|
163
|
-
plural: "
|
|
162
|
+
singular: "Value Chain",
|
|
163
|
+
plural: "Value Chains"
|
|
164
164
|
},
|
|
165
165
|
extensions: [".vc.json"],
|
|
166
166
|
mediaKind: "json",
|
|
@@ -1342,7 +1342,7 @@ const DERIVERS = {
|
|
|
1342
1342
|
return {
|
|
1343
1343
|
notation: "wardley",
|
|
1344
1344
|
name: null,
|
|
1345
|
-
summary: `Wardley
|
|
1345
|
+
summary: `Wardley Map with ${counted(stats)}`,
|
|
1346
1346
|
stats
|
|
1347
1347
|
};
|
|
1348
1348
|
},
|
|
@@ -1354,7 +1354,7 @@ const DERIVERS = {
|
|
|
1354
1354
|
return {
|
|
1355
1355
|
notation: "team-topology",
|
|
1356
1356
|
name: null,
|
|
1357
|
-
summary: `Team
|
|
1357
|
+
summary: `Team Topology with ${counted(stats)}`,
|
|
1358
1358
|
stats
|
|
1359
1359
|
};
|
|
1360
1360
|
},
|
|
@@ -1378,7 +1378,7 @@ const DERIVERS = {
|
|
|
1378
1378
|
return {
|
|
1379
1379
|
notation: "event-storming",
|
|
1380
1380
|
name: typeof title === "string" ? title : null,
|
|
1381
|
-
summary: `Event
|
|
1381
|
+
summary: `Event Storming board with ${Object.keys(present).length > 0 ? counted(present) : "no elements"}`,
|
|
1382
1382
|
stats,
|
|
1383
1383
|
detail: {
|
|
1384
1384
|
level: graph.meta?.level ?? null,
|
|
@@ -1401,7 +1401,7 @@ const DERIVERS = {
|
|
|
1401
1401
|
return {
|
|
1402
1402
|
notation: "context-map",
|
|
1403
1403
|
name: typeof title === "string" ? title : null,
|
|
1404
|
-
summary: `Context
|
|
1404
|
+
summary: `Context Map with ${counted({ contexts: stats.contexts })}${breakdown(CM_SUBDOMAIN_TYPES)}, ${counted({ relationships: stats.relationships })}${breakdown(CM_RELATIONSHIP_PATTERNS)}`,
|
|
1405
1405
|
stats,
|
|
1406
1406
|
detail: {
|
|
1407
1407
|
contexts: graph.nodes.map((n) => ({
|
|
@@ -1432,7 +1432,7 @@ const DERIVERS = {
|
|
|
1432
1432
|
return {
|
|
1433
1433
|
notation: "value-chain",
|
|
1434
1434
|
name: null,
|
|
1435
|
-
summary: `Value
|
|
1435
|
+
summary: `Value Chain with ${counted(stats)}`,
|
|
1436
1436
|
stats
|
|
1437
1437
|
};
|
|
1438
1438
|
}
|
|
@@ -1583,6 +1583,20 @@ function todosConfigFromEnv(env) {
|
|
|
1583
1583
|
apiUrl: env.GITHUB_API_URL
|
|
1584
1584
|
} : void 0;
|
|
1585
1585
|
}
|
|
1586
|
+
/** "a, b and c" */
|
|
1587
|
+
const andList = (items) => items.length < 2 ? items.join("") : `${items.slice(0, -1).join(", ")} and ${items.at(-1)}`;
|
|
1588
|
+
/** every registered notation with its file extensions */
|
|
1589
|
+
const NOTATION_FILES = andList(NOTATIONS.map((n) => `${n.label} (${n.extensions.join("/")})`));
|
|
1590
|
+
function readOnlyInstructions(on) {
|
|
1591
|
+
return [
|
|
1592
|
+
"designIQ is a Git-native workspace where teams model their business and their architecture together, live; this server reads one checkout of such a repository and never writes.",
|
|
1593
|
+
`The repository keeps its models as files under the folder its designiq.yml names, one model per file with the file stem as its id, in these notations: ${NOTATION_FILES}.`,
|
|
1594
|
+
"Start with `list_models` to see which models it holds.",
|
|
1595
|
+
"These tools are notation-neutral: `get_view` (the derived structure), `get_model` (the raw graph of nodes and edges), `enumerate_paths` and `find_cycles` (flow analysis where the notation has flow semantics) and `which_models_use` (which models reference a given one).",
|
|
1596
|
+
"BPMN has deeper tooling: `list_processes`, `get_process` (the derived process view: roles, steps, flow, sub-process calls), `who_owns` (ownership from lanes) and `which_processes_use`" + (on.todos ? "; `list_todos` lists the open todos anchored to processes." : "."),
|
|
1597
|
+
"Live editing, the modeler widgets and release as a pull request are on the designIQ Live Host, not here."
|
|
1598
|
+
].join(" ");
|
|
1599
|
+
}
|
|
1586
1600
|
/** Build a fully configured, read-only MCP server over the repo at `root`. */
|
|
1587
1601
|
function createMcpServer(root = DEFAULT_ROOT, todos, contributions = []) {
|
|
1588
1602
|
const config = () => loadContentConfig(root);
|
|
@@ -1614,17 +1628,19 @@ function createMcpServer(root = DEFAULT_ROOT, todos, contributions = []) {
|
|
|
1614
1628
|
return graph;
|
|
1615
1629
|
};
|
|
1616
1630
|
const isGraph = (g) => !("content" in g);
|
|
1617
|
-
/** the registry nouns for user-facing copy ("
|
|
1631
|
+
/** the registry nouns for user-facing copy ("Wardley Map" / "Team Topologies") */
|
|
1618
1632
|
const nounOf = (notation) => byId(notation)?.noun.singular ?? notation;
|
|
1619
1633
|
const pluralOf = (notation) => byId(notation)?.noun.plural ?? notation;
|
|
1620
1634
|
const notAContentRepo = () => fail(`No usable designiq.yml (or legacy bpmiq.yml) at the content root — not a content repo. Expected a root designiq.yml naming the models folder.`);
|
|
1621
1635
|
const unknownProcess = async (id) => fail(`Unknown process '${id}'. Available: ${(await processes()).map((p) => p.id).join(", ") || "(none)"}.`);
|
|
1622
1636
|
const server = new McpServer({
|
|
1623
1637
|
name: "designiq-mcp",
|
|
1638
|
+
title: "designIQ model repository (read-only)",
|
|
1624
1639
|
version: "0.2.0"
|
|
1625
|
-
});
|
|
1640
|
+
}, { instructions: readOnlyInstructions({ todos: todos !== void 0 }) });
|
|
1626
1641
|
server.registerTool("list_models", {
|
|
1627
|
-
|
|
1642
|
+
title: "List models",
|
|
1643
|
+
description: `List EVERY model file of the repository, grouped by notation (${NOTATIONS.map((n) => n.id).join(", ")}) — the starting point for any question. Each row: id (file stem), path, and — for notations with a registered deriver — the model's own name, summary and stats. Use to see which notations a repo contains before reaching for the notation-specific tools; list_processes is the BPMN-only listing.`,
|
|
1628
1644
|
annotations: READ_ONLY
|
|
1629
1645
|
}, safe(async () => {
|
|
1630
1646
|
const cfg = config();
|
|
@@ -1654,7 +1670,8 @@ function createMcpServer(root = DEFAULT_ROOT, todos, contributions = []) {
|
|
|
1654
1670
|
return ok({ models: grouped });
|
|
1655
1671
|
}));
|
|
1656
1672
|
server.registerTool("list_processes", {
|
|
1657
|
-
|
|
1673
|
+
title: "List BPMN processes",
|
|
1674
|
+
description: "BPMN only: list the processes — every .bpmn file under the repo's designiq.yml models folder. Each row: id (file name without extension), derived name, the file path, and a count of steps/events/gateways/roles. Use for a process overview or to find a process id before calling get_process, get_model, who_owns or enumerate_paths; list_models covers every notation.",
|
|
1658
1675
|
annotations: READ_ONLY
|
|
1659
1676
|
}, safe(async () => {
|
|
1660
1677
|
if (!config()) return notAContentRepo();
|
|
@@ -1677,7 +1694,8 @@ function createMcpServer(root = DEFAULT_ROOT, todos, contributions = []) {
|
|
|
1677
1694
|
}));
|
|
1678
1695
|
}));
|
|
1679
1696
|
server.registerTool("get_process", {
|
|
1680
|
-
|
|
1697
|
+
title: "Get BPMN process view",
|
|
1698
|
+
description: "BPMN only: get one process in full — the process view DERIVED from its BPMN: name, roles (BPMN lanes = owning teams), steps (activities with their role), events, gateways, the sequence/message flow, and the sub-processes it calls (callActivity → calledElement). Use for walkthroughs and any deep question about a single process; get_view covers every notation.",
|
|
1681
1699
|
inputSchema: z.object({ id: z.string().describe("Process id = the .bpmn file name without extension, e.g. order-to-cash") }),
|
|
1682
1700
|
annotations: READ_ONLY
|
|
1683
1701
|
}, safe(async ({ id }) => {
|
|
@@ -1693,6 +1711,7 @@ function createMcpServer(root = DEFAULT_ROOT, todos, contributions = []) {
|
|
|
1693
1711
|
});
|
|
1694
1712
|
}));
|
|
1695
1713
|
server.registerTool("get_model", {
|
|
1714
|
+
title: "Get model graph",
|
|
1696
1715
|
description: "Parse ANY model file into its generic graph: nodes (id, type, name), edges and meta — BPMN flows and lanes, DMN requirements, Wardley components/dependencies, … Use to see the raw structure, or to ground any 'how does X work' answer in the actual model.",
|
|
1697
1716
|
inputSchema: z.object({
|
|
1698
1717
|
id: z.string().describe("Model id = file stem (from list_models), e.g. order-to-cash"),
|
|
@@ -1711,7 +1730,8 @@ function createMcpServer(root = DEFAULT_ROOT, todos, contributions = []) {
|
|
|
1711
1730
|
}) : graph;
|
|
1712
1731
|
}));
|
|
1713
1732
|
server.registerTool("get_view", {
|
|
1714
|
-
|
|
1733
|
+
title: "Get model view",
|
|
1734
|
+
description: `The derived view of ANY model — its own name, a one-line summary, stats, and the rich notation payload in \`detail\` where one exists (the process view for BPMN, the decision tables for DMN). Works for every notation with extract+derive capabilities (${NOTATIONS.filter((n) => hasDeriver(n.id)).map((n) => n.id).join(", ")}).`,
|
|
1715
1735
|
inputSchema: z.object({
|
|
1716
1736
|
id: z.string().describe("Model id = file stem (from list_models), e.g. tea-shop"),
|
|
1717
1737
|
notation: z.string().optional().describe("registry notation id — disambiguates a stem shared across notations")
|
|
@@ -1732,6 +1752,7 @@ function createMcpServer(root = DEFAULT_ROOT, todos, contributions = []) {
|
|
|
1732
1752
|
});
|
|
1733
1753
|
}));
|
|
1734
1754
|
server.registerTool("enumerate_paths", {
|
|
1755
|
+
title: "Enumerate flow paths",
|
|
1735
1756
|
description: "Enumerate the possible start→end paths through a model's flow (cycle-safe, capped) — BPMN sequence flows, Wardley dependencies, … per the notation's graph hints. Each path is the ordered list of element names. Use for walkthroughs ('what are the ways an order can go?'), test-case derivation, and spotting unexpected shortcuts or dead branches.",
|
|
1736
1757
|
inputSchema: z.object({
|
|
1737
1758
|
id: z.string().describe("Model id = file stem, e.g. order-to-cash"),
|
|
@@ -1757,6 +1778,7 @@ function createMcpServer(root = DEFAULT_ROOT, todos, contributions = []) {
|
|
|
1757
1778
|
});
|
|
1758
1779
|
}));
|
|
1759
1780
|
server.registerTool("find_cycles", {
|
|
1781
|
+
title: "Find flow cycles",
|
|
1760
1782
|
description: "Detect cycles (loops) in a model's flow — BPMN rework/retry loops, circular Wardley dependencies, circular DMN requirements — per the notation's graph hints. Returns each cycle as the ordered list of element names. Use when analyzing complexity, rework cost, or 'why does this case never finish'.",
|
|
1761
1783
|
inputSchema: z.object({
|
|
1762
1784
|
id: z.string().describe("Model id = file stem, e.g. order-to-cash"),
|
|
@@ -1778,7 +1800,8 @@ function createMcpServer(root = DEFAULT_ROOT, todos, contributions = []) {
|
|
|
1778
1800
|
});
|
|
1779
1801
|
}));
|
|
1780
1802
|
server.registerTool("who_owns", {
|
|
1781
|
-
|
|
1803
|
+
title: "Find who owns a BPMN process",
|
|
1804
|
+
description: "BPMN only: resolve ownership of a process from its lanes — the roles/teams that own its steps (each lane, with the steps it contains) plus the pools (participants). Use for 'who owns X', 'who does what in X', or handoff questions. Note: on the slim contract ownership is whatever the model's lanes say; a process with no lanes has no modeled owner.",
|
|
1782
1805
|
inputSchema: z.object({ id: z.string().describe("Process id, e.g. order-to-cash") }),
|
|
1783
1806
|
annotations: READ_ONLY
|
|
1784
1807
|
}, safe(async ({ id }) => {
|
|
@@ -1800,7 +1823,8 @@ function createMcpServer(root = DEFAULT_ROOT, todos, contributions = []) {
|
|
|
1800
1823
|
});
|
|
1801
1824
|
}));
|
|
1802
1825
|
server.registerTool("which_processes_use", {
|
|
1803
|
-
|
|
1826
|
+
title: "Search BPMN processes",
|
|
1827
|
+
description: "BPMN only: find processes whose id, derived name, role/lane names, step names, or sub-process calls (calledElement) match a query — case-insensitive substring. Use for 'what calls invoice-handling', 'which processes have a Billing lane', 'what touches the credit check'. which_models_use follows references across every notation.",
|
|
1804
1828
|
inputSchema: z.object({ query: z.string().describe("Case-insensitive substring, e.g. 'invoice-handling', 'Billing', 'credit'") }),
|
|
1805
1829
|
annotations: READ_ONLY
|
|
1806
1830
|
}, safe(async ({ query }) => {
|
|
@@ -1834,7 +1858,8 @@ function createMcpServer(root = DEFAULT_ROOT, todos, contributions = []) {
|
|
|
1834
1858
|
return ok(hits);
|
|
1835
1859
|
}));
|
|
1836
1860
|
server.registerTool("which_models_use", {
|
|
1837
|
-
|
|
1861
|
+
title: "Find models that reference a model",
|
|
1862
|
+
description: "Reference-level impact analysis across EVERY notation: all models whose typed cross-model references (callActivity calls, businessRuleTask decides, …) point at the given model id (file stem, exact match) — the repo-wide reference index behind it also flags dangling references. Use for 'what breaks if I change or delete this model?'.",
|
|
1838
1863
|
inputSchema: z.object({ id: z.string().describe("Target model id = file stem (from list_models), e.g. 'credit-check'") }),
|
|
1839
1864
|
annotations: READ_ONLY
|
|
1840
1865
|
}, safe(async ({ id }) => {
|
|
@@ -1858,6 +1883,7 @@ function createMcpServer(root = DEFAULT_ROOT, todos, contributions = []) {
|
|
|
1858
1883
|
const { repo: todosRepo, token: todosToken } = todos;
|
|
1859
1884
|
const api = (todos.apiUrl ?? "https://api.github.com").replace(/\/$/, "");
|
|
1860
1885
|
server.registerTool("list_todos", {
|
|
1886
|
+
title: "List open todos",
|
|
1861
1887
|
description: "List the OPEN model-anchored todos of this content repo — work items filed from the live model into the repo's issue tracker (label 'todo'). Each row carries the tracker id and URL, title, assignees, createdAt and the parsed anchor (process, model file, anchored BPMN elements). Optional filter on one process. Use for 'what is open on process X' or to cross-check a model answer against known open discrepancies.",
|
|
1862
1888
|
inputSchema: z.object({ process: z.string().optional().describe("Only todos anchored to this process id, e.g. order-to-cash") }),
|
|
1863
1889
|
annotations: {
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@miragon/design-iq-mcp",
|
|
3
|
-
"version": "5.
|
|
4
|
-
"description": "Read-only MCP server exposing a
|
|
3
|
+
"version": "5.1.0",
|
|
4
|
+
"description": "Read-only MCP server exposing a designIQ content repo's models — BPMN processes, DMN decisions, Wardley Maps, Team Topologies, Event Storming boards, Context Maps and more — to any MCP client. Discovered from designiq.yml, views derived from the models.",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"license": "MIT",
|
|
7
7
|
"repository": {
|
|
@@ -10,9 +10,15 @@
|
|
|
10
10
|
"directory": "packages/mcp"
|
|
11
11
|
},
|
|
12
12
|
"keywords": [
|
|
13
|
+
"modeling",
|
|
14
|
+
"architecture",
|
|
13
15
|
"bpm",
|
|
14
16
|
"bpmn",
|
|
15
17
|
"dmn",
|
|
18
|
+
"wardley-maps",
|
|
19
|
+
"team-topologies",
|
|
20
|
+
"event-storming",
|
|
21
|
+
"context-maps",
|
|
16
22
|
"mcp",
|
|
17
23
|
"model-context-protocol",
|
|
18
24
|
"process-documentation"
|
|
@@ -35,17 +41,17 @@
|
|
|
35
41
|
},
|
|
36
42
|
"dependencies": {
|
|
37
43
|
"@modelcontextprotocol/node": "2.1.0",
|
|
38
|
-
"@modelcontextprotocol/server": "2.
|
|
39
|
-
"fast-xml-parser": "5.11.
|
|
44
|
+
"@modelcontextprotocol/server": "2.2.0",
|
|
45
|
+
"fast-xml-parser": "5.11.2",
|
|
40
46
|
"yaml": "2.9.1",
|
|
41
47
|
"zod": "4.6.5"
|
|
42
48
|
},
|
|
43
49
|
"devDependencies": {
|
|
44
|
-
"@modelcontextprotocol/client": "2.
|
|
50
|
+
"@modelcontextprotocol/client": "2.2.0",
|
|
45
51
|
"tsdown": "0.23.0",
|
|
46
52
|
"@designiq/contracts": "0.1.0",
|
|
47
|
-
"@designiq/http-kit": "0.1.0",
|
|
48
53
|
"@designiq/github-app": "0.1.0",
|
|
54
|
+
"@designiq/http-kit": "0.1.0",
|
|
49
55
|
"@designiq/mcp-kit": "0.1.0",
|
|
50
56
|
"@designiq/notations": "0.1.0"
|
|
51
57
|
},
|