dodraw-mcp-server 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.
Files changed (37) hide show
  1. package/README.md +63 -0
  2. package/dist/src/index.js +45 -0
  3. package/dist/src/tools/diagramTools.js +426 -0
  4. package/dist/src/types.js +2 -0
  5. package/dist/src/utils/fileHandler.js +53 -0
  6. package/dist/test/test-auto-placement.js +83 -0
  7. package/dist/test/test-client.js +100 -0
  8. package/dist/test/test-collision.js +84 -0
  9. package/dist/test/test-constraints.js +88 -0
  10. package/dist/test/test-debug.js +41 -0
  11. package/dist/test/test-directional.js +90 -0
  12. package/dist/test/test-layer-support.js +69 -0
  13. package/dist/test/test-refined-spacing.js +58 -0
  14. package/dist/test/verify_types.js +29 -0
  15. package/package.json +24 -0
  16. package/src/index.ts +54 -0
  17. package/src/tools/diagramTools.ts +440 -0
  18. package/src/types.ts +78 -0
  19. package/src/utils/fileHandler.ts +51 -0
  20. package/test/test-auto-placement.ts +88 -0
  21. package/test/test-client.ts +116 -0
  22. package/test/test-collision.ts +93 -0
  23. package/test/test-constraints.ts +95 -0
  24. package/test/test-debug.ts +40 -0
  25. package/test/test-directional.ts +95 -0
  26. package/test/test-layer-support.ts +77 -0
  27. package/test/test-refined-spacing.ts +62 -0
  28. package/test/verify_types.ts +28 -0
  29. package/test_output/test_autoplacement.3duml +0 -0
  30. package/test_output/test_collision.3duml +0 -0
  31. package/test_output/test_constraints.3duml +0 -0
  32. package/test_output/test_debug.3duml +0 -0
  33. package/test_output/test_diagram.3duml +0 -0
  34. package/test_output/test_directional.3duml +0 -0
  35. package/test_output/test_layers.3duml +0 -0
  36. package/test_output/test_refined_spacing.3duml +0 -0
  37. package/tsconfig.json +13 -0
