@miragon/design-iq-mcp 5.9.0 → 5.11.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/dist/http.js +1 -1
- package/dist/server.js +1 -1
- package/dist/{tools-DizBhl75.js → tools-CszDSqzk.js} +107 -24
- package/package.json +1 -1
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-CszDSqzk.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-CszDSqzk.js";
|
|
3
3
|
import { existsSync } from "node:fs";
|
|
4
4
|
import { resolve } from "node:path";
|
|
5
5
|
import { StdioServerTransport } from "@modelcontextprotocol/server/stdio";
|
|
@@ -68,6 +68,7 @@ const NOTATIONS = [
|
|
|
68
68
|
mediaKind: "xml",
|
|
69
69
|
docShape: "text",
|
|
70
70
|
monacoLanguage: "xml",
|
|
71
|
+
todos: true,
|
|
71
72
|
graphHints: {
|
|
72
73
|
flowEdgeKinds: ["sequenceFlow"],
|
|
73
74
|
entryNodeTypes: ["startEvent"]
|
|
@@ -100,6 +101,7 @@ const NOTATIONS = [
|
|
|
100
101
|
mediaKind: "dsl",
|
|
101
102
|
docShape: "text",
|
|
102
103
|
monacoLanguage: "plaintext",
|
|
104
|
+
todos: true,
|
|
103
105
|
graphHints: {
|
|
104
106
|
flowEdgeKinds: ["dependency"],
|
|
105
107
|
entryNodeTypes: []
|
|
@@ -115,7 +117,8 @@ const NOTATIONS = [
|
|
|
115
117
|
extensions: [".tt", ".ttm.json"],
|
|
116
118
|
mediaKind: "json",
|
|
117
119
|
docShape: "text",
|
|
118
|
-
monacoLanguage: "json"
|
|
120
|
+
monacoLanguage: "json",
|
|
121
|
+
todos: true
|
|
119
122
|
},
|
|
120
123
|
{
|
|
121
124
|
id: "event-storming",
|
|
@@ -128,6 +131,7 @@ const NOTATIONS = [
|
|
|
128
131
|
mediaKind: "dsl",
|
|
129
132
|
docShape: "text",
|
|
130
133
|
monacoLanguage: "plaintext",
|
|
134
|
+
todos: true,
|
|
131
135
|
graphHints: {
|
|
132
136
|
flowEdgeKinds: ["arrow"],
|
|
133
137
|
entryNodeTypes: []
|
|
@@ -144,6 +148,7 @@ const NOTATIONS = [
|
|
|
144
148
|
mediaKind: "json",
|
|
145
149
|
docShape: "text",
|
|
146
150
|
monacoLanguage: "json",
|
|
151
|
+
todos: true,
|
|
147
152
|
graphHints: {
|
|
148
153
|
flowEdgeKinds: [
|
|
149
154
|
"partnership",
|
|
@@ -177,7 +182,8 @@ const NOTATIONS = [
|
|
|
177
182
|
extensions: [".md"],
|
|
178
183
|
mediaKind: "markdown",
|
|
179
184
|
docShape: "text",
|
|
180
|
-
monacoLanguage: "markdown"
|
|
185
|
+
monacoLanguage: "markdown",
|
|
186
|
+
todos: true
|
|
181
187
|
}
|
|
182
188
|
];
|
|
183
189
|
function byId(id) {
|
|
@@ -542,6 +548,8 @@ const TT_EDGE_INTERACTIONS_VERSION = 1;
|
|
|
542
548
|
function extractTeamTopology(raw) {
|
|
543
549
|
const data = JSON.parse(raw);
|
|
544
550
|
const list = (v) => Array.isArray(v) ? v : [];
|
|
551
|
+
const objects = (v) => list(v).filter((i) => i !== null && typeof i === "object");
|
|
552
|
+
const text = (v) => typeof v === "string" && v !== "" ? v : void 0;
|
|
545
553
|
const teams = list(data.nodes).map((n) => ({
|
|
546
554
|
id: n.id,
|
|
547
555
|
type: n.type ?? "team",
|
|
@@ -549,16 +557,38 @@ function extractTeamTopology(raw) {
|
|
|
549
557
|
extra: n.description ? { description: n.description } : void 0
|
|
550
558
|
}));
|
|
551
559
|
const placed = (i) => "position" in i && "size" in i;
|
|
552
|
-
const interactions =
|
|
560
|
+
const interactions = objects(data.interactions).filter((i) => data.version !== TT_EDGE_INTERACTIONS_VERSION || placed(i)).map((i) => ({
|
|
553
561
|
id: i.id,
|
|
554
562
|
type: "interaction",
|
|
555
563
|
name: i.label,
|
|
556
564
|
extra: { mode: i.mode }
|
|
557
565
|
}));
|
|
566
|
+
const flows = objects(data.flows).map((f) => ({
|
|
567
|
+
id: f.id,
|
|
568
|
+
type: "flow",
|
|
569
|
+
name: text(f.label)
|
|
570
|
+
}));
|
|
571
|
+
const attachable = new Set([
|
|
572
|
+
...teams,
|
|
573
|
+
...interactions,
|
|
574
|
+
...flows
|
|
575
|
+
].map((n) => n.id));
|
|
576
|
+
const annotations = objects(data.annotations).map((a) => ({
|
|
577
|
+
id: a.id,
|
|
578
|
+
type: "annotation",
|
|
579
|
+
name: text(a.text),
|
|
580
|
+
extra: typeof a.attachedTo === "string" && attachable.has(a.attachedTo) ? { attachedTo: a.attachedTo } : void 0
|
|
581
|
+
}));
|
|
558
582
|
return {
|
|
559
583
|
notation: "team-topology",
|
|
560
|
-
nodes: [
|
|
561
|
-
|
|
584
|
+
nodes: [
|
|
585
|
+
...teams,
|
|
586
|
+
...interactions,
|
|
587
|
+
...flows,
|
|
588
|
+
...annotations
|
|
589
|
+
],
|
|
590
|
+
edges: [],
|
|
591
|
+
meta: { title: text(data.title) ?? null }
|
|
562
592
|
};
|
|
563
593
|
}
|
|
564
594
|
const STORM_ID_PREFIX = {
|
|
@@ -1033,7 +1063,8 @@ function parseAnchor(text) {
|
|
|
1033
1063
|
const end = text.indexOf(CLOSE, start);
|
|
1034
1064
|
if (end === -1) return null;
|
|
1035
1065
|
const anchor = {
|
|
1036
|
-
|
|
1066
|
+
notation: "",
|
|
1067
|
+
model: "",
|
|
1037
1068
|
file: null,
|
|
1038
1069
|
elements: [],
|
|
1039
1070
|
processVersion: null
|
|
@@ -1044,7 +1075,8 @@ function parseAnchor(text) {
|
|
|
1044
1075
|
if (sep === -1) continue;
|
|
1045
1076
|
const key = line.slice(0, sep);
|
|
1046
1077
|
const value = line.slice(sep + 2).trim();
|
|
1047
|
-
if (key === "
|
|
1078
|
+
if (key === "model") anchor.model = value;
|
|
1079
|
+
else if (key === "notation") anchor.notation = value;
|
|
1048
1080
|
else if (key === "file") anchor.file = value;
|
|
1049
1081
|
else if (key === "version") anchor.processVersion = value;
|
|
1050
1082
|
else if (key === "type") {
|
|
@@ -1067,7 +1099,7 @@ function parseAnchor(text) {
|
|
|
1067
1099
|
});
|
|
1068
1100
|
}
|
|
1069
1101
|
}
|
|
1070
|
-
return anchor.
|
|
1102
|
+
return anchor.notation && anchor.model ? anchor : null;
|
|
1071
1103
|
}
|
|
1072
1104
|
//#endregion
|
|
1073
1105
|
//#region ../github-app/src/todos.ts
|
|
@@ -1083,10 +1115,12 @@ function parseAnchor(text) {
|
|
|
1083
1115
|
*/
|
|
1084
1116
|
/** the label every platform-managed todo carries */
|
|
1085
1117
|
const TODO_LABEL = "todo";
|
|
1086
|
-
/** the per-
|
|
1087
|
-
|
|
1088
|
-
|
|
1089
|
-
const
|
|
1118
|
+
/** the per-model label that makes the tracker-side filter cheap:
|
|
1119
|
+
* `<notation>:<id>` (`bpmn:order-to-cash`, `wardley:tea-shop`) — ids are
|
|
1120
|
+
* unique per notation only */
|
|
1121
|
+
const modelLabel = (model) => `${model.notation}:${model.id}`;
|
|
1122
|
+
/** the `labels=` filter for listing: every todo, or one model's */
|
|
1123
|
+
const todoLabelQuery = (model) => model ? `${TODO_LABEL},${modelLabel(model)}` : TODO_LABEL;
|
|
1090
1124
|
const isPullRequestRow = (row) => row.pull_request !== void 0;
|
|
1091
1125
|
//#endregion
|
|
1092
1126
|
//#region ../mcp-kit/index.ts
|
|
@@ -1369,16 +1403,55 @@ const DERIVERS = {
|
|
|
1369
1403
|
};
|
|
1370
1404
|
},
|
|
1371
1405
|
"team-topology": (graph) => {
|
|
1372
|
-
const
|
|
1406
|
+
const ofType = (type) => graph.nodes.filter((n) => n.type === type);
|
|
1407
|
+
const interactions = ofType("interaction");
|
|
1408
|
+
const flows = ofType("flow");
|
|
1409
|
+
const annotations = ofType("annotation");
|
|
1410
|
+
const teams = graph.nodes.filter((n) => ![
|
|
1411
|
+
"interaction",
|
|
1412
|
+
"flow",
|
|
1413
|
+
"annotation"
|
|
1414
|
+
].includes(n.type));
|
|
1373
1415
|
const stats = {
|
|
1374
|
-
teams:
|
|
1375
|
-
interactions
|
|
1416
|
+
teams: teams.length,
|
|
1417
|
+
interactions: interactions.length,
|
|
1418
|
+
flows: flows.length,
|
|
1419
|
+
annotations: annotations.length
|
|
1420
|
+
};
|
|
1421
|
+
const shown = {
|
|
1422
|
+
teams: stats.teams,
|
|
1423
|
+
interactions: stats.interactions,
|
|
1424
|
+
...stats.flows > 0 ? { flows: stats.flows } : {},
|
|
1425
|
+
...stats.annotations > 0 ? { annotations: stats.annotations } : {}
|
|
1376
1426
|
};
|
|
1427
|
+
const title = graph.meta?.title;
|
|
1377
1428
|
return {
|
|
1378
1429
|
notation: "team-topology",
|
|
1379
|
-
name: null,
|
|
1380
|
-
summary: `Team Topology with ${counted(
|
|
1381
|
-
stats
|
|
1430
|
+
name: typeof title === "string" ? title : null,
|
|
1431
|
+
summary: `Team Topology with ${counted(shown)}`,
|
|
1432
|
+
stats,
|
|
1433
|
+
detail: {
|
|
1434
|
+
teams: teams.map((n) => ({
|
|
1435
|
+
id: n.id,
|
|
1436
|
+
label: n.name ?? null,
|
|
1437
|
+
type: n.type,
|
|
1438
|
+
description: n.extra?.description ?? null
|
|
1439
|
+
})),
|
|
1440
|
+
interactions: interactions.map((n) => ({
|
|
1441
|
+
id: n.id,
|
|
1442
|
+
label: n.name ?? null,
|
|
1443
|
+
mode: n.extra?.mode ?? null
|
|
1444
|
+
})),
|
|
1445
|
+
flows: flows.map((n) => ({
|
|
1446
|
+
id: n.id,
|
|
1447
|
+
label: n.name ?? null
|
|
1448
|
+
})),
|
|
1449
|
+
annotations: annotations.map((n) => ({
|
|
1450
|
+
id: n.id,
|
|
1451
|
+
text: n.name ?? null,
|
|
1452
|
+
attachedTo: n.extra?.attachedTo ?? null
|
|
1453
|
+
}))
|
|
1454
|
+
}
|
|
1382
1455
|
};
|
|
1383
1456
|
},
|
|
1384
1457
|
"event-storming": (graph) => {
|
|
@@ -1617,7 +1690,7 @@ function readOnlyInstructions(on) {
|
|
|
1617
1690
|
DIAGRAMS_IN_DOCUMENTS,
|
|
1618
1691
|
"Start with `list_models` to see which models it holds.",
|
|
1619
1692
|
"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).",
|
|
1620
|
-
"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
|
|
1693
|
+
"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 filed on models and their elements." : "."),
|
|
1621
1694
|
"Live editing, the modeler widgets and release as a pull request are on the designIQ Live Host, not here."
|
|
1622
1695
|
].join(" ");
|
|
1623
1696
|
}
|
|
@@ -1908,14 +1981,21 @@ function createMcpServer(root = DEFAULT_ROOT, todos, contributions = []) {
|
|
|
1908
1981
|
const api = (todos.apiUrl ?? "https://api.github.com").replace(/\/$/, "");
|
|
1909
1982
|
server.registerTool("list_todos", {
|
|
1910
1983
|
title: "List open todos",
|
|
1911
|
-
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 (
|
|
1912
|
-
inputSchema: z.object({
|
|
1984
|
+
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 (notation, model id, model file, anchored elements). Optional filter on one model: `id` (and `notation` for a stem shared across notations; without it a process wins). Use for 'what is open on process X' or to cross-check a model answer against known open discrepancies.",
|
|
1985
|
+
inputSchema: z.object({
|
|
1986
|
+
id: z.string().optional().describe("Only todos of this model id (any notation, from list_models)"),
|
|
1987
|
+
notation: z.string().optional().describe("registry notation id — disambiguates a stem shared across notations")
|
|
1988
|
+
}),
|
|
1913
1989
|
annotations: {
|
|
1914
1990
|
readOnlyHint: true,
|
|
1915
1991
|
openWorldHint: true
|
|
1916
1992
|
}
|
|
1917
|
-
}, safe(async ({
|
|
1918
|
-
const
|
|
1993
|
+
}, safe(async ({ id, notation }) => {
|
|
1994
|
+
const model = id ? {
|
|
1995
|
+
notation: notation ?? (await findModel(id))?.notation ?? "bpmn",
|
|
1996
|
+
id
|
|
1997
|
+
} : void 0;
|
|
1998
|
+
const res = await fetch(`${api}/repos/${todosRepo}/issues?state=open&labels=${encodeURIComponent(todoLabelQuery(model))}&per_page=100`, { headers: {
|
|
1919
1999
|
accept: "application/vnd.github+json",
|
|
1920
2000
|
authorization: `Bearer ${todosToken}`,
|
|
1921
2001
|
"user-agent": "designiq-mcp"
|
|
@@ -1929,7 +2009,10 @@ function createMcpServer(root = DEFAULT_ROOT, todos, contributions = []) {
|
|
|
1929
2009
|
assignees: (row.assignees ?? []).map((a) => a.login),
|
|
1930
2010
|
createdAt: row.created_at
|
|
1931
2011
|
}));
|
|
1932
|
-
if (todos.length === 0)
|
|
2012
|
+
if (todos.length === 0) {
|
|
2013
|
+
const of = model ? ` for ${model.notation === "bpmn" ? "process" : model.notation} '${model.id}'` : "";
|
|
2014
|
+
return ok(`No open todos${of} in ${todosRepo}.`);
|
|
2015
|
+
}
|
|
1933
2016
|
return ok(todos);
|
|
1934
2017
|
}));
|
|
1935
2018
|
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@miragon/design-iq-mcp",
|
|
3
|
-
"version": "5.
|
|
3
|
+
"version": "5.11.0",
|
|
4
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",
|