@zivis/mcp 0.1.11 → 0.1.12

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.
@@ -3,7 +3,7 @@
3
3
  "pack_id": "zivis-public",
4
4
  "pack_name": "ZIVIS Public Pattern Pack",
5
5
  "version": "0.2.0",
6
- "built_at": "2026-08-31T22:32:10.810Z",
6
+ "built_at": "2026-09-01T21:19:00.226Z",
7
7
  "tier": "customer_safe",
8
8
  "description": "ZIVIS-curated public pattern pack — capsules + inference prompts evaluated locally on the user's machine.",
9
9
  "capsules": [
package/dist/server.js CHANGED
@@ -73,7 +73,6 @@ import { UPDATE_ENDPOINT_NAME, UPDATE_ENDPOINT_DESCRIPTION, UPDATE_ENDPOINT_SCHE
73
73
  import { MANAGE_APPLICATION_NAME, MANAGE_APPLICATION_DESCRIPTION, MANAGE_APPLICATION_SCHEMA, createManageApplicationHandler, } from "./tools/manage-application.js";
74
74
  import { MANAGE_ENDPOINT_LIFECYCLE_NAME, MANAGE_ENDPOINT_LIFECYCLE_DESCRIPTION, MANAGE_ENDPOINT_LIFECYCLE_SCHEMA, createManageEndpointLifecycleHandler, } from "./tools/manage-endpoint-lifecycle.js";
75
75
  import { DISCOVER_LOCAL_INFRA_NAME, DISCOVER_LOCAL_INFRA_DESCRIPTION, DISCOVER_LOCAL_INFRA_SCHEMA, createDiscoverLocalInfraHandler, } from "./tools/discover-local-infra.js";
76
- import { GENERATE_DIAGRAM_NAME, GENERATE_DIAGRAM_DESCRIPTION, GENERATE_DIAGRAM_SCHEMA, createGenerateDiagramHandler, } from "./tools/generate-diagram.js";
77
76
  import { LIST_DIAGRAMS_NAME, LIST_DIAGRAMS_DESCRIPTION, LIST_DIAGRAMS_SCHEMA, createListDiagramsHandler, } from "./tools/list-diagrams.js";
78
77
  import { GET_DIAGRAM_NAME, GET_DIAGRAM_DESCRIPTION, GET_DIAGRAM_SCHEMA, createGetDiagramHandler, } from "./tools/get-diagram.js";
79
78
  import { CREATE_DIAGRAM_NAME, CREATE_DIAGRAM_DESCRIPTION, CREATE_DIAGRAM_SCHEMA, createCreateDiagramHandler, } from "./tools/create-diagram.js";
@@ -215,10 +214,6 @@ export async function startServer(incoming = DEFAULT_CONFIG) {
215
214
  description: DISCOVER_LOCAL_INFRA_DESCRIPTION,
216
215
  inputSchema: DISCOVER_LOCAL_INFRA_SCHEMA,
217
216
  }, createDiscoverLocalInfraHandler());
218
- server.registerTool(GENERATE_DIAGRAM_NAME, {
219
- description: GENERATE_DIAGRAM_DESCRIPTION,
220
- inputSchema: GENERATE_DIAGRAM_SCHEMA,
221
- }, createGenerateDiagramHandler(apiClient));
222
217
  server.registerTool(LIST_DIAGRAMS_NAME, {
223
218
  description: LIST_DIAGRAMS_DESCRIPTION,
224
219
  inputSchema: LIST_DIAGRAMS_SCHEMA,
@@ -1,7 +1,7 @@
1
1
  import { z } from "zod";
2
2
  import type { ApiClient } from "../api-client.js";
3
3
  export declare const CREATE_DIAGRAM_NAME = "zivis_create_diagram";
4
- export declare const CREATE_DIAGRAM_DESCRIPTION = "Create a new canvas diagram with nodes, connections, and boundaries in a single call.\n\nUse this to build system architecture diagrams, data flow diagrams, attack chains, etc. from code analysis.\n\n**Temp IDs:** When creating nodes and connections together, assign each node a temp_id (e.g., \"node_0\", \"node_1\") and reference them in connections via source_temp_id / target_temp_id. Similarly, assign boundaries a temp_id and reference them in nodes via boundary_temp_id.\n\n**Positioning:** Nodes default to (0,0). For readable layouts, space nodes apart (e.g., 250px horizontal, 150px vertical gaps). Default node size is 200x100px. Boundaries should be sized to contain their child nodes with padding.\n\n**Tags:** Use tags to annotate nodes with metadata (e.g., [\"database\", \"postgres\", \"port:5432\", \"pii\"]). These are searchable and displayed in the UI.\n\n**Colors:** Use hex colors (e.g., \"#336791\" for databases, \"#DC382D\" for caches, \"#009639\" for proxies).";
4
+ export declare const CREATE_DIAGRAM_DESCRIPTION = "Create a new diagram from Mermaid source.\n\nUse this to record system architecture diagrams, data flow diagrams, attack chains, sequence diagrams, etc. from code analysis. Content is Mermaid syntax (flowchart, sequenceDiagram, etc.) \u2014 see zivis_update_mermaid_source for editing an existing diagram's source.";
5
5
  export declare const CREATE_DIAGRAM_SCHEMA: {
6
6
  name: z.ZodString;
7
7
  description: z.ZodOptional<z.ZodString>;
@@ -15,84 +15,14 @@ export declare const CREATE_DIAGRAM_SCHEMA: {
15
15
  trust_boundary: "trust_boundary";
16
16
  network: "network";
17
17
  }>;
18
- nodes: z.ZodOptional<z.ZodArray<z.ZodObject<{
19
- temp_id: z.ZodOptional<z.ZodString>;
20
- name: z.ZodString;
21
- description: z.ZodOptional<z.ZodString>;
22
- tags: z.ZodOptional<z.ZodArray<z.ZodString>>;
23
- icon: z.ZodOptional<z.ZodString>;
24
- color: z.ZodOptional<z.ZodString>;
25
- position_x: z.ZodOptional<z.ZodNumber>;
26
- position_y: z.ZodOptional<z.ZodNumber>;
27
- width: z.ZodOptional<z.ZodNumber>;
28
- height: z.ZodOptional<z.ZodNumber>;
29
- step_order: z.ZodOptional<z.ZodNumber>;
30
- boundary_temp_id: z.ZodOptional<z.ZodString>;
31
- metadata: z.ZodOptional<z.ZodRecord<z.ZodString, z.ZodUnknown>>;
32
- }, z.core.$strip>>>;
33
- connections: z.ZodOptional<z.ZodArray<z.ZodObject<{
34
- source_temp_id: z.ZodOptional<z.ZodString>;
35
- target_temp_id: z.ZodOptional<z.ZodString>;
36
- source_node_id: z.ZodOptional<z.ZodString>;
37
- target_node_id: z.ZodOptional<z.ZodString>;
38
- label: z.ZodOptional<z.ZodString>;
39
- description: z.ZodOptional<z.ZodString>;
40
- tags: z.ZodOptional<z.ZodArray<z.ZodString>>;
41
- bidirectional: z.ZodOptional<z.ZodBoolean>;
42
- metadata: z.ZodOptional<z.ZodRecord<z.ZodString, z.ZodUnknown>>;
43
- }, z.core.$strip>>>;
44
- boundaries: z.ZodOptional<z.ZodArray<z.ZodObject<{
45
- temp_id: z.ZodOptional<z.ZodString>;
46
- label: z.ZodString;
47
- description: z.ZodOptional<z.ZodString>;
48
- color: z.ZodOptional<z.ZodString>;
49
- position_x: z.ZodOptional<z.ZodNumber>;
50
- position_y: z.ZodOptional<z.ZodNumber>;
51
- width: z.ZodOptional<z.ZodNumber>;
52
- height: z.ZodOptional<z.ZodNumber>;
53
- }, z.core.$strip>>>;
18
+ content: z.ZodString;
54
19
  linked_threat_model_id: z.ZodOptional<z.ZodString>;
55
20
  };
56
21
  export declare function createCreateDiagramHandler(apiClient: ApiClient): (params: {
57
22
  name: string;
58
23
  description?: string;
59
24
  diagram_type: string;
60
- nodes?: Array<{
61
- temp_id?: string;
62
- name: string;
63
- description?: string;
64
- tags?: string[];
65
- icon?: string;
66
- color?: string;
67
- position_x?: number;
68
- position_y?: number;
69
- width?: number;
70
- height?: number;
71
- step_order?: number;
72
- boundary_temp_id?: string;
73
- metadata?: Record<string, unknown>;
74
- }>;
75
- connections?: Array<{
76
- source_temp_id?: string;
77
- target_temp_id?: string;
78
- source_node_id?: string;
79
- target_node_id?: string;
80
- label?: string;
81
- description?: string;
82
- tags?: string[];
83
- bidirectional?: boolean;
84
- metadata?: Record<string, unknown>;
85
- }>;
86
- boundaries?: Array<{
87
- temp_id?: string;
88
- label: string;
89
- description?: string;
90
- color?: string;
91
- position_x?: number;
92
- position_y?: number;
93
- width?: number;
94
- height?: number;
95
- }>;
25
+ content: string;
96
26
  linked_threat_model_id?: string;
97
27
  }) => Promise<{
98
28
  content: {
@@ -1,17 +1,9 @@
1
1
  import { z } from "zod";
2
2
  import { sanitizeResponse } from "../sanitize.js";
3
3
  export const CREATE_DIAGRAM_NAME = "zivis_create_diagram";
4
- export const CREATE_DIAGRAM_DESCRIPTION = `Create a new canvas diagram with nodes, connections, and boundaries in a single call.
4
+ export const CREATE_DIAGRAM_DESCRIPTION = `Create a new diagram from Mermaid source.
5
5
 
6
- Use this to build system architecture diagrams, data flow diagrams, attack chains, etc. from code analysis.
7
-
8
- **Temp IDs:** When creating nodes and connections together, assign each node a temp_id (e.g., "node_0", "node_1") and reference them in connections via source_temp_id / target_temp_id. Similarly, assign boundaries a temp_id and reference them in nodes via boundary_temp_id.
9
-
10
- **Positioning:** Nodes default to (0,0). For readable layouts, space nodes apart (e.g., 250px horizontal, 150px vertical gaps). Default node size is 200x100px. Boundaries should be sized to contain their child nodes with padding.
11
-
12
- **Tags:** Use tags to annotate nodes with metadata (e.g., ["database", "postgres", "port:5432", "pii"]). These are searchable and displayed in the UI.
13
-
14
- **Colors:** Use hex colors (e.g., "#336791" for databases, "#DC382D" for caches, "#009639" for proxies).`;
6
+ Use this to record system architecture diagrams, data flow diagrams, attack chains, sequence diagrams, etc. from code analysis. Content is Mermaid syntax (flowchart, sequenceDiagram, etc.) — see zivis_update_mermaid_source for editing an existing diagram's source.`;
15
7
  export const CREATE_DIAGRAM_SCHEMA = {
16
8
  name: z
17
9
  .string()
@@ -23,51 +15,9 @@ export const CREATE_DIAGRAM_SCHEMA = {
23
15
  diagram_type: z
24
16
  .enum(["architecture", "data_flow", "attack_chain", "sequence", "trust_boundary", "network", "deployment", "custom"])
25
17
  .describe("Type of diagram"),
26
- nodes: z
27
- .array(z.object({
28
- temp_id: z.string().optional().describe("Temporary ID for referencing in connections (e.g., 'node_0')"),
29
- name: z.string().describe("Node name (e.g., 'PostgreSQL', 'API Gateway')"),
30
- description: z.string().optional().describe("Node description"),
31
- tags: z.array(z.string()).optional().describe("Tags (e.g., ['database', 'port:5432'])"),
32
- icon: z.string().optional().describe("Icon name (e.g., 'database', 'server', 'shield', 'globe')"),
33
- color: z.string().optional().describe("Hex color (e.g., '#336791')"),
34
- position_x: z.number().optional().describe("X position on canvas (default 0)"),
35
- position_y: z.number().optional().describe("Y position on canvas (default 0)"),
36
- width: z.number().optional().describe("Node width (default 200)"),
37
- height: z.number().optional().describe("Node height (default 100)"),
38
- step_order: z.number().optional().describe("Step order for attack chain diagrams"),
39
- boundary_temp_id: z.string().optional().describe("Temp ID of boundary this node belongs to"),
40
- metadata: z.record(z.string(), z.unknown()).optional().describe("Custom metadata"),
41
- }))
42
- .optional()
43
- .describe("Nodes to create"),
44
- connections: z
45
- .array(z.object({
46
- source_temp_id: z.string().optional().describe("Source node temp ID"),
47
- target_temp_id: z.string().optional().describe("Target node temp ID"),
48
- source_node_id: z.string().optional().describe("Source node UUID (if referencing existing node)"),
49
- target_node_id: z.string().optional().describe("Target node UUID (if referencing existing node)"),
50
- label: z.string().optional().describe("Connection label (e.g., 'HTTPS', 'depends on')"),
51
- description: z.string().optional().describe("Connection description"),
52
- tags: z.array(z.string()).optional().describe("Connection tags"),
53
- bidirectional: z.boolean().optional().describe("Whether connection goes both ways (default false)"),
54
- metadata: z.record(z.string(), z.unknown()).optional().describe("Custom metadata"),
55
- }))
56
- .optional()
57
- .describe("Connections between nodes"),
58
- boundaries: z
59
- .array(z.object({
60
- temp_id: z.string().optional().describe("Temporary ID for referencing in nodes (e.g., 'boundary_0')"),
61
- label: z.string().describe("Boundary label (e.g., 'DMZ', 'Internal Network')"),
62
- description: z.string().optional().describe("Boundary description"),
63
- color: z.string().optional().describe("Hex color"),
64
- position_x: z.number().optional().describe("X position (default 0)"),
65
- position_y: z.number().optional().describe("Y position (default 0)"),
66
- width: z.number().optional().describe("Boundary width (default 400)"),
67
- height: z.number().optional().describe("Boundary height (default 300)"),
68
- }))
69
- .optional()
70
- .describe("Boundary groups (trust boundaries, network segments)"),
18
+ content: z
19
+ .string()
20
+ .describe("Mermaid diagram source (e.g., 'flowchart TD\\n A[Client] --> B[Server]')"),
71
21
  linked_threat_model_id: z
72
22
  .string()
73
23
  .optional()
@@ -76,51 +26,13 @@ export const CREATE_DIAGRAM_SCHEMA = {
76
26
  export function createCreateDiagramHandler(apiClient) {
77
27
  return async (params) => {
78
28
  try {
79
- const apiNodes = params.nodes?.map((n) => ({
80
- tempId: n.temp_id,
81
- name: n.name,
82
- description: n.description,
83
- tags: n.tags,
84
- icon: n.icon,
85
- color: n.color,
86
- positionX: n.position_x,
87
- positionY: n.position_y,
88
- width: n.width,
89
- height: n.height,
90
- stepOrder: n.step_order,
91
- boundaryTempId: n.boundary_temp_id,
92
- metadata: n.metadata,
93
- }));
94
- const apiConnections = params.connections?.map((c) => ({
95
- sourceTempId: c.source_temp_id,
96
- targetTempId: c.target_temp_id,
97
- sourceNodeId: c.source_node_id,
98
- targetNodeId: c.target_node_id,
99
- label: c.label,
100
- description: c.description,
101
- tags: c.tags,
102
- bidirectional: c.bidirectional,
103
- metadata: c.metadata,
104
- }));
105
- const apiBoundaries = params.boundaries?.map((b) => ({
106
- tempId: b.temp_id,
107
- label: b.label,
108
- description: b.description,
109
- color: b.color,
110
- positionX: b.position_x,
111
- positionY: b.position_y,
112
- width: b.width,
113
- height: b.height,
114
- }));
115
29
  const data = await apiClient.post("/api/diagrams", {
116
30
  name: params.name,
117
31
  description: params.description,
118
32
  diagramType: params.diagram_type,
119
- contentType: "canvas",
33
+ contentType: "mermaid",
34
+ content: params.content,
120
35
  sourceType: "manual",
121
- nodes: apiNodes,
122
- connections: apiConnections,
123
- boundaries: apiBoundaries,
124
36
  });
125
37
  const sanitized = sanitizeResponse(data);
126
38
  const diagramId = sanitized.id;
@@ -135,16 +47,12 @@ export function createCreateDiagramHandler(apiClient) {
135
47
  catch {
136
48
  }
137
49
  }
138
- const nodeCount = Array.isArray(sanitized.nodes) ? sanitized.nodes.length : 0;
139
- const connCount = Array.isArray(sanitized.connections) ? sanitized.connections.length : 0;
140
- const boundaryCount = Array.isArray(sanitized.boundaries) ? sanitized.boundaries.length : 0;
141
50
  const result = {
142
51
  diagram_id: diagramId,
143
52
  name: sanitized.name,
144
53
  diagram_type: sanitized.diagramType,
145
- stats: { nodes: nodeCount, connections: connCount, boundaries: boundaryCount },
146
54
  linked_threat_model_id: linkedThreatModelId,
147
- _instruction: "Diagram created. Use zivis_get_diagram to see full content, or zivis_manage_diagram to modify.",
55
+ _instruction: "Diagram created. Use zivis_get_diagram to see full content, or zivis_manage_diagram to modify metadata/links, or zivis_update_mermaid_source to change the diagram source.",
148
56
  };
149
57
  return {
150
58
  content: [
@@ -1,7 +1,7 @@
1
1
  import { z } from "zod";
2
2
  import type { ApiClient } from "../api-client.js";
3
3
  export declare const GET_DIAGRAM_NAME = "zivis_get_diagram";
4
- export declare const GET_DIAGRAM_DESCRIPTION = "Get the full content of a diagram including all nodes, connections, boundaries, and Mermaid source.\n\nReturns node IDs, names, tags, positions, boundary assignments, and metadata. Connection IDs include source/target node references and labels. Boundary IDs include labels and positions.\n\nFor mermaid-type diagrams, the `content` field contains the full Mermaid source string \u2014 use it to read or render the diagram. For canvas-type diagrams, `content` is null and the structure is expressed via nodes/connections/boundaries.\n\nUse this before modifying a diagram \u2014 you need node/connection/boundary IDs for zivis_manage_diagram (canvas) or the Mermaid source for zivis_update_mermaid_source (mermaid).";
4
+ export declare const GET_DIAGRAM_DESCRIPTION = "Get the full content of a diagram, including its Mermaid source.\n\nUse this before modifying a diagram \u2014 you need the current Mermaid source for zivis_update_mermaid_source.";
5
5
  export declare const GET_DIAGRAM_SCHEMA: {
6
6
  diagram_id: z.ZodString;
7
7
  };
@@ -1,13 +1,9 @@
1
1
  import { z } from "zod";
2
2
  import { sanitizeResponse } from "../sanitize.js";
3
3
  export const GET_DIAGRAM_NAME = "zivis_get_diagram";
4
- export const GET_DIAGRAM_DESCRIPTION = `Get the full content of a diagram including all nodes, connections, boundaries, and Mermaid source.
4
+ export const GET_DIAGRAM_DESCRIPTION = `Get the full content of a diagram, including its Mermaid source.
5
5
 
6
- Returns node IDs, names, tags, positions, boundary assignments, and metadata. Connection IDs include source/target node references and labels. Boundary IDs include labels and positions.
7
-
8
- For mermaid-type diagrams, the \`content\` field contains the full Mermaid source string — use it to read or render the diagram. For canvas-type diagrams, \`content\` is null and the structure is expressed via nodes/connections/boundaries.
9
-
10
- Use this before modifying a diagram — you need node/connection/boundary IDs for zivis_manage_diagram (canvas) or the Mermaid source for zivis_update_mermaid_source (mermaid).`;
6
+ Use this before modifying a diagram you need the current Mermaid source for zivis_update_mermaid_source.`;
11
7
  export const GET_DIAGRAM_SCHEMA = {
12
8
  diagram_id: z
13
9
  .string()
@@ -18,49 +14,6 @@ export function createGetDiagramHandler(apiClient) {
18
14
  try {
19
15
  const data = await apiClient.get(`/api/diagrams/${params.diagram_id}`);
20
16
  const sanitized = sanitizeResponse(data);
21
- const nodes = Array.isArray(sanitized.nodes)
22
- ? sanitized.nodes.map((n) => ({
23
- node_id: n.id,
24
- name: n.name,
25
- description: n.description || null,
26
- tags: n.tags || [],
27
- icon: n.icon || null,
28
- color: n.color || null,
29
- position_x: n.positionX,
30
- position_y: n.positionY,
31
- width: n.width,
32
- height: n.height,
33
- step_order: n.stepOrder || null,
34
- boundary_id: n.boundaryId || null,
35
- metadata: n.metadata || null,
36
- linked_finding_ids: n.linkedFindingIds || [],
37
- linked_evidence_ids: n.linkedEvidenceIds || [],
38
- }))
39
- : [];
40
- const connections = Array.isArray(sanitized.connections)
41
- ? sanitized.connections.map((c) => ({
42
- connection_id: c.id,
43
- source_node_id: c.sourceNodeId,
44
- target_node_id: c.targetNodeId,
45
- label: c.label || null,
46
- description: c.description || null,
47
- tags: c.tags || [],
48
- bidirectional: c.bidirectional || false,
49
- metadata: c.metadata || null,
50
- }))
51
- : [];
52
- const boundaries = Array.isArray(sanitized.boundaries)
53
- ? sanitized.boundaries.map((b) => ({
54
- boundary_id: b.id,
55
- label: b.label,
56
- description: b.description || null,
57
- color: b.color || null,
58
- position_x: b.positionX,
59
- position_y: b.positionY,
60
- width: b.width,
61
- height: b.height,
62
- }))
63
- : [];
64
17
  const linkedThreatModelIds = Array.isArray(sanitized.threatModelLinks)
65
18
  ? sanitized.threatModelLinks.map((l) => l.threatModelId)
66
19
  : [];
@@ -74,9 +27,6 @@ export function createGetDiagramHandler(apiClient) {
74
27
  source_type: sanitized.sourceType,
75
28
  created_at: sanitized.createdAt,
76
29
  updated_at: sanitized.updatedAt,
77
- nodes,
78
- connections,
79
- boundaries,
80
30
  linked_threat_model_ids: linkedThreatModelIds,
81
31
  };
82
32
  return {
@@ -1,7 +1,7 @@
1
1
  import { z } from "zod";
2
2
  import type { ApiClient } from "../api-client.js";
3
3
  export declare const LIST_DIAGRAMS_NAME = "zivis_list_diagrams";
4
- export declare const LIST_DIAGRAMS_DESCRIPTION = "List diagrams for your organization. Returns summary info (name, type, node/connection counts) for each diagram.\n\nUse this tool to find existing diagrams before modifying them. To get the full content (nodes, connections, boundaries), use zivis_get_diagram with the diagram_id from this response.\n\nDiagrams can be linked to threat models. Use linked_threat_model_id to find diagrams for a specific threat model.";
4
+ export declare const LIST_DIAGRAMS_DESCRIPTION = "List diagrams for your organization. Returns summary info (name, type, description) for each diagram.\n\nUse this tool to find existing diagrams before modifying them. To get the full content (Mermaid source), use zivis_get_diagram with the diagram_id from this response.\n\nDiagrams can be linked to threat models. Use linked_threat_model_id to find diagrams for a specific threat model.";
5
5
  export declare const LIST_DIAGRAMS_SCHEMA: {
6
6
  diagram_type: z.ZodOptional<z.ZodEnum<{
7
7
  custom: "custom";
@@ -1,9 +1,9 @@
1
1
  import { z } from "zod";
2
2
  import { sanitizeResponse } from "../sanitize.js";
3
3
  export const LIST_DIAGRAMS_NAME = "zivis_list_diagrams";
4
- export const LIST_DIAGRAMS_DESCRIPTION = `List diagrams for your organization. Returns summary info (name, type, node/connection counts) for each diagram.
4
+ export const LIST_DIAGRAMS_DESCRIPTION = `List diagrams for your organization. Returns summary info (name, type, description) for each diagram.
5
5
 
6
- Use this tool to find existing diagrams before modifying them. To get the full content (nodes, connections, boundaries), use zivis_get_diagram with the diagram_id from this response.
6
+ Use this tool to find existing diagrams before modifying them. To get the full content (Mermaid source), use zivis_get_diagram with the diagram_id from this response.
7
7
 
8
8
  Diagrams can be linked to threat models. Use linked_threat_model_id to find diagrams for a specific threat model.`;
9
9
  export const LIST_DIAGRAMS_SCHEMA = {
@@ -52,7 +52,6 @@ export function createListDiagramsHandler(apiClient) {
52
52
  description: d.description || null,
53
53
  created_at: d.createdAt,
54
54
  updated_at: d.updatedAt,
55
- stats: d._count || null,
56
55
  }))
57
56
  : sanitized.diagrams;
58
57
  return {
@@ -1,21 +1,12 @@
1
1
  import { z } from "zod";
2
2
  import type { ApiClient } from "../api-client.js";
3
3
  export declare const MANAGE_DIAGRAM_NAME = "zivis_manage_diagram";
4
- export declare const MANAGE_DIAGRAM_DESCRIPTION = "Modify an existing diagram: update metadata, add/update/delete nodes, connections, and boundaries, or link/unlink threat models.\n\n**Before modifying:** Use zivis_get_diagram to fetch current content and get node/connection/boundary IDs.\n\nActions:\n- update_metadata: Update diagram name, description, or type\n- delete_diagram: Delete the entire diagram\n- add_node: Add a new node (requires node_name)\n- update_node: Update an existing node (requires node_id)\n- delete_node: Remove a node (requires node_id)\n- add_connection: Add a connection between two nodes (requires source_node_id, target_node_id)\n- update_connection: Update a connection (requires connection_id)\n- delete_connection: Remove a connection (requires connection_id)\n- add_boundary: Add a boundary group (requires boundary_label)\n- update_boundary: Update a boundary (requires boundary_id)\n- delete_boundary: Remove a boundary (requires boundary_id)\n- link_threat_model: Link diagram to a threat model (requires threat_model_id)\n- unlink_threat_model: Unlink from a threat model (requires threat_model_id)";
4
+ export declare const MANAGE_DIAGRAM_DESCRIPTION = "Modify an existing diagram: update metadata, delete it, or link/unlink it to a threat model.\n\nTo change a diagram's Mermaid source, use zivis_update_mermaid_source instead.\n\nActions:\n- update_metadata: Update diagram name, description, or type\n- delete_diagram: Delete the entire diagram\n- link_threat_model: Link diagram to a threat model (requires threat_model_id)\n- unlink_threat_model: Unlink from a threat model (requires threat_model_id)";
5
5
  export declare const MANAGE_DIAGRAM_SCHEMA: {
6
6
  diagram_id: z.ZodString;
7
7
  action: z.ZodEnum<{
8
8
  update_metadata: "update_metadata";
9
9
  delete_diagram: "delete_diagram";
10
- add_node: "add_node";
11
- update_node: "update_node";
12
- delete_node: "delete_node";
13
- add_connection: "add_connection";
14
- update_connection: "update_connection";
15
- delete_connection: "delete_connection";
16
- add_boundary: "add_boundary";
17
- update_boundary: "update_boundary";
18
- delete_boundary: "delete_boundary";
19
10
  link_threat_model: "link_threat_model";
20
11
  unlink_threat_model: "unlink_threat_model";
21
12
  }>;
@@ -31,33 +22,6 @@ export declare const MANAGE_DIAGRAM_SCHEMA: {
31
22
  trust_boundary: "trust_boundary";
32
23
  network: "network";
33
24
  }>>;
34
- node_id: z.ZodOptional<z.ZodString>;
35
- node_name: z.ZodOptional<z.ZodString>;
36
- node_description: z.ZodOptional<z.ZodString>;
37
- node_tags: z.ZodOptional<z.ZodArray<z.ZodString>>;
38
- node_icon: z.ZodOptional<z.ZodString>;
39
- node_color: z.ZodOptional<z.ZodString>;
40
- position_x: z.ZodOptional<z.ZodNumber>;
41
- position_y: z.ZodOptional<z.ZodNumber>;
42
- width: z.ZodOptional<z.ZodNumber>;
43
- height: z.ZodOptional<z.ZodNumber>;
44
- step_order: z.ZodOptional<z.ZodNumber>;
45
- boundary_id: z.ZodOptional<z.ZodString>;
46
- metadata: z.ZodOptional<z.ZodRecord<z.ZodString, z.ZodUnknown>>;
47
- connection_id: z.ZodOptional<z.ZodString>;
48
- source_node_id: z.ZodOptional<z.ZodString>;
49
- target_node_id: z.ZodOptional<z.ZodString>;
50
- label: z.ZodOptional<z.ZodString>;
51
- connection_description: z.ZodOptional<z.ZodString>;
52
- connection_tags: z.ZodOptional<z.ZodArray<z.ZodString>>;
53
- bidirectional: z.ZodOptional<z.ZodBoolean>;
54
- boundary_label: z.ZodOptional<z.ZodString>;
55
- boundary_description: z.ZodOptional<z.ZodString>;
56
- boundary_color: z.ZodOptional<z.ZodString>;
57
- boundary_position_x: z.ZodOptional<z.ZodNumber>;
58
- boundary_position_y: z.ZodOptional<z.ZodNumber>;
59
- boundary_width: z.ZodOptional<z.ZodNumber>;
60
- boundary_height: z.ZodOptional<z.ZodNumber>;
61
25
  threat_model_id: z.ZodOptional<z.ZodString>;
62
26
  };
63
27
  type ManageDiagramParams = {
@@ -66,33 +30,6 @@ type ManageDiagramParams = {
66
30
  name?: string;
67
31
  description?: string;
68
32
  diagram_type?: string;
69
- node_id?: string;
70
- node_name?: string;
71
- node_description?: string;
72
- node_tags?: string[];
73
- node_icon?: string;
74
- node_color?: string;
75
- position_x?: number;
76
- position_y?: number;
77
- width?: number;
78
- height?: number;
79
- step_order?: number;
80
- boundary_id?: string;
81
- metadata?: Record<string, unknown>;
82
- connection_id?: string;
83
- source_node_id?: string;
84
- target_node_id?: string;
85
- label?: string;
86
- connection_description?: string;
87
- connection_tags?: string[];
88
- bidirectional?: boolean;
89
- boundary_label?: string;
90
- boundary_description?: string;
91
- boundary_color?: string;
92
- boundary_position_x?: number;
93
- boundary_position_y?: number;
94
- boundary_width?: number;
95
- boundary_height?: number;
96
33
  threat_model_id?: string;
97
34
  };
98
35
  export declare function createManageDiagramHandler(apiClient: ApiClient): (params: ManageDiagramParams) => Promise<{
@@ -1,22 +1,13 @@
1
1
  import { z } from "zod";
2
2
  import { sanitizeResponse } from "../sanitize.js";
3
3
  export const MANAGE_DIAGRAM_NAME = "zivis_manage_diagram";
4
- export const MANAGE_DIAGRAM_DESCRIPTION = `Modify an existing diagram: update metadata, add/update/delete nodes, connections, and boundaries, or link/unlink threat models.
4
+ export const MANAGE_DIAGRAM_DESCRIPTION = `Modify an existing diagram: update metadata, delete it, or link/unlink it to a threat model.
5
5
 
6
- **Before modifying:** Use zivis_get_diagram to fetch current content and get node/connection/boundary IDs.
6
+ To change a diagram's Mermaid source, use zivis_update_mermaid_source instead.
7
7
 
8
8
  Actions:
9
9
  - update_metadata: Update diagram name, description, or type
10
10
  - delete_diagram: Delete the entire diagram
11
- - add_node: Add a new node (requires node_name)
12
- - update_node: Update an existing node (requires node_id)
13
- - delete_node: Remove a node (requires node_id)
14
- - add_connection: Add a connection between two nodes (requires source_node_id, target_node_id)
15
- - update_connection: Update a connection (requires connection_id)
16
- - delete_connection: Remove a connection (requires connection_id)
17
- - add_boundary: Add a boundary group (requires boundary_label)
18
- - update_boundary: Update a boundary (requires boundary_id)
19
- - delete_boundary: Remove a boundary (requires boundary_id)
20
11
  - link_threat_model: Link diagram to a threat model (requires threat_model_id)
21
12
  - unlink_threat_model: Unlink from a threat model (requires threat_model_id)`;
22
13
  export const MANAGE_DIAGRAM_SCHEMA = {
@@ -27,15 +18,6 @@ export const MANAGE_DIAGRAM_SCHEMA = {
27
18
  .enum([
28
19
  "update_metadata",
29
20
  "delete_diagram",
30
- "add_node",
31
- "update_node",
32
- "delete_node",
33
- "add_connection",
34
- "update_connection",
35
- "delete_connection",
36
- "add_boundary",
37
- "update_boundary",
38
- "delete_boundary",
39
21
  "link_threat_model",
40
22
  "unlink_threat_model",
41
23
  ])
@@ -46,33 +28,6 @@ export const MANAGE_DIAGRAM_SCHEMA = {
46
28
  .enum(["architecture", "data_flow", "attack_chain", "sequence", "trust_boundary", "network", "deployment", "custom"])
47
29
  .optional()
48
30
  .describe("Diagram type (update_metadata)"),
49
- node_id: z.string().optional().describe("Node UUID (required for update_node, delete_node)"),
50
- node_name: z.string().optional().describe("Node name (required for add_node, optional for update_node)"),
51
- node_description: z.string().optional().describe("Node description"),
52
- node_tags: z.array(z.string()).optional().describe("Node tags (e.g., ['database', 'port:5432'])"),
53
- node_icon: z.string().optional().describe("Node icon"),
54
- node_color: z.string().optional().describe("Hex color (e.g., '#336791')"),
55
- position_x: z.number().optional().describe("X position on canvas"),
56
- position_y: z.number().optional().describe("Y position on canvas"),
57
- width: z.number().optional().describe("Width in pixels"),
58
- height: z.number().optional().describe("Height in pixels"),
59
- step_order: z.number().optional().describe("Step order (attack chain diagrams)"),
60
- boundary_id: z.string().optional().describe("Boundary UUID to assign node to, or boundary to update/delete"),
61
- metadata: z.record(z.string(), z.unknown()).optional().describe("Custom metadata JSON"),
62
- connection_id: z.string().optional().describe("Connection UUID (required for update_connection, delete_connection)"),
63
- source_node_id: z.string().optional().describe("Source node UUID (required for add_connection)"),
64
- target_node_id: z.string().optional().describe("Target node UUID (required for add_connection)"),
65
- label: z.string().optional().describe("Connection label"),
66
- connection_description: z.string().optional().describe("Connection description"),
67
- connection_tags: z.array(z.string()).optional().describe("Connection tags"),
68
- bidirectional: z.boolean().optional().describe("Whether connection goes both ways"),
69
- boundary_label: z.string().optional().describe("Boundary label (required for add_boundary)"),
70
- boundary_description: z.string().optional().describe("Boundary description"),
71
- boundary_color: z.string().optional().describe("Boundary hex color"),
72
- boundary_position_x: z.number().optional().describe("Boundary X position"),
73
- boundary_position_y: z.number().optional().describe("Boundary Y position"),
74
- boundary_width: z.number().optional().describe("Boundary width"),
75
- boundary_height: z.number().optional().describe("Boundary height"),
76
31
  threat_model_id: z.string().optional().describe("Threat model UUID (link/unlink)"),
77
32
  };
78
33
  function errorResult(message) {
@@ -107,170 +62,6 @@ export function createManageDiagramHandler(apiClient) {
107
62
  await apiClient.del(base);
108
63
  return successResult({ action: "deleted", diagram_id });
109
64
  }
110
- case "add_node": {
111
- if (!params.node_name)
112
- return errorResult("node_name is required for add_node");
113
- const body = {
114
- name: params.node_name,
115
- };
116
- if (params.node_description)
117
- body.description = params.node_description;
118
- if (params.node_tags)
119
- body.tags = params.node_tags;
120
- if (params.node_icon)
121
- body.icon = params.node_icon;
122
- if (params.node_color)
123
- body.color = params.node_color;
124
- if (params.position_x !== undefined)
125
- body.positionX = params.position_x;
126
- if (params.position_y !== undefined)
127
- body.positionY = params.position_y;
128
- if (params.width !== undefined)
129
- body.width = params.width;
130
- if (params.height !== undefined)
131
- body.height = params.height;
132
- if (params.step_order !== undefined)
133
- body.stepOrder = params.step_order;
134
- if (params.boundary_id)
135
- body.boundaryId = params.boundary_id;
136
- if (params.metadata)
137
- body.metadata = params.metadata;
138
- const data = await apiClient.post(`${base}/nodes`, body);
139
- return successResult(data);
140
- }
141
- case "update_node": {
142
- if (!params.node_id)
143
- return errorResult("node_id is required for update_node");
144
- const body = {};
145
- if (params.node_name)
146
- body.name = params.node_name;
147
- if (params.node_description !== undefined)
148
- body.description = params.node_description;
149
- if (params.node_tags)
150
- body.tags = params.node_tags;
151
- if (params.node_icon !== undefined)
152
- body.icon = params.node_icon;
153
- if (params.node_color !== undefined)
154
- body.color = params.node_color;
155
- if (params.position_x !== undefined)
156
- body.positionX = params.position_x;
157
- if (params.position_y !== undefined)
158
- body.positionY = params.position_y;
159
- if (params.width !== undefined)
160
- body.width = params.width;
161
- if (params.height !== undefined)
162
- body.height = params.height;
163
- if (params.step_order !== undefined)
164
- body.stepOrder = params.step_order;
165
- if (params.boundary_id !== undefined)
166
- body.boundaryId = params.boundary_id;
167
- if (params.metadata)
168
- body.metadata = params.metadata;
169
- const data = await apiClient.patch(`${base}/nodes/${params.node_id}`, body);
170
- return successResult(data);
171
- }
172
- case "delete_node": {
173
- if (!params.node_id)
174
- return errorResult("node_id is required for delete_node");
175
- await apiClient.del(`${base}/nodes/${params.node_id}`);
176
- return successResult({ action: "deleted", node_id: params.node_id });
177
- }
178
- case "add_connection": {
179
- if (!params.source_node_id || !params.target_node_id) {
180
- return errorResult("source_node_id and target_node_id are required for add_connection");
181
- }
182
- const body = {
183
- sourceNodeId: params.source_node_id,
184
- targetNodeId: params.target_node_id,
185
- };
186
- if (params.label)
187
- body.label = params.label;
188
- if (params.connection_description)
189
- body.description = params.connection_description;
190
- if (params.connection_tags)
191
- body.tags = params.connection_tags;
192
- if (params.bidirectional !== undefined)
193
- body.bidirectional = params.bidirectional;
194
- if (params.metadata)
195
- body.metadata = params.metadata;
196
- const data = await apiClient.post(`${base}/connections`, body);
197
- return successResult(data);
198
- }
199
- case "update_connection": {
200
- if (!params.connection_id)
201
- return errorResult("connection_id is required for update_connection");
202
- const body = {};
203
- if (params.source_node_id)
204
- body.sourceNodeId = params.source_node_id;
205
- if (params.target_node_id)
206
- body.targetNodeId = params.target_node_id;
207
- if (params.label !== undefined)
208
- body.label = params.label;
209
- if (params.connection_description !== undefined)
210
- body.description = params.connection_description;
211
- if (params.connection_tags)
212
- body.tags = params.connection_tags;
213
- if (params.bidirectional !== undefined)
214
- body.bidirectional = params.bidirectional;
215
- if (params.metadata)
216
- body.metadata = params.metadata;
217
- const data = await apiClient.patch(`${base}/connections/${params.connection_id}`, body);
218
- return successResult(data);
219
- }
220
- case "delete_connection": {
221
- if (!params.connection_id)
222
- return errorResult("connection_id is required for delete_connection");
223
- await apiClient.del(`${base}/connections/${params.connection_id}`);
224
- return successResult({ action: "deleted", connection_id: params.connection_id });
225
- }
226
- case "add_boundary": {
227
- if (!params.boundary_label)
228
- return errorResult("boundary_label is required for add_boundary");
229
- const body = {
230
- label: params.boundary_label,
231
- };
232
- if (params.boundary_description)
233
- body.description = params.boundary_description;
234
- if (params.boundary_color)
235
- body.color = params.boundary_color;
236
- if (params.boundary_position_x !== undefined)
237
- body.positionX = params.boundary_position_x;
238
- if (params.boundary_position_y !== undefined)
239
- body.positionY = params.boundary_position_y;
240
- if (params.boundary_width !== undefined)
241
- body.width = params.boundary_width;
242
- if (params.boundary_height !== undefined)
243
- body.height = params.boundary_height;
244
- const data = await apiClient.post(`${base}/boundaries`, body);
245
- return successResult(data);
246
- }
247
- case "update_boundary": {
248
- if (!params.boundary_id)
249
- return errorResult("boundary_id is required for update_boundary");
250
- const body = {};
251
- if (params.boundary_label)
252
- body.label = params.boundary_label;
253
- if (params.boundary_description !== undefined)
254
- body.description = params.boundary_description;
255
- if (params.boundary_color !== undefined)
256
- body.color = params.boundary_color;
257
- if (params.boundary_position_x !== undefined)
258
- body.positionX = params.boundary_position_x;
259
- if (params.boundary_position_y !== undefined)
260
- body.positionY = params.boundary_position_y;
261
- if (params.boundary_width !== undefined)
262
- body.width = params.boundary_width;
263
- if (params.boundary_height !== undefined)
264
- body.height = params.boundary_height;
265
- const data = await apiClient.patch(`${base}/boundaries/${params.boundary_id}`, body);
266
- return successResult(data);
267
- }
268
- case "delete_boundary": {
269
- if (!params.boundary_id)
270
- return errorResult("boundary_id is required for delete_boundary");
271
- await apiClient.del(`${base}/boundaries/${params.boundary_id}`);
272
- return successResult({ action: "deleted", boundary_id: params.boundary_id });
273
- }
274
65
  case "link_threat_model": {
275
66
  if (!params.threat_model_id)
276
67
  return errorResult("threat_model_id is required for link_threat_model");
@@ -1,7 +1,7 @@
1
1
  import { z } from "zod";
2
2
  import type { ApiClient } from "../api-client.js";
3
3
  export declare const UPDATE_MERMAID_SOURCE_NAME = "zivis_update_mermaid_source";
4
- export declare const UPDATE_MERMAID_SOURCE_DESCRIPTION = "Replace the Mermaid source of a diagram with new Mermaid syntax.\n\n**Use this when:** the diagram's contentType is \"mermaid\" (text-based) and you want to add, rename, delete, or reconnect nodes in the diagram via Mermaid syntax.\n\n**Workflow:**\n1. Call zivis_get_diagram first to read the current Mermaid source.\n2. Reason about the requested change (rename a node, add a connection, restructure a subgraph, etc.).\n3. Produce a COMPLETE, valid Mermaid source string.\n4. Call this tool with the new source \u2014 it replaces the entire content atomically.\n\n**Do not use for canvas diagrams** (structured nodes/connections). Use zivis_manage_diagram for those.\n\n**Keep the overall structure.** Only change what the user asked for. Preserve unrelated nodes, edges, labels, subgraphs, styles.";
4
+ export declare const UPDATE_MERMAID_SOURCE_DESCRIPTION = "Replace the Mermaid source of a diagram with new Mermaid syntax.\n\n**Use this when:** you want to add, rename, delete, or reconnect nodes in a diagram via Mermaid syntax.\n\n**Workflow:**\n1. Call zivis_get_diagram first to read the current Mermaid source.\n2. Reason about the requested change (rename a node, add a connection, restructure a subgraph, etc.).\n3. Produce a COMPLETE, valid Mermaid source string.\n4. Call this tool with the new source \u2014 it replaces the entire content atomically.\n\n**Keep the overall structure.** Only change what the user asked for. Preserve unrelated nodes, edges, labels, subgraphs, styles.";
5
5
  export declare const UPDATE_MERMAID_SOURCE_SCHEMA: {
6
6
  diagram_id: z.ZodString;
7
7
  mermaid_source: z.ZodString;
@@ -3,7 +3,7 @@ import { sanitizeResponse } from "../sanitize.js";
3
3
  export const UPDATE_MERMAID_SOURCE_NAME = "zivis_update_mermaid_source";
4
4
  export const UPDATE_MERMAID_SOURCE_DESCRIPTION = `Replace the Mermaid source of a diagram with new Mermaid syntax.
5
5
 
6
- **Use this when:** the diagram's contentType is "mermaid" (text-based) and you want to add, rename, delete, or reconnect nodes in the diagram via Mermaid syntax.
6
+ **Use this when:** you want to add, rename, delete, or reconnect nodes in a diagram via Mermaid syntax.
7
7
 
8
8
  **Workflow:**
9
9
  1. Call zivis_get_diagram first to read the current Mermaid source.
@@ -11,8 +11,6 @@ export const UPDATE_MERMAID_SOURCE_DESCRIPTION = `Replace the Mermaid source of
11
11
  3. Produce a COMPLETE, valid Mermaid source string.
12
12
  4. Call this tool with the new source — it replaces the entire content atomically.
13
13
 
14
- **Do not use for canvas diagrams** (structured nodes/connections). Use zivis_manage_diagram for those.
15
-
16
14
  **Keep the overall structure.** Only change what the user asked for. Preserve unrelated nodes, edges, labels, subgraphs, styles.`;
17
15
  export const UPDATE_MERMAID_SOURCE_SCHEMA = {
18
16
  diagram_id: z.string().describe("UUID of the diagram to update"),
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@zivis/mcp",
3
- "version": "0.1.11",
3
+ "version": "0.1.12",
4
4
  "description": "ZIVIS MCP server — threat modeling, security scans, and AI red team tools for IDE integration",
5
5
  "license": "Apache-2.0",
6
6
  "homepage": "https://zivis.ai",
@@ -59,7 +59,7 @@
59
59
  "@ast-grep/lang-python": "^0.0.6",
60
60
  "@ast-grep/napi": "^0.42.1",
61
61
  "@modelcontextprotocol/sdk": "^1.26.0",
62
- "js-yaml": "^4.1.0",
62
+ "js-yaml": "^4.3.2",
63
63
  "open": "^10.1.0",
64
64
  "zod": "^4.0.0"
65
65
  },
@@ -1,30 +0,0 @@
1
- import { z } from "zod";
2
- import type { ApiClient } from "../api-client.js";
3
- export declare const GENERATE_DIAGRAM_NAME = "zivis_generate_diagram";
4
- export declare const GENERATE_DIAGRAM_DESCRIPTION = "Generate a visual architecture diagram from a Docker Compose file.\n\nReads a local docker-compose.yml and sends it to the ZIVIS platform to generate\na positioned canvas diagram with:\n- Services mapped to color-coded nodes (database, cache, app, proxy, etc.)\n- Docker networks mapped to boundary groups\n- depends_on relationships mapped to connections\n- Auto-positioned grid layout grouped by network\n\nThe diagram is saved to your organization and can be viewed/edited in the diagram editor.\n\nSupported formats: docker-compose (docker-compose.yml, compose.yml)\nComing soon: Kubernetes manifests, Terraform configs";
5
- export declare const GENERATE_DIAGRAM_SCHEMA: {
6
- file_path: z.ZodOptional<z.ZodString>;
7
- source_format: z.ZodDefault<z.ZodEnum<{
8
- "docker-compose": "docker-compose";
9
- }>>;
10
- name: z.ZodOptional<z.ZodString>;
11
- project_dir: z.ZodOptional<z.ZodString>;
12
- };
13
- export declare function createGenerateDiagramHandler(apiClient: ApiClient): (params: {
14
- file_path?: string;
15
- source_format?: string;
16
- name?: string;
17
- project_dir?: string;
18
- }) => Promise<{
19
- content: {
20
- type: "text";
21
- text: string;
22
- }[];
23
- isError: boolean;
24
- } | {
25
- content: {
26
- type: "text";
27
- text: string;
28
- }[];
29
- isError?: undefined;
30
- }>;
@@ -1,161 +0,0 @@
1
- import { z } from "zod";
2
- import { readFile } from "fs/promises";
3
- import { join, relative, resolve } from "path";
4
- import { sanitizeResponse } from "../sanitize.js";
5
- function resolveWithinProjectDir(projectDir, candidate) {
6
- const base = resolve(projectDir);
7
- const target = resolve(base, candidate);
8
- const rel = relative(base, target);
9
- if (rel.startsWith(".."))
10
- return null;
11
- return target;
12
- }
13
- export const GENERATE_DIAGRAM_NAME = "zivis_generate_diagram";
14
- export const GENERATE_DIAGRAM_DESCRIPTION = `Generate a visual architecture diagram from a Docker Compose file.
15
-
16
- Reads a local docker-compose.yml and sends it to the ZIVIS platform to generate
17
- a positioned canvas diagram with:
18
- - Services mapped to color-coded nodes (database, cache, app, proxy, etc.)
19
- - Docker networks mapped to boundary groups
20
- - depends_on relationships mapped to connections
21
- - Auto-positioned grid layout grouped by network
22
-
23
- The diagram is saved to your organization and can be viewed/edited in the diagram editor.
24
-
25
- Supported formats: docker-compose (docker-compose.yml, compose.yml)
26
- Coming soon: Kubernetes manifests, Terraform configs`;
27
- export const GENERATE_DIAGRAM_SCHEMA = {
28
- file_path: z
29
- .string()
30
- .optional()
31
- .describe("Path to the infrastructure file (e.g., docker-compose.yml). " +
32
- "If not provided, searches the current directory for docker-compose.yml, " +
33
- "docker-compose.yaml, compose.yml, or compose.yaml."),
34
- source_format: z
35
- .enum(["docker-compose"])
36
- .default("docker-compose")
37
- .describe("The format of the source file. Currently only docker-compose is supported."),
38
- name: z
39
- .string()
40
- .optional()
41
- .describe("Custom name for the generated diagram. Defaults to 'Docker Compose Architecture'."),
42
- project_dir: z
43
- .string()
44
- .optional()
45
- .describe("Project directory to search for compose files. Defaults to current working directory."),
46
- };
47
- const COMPOSE_FILE_CANDIDATES = [
48
- "docker-compose.yml",
49
- "docker-compose.yaml",
50
- "compose.yml",
51
- "compose.yaml",
52
- ];
53
- export function createGenerateDiagramHandler(apiClient) {
54
- return async (params) => {
55
- const projectDir = params.project_dir || process.cwd();
56
- const sourceFormat = params.source_format || "docker-compose";
57
- let filePath = params.file_path;
58
- let content = null;
59
- if (filePath) {
60
- const resolved = resolveWithinProjectDir(projectDir, filePath);
61
- if (!resolved) {
62
- return {
63
- content: [
64
- {
65
- type: "text",
66
- text: `Error: file_path must resolve inside project_dir (got: ${filePath})`,
67
- },
68
- ],
69
- isError: true,
70
- };
71
- }
72
- try {
73
- content = await readFile(resolved, "utf-8");
74
- }
75
- catch {
76
- return {
77
- content: [
78
- {
79
- type: "text",
80
- text: `Error: File not found: ${resolved}`,
81
- },
82
- ],
83
- isError: true,
84
- };
85
- }
86
- }
87
- else {
88
- for (const candidate of COMPOSE_FILE_CANDIDATES) {
89
- try {
90
- content = await readFile(join(projectDir, candidate), "utf-8");
91
- filePath = candidate;
92
- break;
93
- }
94
- catch {
95
- }
96
- }
97
- if (!content) {
98
- return {
99
- content: [
100
- {
101
- type: "text",
102
- text: "Error: No docker-compose file found. Searched for: " +
103
- COMPOSE_FILE_CANDIDATES.join(", "),
104
- },
105
- ],
106
- isError: true,
107
- };
108
- }
109
- }
110
- if (content.length > 500 * 1024) {
111
- return {
112
- content: [
113
- {
114
- type: "text",
115
- text: "Error: File too large (max 500KB)",
116
- },
117
- ],
118
- isError: true,
119
- };
120
- }
121
- try {
122
- const data = await apiClient.post("/api/diagrams/generate", {
123
- content,
124
- sourceFormat,
125
- name: params.name,
126
- });
127
- const summary = {
128
- diagram_id: data.id,
129
- name: data.name,
130
- type: data.diagramType,
131
- source_file: filePath,
132
- stats: {
133
- nodes: data.nodes?.length || 0,
134
- connections: data.connections?.length || 0,
135
- boundaries: data.boundaries?.length || 0,
136
- },
137
- nodes: (data.nodes || []).map((n) => ({
138
- name: n.name,
139
- tags: n.tags,
140
- })),
141
- boundaries: (data.boundaries || []).map((b) => b.label),
142
- };
143
- const sanitized = sanitizeResponse(summary);
144
- return {
145
- content: [
146
- {
147
- type: "text",
148
- text: JSON.stringify(sanitized, null, 2),
149
- },
150
- ],
151
- };
152
- }
153
- catch (err) {
154
- const message = err instanceof Error ? err.message : "Failed to generate diagram";
155
- return {
156
- content: [{ type: "text", text: `Error: ${message}` }],
157
- isError: true,
158
- };
159
- }
160
- };
161
- }