@@ -0,0 +1,100 @@
1
+ "use strict";
2
+ var __importDefault = (this && this.__importDefault) || function (mod) {
3
+ return (mod && mod.__esModule) ? mod : { "default": mod };
4
+ };
5
+ Object.defineProperty(exports, "__esModule", { value: true });
6
+ const index_js_1 = require("@modelcontextprotocol/sdk/client/index.js");
7
+ const stdio_js_1 = require("@modelcontextprotocol/sdk/client/stdio.js");
8
+ const path_1 = __importDefault(require("path"));
9
+ const fs_1 = __importDefault(require("fs"));
10
+ async function main() {
11
+ const serverPath = path_1.default.join(process.cwd(), "dist/src/index.js");
12
+ const transport = new stdio_js_1.StdioClientTransport({
13
+ command: "node",
14
+ args: [serverPath]
15
+ });
16
+ const client = new index_js_1.Client({
17
+ name: "test-client",
18
+ version: "1.0.0",
19
+ }, {
20
+ capabilities: {},
21
+ });
22
+ console.log("Connecting to server...");
23
+ await client.connect(transport);
24
+ // List tools
25
+ console.log("Listing tools...");
26
+ const tools = await client.listTools();
27
+ console.log("Tools found:", tools.tools.map(t => t.name).join(", "));
28
+ // Create diagram
29
+ const testDir = path_1.default.join(__dirname, "../../test_output");
30
+ if (!fs_1.default.existsSync(testDir)) {
31
+ fs_1.default.mkdirSync(testDir);
32
+ }
33
+ const filePath = path_1.default.join(testDir, "test_diagram.3duml");
34
+ // Clean up previous run
35
+ if (fs_1.default.existsSync(filePath)) {
36
+ fs_1.default.unlinkSync(filePath);
37
+ }
38
+ console.log(`Creating diagram at ${filePath}...`);
39
+ await client.callTool({
40
+ name: "create_new_diagram",
41
+ arguments: { filePath }
42
+ });
43
+ console.log("Created diagram.");
44
+ // Add node
45
+ console.log("Adding node...");
46
+ const nodeResult = await client.callTool({
47
+ name: "add_node",
48
+ arguments: {
49
+ filePath,
50
+ label: "Test Node 1",
51
+ shape: "rectangle",
52
+ x: 0,
53
+ y: 0,
54
+ backgroundColor: "#ff0000"
55
+ }
56
+ });
57
+ console.log("Added node result:", nodeResult);
58
+ // Add another node
59
+ await client.callTool({
60
+ name: "add_node",
61
+ arguments: {
62
+ filePath,
63
+ label: "Test Node 2",
64
+ shape: "rounded",
65
+ x: 5,
66
+ y: 0
67
+ }
68
+ });
69
+ // Read structure to find IDs
70
+ const structure = await client.callTool({
71
+ name: "read_diagram_structure",
72
+ arguments: { filePath }
73
+ });
74
+ const content = JSON.parse(structure.content[0].text);
75
+ const id1 = content.nodes[0].id;
76
+ const id2 = content.nodes[1].id;
77
+ console.log(`Nodes created: ${id1}, ${id2}`);
78
+ // Add edge
79
+ console.log("Adding edge...");
80
+ await client.callTool({
81
+ name: "add_edge",
82
+ arguments: {
83
+ filePath,
84
+ sourceId: id1,
85
+ targetId: id2,
86
+ sourcePointIndex: 1, // Right
87
+ targetPointIndex: 3, // Left
88
+ label: "Connects to"
89
+ }
90
+ });
91
+ console.log("Added edge.");
92
+ // Final read
93
+ const finalStructure = await client.callTool({
94
+ name: "read_diagram_structure",
95
+ arguments: { filePath }
96
+ });
97
+ console.log("Final Structure:", finalStructure.content[0].text);
98
+ await client.close();
99
+ }
100
+ main().catch(console.error);
@@ -0,0 +1,84 @@
1
+ "use strict";
2
+ var __importDefault = (this && this.__importDefault) || function (mod) {
3
+ return (mod && mod.__esModule) ? mod : { "default": mod };
4
+ };
5
+ Object.defineProperty(exports, "__esModule", { value: true });
6
+ const index_js_1 = require("@modelcontextprotocol/sdk/client/index.js");
7
+ const stdio_js_1 = require("@modelcontextprotocol/sdk/client/stdio.js");
8
+ const path_1 = __importDefault(require("path"));
9
+ const process_1 = __importDefault(require("process"));
10
+ async function main() {
11
+ console.log("Connecting...");
12
+ const transport = new stdio_js_1.StdioClientTransport({
13
+ command: "node",
14
+ args: [path_1.default.join(process_1.default.cwd(), "dist", "src", "index.js")],
15
+ });
16
+ const client = new index_js_1.Client({ name: "test-collision", version: "1.0" }, { capabilities: {} });
17
+ await client.connect(transport);
18
+ try {
19
+ const filePath = path_1.default.join(process_1.default.cwd(), "test_output", "test_collision.3duml");
20
+ await client.callTool({ name: "create_new_diagram", arguments: { filePath } });
21
+ // 1. Add Root Node
22
+ console.log("Adding Root Node...");
23
+ const rootNode = await client.callTool({
24
+ name: "add_node",
25
+ arguments: { filePath, label: "Root", x: 0, y: 0, width: 2, height: 1.5 }
26
+ });
27
+ const rootId = rootNode.content[0].text.match(/Added node ([a-zA-Z0-9-]+)/)[1];
28
+ // 2. Add Node A to RIGHT
29
+ console.log("Adding Node A (RIGHT)...");
30
+ await client.callTool({
31
+ name: "add_directional_node",
32
+ arguments: { filePath, sourceNodeId: rootId, direction: "RIGHT", label: "Node A" }
33
+ });
34
+ // 3. Add Node B to RIGHT (Collision with A?)
35
+ console.log("Adding Node B (RIGHT) - Should Collide with A...");
36
+ await client.callTool({
37
+ name: "add_directional_node",
38
+ arguments: { filePath, sourceNodeId: rootId, direction: "RIGHT", label: "Node B" }
39
+ });
40
+ // Verify state
41
+ const result = await client.callTool({ name: "read_diagram_structure", arguments: { filePath } });
42
+ const state = JSON.parse(result.content[0].text);
43
+ const nodeA = state.nodes.find((n) => n.label === "Node A");
44
+ const nodeB = state.nodes.find((n) => n.label === "Node B");
45
+ const root = state.nodes.find((n) => n.label === "Root");
46
+ console.log(`Root: (${root.x}, ${root.z})`);
47
+ console.log(`Node A: (${nodeA.x}, ${nodeA.z})`);
48
+ console.log(`Node B: (${nodeB.x}, ${nodeB.z})`);
49
+ // Check Spacing Logic
50
+ // Spacing = 2. Width = 2.
51
+ // Node A should be at: Root.x + (2 + 2) = 4?
52
+ // Let's check formula: newX = source.x + (dirX * (srcW + INITIAL_SPACING))
53
+ // srcW = 2. Spacing = 2.
54
+ // newX = 0 + 1 * (2 + 2) = 4.
55
+ if (Math.abs(nodeA.x - 4) > 0.1) {
56
+ throw new Error(`Node A X position incorrect. Expected 4, got ${nodeA.x}`);
57
+ }
58
+ if (Math.abs(nodeA.z - 0) > 0.1) {
59
+ throw new Error(`Node A Z position incorrect. Expected 0, got ${nodeA.z}`);
60
+ }
61
+ // Check Collision Logic
62
+ // Node B initially tries to go to (4, 0). Collides with A.
63
+ // Shift Rule: Horizontal move -> Shift Z (Down).
64
+ // Shift Z step: srcH + COLLISION_SPACING = 1.5 + 0.5 = 2.0.
65
+ // New Z should be 0 + 2 = 2. (Or z + step)
66
+ // Wait, loop says: newZ += shiftStepZ.
67
+ // So Node B should be at (4, 2).
68
+ if (Math.abs(nodeB.x - 4) > 0.1) {
69
+ throw new Error(`Node B X position incorrect. Expected 4, got ${nodeB.x}`);
70
+ }
71
+ if (Math.abs(nodeB.z - 2) > 0.1) {
72
+ throw new Error(`Node B Z position incorrect. Expected 2, got ${nodeB.z}`);
73
+ }
74
+ console.log("SUCCESS: Collision avoidance verified.");
75
+ }
76
+ catch (e) {
77
+ console.error("FAIL:", e);
78
+ process_1.default.exit(1);
79
+ }
80
+ finally {
81
+ await client.close();
82
+ }
83
+ }
84
+ main();
@@ -0,0 +1,88 @@
1
+ "use strict";
2
+ var __importDefault = (this && this.__importDefault) || function (mod) {
3
+ return (mod && mod.__esModule) ? mod : { "default": mod };
4
+ };
5
+ Object.defineProperty(exports, "__esModule", { value: true });
6
+ const index_js_1 = require("@modelcontextprotocol/sdk/client/index.js");
7
+ const stdio_js_1 = require("@modelcontextprotocol/sdk/client/stdio.js");
8
+ const path_1 = __importDefault(require("path"));
9
+ const process_1 = __importDefault(require("process"));
10
+ async function main() {
11
+ console.log("Connecting...");
12
+ const transport = new stdio_js_1.StdioClientTransport({
13
+ command: "node",
14
+ args: [path_1.default.join(process_1.default.cwd(), "dist", "src", "index.js")],
15
+ });
16
+ const client = new index_js_1.Client({ name: "test-constraints", version: "1.0" }, { capabilities: {} });
17
+ await client.connect(transport);
18
+ try {
19
+ const filePath = path_1.default.join(process_1.default.cwd(), "test_output", "test_constraints.3duml");
20
+ await client.callTool({ name: "create_new_diagram", arguments: { filePath } });
21
+ // 1. Test Layer Auto-Stacking
22
+ console.log("Adding Layer 2 (auto)...");
23
+ const l2 = await client.callTool({
24
+ name: "add_layer",
25
+ arguments: { filePath, name: "Layer 2" }
26
+ });
27
+ console.log("L2 Output:", l2.content[0].text);
28
+ console.log("Adding Layer 3 (auto)...");
29
+ const l3 = await client.callTool({
30
+ name: "add_layer",
31
+ arguments: { filePath, name: "Layer 3" }
32
+ });
33
+ console.log("L3 Output:", l3.content[0].text);
34
+ // 2. Test Node Constraints (Max Width)
35
+ console.log("Adding Giant Node...");
36
+ await client.callTool({
37
+ name: "add_node",
38
+ arguments: { filePath, label: "Giant Node", width: 1000, height: 1000 }
39
+ });
40
+ // 3. Test Edge Constraints (Max Thickness)
41
+ console.log("Add Tiny Edge...");
42
+ // Add nodes to connect
43
+ await client.callTool({ name: "add_node", arguments: { filePath, label: "N1" } });
44
+ await client.callTool({ name: "add_node", arguments: { filePath, label: "N2" } });
45
+ await client.callTool({
46
+ name: "add_edge",
47
+ arguments: {
48
+ filePath,
49
+ sourceId: (await getNodes(client, filePath))[1].id,
50
+ targetId: (await getNodes(client, filePath))[2].id,
51
+ sourcePointIndex: 0, targetPointIndex: 0,
52
+ thickness: 10 // Huge thickness
53
+ }
54
+ });
55
+ // Verify
56
+ const state = await getState(client, filePath);
57
+ // Check Layers
58
+ const layer2 = state.layers.find((l) => l.name === "Layer 2");
59
+ const layer3 = state.layers.find((l) => l.name === "Layer 3");
60
+ if (layer2.position.y !== 50)
61
+ throw new Error(`Layer 2 should be at Y=50, got ${layer2.position.y}`);
62
+ if (layer3.position.y !== 100)
63
+ throw new Error(`Layer 3 should be at Y=100, got ${layer3.position.y}`);
64
+ // Check Node Size
65
+ const giantNode = state.nodes.find((n) => n.label === "Giant Node");
66
+ if (giantNode.width > 50)
67
+ throw new Error(`Giant Node width should be capped at 50, got ${giantNode.width}`);
68
+ // Check Edge Thickness
69
+ const edge = state.edges[0];
70
+ if (edge && edge.thickness > 0.5)
71
+ throw new Error(`Edge thickness should be capped at 0.5, got ${edge.thickness}`);
72
+ console.log("SUCCESS: All constraints and auto-positioning verified.");
73
+ }
74
+ catch (e) {
75
+ console.error("FAIL:", e);
76
+ }
77
+ finally {
78
+ await client.close();
79
+ }
80
+ }
81
+ async function getState(client, filePath) {
82
+ const result = await client.callTool({ name: "read_diagram_structure", arguments: { filePath } });
83
+ return JSON.parse(result.content[0].text);
84
+ }
85
+ async function getNodes(client, filePath) {
86
+ return (await getState(client, filePath)).nodes;
87
+ }
88
+ main();
@@ -0,0 +1,41 @@
1
+ "use strict";
2
+ var __importDefault = (this && this.__importDefault) || function (mod) {
3
+ return (mod && mod.__esModule) ? mod : { "default": mod };
4
+ };
5
+ Object.defineProperty(exports, "__esModule", { value: true });
6
+ const index_js_1 = require("@modelcontextprotocol/sdk/client/index.js");
7
+ const stdio_js_1 = require("@modelcontextprotocol/sdk/client/stdio.js");
8
+ const path_1 = __importDefault(require("path"));
9
+ const process_1 = __importDefault(require("process"));
10
+ async function main() {
11
+ console.log("Connecting...");
12
+ const transport = new stdio_js_1.StdioClientTransport({
13
+ command: "node",
14
+ args: [path_1.default.join(process_1.default.cwd(), "dist", "src", "index.js")],
15
+ });
16
+ const client = new index_js_1.Client({ name: "debug", version: "1.0" }, { capabilities: {} });
17
+ await client.connect(transport);
18
+ try {
19
+ const filePath = path_1.default.join(process_1.default.cwd(), "test_output", "test_debug.3duml");
20
+ await client.callTool({ name: "create_new_diagram", arguments: { filePath } });
21
+ console.log("Adding Node C...");
22
+ await client.callTool({
23
+ name: "add_node",
24
+ arguments: { filePath, label: "Node C", x: 10, y: 10 }
25
+ });
26
+ console.log("Node C added.");
27
+ console.log("Adding Node D...");
28
+ await client.callTool({
29
+ name: "add_node",
30
+ arguments: { filePath, label: "Node D" }
31
+ });
32
+ console.log("Node D added.");
33
+ }
34
+ catch (e) {
35
+ console.error("FAIL:", e);
36
+ }
37
+ finally {
38
+ await client.close();
39
+ }
40
+ }
41
+ main();
@@ -0,0 +1,90 @@
1
+ "use strict";
2
+ var __importDefault = (this && this.__importDefault) || function (mod) {
3
+ return (mod && mod.__esModule) ? mod : { "default": mod };
4
+ };
5
+ Object.defineProperty(exports, "__esModule", { value: true });
6
+ const index_js_1 = require("@modelcontextprotocol/sdk/client/index.js");
7
+ const stdio_js_1 = require("@modelcontextprotocol/sdk/client/stdio.js");
8
+ const path_1 = __importDefault(require("path"));
9
+ const process_1 = __importDefault(require("process"));
10
+ async function main() {
11
+ console.log("Connecting...");
12
+ const transport = new stdio_js_1.StdioClientTransport({
13
+ command: "node",
14
+ args: [path_1.default.join(process_1.default.cwd(), "dist", "src", "index.js")],
15
+ });
16
+ const client = new index_js_1.Client({ name: "test-directional", version: "1.0" }, { capabilities: {} });
17
+ await client.connect(transport);
18
+ try {
19
+ const filePath = path_1.default.join(process_1.default.cwd(), "test_output", "test_directional.3duml");
20
+ await client.callTool({ name: "create_new_diagram", arguments: { filePath } });
21
+ // 1. Add Root Node
22
+ console.log("Adding Root Node...");
23
+ const rootNode = await client.callTool({
24
+ name: "add_node",
25
+ arguments: { filePath, label: "Root", x: 0, y: 0 } // Central point
26
+ });
27
+ const rootId = rootNode.content[0].text.match(/Added node ([a-zA-Z0-9-]+)/)[1];
28
+ console.log(`Root ID: ${rootId}`);
29
+ // 2. Add RIGHT Node
30
+ console.log("Adding RIGHT Node...");
31
+ await client.callTool({
32
+ name: "add_directional_node",
33
+ arguments: { filePath, sourceNodeId: rootId, direction: "RIGHT", label: "Right Node" }
34
+ });
35
+ // 3. Add LEFT Node
36
+ console.log("Adding LEFT Node...");
37
+ await client.callTool({
38
+ name: "add_directional_node",
39
+ arguments: { filePath, sourceNodeId: rootId, direction: "LEFT", label: "Left Node" }
40
+ });
41
+ // 4. Add DOWN Node
42
+ console.log("Adding DOWN Node...");
43
+ await client.callTool({
44
+ name: "add_directional_node",
45
+ arguments: { filePath, sourceNodeId: rootId, direction: "DOWN", label: "Down Node" }
46
+ });
47
+ // 5. Add UP Node
48
+ console.log("Adding UP Node...");
49
+ await client.callTool({
50
+ name: "add_directional_node",
51
+ arguments: { filePath, sourceNodeId: rootId, direction: "UP", label: "Up Node" }
52
+ });
53
+ // Verify state
54
+ const result = await client.callTool({ name: "read_diagram_structure", arguments: { filePath } });
55
+ const state = JSON.parse(result.content[0].text);
56
+ console.log("Verifying nodes and edges...");
57
+ const rightNode = state.nodes.find((n) => n.label === "Right Node");
58
+ const leftNode = state.nodes.find((n) => n.label === "Left Node");
59
+ const downNode = state.nodes.find((n) => n.label === "Down Node");
60
+ const upNode = state.nodes.find((n) => n.label === "Up Node");
61
+ // Verify Positions
62
+ // Expected: Right(5, 0), Left(-5, 0), Down(0, 4), Up(0, -4)
63
+ console.log(`Right: (${rightNode.x}, ${rightNode.z})`); // z is diagram Y
64
+ console.log(`Left: (${leftNode.x}, ${leftNode.z})`);
65
+ console.log(`Down: (${downNode.x}, ${downNode.z})`);
66
+ console.log(`Up: (${upNode.x}, ${upNode.z})`);
67
+ if (rightNode.x !== 5)
68
+ throw new Error("Right node X incorrect");
69
+ if (leftNode.x !== -5)
70
+ throw new Error("Left node X incorrect");
71
+ if (downNode.z !== 4)
72
+ throw new Error("Down node Z incorrect");
73
+ if (upNode.z !== -4)
74
+ throw new Error("Up node Z incorrect");
75
+ // Verify Connections
76
+ // Start counting edges connected to Root
77
+ const edges = state.edges.filter((e) => e.sourceId === rootId || e.targetId === rootId);
78
+ console.log(`Edges connected to Root: ${edges.length}`);
79
+ if (edges.length !== 4)
80
+ throw new Error("Should be 4 edges connecting to Root");
81
+ console.log("SUCCESS: Directional node creation verified.");
82
+ }
83
+ catch (e) {
84
+ console.error("FAIL:", e);
85
+ }
86
+ finally {
87
+ await client.close();
88
+ }
89
+ }
90
+ main();
@@ -0,0 +1,69 @@
1
+ "use strict";
2
+ var __importDefault = (this && this.__importDefault) || function (mod) {
3
+ return (mod && mod.__esModule) ? mod : { "default": mod };
4
+ };
5
+ Object.defineProperty(exports, "__esModule", { value: true });
6
+ const index_js_1 = require("@modelcontextprotocol/sdk/client/index.js");
7
+ const stdio_js_1 = require("@modelcontextprotocol/sdk/client/stdio.js");
8
+ const path_1 = __importDefault(require("path"));
9
+ const process_1 = __importDefault(require("process"));
10
+ async function main() {
11
+ console.log("Connecting to server...");
12
+ const transport = new stdio_js_1.StdioClientTransport({
13
+ command: "node",
14
+ args: [path_1.default.join(process_1.default.cwd(), "dist", "src", "index.js")],
15
+ });
16
+ const client = new index_js_1.Client({ name: "dodraw-test-client", version: "1.0.0" }, { capabilities: {} });
17
+ await client.connect(transport);
18
+ console.log("Connected.");
19
+ try {
20
+ const filePath = path_1.default.join(process_1.default.cwd(), "test_output", "test_layers.3duml");
21
+ // 1. Create Diagram
22
+ await client.callTool({ name: "create_new_diagram", arguments: { filePath } });
23
+ console.log("Created diagram.");
24
+ // 2. Add Layer
25
+ const layerResult = await client.callTool({
26
+ name: "add_layer",
27
+ arguments: {
28
+ filePath,
29
+ name: "Upper Layer",
30
+ position: { x: 0, y: 50, z: 0 }
31
+ }
32
+ });
33
+ console.log(layerResult.content[0].text);
34
+ // Extract Layer ID (hacky parsing for test)
35
+ const outputText = layerResult.content[0].text;
36
+ const layerId = outputText.match(/ID ([0-9a-f-]+)/)[1];
37
+ console.log(`Extracted Layer ID: ${layerId}`);
38
+ // 3. Add Node to new Layer
39
+ await client.callTool({
40
+ name: "add_node",
41
+ arguments: {
42
+ filePath,
43
+ label: "Node on Upper Layer",
44
+ x: 0,
45
+ y: 0,
46
+ layerId: layerId
47
+ }
48
+ });
49
+ console.log("Added node to upper layer.");
50
+ // 4. Read Structure
51
+ const structureResult = await client.callTool({
52
+ name: "read_diagram_structure",
53
+ arguments: { filePath }
54
+ });
55
+ const structure = JSON.parse(structureResult.content[0].text);
56
+ console.log("Structure:", JSON.stringify(structure, null, 2));
57
+ if (structure.layerCount !== 2)
58
+ throw new Error("Expected 2 layers (default + new)");
59
+ if (structure.nodes[0].layerId !== layerId)
60
+ throw new Error("Node layer ID mismatch");
61
+ }
62
+ catch (error) {
63
+ console.error("Test failed:", error);
64
+ }
65
+ finally {
66
+ await client.close();
67
+ }
68
+ }
69
+ main();
@@ -0,0 +1,58 @@
1
+ "use strict";
2
+ var __importDefault = (this && this.__importDefault) || function (mod) {
3
+ return (mod && mod.__esModule) ? mod : { "default": mod };
4
+ };
5
+ Object.defineProperty(exports, "__esModule", { value: true });
6
+ const index_js_1 = require("@modelcontextprotocol/sdk/client/index.js");
7
+ const stdio_js_1 = require("@modelcontextprotocol/sdk/client/stdio.js");
8
+ const path_1 = __importDefault(require("path"));
9
+ const process_1 = __importDefault(require("process"));
10
+ async function main() {
11
+ console.log("Connecting...");
12
+ const transport = new stdio_js_1.StdioClientTransport({
13
+ command: "node",
14
+ args: [path_1.default.join(process_1.default.cwd(), "dist", "src", "index.js")],
15
+ });
16
+ const client = new index_js_1.Client({ name: "test-refined", version: "1.0" }, { capabilities: {} });
17
+ await client.connect(transport);
18
+ try {
19
+ const filePath = path_1.default.join(process_1.default.cwd(), "test_output", "test_refined_spacing.3duml");
20
+ await client.callTool({ name: "create_new_diagram", arguments: { filePath } });
21
+ // Default Layer 1 is at Y=0
22
+ // 1. Add Layer 2 (auto) -> Should be -2
23
+ console.log("Adding Layer 2...");
24
+ const l2 = await client.callTool({
25
+ name: "add_layer",
26
+ arguments: { filePath, name: "Layer 2" }
27
+ });
28
+ console.log("L2 Output:", l2.content[0].text);
29
+ // 2. Add Layer 3 (auto) -> Should be -4
30
+ console.log("Adding Layer 3...");
31
+ const l3 = await client.callTool({
32
+ name: "add_layer",
33
+ arguments: { filePath, name: "Layer 3" }
34
+ });
35
+ console.log("L3 Output:", l3.content[0].text);
36
+ // Verify state
37
+ const result = await client.callTool({ name: "read_diagram_structure", arguments: { filePath } });
38
+ const state = JSON.parse(result.content[0].text);
39
+ const layer1 = state.layers[0];
40
+ const layer2 = state.layers.find((l) => l.name === "Layer 2");
41
+ const layer3 = state.layers.find((l) => l.name === "Layer 3");
42
+ console.log(`Layer 1 Y: ${layer1.position.y}`);
43
+ console.log(`Layer 2 Y: ${layer2.position.y}`);
44
+ console.log(`Layer 3 Y: ${layer3.position.y}`);
45
+ if (layer2.position.y !== -2)
46
+ throw new Error(`Layer 2 should be at Y=-2, got ${layer2.position.y}`);
47
+ if (layer3.position.y !== -4)
48
+ throw new Error(`Layer 3 should be at Y=-4, got ${layer3.position.y}`);
49
+ console.log("SUCCESS: Refined spacing verified.");
50
+ }
51
+ catch (e) {
52
+ console.error("FAIL:", e);
53
+ }
54
+ finally {
55
+ await client.close();
56
+ }
57
+ }
58
+ main();
@@ -0,0 +1,29 @@
1
+ "use strict";
2
+ var __importDefault = (this && this.__importDefault) || function (mod) {
3
+ return (mod && mod.__esModule) ? mod : { "default": mod };
4
+ };
5
+ Object.defineProperty(exports, "__esModule", { value: true });
6
+ const promises_1 = __importDefault(require("fs/promises"));
7
+ const jszip_1 = __importDefault(require("jszip"));
8
+ async function checkFile(filePath, label) {
9
+ try {
10
+ console.log(`Checking ${label}: ${filePath}`);
11
+ const content = await promises_1.default.readFile(filePath);
12
+ const zip = await jszip_1.default.loadAsync(content);
13
+ const jsonStr = await zip.file("diagram.json")?.async("string");
14
+ if (!jsonStr)
15
+ throw new Error("No diagram.json");
16
+ const json = JSON.parse(jsonStr);
17
+ console.log(`Layer Count: ${json.layers.length}`);
18
+ json.layers.forEach((l) => {
19
+ console.log(`Layer '${l.name}': Y=${l.transform.position.y}`);
20
+ });
21
+ }
22
+ catch (e) {
23
+ console.log(`Error checking ${label}: ${e.message}`);
24
+ }
25
+ }
26
+ async function main() {
27
+ await checkFile("q:/source/Antigravity/Learn/3DUML/mcp_layer_refined_test.3duml", "Refined Layer Auto-Pos Check");
28
+ }
29
+ main();
package/package.json ADDED
@@ -0,0 +1,24 @@
1
+ {
2
+ "name": "dodraw-mcp-server",
3
+ "version": "0.1.0",
4
+ "description": "MCP server for DoDraw",
5
+ "main": "dist/src/index.js",
6
+ "bin": {
7
+ "dodraw-mcp-server": "dist/src/index.js"
8
+ },
9
+ "scripts": {
10
+ "build": "tsc",
11
+ "start": "node dist/src/index.js",
12
+ "dev": "tsc -w"
13
+ },
14
+ "dependencies": {
15
+ "@modelcontextprotocol/sdk": "^0.6.0",
16
+ "jszip": "^3.10.1",
17
+ "zod": "^3.22.4"
18
+ },
19
+ "devDependencies": {
20
+ "typescript": "^5.3.3",
21
+ "@types/node": "^20.10.5",
22
+ "@types/jszip": "^3.4.1"
23
+ }
24
+ }
package/src/index.ts ADDED
@@ -0,0 +1,54 @@
1
+ #!/usr/bin/env node
2
+
3
+ import { Server } from "@modelcontextprotocol/sdk/server/index.js";
4
+ import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio.js";
5
+ import {
6
+ CallToolRequestSchema,
7
+ ListToolsRequestSchema,
8
+ } from "@modelcontextprotocol/sdk/types.js";
9
+ import { toolDefinitions, handleToolCall } from "./tools/diagramTools.js";
10
+
11
+ const server = new Server(
12
+ {
13
+ name: "dodraw-mcp-server",
14
+ version: "0.1.0",
15
+ },
16
+ {
17
+ capabilities: {
18
+ tools: {},
19
+ },
20
+ }
21
+ );
22
+
23
+ server.setRequestHandler(ListToolsRequestSchema, async () => {
24
+ return {
25
+ tools: toolDefinitions,
26
+ };
27
+ });
28
+
29
+ server.setRequestHandler(CallToolRequestSchema, async (request) => {
30
+ try {
31
+ return await handleToolCall(request.params.name, request.params.arguments);
32
+ } catch (error: any) {
33
+ return {
34
+ content: [
35
+ {
36
+ type: "text",
37
+ text: `Error: ${error.message}`,
38
+ },
39
+ ],
40
+ isError: true,
41
+ };
42
+ }
43
+ });
44
+
45
+ async function main() {
46
+ const transport = new StdioServerTransport();
47
+ await server.connect(transport);
48
+ console.error("DoDraw MCP Server running on stdio");
49
+ }
50
+
51
+ main().catch((error) => {
52
+ console.error("Fatal error in main():", error);
53
+ process.exit(1);
54
+ });