@endiagram/mcp 0.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/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2025 EN Diagram
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
package/README.md ADDED
@@ -0,0 +1,79 @@
1
+ # @endiagram/mcp
2
+
3
+ MCP server for [EN Diagram](https://endiagram.com) — structural analysis powered by deterministic graph algorithms.
4
+
5
+ Write your system in plain text. Get back structural facts: bottlenecks, blast radius, flow landmarks, concurrency groups, and more. No AI inside the computation — every result is deterministic.
6
+
7
+ ## Installation
8
+
9
+ Run directly:
10
+
11
+ ```bash
12
+ npx @endiagram/mcp
13
+ ```
14
+
15
+ Or install globally:
16
+
17
+ ```bash
18
+ npm install -g @endiagram/mcp
19
+ ```
20
+
21
+ ## Configuration
22
+
23
+ ### Claude Desktop
24
+
25
+ Add to your `claude_desktop_config.json`:
26
+
27
+ ```json
28
+ {
29
+ "mcpServers": {
30
+ "en-diagram": {
31
+ "command": "npx",
32
+ "args": ["@endiagram/mcp"]
33
+ }
34
+ }
35
+ }
36
+ ```
37
+
38
+ ### Claude Code
39
+
40
+ ```bash
41
+ claude mcp add en-diagram npx @endiagram/mcp
42
+ ```
43
+
44
+ ## Environment Variables
45
+
46
+ | Variable | Default | Description |
47
+ |----------|---------|-------------|
48
+ | `EN_API_URL` | `https://api.endiagram.com` | API endpoint for the EN Diagram service |
49
+
50
+ ## Tools
51
+
52
+ | Tool | Description |
53
+ |------|-------------|
54
+ | `analyze_system` | Structural signal — computes topology, roles, antipatterns from EN source |
55
+ | `render` | Render a dependency graph as publication-quality SVG |
56
+ | `detail` | Deep structural analysis — concurrency, flow landmarks, resilience, dominator tree, min-cuts |
57
+ | `distance` | Shortest path between two nodes with subsystem crossing annotations |
58
+ | `diff` | Structural diff between two systems — topology, role, and subsystem changes |
59
+ | `trace` | Follow directed flow from node A to node B with role and subsystem annotations |
60
+ | `extract` | Extract a named subsystem as standalone EN source code |
61
+ | `impact` | Blast radius — remove a node and see what disconnects |
62
+ | `evolve` | Dry-run architectural changes — apply a patch and see the structural delta |
63
+ | `between` | Betweenness centrality — what fraction of all shortest paths flow through a node |
64
+ | `categorize` | Auto-discover subsystem boundaries from dependency structure |
65
+ | `compose` | Merge two EN graphs into one with entity linking |
66
+
67
+ ## EN Syntax
68
+
69
+ ```
70
+ Customer do: place order needs: menu yields: order
71
+ Kitchen do: prepare food needs: order yields: meal
72
+ Waiter do: deliver needs: meal yields: served customer
73
+ ```
74
+
75
+ Learn more at [endiagram.com](https://endiagram.com).
76
+
77
+ ## License
78
+
79
+ MIT
@@ -0,0 +1,2 @@
1
+ #!/usr/bin/env node
2
+ export {};
package/dist/index.js ADDED
@@ -0,0 +1,204 @@
1
+ #!/usr/bin/env node
2
+ import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
3
+ import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio.js";
4
+ import { z } from "zod";
5
+ const EN_API_URL = process.env.EN_API_URL ?? "https://api.endiagram.com";
6
+ async function callApi(toolName, args) {
7
+ try {
8
+ const response = await fetch(`${EN_API_URL}/api/tools/${toolName}`, {
9
+ method: "POST",
10
+ headers: { "Content-Type": "application/json" },
11
+ body: JSON.stringify(args),
12
+ });
13
+ const text = await response.text();
14
+ if (!response.ok) {
15
+ return {
16
+ text: `API error (${response.status}): ${text}`,
17
+ isError: true,
18
+ };
19
+ }
20
+ return { text, isError: false };
21
+ }
22
+ catch (error) {
23
+ const message = error instanceof Error ? error.message : "Unknown error";
24
+ return {
25
+ text: `Failed to reach EN API at ${EN_API_URL}: ${message}`,
26
+ isError: true,
27
+ };
28
+ }
29
+ }
30
+ const server = new McpServer({
31
+ name: "en-diagram",
32
+ version: "0.1.0",
33
+ });
34
+ // --- analyze_system ---
35
+ server.tool("analyze_system", "Structural signal. You describe the system, the tool computes structural facts. All computation is deterministic — no AI inside. EN syntax: subject do: action needs: inputs yields: outputs.", {
36
+ source: z.string().describe("EN source code describing the system"),
37
+ invariants: z
38
+ .string()
39
+ .optional()
40
+ .describe("Invariants to check against the structure"),
41
+ detect_antipatterns: z
42
+ .string()
43
+ .optional()
44
+ .describe("Antipatterns to detect in the structure"),
45
+ }, async ({ source, invariants, detect_antipatterns }) => {
46
+ const result = await callApi("analyze_system", {
47
+ source,
48
+ invariants,
49
+ detect_antipatterns,
50
+ });
51
+ return {
52
+ content: [{ type: "text", text: result.text }],
53
+ isError: result.isError,
54
+ };
55
+ });
56
+ // --- render ---
57
+ server.tool("render", "Render an EN dependency graph as a publication-quality SVG image.", {
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 });
69
+ return {
70
+ content: [{ type: "text", text: result.text }],
71
+ isError: result.isError,
72
+ };
73
+ });
74
+ // --- detail ---
75
+ server.tool("detail", "Deep structural analysis — concurrency, flow landmarks, resilience, dominator tree, min-cuts.", {
76
+ source: z.string().describe("EN source code describing the system"),
77
+ }, async ({ source }) => {
78
+ const result = await callApi("detail", { source });
79
+ return {
80
+ content: [{ type: "text", text: result.text }],
81
+ isError: result.isError,
82
+ };
83
+ });
84
+ // --- distance ---
85
+ server.tool("distance", "Shortest path between two nodes with subsystem crossing annotations.", {
86
+ source: z.string().describe("EN source code describing the system"),
87
+ from: z.string().describe("Starting node name"),
88
+ to: z.string().describe("Target node name"),
89
+ }, async ({ source, from, to }) => {
90
+ const result = await callApi("distance", { source, from, to });
91
+ return {
92
+ content: [{ type: "text", text: result.text }],
93
+ isError: result.isError,
94
+ };
95
+ });
96
+ // --- diff ---
97
+ server.tool("diff", "Structural diff between two systems — topology, role, and subsystem changes.", {
98
+ source_a: z.string().describe("EN source code for the first system"),
99
+ source_b: z.string().describe("EN source code for the second system"),
100
+ }, async ({ source_a, source_b }) => {
101
+ const result = await callApi("diff", { source_a, source_b });
102
+ return {
103
+ content: [{ type: "text", text: result.text }],
104
+ isError: result.isError,
105
+ };
106
+ });
107
+ // --- trace ---
108
+ server.tool("trace", "Follow directed flow from node A to node B with role and subsystem annotations.", {
109
+ source: z.string().describe("EN source code describing the system"),
110
+ from: z.string().describe("Starting node name"),
111
+ to: z.string().describe("Target node name"),
112
+ defense_nodes: z
113
+ .string()
114
+ .optional()
115
+ .describe("Comma-separated list of defense nodes to annotate"),
116
+ }, async ({ source, from, to, defense_nodes }) => {
117
+ const result = await callApi("trace", {
118
+ source,
119
+ from,
120
+ to,
121
+ defense_nodes,
122
+ });
123
+ return {
124
+ content: [{ type: "text", text: result.text }],
125
+ isError: result.isError,
126
+ };
127
+ });
128
+ // --- extract ---
129
+ server.tool("extract", "Extract a named subsystem as standalone EN source code.", {
130
+ source: z.string().describe("EN source code describing the system"),
131
+ subsystem: z.string().describe("Name of the subsystem to extract"),
132
+ }, async ({ source, subsystem }) => {
133
+ const result = await callApi("extract", { source, subsystem });
134
+ return {
135
+ content: [{ type: "text", text: result.text }],
136
+ isError: result.isError,
137
+ };
138
+ });
139
+ // --- impact ---
140
+ server.tool("impact", "Blast radius — remove a node and see what disconnects.", {
141
+ source: z.string().describe("EN source code describing the system"),
142
+ node: z.string().describe("Node to remove for impact analysis"),
143
+ }, async ({ source, node }) => {
144
+ const result = await callApi("impact", { source, node });
145
+ return {
146
+ content: [{ type: "text", text: result.text }],
147
+ isError: result.isError,
148
+ };
149
+ });
150
+ // --- evolve ---
151
+ server.tool("evolve", "Dry-run architectural changes — apply a patch and see the structural delta.", {
152
+ source: z.string().describe("EN source code describing the current system"),
153
+ patch: z.string().describe("EN source code patch to apply"),
154
+ }, async ({ source, patch }) => {
155
+ const result = await callApi("evolve", { source, patch });
156
+ return {
157
+ content: [{ type: "text", text: result.text }],
158
+ isError: result.isError,
159
+ };
160
+ });
161
+ // --- between ---
162
+ server.tool("between", "Betweenness centrality for a node — what fraction of all shortest paths flow through it.", {
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-discover subsystem boundaries from dependency structure.", {
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
+ // --- compose ---
183
+ server.tool("compose", "Merge two EN graphs into one with entity linking.", {
184
+ source_a: z.string().describe("EN source code for the first system"),
185
+ source_b: z.string().describe("EN source code for the second system"),
186
+ links: z
187
+ .string()
188
+ .describe("Entity links between the two systems (e.g. 'a.node1=b.node2, a.node3=b.node4')"),
189
+ }, async ({ source_a, source_b, links }) => {
190
+ const result = await callApi("compose", { source_a, source_b, links });
191
+ return {
192
+ content: [{ type: "text", text: result.text }],
193
+ isError: result.isError,
194
+ };
195
+ });
196
+ // --- start server ---
197
+ async function main() {
198
+ const transport = new StdioServerTransport();
199
+ await server.connect(transport);
200
+ }
201
+ main().catch((error) => {
202
+ console.error("Failed to start EN Diagram MCP server:", error);
203
+ process.exit(1);
204
+ });
package/package.json ADDED
@@ -0,0 +1,41 @@
1
+ {
2
+ "name": "@endiagram/mcp",
3
+ "version": "0.1.0",
4
+ "description": "MCP server for EN Diagram — structural analysis for any system",
5
+ "type": "module",
6
+ "main": "dist/index.js",
7
+ "bin": {
8
+ "endiagram-mcp": "dist/index.js"
9
+ },
10
+ "files": [
11
+ "dist",
12
+ "README.md",
13
+ "LICENSE"
14
+ ],
15
+ "scripts": {
16
+ "build": "tsc",
17
+ "start": "node dist/index.js",
18
+ "prepublishOnly": "npm run build"
19
+ },
20
+ "dependencies": {
21
+ "@modelcontextprotocol/sdk": "^1.12.1",
22
+ "zod": "^3.23.0"
23
+ },
24
+ "devDependencies": {
25
+ "typescript": "^5.5.0",
26
+ "@types/node": "^20.0.0"
27
+ },
28
+ "publishConfig": {
29
+ "access": "public"
30
+ },
31
+ "license": "MIT",
32
+ "keywords": ["mcp", "en-diagram", "structural-analysis", "graph-theory", "dependency-graph"],
33
+ "repository": {
34
+ "type": "git",
35
+ "url": "https://github.com/dushyant30suthar/TheEmergentNarrative",
36
+ "directory": "mcp"
37
+ },
38
+ "engines": {
39
+ "node": ">=18"
40
+ }
41
+ }