@endiagram/mcp 0.2.0 → 0.2.2

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 +51 -13
  2. package/package.json +1 -1
package/dist/index.js CHANGED
@@ -2,22 +2,47 @@
2
2
  import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
3
3
  import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio.js";
4
4
  import { z } from "zod";
5
+ import { writeFileSync, mkdirSync, existsSync } from "node:fs";
6
+ import { join } from "node:path";
5
7
  const EN_API_URL = process.env.EN_API_URL ?? "https://api.endiagram.com";
6
8
  async function callApi(toolName, args) {
7
9
  try {
8
- const response = await fetch(`${EN_API_URL}/api/tools/${toolName}`, {
10
+ const response = await fetch(`${EN_API_URL}/mcp`, {
9
11
  method: "POST",
10
12
  headers: { "Content-Type": "application/json" },
11
- body: JSON.stringify(args),
13
+ body: JSON.stringify({
14
+ jsonrpc: "2.0",
15
+ id: Date.now(),
16
+ method: "tools/call",
17
+ params: {
18
+ name: toolName,
19
+ arguments: args,
20
+ },
21
+ }),
12
22
  });
13
- const text = await response.text();
23
+ const body = await response.text();
14
24
  if (!response.ok) {
15
- return {
16
- text: `API error (${response.status}): ${text}`,
17
- isError: true,
18
- };
25
+ return { text: `API error (${response.status}): ${body}`, isError: true };
26
+ }
27
+ try {
28
+ const rpcResponse = JSON.parse(body);
29
+ if (rpcResponse.error) {
30
+ return { text: rpcResponse.error.message, isError: true };
31
+ }
32
+ const result = rpcResponse.result;
33
+ const content = result?.content?.[0];
34
+ const text = content?.text ?? body;
35
+ const isError = result?.isError ?? false;
36
+ // Check for SVG in second content block (render tool)
37
+ const svgContent = result?.content?.[1];
38
+ const svg = svgContent?.text?.startsWith("<svg")
39
+ ? svgContent.text
40
+ : undefined;
41
+ return { text, isError, svg, data: undefined };
42
+ }
43
+ catch {
44
+ return { text: body, isError: false };
19
45
  }
20
- return { text, isError: false };
21
46
  }
22
47
  catch (error) {
23
48
  const message = error instanceof Error ? error.message : "Unknown error";
@@ -36,7 +61,9 @@ Shared names between yields and needs create connections automatically. Multi-wo
36
61
 
37
62
  The engine computes structural truth from the description — the tool outputs are raw mathematical findings. Translate them into clear, practical insights relevant to what the user is trying to achieve.
38
63
 
39
- How to use these tools effectively: model the system first, then explore. The first tool call reveals the structure — but the real insights come from following up. A node labeled HUB that should be simple? Dig into it with between or impact. A surprising subsystem boundary? Extract it and analyze deeper. An unexpected dependency chain? Trace it. A proposed change? Evolve it and diff. The tools are designed to chain — each finding opens a question that another tool can answer. Don't stop at one call. Explore, tinker, compare, and let the math surface what no one expected.`;
64
+ How to use these tools effectively: model the system first, then explore. The first tool call reveals the structure — but the real insights come from following up. A node labeled HUB that should be simple? Dig into it with between or impact. A surprising subsystem boundary? Extract it and analyze deeper. An unexpected dependency chain? Trace it. A proposed change? Evolve it and diff. The tools are designed to chain — each finding opens a question that another tool can answer. Don't stop at one call. Explore, tinker, compare, and let the math surface what no one expected.
65
+
66
+ Go deep, not wide. When a finding catches your attention — a surprising hub, an unexpected bottleneck, a structural anomaly — lock onto it. Use one tool to surface it, then chain the next tool to explain it, then the next to stress-test it. Keep narrowing until you reach the root. One thread, followed to the end, beats ten shallow observations. Only call render when the user explicitly asks to visualize.`;
40
67
  const server = new McpServer({
41
68
  name: "endiagram",
42
69
  version: "0.2.0",
@@ -53,7 +80,7 @@ server.tool("analyze", EN_INSTRUCTIONS + " This tool gives the system overview:
53
80
  .optional()
54
81
  .describe("Set to 'true' to detect structural antipatterns"),
55
82
  }, async ({ source, invariants, detect_antipatterns }) => {
56
- const result = await callApi("analyze_system", {
83
+ const result = await callApi("analyze", {
57
84
  source,
58
85
  invariants,
59
86
  detect_antipatterns,
@@ -196,7 +223,7 @@ server.tool("conserve", "Structural invariants, deadlock analysis, complexity, a
196
223
  };
197
224
  });
198
225
  // --- render ---
199
- server.tool("render", "SVG diagram. Only when user asks to visualize.", {
226
+ server.tool("render", "SVG diagram. Only call when user explicitly asks to visualize. Saves SVG to a local file — no SVG content enters the conversation.", {
200
227
  source: z.string().describe("EN source code describing the system"),
201
228
  theme: z
202
229
  .enum(["dark", "light"])
@@ -208,9 +235,20 @@ server.tool("render", "SVG diagram. Only when user asks to visualize.", {
208
235
  .describe("Output quality"),
209
236
  }, async ({ source, theme, quality }) => {
210
237
  const result = await callApi("render", { source, theme, quality });
238
+ if (result.isError || !result.svg) {
239
+ return {
240
+ content: [{ type: "text", text: result.text }],
241
+ isError: result.isError,
242
+ };
243
+ }
244
+ const outDir = join(process.cwd(), ".endiagram");
245
+ if (!existsSync(outDir))
246
+ mkdirSync(outDir, { recursive: true });
247
+ const filePath = join(outDir, `en-${Date.now()}.svg`);
248
+ writeFileSync(filePath, result.svg);
211
249
  return {
212
- content: [{ type: "text", text: result.text }],
213
- isError: result.isError,
250
+ content: [{ type: "text", text: `SVG saved: ${filePath}` }],
251
+ isError: false,
214
252
  };
215
253
  });
216
254
  // --- start server ---
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@endiagram/mcp",
3
- "version": "0.2.0",
3
+ "version": "0.2.2",
4
4
  "description": "MCP server for EN Diagram — deterministic structural analysis backed by named theorems",
5
5
  "type": "module",
6
6
  "main": "dist/index.js",