@endiagram/mcp 0.1.7 → 0.1.8

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.
Files changed (2) hide show
  1. package/dist/index.js +36 -36
  2. package/package.json +1 -1
package/dist/index.js CHANGED
@@ -53,29 +53,21 @@ server.tool("analyze_system", "Structural signal. You describe the system, the t
53
53
  isError: result.isError,
54
54
  };
55
55
  });
56
- // --- render ---
57
- server.tool("render", "Render an EN dependency graph as a publication-quality SVG image. Nodes are colored by structural role (source, sink, hub, etc.) and grouped by auto-detected subsystem. Use when the user wants to SEE the structure -- the visual often reveals patterns (clusters, isolated subgraphs, fan-out imbalance) that text output alone misses.", {
56
+ // --- detail ---
57
+ server.tool("detail", "The depth layer. Run after analyze_system to get the full picture Returns: concurrency metrics (max parallelism, critical path length, parallel paths per depth level), flow landmarks (exact depths where the graph diverges/converges -- these are your bottleneck boundaries), full resilience analysis (bridge implications with which subsystems disconnect if each bridge fails), and structural dependency chains (what feeds what, what must complete first). analyze_system tells you WHERE to look. detail tells you WHY it matters. Use categorize -> extract to isolate a subsystem first, then detail on the extracted source for focused depth.", {
58
58
  source: z.string().describe("EN source code describing the system"),
59
- theme: z
60
- .enum(["dark", "light"])
61
- .optional()
62
- .describe("Color theme for the rendered image"),
63
- quality: z
64
- .enum(["small", "mid", "max"])
65
- .optional()
66
- .describe("Output quality / resolution"),
67
- }, async ({ source, theme, quality }) => {
68
- const result = await callApi("render", { source, theme, quality });
59
+ }, async ({ source }) => {
60
+ const result = await callApi("detail", { source });
69
61
  return {
70
62
  content: [{ type: "text", text: result.text }],
71
63
  isError: result.isError,
72
64
  };
73
65
  });
74
- // --- detail ---
75
- server.tool("detail", "The depth layer. Run after analyze_system to get the full picture Returns: concurrency metrics (max parallelism, critical path length, parallel paths per depth level), flow landmarks (exact depths where the graph diverges/converges -- these are your bottleneck boundaries), full resilience analysis (bridge implications with which subsystems disconnect if each bridge fails), and structural dependency chains (what feeds what, what must complete first). analyze_system tells you WHERE to look. detail tells you WHY it matters. Use categorize -> extract to isolate a subsystem first, then detail on the extracted source for focused depth.", {
66
+ // --- categorize ---
67
+ server.tool("categorize", "Auto-organize a flat list into named groups. You give it ungrouped actions with inputs and outputs -- the tool discovers subsystem boundaries from the dependency structure and names them. 25 nodes become 5-6 named subsystems. You don't define the groups. The structure does. When the discovered boundaries differ from your module structure, that difference is a finding. Use after analyze_system to see how the system organizes itself. Then feed subsystem names into extract for fractal zoom.", {
76
68
  source: z.string().describe("EN source code describing the system"),
77
69
  }, async ({ source }) => {
78
- const result = await callApi("detail", { source });
70
+ const result = await callApi("categorize", { source });
79
71
  return {
80
72
  content: [{ type: "text", text: result.text }],
81
73
  isError: result.isError,
@@ -125,6 +117,17 @@ server.tool("trace", "Follow the flow -- data, materials, authority, money, risk
125
117
  isError: result.isError,
126
118
  };
127
119
  });
120
+ // --- between ---
121
+ server.tool("between", "Quantify coupling. Computes betweenness centrality for a node: what fraction of all shortest paths in the system flow through it. Returns normalized score [0-1], absolute shortest-paths-through count, and total paths. A score of 0.25 means one quarter of all communication in the system passes through this node -- it's a coupling hotspot. Use on nodes flagged as HUB or FORK by analyze_system to get a precise number. Compare centrality scores across nodes to find the true bottleneck vs nodes that just look important.", {
122
+ source: z.string().describe("EN source code describing the system"),
123
+ node: z.string().describe("Node to compute betweenness centrality for"),
124
+ }, async ({ source, node }) => {
125
+ const result = await callApi("between", { source, node });
126
+ return {
127
+ content: [{ type: "text", text: result.text }],
128
+ isError: result.isError,
129
+ };
130
+ });
128
131
  // --- extract ---
129
132
  server.tool("extract", "Fractal zoom. Extract a named subsystem as standalone EN source code you can feed back into analyze_system for a deeper look. Reports boundary inputs (dependencies from outside the subsystem), boundary outputs (consumed by other subsystems), and internal entities. This is how you go from surface findings to root causes: categorize gives you subsystem names -> extract gives you the subsystem as its own graph -> analyze_system on that graph reveals internal structure invisible at the top level.", {
130
133
  source: z.string().describe("EN source code describing the system"),
@@ -158,27 +161,6 @@ server.tool("evolve", "Dry-run for architectural changes. Apply a patch to a sys
158
161
  isError: result.isError,
159
162
  };
160
163
  });
161
- // --- between ---
162
- server.tool("between", "Quantify coupling. Computes betweenness centrality for a node: what fraction of all shortest paths in the system flow through it. Returns normalized score [0-1], absolute shortest-paths-through count, and total paths. A score of 0.25 means one quarter of all communication in the system passes through this node -- it's a coupling hotspot. Use on nodes flagged as HUB or FORK by analyze_system to get a precise number. Compare centrality scores across nodes to find the true bottleneck vs nodes that just look important.", {
163
- source: z.string().describe("EN source code describing the system"),
164
- node: z.string().describe("Node to compute betweenness centrality for"),
165
- }, async ({ source, node }) => {
166
- const result = await callApi("between", { source, node });
167
- return {
168
- content: [{ type: "text", text: result.text }],
169
- isError: result.isError,
170
- };
171
- });
172
- // --- categorize ---
173
- server.tool("categorize", "Auto-organize a flat list into named groups. You give it ungrouped actions with inputs and outputs -- the tool discovers subsystem boundaries from the dependency structure and names them. 25 nodes become 5-6 named subsystems. You don't define the groups. The structure does. When the discovered boundaries differ from your module structure, that difference is a finding. Use after analyze_system to see how the system organizes itself. Then feed subsystem names into extract for fractal zoom.", {
174
- source: z.string().describe("EN source code describing the system"),
175
- }, async ({ source }) => {
176
- const result = await callApi("categorize", { source });
177
- return {
178
- content: [{ type: "text", text: result.text }],
179
- isError: result.isError,
180
- };
181
- });
182
164
  // --- compose ---
183
165
  server.tool("compose", "Merge two EN graphs into one. Takes two separate system descriptions and a list of entity links that connect them. Linked entities are merged under source A's name. Unlinked entities that share a name are automatically disambiguated. Returns combined EN source that you feed into any other tool -- analyze_system sees cross-graph bridges, impact shows blast radius across both graphs, distance measures paths crossing graph boundaries. Use when modeling two interacting systems (client/server, producer/consumer, spec/implementation) that share specific data points.", {
184
166
  source_a: z.string().describe("EN source code for the first system"),
@@ -193,6 +175,24 @@ server.tool("compose", "Merge two EN graphs into one. Takes two separate system
193
175
  isError: result.isError,
194
176
  };
195
177
  });
178
+ // --- render (last — only use when user explicitly asks to visualize) ---
179
+ server.tool("render", "Render an EN dependency graph as a publication-quality SVG image. Only call this when the user explicitly asks to visualize or render. Nodes are colored by structural role (source, sink, hub, etc.) and grouped by auto-detected subsystem. The visual reveals patterns (clusters, isolated subgraphs, fan-out imbalance) that text output alone misses.", {
180
+ source: z.string().describe("EN source code describing the system"),
181
+ theme: z
182
+ .enum(["dark", "light"])
183
+ .optional()
184
+ .describe("Color theme for the rendered image"),
185
+ quality: z
186
+ .enum(["small", "mid", "max"])
187
+ .optional()
188
+ .describe("Output quality / resolution"),
189
+ }, async ({ source, theme, quality }) => {
190
+ const result = await callApi("render", { source, theme, quality });
191
+ return {
192
+ content: [{ type: "text", text: result.text }],
193
+ isError: result.isError,
194
+ };
195
+ });
196
196
  // --- start server ---
197
197
  async function main() {
198
198
  const transport = new StdioServerTransport();
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@endiagram/mcp",
3
- "version": "0.1.7",
3
+ "version": "0.1.8",
4
4
  "description": "MCP server for EN Diagram — structural analysis for any system",
5
5
  "type": "module",
6
6
  "main": "dist/index.js",