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.
- package/README.md +63 -0
- package/dist/src/index.js +45 -0
- package/dist/src/tools/diagramTools.js +426 -0
- package/dist/src/types.js +2 -0
- package/dist/src/utils/fileHandler.js +53 -0
- package/dist/test/test-auto-placement.js +83 -0
- package/dist/test/test-client.js +100 -0
- package/dist/test/test-collision.js +84 -0
- package/dist/test/test-constraints.js +88 -0
- package/dist/test/test-debug.js +41 -0
- package/dist/test/test-directional.js +90 -0
- package/dist/test/test-layer-support.js +69 -0
- package/dist/test/test-refined-spacing.js +58 -0
- package/dist/test/verify_types.js +29 -0
- package/package.json +24 -0
- package/src/index.ts +54 -0
- package/src/tools/diagramTools.ts +440 -0
- package/src/types.ts +78 -0
- package/src/utils/fileHandler.ts +51 -0
- package/test/test-auto-placement.ts +88 -0
- package/test/test-client.ts +116 -0
- package/test/test-collision.ts +93 -0
- package/test/test-constraints.ts +95 -0
- package/test/test-debug.ts +40 -0
- package/test/test-directional.ts +95 -0
- package/test/test-layer-support.ts +77 -0
- package/test/test-refined-spacing.ts +62 -0
- package/test/verify_types.ts +28 -0
- package/test_output/test_autoplacement.3duml +0 -0
- package/test_output/test_collision.3duml +0 -0
- package/test_output/test_constraints.3duml +0 -0
- package/test_output/test_debug.3duml +0 -0
- package/test_output/test_diagram.3duml +0 -0
- package/test_output/test_directional.3duml +0 -0
- package/test_output/test_layers.3duml +0 -0
- package/test_output/test_refined_spacing.3duml +0 -0
- 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
|
+
});
|