@io.github.hj1003862396/draw-flow-mcp-server 1.0.1
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 +208 -0
- package/dist/diagram-operations.d.ts +28 -0
- package/dist/diagram-operations.d.ts.map +1 -0
- package/dist/diagram-operations.js +211 -0
- package/dist/diagram-operations.js.map +1 -0
- package/dist/history.d.ts +16 -0
- package/dist/history.d.ts.map +1 -0
- package/dist/history.js +48 -0
- package/dist/history.js.map +1 -0
- package/dist/http-server.d.ts +22 -0
- package/dist/http-server.d.ts.map +1 -0
- package/dist/http-server.js +562 -0
- package/dist/http-server.js.map +1 -0
- package/dist/index.d.ts +11 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +531 -0
- package/dist/index.js.map +1 -0
- package/dist/logger.d.ts +14 -0
- package/dist/logger.d.ts.map +1 -0
- package/dist/logger.js +24 -0
- package/dist/logger.js.map +1 -0
- package/dist/xml-validation.d.ts +40 -0
- package/dist/xml-validation.d.ts.map +1 -0
- package/dist/xml-validation.js +790 -0
- package/dist/xml-validation.js.map +1 -0
- package/package.json +55 -0
package/README.md
ADDED
|
@@ -0,0 +1,208 @@
|
|
|
1
|
+
# Next AI Draw.io MCP Server
|
|
2
|
+
|
|
3
|
+
MCP (Model Context Protocol) server that enables AI agents like Claude Desktop and Cursor to generate and edit draw.io diagrams with **real-time browser preview**.
|
|
4
|
+
|
|
5
|
+
**Self-contained** - includes an embedded HTTP server, no external dependencies required.
|
|
6
|
+
|
|
7
|
+
## Quick Start
|
|
8
|
+
|
|
9
|
+
```json
|
|
10
|
+
{
|
|
11
|
+
"mcpServers": {
|
|
12
|
+
"drawio": {
|
|
13
|
+
"command": "npx",
|
|
14
|
+
"args": ["@next-ai-drawio/mcp-server@latest"]
|
|
15
|
+
}
|
|
16
|
+
}
|
|
17
|
+
}
|
|
18
|
+
```
|
|
19
|
+
|
|
20
|
+
## Installation
|
|
21
|
+
|
|
22
|
+
### Claude Desktop
|
|
23
|
+
|
|
24
|
+
Add to your Claude Desktop config (`~/Library/Application Support/Claude/claude_desktop_config.json` on macOS):
|
|
25
|
+
|
|
26
|
+
```json
|
|
27
|
+
{
|
|
28
|
+
"mcpServers": {
|
|
29
|
+
"drawio": {
|
|
30
|
+
"command": "npx",
|
|
31
|
+
"args": ["@next-ai-drawio/mcp-server@latest"]
|
|
32
|
+
}
|
|
33
|
+
}
|
|
34
|
+
}
|
|
35
|
+
```
|
|
36
|
+
|
|
37
|
+
### VS Code
|
|
38
|
+
|
|
39
|
+
Add to your VS Code settings (`.vscode/mcp.json` in workspace or user settings):
|
|
40
|
+
|
|
41
|
+
```json
|
|
42
|
+
{
|
|
43
|
+
"mcpServers": {
|
|
44
|
+
"drawio": {
|
|
45
|
+
"command": "npx",
|
|
46
|
+
"args": ["@next-ai-drawio/mcp-server@latest"]
|
|
47
|
+
}
|
|
48
|
+
}
|
|
49
|
+
}
|
|
50
|
+
```
|
|
51
|
+
|
|
52
|
+
### Cursor
|
|
53
|
+
|
|
54
|
+
Add to Cursor MCP config (`~/.cursor/mcp.json`):
|
|
55
|
+
|
|
56
|
+
```json
|
|
57
|
+
{
|
|
58
|
+
"mcpServers": {
|
|
59
|
+
"drawio": {
|
|
60
|
+
"command": "npx",
|
|
61
|
+
"args": ["@next-ai-drawio/mcp-server@latest"]
|
|
62
|
+
}
|
|
63
|
+
}
|
|
64
|
+
}
|
|
65
|
+
```
|
|
66
|
+
|
|
67
|
+
### Cline (VS Code Extension)
|
|
68
|
+
|
|
69
|
+
1. Click the **MCP Servers** icon in Cline's top menu bar
|
|
70
|
+
2. Select the **Configure** tab
|
|
71
|
+
3. Click **Configure MCP Servers** to edit `cline_mcp_settings.json`
|
|
72
|
+
4. Add the drawio server:
|
|
73
|
+
|
|
74
|
+
```json
|
|
75
|
+
{
|
|
76
|
+
"mcpServers": {
|
|
77
|
+
"drawio": {
|
|
78
|
+
"command": "npx",
|
|
79
|
+
"args": ["@next-ai-drawio/mcp-server@latest"]
|
|
80
|
+
}
|
|
81
|
+
}
|
|
82
|
+
}
|
|
83
|
+
```
|
|
84
|
+
|
|
85
|
+
### Claude Code CLI
|
|
86
|
+
|
|
87
|
+
```bash
|
|
88
|
+
claude mcp add drawio -- npx @next-ai-drawio/mcp-server@latest
|
|
89
|
+
```
|
|
90
|
+
|
|
91
|
+
### Other MCP Clients
|
|
92
|
+
|
|
93
|
+
Use the standard MCP configuration with:
|
|
94
|
+
- **Command**: `npx`
|
|
95
|
+
- **Args**: `["@next-ai-drawio/mcp-server@latest"]`
|
|
96
|
+
|
|
97
|
+
## Usage
|
|
98
|
+
|
|
99
|
+
1. Restart your MCP client after updating config
|
|
100
|
+
2. Ask the AI to create a diagram:
|
|
101
|
+
> "Create a flowchart showing user authentication with login, MFA, and session management"
|
|
102
|
+
3. The diagram appears in your browser in real-time!
|
|
103
|
+
|
|
104
|
+
## Features
|
|
105
|
+
|
|
106
|
+
- **Real-time Preview**: Diagrams appear and update in your browser as the AI creates them
|
|
107
|
+
- **Version History**: Restore previous diagram versions with visual thumbnails - click the clock button (bottom-right) to browse and restore earlier states
|
|
108
|
+
- **Natural Language**: Describe diagrams in plain text - flowcharts, architecture diagrams, etc.
|
|
109
|
+
- **Edit Support**: Modify existing diagrams with natural language instructions
|
|
110
|
+
- **Export**: Save diagrams as `.drawio` files
|
|
111
|
+
- **Self-contained**: Embedded server, works offline (except draw.io UI which loads from `embed.diagrams.net` by default, configurable via `DRAWIO_BASE_URL`)
|
|
112
|
+
|
|
113
|
+
## Available Tools
|
|
114
|
+
|
|
115
|
+
| Tool | Description |
|
|
116
|
+
|------|-------------|
|
|
117
|
+
| `start_session` | Opens browser with real-time diagram preview |
|
|
118
|
+
| `create_new_diagram` | Create a new diagram from XML (requires `xml` argument) |
|
|
119
|
+
| `edit_diagram` | Edit diagram by ID-based operations (update/add/delete cells) |
|
|
120
|
+
| `get_diagram` | Get the current diagram XML |
|
|
121
|
+
| `export_diagram` | Save diagram to a `.drawio` file |
|
|
122
|
+
|
|
123
|
+
## How It Works
|
|
124
|
+
|
|
125
|
+
```
|
|
126
|
+
┌─────────────────┐ stdio ┌─────────────────┐
|
|
127
|
+
│ Claude Desktop │ <───────────> │ MCP Server │
|
|
128
|
+
│ (AI Agent) │ │ (this package) │
|
|
129
|
+
└─────────────────┘ └────────┬────────┘
|
|
130
|
+
│
|
|
131
|
+
┌────────▼────────┐
|
|
132
|
+
│ Embedded HTTP │
|
|
133
|
+
│ Server (:6002) │
|
|
134
|
+
└────────┬────────┘
|
|
135
|
+
│
|
|
136
|
+
┌────────▼────────┐
|
|
137
|
+
│ User's Browser │
|
|
138
|
+
│ (draw.io embed) │
|
|
139
|
+
└─────────────────┘
|
|
140
|
+
```
|
|
141
|
+
|
|
142
|
+
1. **MCP Server** receives tool calls from Claude via stdio
|
|
143
|
+
2. **Embedded HTTP Server** serves the draw.io UI and handles state
|
|
144
|
+
3. **Browser** shows real-time diagram updates via polling
|
|
145
|
+
|
|
146
|
+
## Configuration
|
|
147
|
+
|
|
148
|
+
| Variable | Default | Description |
|
|
149
|
+
|----------|---------|-------------|
|
|
150
|
+
| `PORT` | `6002` | Port for the embedded HTTP server |
|
|
151
|
+
| `DRAWIO_BASE_URL` | `https://embed.diagrams.net` | Base URL for the draw.io embed. Set this to use a self-hosted draw.io instance for private deployments. |
|
|
152
|
+
|
|
153
|
+
### Private Deployment (Self-hosted draw.io)
|
|
154
|
+
|
|
155
|
+
For security-sensitive environments that require private deployment of draw.io:
|
|
156
|
+
|
|
157
|
+
```json
|
|
158
|
+
{
|
|
159
|
+
"mcpServers": {
|
|
160
|
+
"drawio": {
|
|
161
|
+
"command": "npx",
|
|
162
|
+
"args": ["@next-ai-drawio/mcp-server@latest"],
|
|
163
|
+
"env": {
|
|
164
|
+
"DRAWIO_BASE_URL": "https://drawio.your-company.com"
|
|
165
|
+
}
|
|
166
|
+
}
|
|
167
|
+
}
|
|
168
|
+
}
|
|
169
|
+
```
|
|
170
|
+
|
|
171
|
+
You can deploy your own draw.io instance using the official Docker image:
|
|
172
|
+
|
|
173
|
+
```bash
|
|
174
|
+
docker run -d -p 8080:8080 jgraph/drawio
|
|
175
|
+
```
|
|
176
|
+
|
|
177
|
+
Then set `DRAWIO_BASE_URL=http://localhost:8080` (or your server's URL).
|
|
178
|
+
|
|
179
|
+
## Troubleshooting
|
|
180
|
+
|
|
181
|
+
### Port already in use
|
|
182
|
+
|
|
183
|
+
If port 6002 is in use, the server will automatically try the next available port (up to 6020).
|
|
184
|
+
|
|
185
|
+
Or set a custom port:
|
|
186
|
+
```json
|
|
187
|
+
{
|
|
188
|
+
"mcpServers": {
|
|
189
|
+
"drawio": {
|
|
190
|
+
"command": "npx",
|
|
191
|
+
"args": ["@next-ai-drawio/mcp-server@latest"],
|
|
192
|
+
"env": { "PORT": "6003" }
|
|
193
|
+
}
|
|
194
|
+
}
|
|
195
|
+
}
|
|
196
|
+
```
|
|
197
|
+
|
|
198
|
+
### "No active session"
|
|
199
|
+
|
|
200
|
+
Call `start_session` first to open the browser window.
|
|
201
|
+
|
|
202
|
+
### Browser not updating
|
|
203
|
+
|
|
204
|
+
Check that the browser URL has the `?mcp=` query parameter. The MCP session ID connects the browser to the server.
|
|
205
|
+
|
|
206
|
+
## License
|
|
207
|
+
|
|
208
|
+
Apache-2.0
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* ID-based diagram operations
|
|
3
|
+
* Copied from lib/utils.ts to avoid cross-package imports
|
|
4
|
+
*/
|
|
5
|
+
export interface DiagramOperation {
|
|
6
|
+
operation: "update" | "add" | "delete";
|
|
7
|
+
cell_id: string;
|
|
8
|
+
new_xml?: string;
|
|
9
|
+
}
|
|
10
|
+
export interface OperationError {
|
|
11
|
+
type: "update" | "add" | "delete";
|
|
12
|
+
cellId: string;
|
|
13
|
+
message: string;
|
|
14
|
+
}
|
|
15
|
+
export interface ApplyOperationsResult {
|
|
16
|
+
result: string;
|
|
17
|
+
errors: OperationError[];
|
|
18
|
+
}
|
|
19
|
+
/**
|
|
20
|
+
* Apply diagram operations (update/add/delete) using ID-based lookup.
|
|
21
|
+
* This replaces the text-matching approach with direct DOM manipulation.
|
|
22
|
+
*
|
|
23
|
+
* @param xmlContent - The full mxfile XML content
|
|
24
|
+
* @param operations - Array of operations to apply
|
|
25
|
+
* @returns Object with result XML and any errors
|
|
26
|
+
*/
|
|
27
|
+
export declare function applyDiagramOperations(xmlContent: string, operations: DiagramOperation[]): ApplyOperationsResult;
|
|
28
|
+
//# sourceMappingURL=diagram-operations.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"diagram-operations.d.ts","sourceRoot":"","sources":["../src/diagram-operations.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,MAAM,WAAW,gBAAgB;IAC7B,SAAS,EAAE,QAAQ,GAAG,KAAK,GAAG,QAAQ,CAAA;IACtC,OAAO,EAAE,MAAM,CAAA;IACf,OAAO,CAAC,EAAE,MAAM,CAAA;CACnB;AAED,MAAM,WAAW,cAAc;IAC3B,IAAI,EAAE,QAAQ,GAAG,KAAK,GAAG,QAAQ,CAAA;IACjC,MAAM,EAAE,MAAM,CAAA;IACd,OAAO,EAAE,MAAM,CAAA;CAClB;AAED,MAAM,WAAW,qBAAqB;IAClC,MAAM,EAAE,MAAM,CAAA;IACd,MAAM,EAAE,cAAc,EAAE,CAAA;CAC3B;AAED;;;;;;;GAOG;AACH,wBAAgB,sBAAsB,CAClC,UAAU,EAAE,MAAM,EAClB,UAAU,EAAE,gBAAgB,EAAE,GAC/B,qBAAqB,CAsOvB"}
|
|
@@ -0,0 +1,211 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* ID-based diagram operations
|
|
3
|
+
* Copied from lib/utils.ts to avoid cross-package imports
|
|
4
|
+
*/
|
|
5
|
+
/**
|
|
6
|
+
* Apply diagram operations (update/add/delete) using ID-based lookup.
|
|
7
|
+
* This replaces the text-matching approach with direct DOM manipulation.
|
|
8
|
+
*
|
|
9
|
+
* @param xmlContent - The full mxfile XML content
|
|
10
|
+
* @param operations - Array of operations to apply
|
|
11
|
+
* @returns Object with result XML and any errors
|
|
12
|
+
*/
|
|
13
|
+
export function applyDiagramOperations(xmlContent, operations) {
|
|
14
|
+
const errors = [];
|
|
15
|
+
// Parse the XML
|
|
16
|
+
const parser = new DOMParser();
|
|
17
|
+
const doc = parser.parseFromString(xmlContent, "text/xml");
|
|
18
|
+
// Check for parse errors
|
|
19
|
+
const parseError = doc.querySelector("parsererror");
|
|
20
|
+
if (parseError) {
|
|
21
|
+
return {
|
|
22
|
+
result: xmlContent,
|
|
23
|
+
errors: [
|
|
24
|
+
{
|
|
25
|
+
type: "update",
|
|
26
|
+
cellId: "",
|
|
27
|
+
message: `XML parse error: ${parseError.textContent}`,
|
|
28
|
+
},
|
|
29
|
+
],
|
|
30
|
+
};
|
|
31
|
+
}
|
|
32
|
+
// Find the root element (inside mxGraphModel)
|
|
33
|
+
const root = doc.querySelector("root");
|
|
34
|
+
if (!root) {
|
|
35
|
+
return {
|
|
36
|
+
result: xmlContent,
|
|
37
|
+
errors: [
|
|
38
|
+
{
|
|
39
|
+
type: "update",
|
|
40
|
+
cellId: "",
|
|
41
|
+
message: "Could not find <root> element in XML",
|
|
42
|
+
},
|
|
43
|
+
],
|
|
44
|
+
};
|
|
45
|
+
}
|
|
46
|
+
// Build a map of cell IDs to elements
|
|
47
|
+
const cellMap = new Map();
|
|
48
|
+
root.querySelectorAll("mxCell").forEach((cell) => {
|
|
49
|
+
const id = cell.getAttribute("id");
|
|
50
|
+
if (id)
|
|
51
|
+
cellMap.set(id, cell);
|
|
52
|
+
});
|
|
53
|
+
// Process each operation
|
|
54
|
+
for (const op of operations) {
|
|
55
|
+
if (op.operation === "update") {
|
|
56
|
+
const existingCell = cellMap.get(op.cell_id);
|
|
57
|
+
if (!existingCell) {
|
|
58
|
+
errors.push({
|
|
59
|
+
type: "update",
|
|
60
|
+
cellId: op.cell_id,
|
|
61
|
+
message: `Cell with id="${op.cell_id}" not found`,
|
|
62
|
+
});
|
|
63
|
+
continue;
|
|
64
|
+
}
|
|
65
|
+
if (!op.new_xml) {
|
|
66
|
+
errors.push({
|
|
67
|
+
type: "update",
|
|
68
|
+
cellId: op.cell_id,
|
|
69
|
+
message: "new_xml is required for update operation",
|
|
70
|
+
});
|
|
71
|
+
continue;
|
|
72
|
+
}
|
|
73
|
+
// Parse the new XML
|
|
74
|
+
const newDoc = parser.parseFromString(`<wrapper>${op.new_xml}</wrapper>`, "text/xml");
|
|
75
|
+
const newCell = newDoc.querySelector("mxCell");
|
|
76
|
+
if (!newCell) {
|
|
77
|
+
errors.push({
|
|
78
|
+
type: "update",
|
|
79
|
+
cellId: op.cell_id,
|
|
80
|
+
message: "new_xml must contain an mxCell element",
|
|
81
|
+
});
|
|
82
|
+
continue;
|
|
83
|
+
}
|
|
84
|
+
// Validate ID matches
|
|
85
|
+
const newCellId = newCell.getAttribute("id");
|
|
86
|
+
if (newCellId !== op.cell_id) {
|
|
87
|
+
errors.push({
|
|
88
|
+
type: "update",
|
|
89
|
+
cellId: op.cell_id,
|
|
90
|
+
message: `ID mismatch: cell_id is "${op.cell_id}" but new_xml has id="${newCellId}"`,
|
|
91
|
+
});
|
|
92
|
+
continue;
|
|
93
|
+
}
|
|
94
|
+
// Import and replace the node
|
|
95
|
+
const importedNode = doc.importNode(newCell, true);
|
|
96
|
+
existingCell.parentNode?.replaceChild(importedNode, existingCell);
|
|
97
|
+
// Update the map with the new element
|
|
98
|
+
cellMap.set(op.cell_id, importedNode);
|
|
99
|
+
}
|
|
100
|
+
else if (op.operation === "add") {
|
|
101
|
+
// Check if ID already exists
|
|
102
|
+
if (cellMap.has(op.cell_id)) {
|
|
103
|
+
errors.push({
|
|
104
|
+
type: "add",
|
|
105
|
+
cellId: op.cell_id,
|
|
106
|
+
message: `Cell with id="${op.cell_id}" already exists`,
|
|
107
|
+
});
|
|
108
|
+
continue;
|
|
109
|
+
}
|
|
110
|
+
if (!op.new_xml) {
|
|
111
|
+
errors.push({
|
|
112
|
+
type: "add",
|
|
113
|
+
cellId: op.cell_id,
|
|
114
|
+
message: "new_xml is required for add operation",
|
|
115
|
+
});
|
|
116
|
+
continue;
|
|
117
|
+
}
|
|
118
|
+
// Parse the new XML
|
|
119
|
+
const newDoc = parser.parseFromString(`<wrapper>${op.new_xml}</wrapper>`, "text/xml");
|
|
120
|
+
const newCell = newDoc.querySelector("mxCell");
|
|
121
|
+
if (!newCell) {
|
|
122
|
+
errors.push({
|
|
123
|
+
type: "add",
|
|
124
|
+
cellId: op.cell_id,
|
|
125
|
+
message: "new_xml must contain an mxCell element",
|
|
126
|
+
});
|
|
127
|
+
continue;
|
|
128
|
+
}
|
|
129
|
+
// Validate ID matches
|
|
130
|
+
const newCellId = newCell.getAttribute("id");
|
|
131
|
+
if (newCellId !== op.cell_id) {
|
|
132
|
+
errors.push({
|
|
133
|
+
type: "add",
|
|
134
|
+
cellId: op.cell_id,
|
|
135
|
+
message: `ID mismatch: cell_id is "${op.cell_id}" but new_xml has id="${newCellId}"`,
|
|
136
|
+
});
|
|
137
|
+
continue;
|
|
138
|
+
}
|
|
139
|
+
// Import and append the node
|
|
140
|
+
const importedNode = doc.importNode(newCell, true);
|
|
141
|
+
root.appendChild(importedNode);
|
|
142
|
+
// Add to map
|
|
143
|
+
cellMap.set(op.cell_id, importedNode);
|
|
144
|
+
}
|
|
145
|
+
else if (op.operation === "delete") {
|
|
146
|
+
// Protect root cells from deletion
|
|
147
|
+
if (op.cell_id === "0" || op.cell_id === "1") {
|
|
148
|
+
errors.push({
|
|
149
|
+
type: "delete",
|
|
150
|
+
cellId: op.cell_id,
|
|
151
|
+
message: `Cannot delete root cell "${op.cell_id}"`,
|
|
152
|
+
});
|
|
153
|
+
continue;
|
|
154
|
+
}
|
|
155
|
+
const existingCell = cellMap.get(op.cell_id);
|
|
156
|
+
if (!existingCell) {
|
|
157
|
+
// Cell not found - might have been cascade-deleted by a previous operation
|
|
158
|
+
// Skip silently instead of erroring (AI may redundantly list children/edges)
|
|
159
|
+
continue;
|
|
160
|
+
}
|
|
161
|
+
// Cascade delete: collect all cells to delete (children + edges + self)
|
|
162
|
+
const cellsToDelete = new Set();
|
|
163
|
+
// Recursive function to find all descendants
|
|
164
|
+
const collectDescendants = (cellId) => {
|
|
165
|
+
if (cellsToDelete.has(cellId))
|
|
166
|
+
return;
|
|
167
|
+
cellsToDelete.add(cellId);
|
|
168
|
+
// Find children (cells where parent === cellId)
|
|
169
|
+
const children = root.querySelectorAll(`mxCell[parent="${cellId}"]`);
|
|
170
|
+
children.forEach((child) => {
|
|
171
|
+
const childId = child.getAttribute("id");
|
|
172
|
+
if (childId && childId !== "0" && childId !== "1") {
|
|
173
|
+
collectDescendants(childId);
|
|
174
|
+
}
|
|
175
|
+
});
|
|
176
|
+
};
|
|
177
|
+
// Collect the target cell and all its descendants
|
|
178
|
+
collectDescendants(op.cell_id);
|
|
179
|
+
// Find edges referencing any of the cells to be deleted
|
|
180
|
+
// Also recursively collect children of those edges (e.g., edge labels)
|
|
181
|
+
for (const cellId of cellsToDelete) {
|
|
182
|
+
const referencingEdges = root.querySelectorAll(`mxCell[source="${cellId}"], mxCell[target="${cellId}"]`);
|
|
183
|
+
referencingEdges.forEach((edge) => {
|
|
184
|
+
const edgeId = edge.getAttribute("id");
|
|
185
|
+
// Protect root cells from being added via edge references
|
|
186
|
+
if (edgeId && edgeId !== "0" && edgeId !== "1") {
|
|
187
|
+
// Recurse to collect edge's children (like labels)
|
|
188
|
+
collectDescendants(edgeId);
|
|
189
|
+
}
|
|
190
|
+
});
|
|
191
|
+
}
|
|
192
|
+
// Log what will be deleted
|
|
193
|
+
if (cellsToDelete.size > 1) {
|
|
194
|
+
console.log(`[applyDiagramOperations] Cascade delete "${op.cell_id}" → deleting ${cellsToDelete.size} cells: ${Array.from(cellsToDelete).join(", ")}`);
|
|
195
|
+
}
|
|
196
|
+
// Delete all collected cells
|
|
197
|
+
for (const cellId of cellsToDelete) {
|
|
198
|
+
const cell = cellMap.get(cellId);
|
|
199
|
+
if (cell) {
|
|
200
|
+
cell.parentNode?.removeChild(cell);
|
|
201
|
+
cellMap.delete(cellId);
|
|
202
|
+
}
|
|
203
|
+
}
|
|
204
|
+
}
|
|
205
|
+
}
|
|
206
|
+
// Serialize back to string
|
|
207
|
+
const serializer = new XMLSerializer();
|
|
208
|
+
const result = serializer.serializeToString(doc);
|
|
209
|
+
return { result, errors };
|
|
210
|
+
}
|
|
211
|
+
//# sourceMappingURL=diagram-operations.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"diagram-operations.js","sourceRoot":"","sources":["../src/diagram-operations.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Simple diagram history - matches Next.js app pattern
|
|
3
|
+
* Stores {xml, svg} entries in a circular buffer
|
|
4
|
+
*/
|
|
5
|
+
export declare function addHistory(sessionId: string, xml: string, svg?: string): number;
|
|
6
|
+
export declare function getHistory(sessionId: string): Array<{
|
|
7
|
+
xml: string;
|
|
8
|
+
svg: string;
|
|
9
|
+
}>;
|
|
10
|
+
export declare function getHistoryEntry(sessionId: string, index: number): {
|
|
11
|
+
xml: string;
|
|
12
|
+
svg: string;
|
|
13
|
+
} | undefined;
|
|
14
|
+
export declare function clearHistory(sessionId: string): void;
|
|
15
|
+
export declare function updateLastHistorySvg(sessionId: string, svg: string): boolean;
|
|
16
|
+
//# sourceMappingURL=history.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"history.d.ts","sourceRoot":"","sources":["../src/history.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAOH,wBAAgB,UAAU,CAAC,SAAS,EAAE,MAAM,EAAE,GAAG,EAAE,MAAM,EAAE,GAAG,SAAK,GAAG,MAAM,CAsB3E;AAED,wBAAgB,UAAU,CACtB,SAAS,EAAE,MAAM,GAClB,KAAK,CAAC;IAAE,GAAG,EAAE,MAAM,CAAC;IAAC,GAAG,EAAE,MAAM,CAAA;CAAE,CAAC,CAErC;AAED,wBAAgB,eAAe,CAC3B,SAAS,EAAE,MAAM,EACjB,KAAK,EAAE,MAAM,GACd;IAAE,GAAG,EAAE,MAAM,CAAC;IAAC,GAAG,EAAE,MAAM,CAAA;CAAE,GAAG,SAAS,CAG1C;AAED,wBAAgB,YAAY,CAAC,SAAS,EAAE,MAAM,GAAG,IAAI,CAEpD;AAED,wBAAgB,oBAAoB,CAAC,SAAS,EAAE,MAAM,EAAE,GAAG,EAAE,MAAM,GAAG,OAAO,CAS5E"}
|
package/dist/history.js
ADDED
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Simple diagram history - matches Next.js app pattern
|
|
3
|
+
* Stores {xml, svg} entries in a circular buffer
|
|
4
|
+
*/
|
|
5
|
+
import { log } from "./logger.js";
|
|
6
|
+
const MAX_HISTORY = 20;
|
|
7
|
+
const historyStore = new Map();
|
|
8
|
+
export function addHistory(sessionId, xml, svg = "") {
|
|
9
|
+
let history = historyStore.get(sessionId);
|
|
10
|
+
if (!history) {
|
|
11
|
+
history = [];
|
|
12
|
+
historyStore.set(sessionId, history);
|
|
13
|
+
}
|
|
14
|
+
// Dedupe: skip if same as last entry
|
|
15
|
+
const last = history[history.length - 1];
|
|
16
|
+
if (last?.xml === xml) {
|
|
17
|
+
return history.length - 1;
|
|
18
|
+
}
|
|
19
|
+
history.push({ xml, svg });
|
|
20
|
+
// Circular buffer
|
|
21
|
+
if (history.length > MAX_HISTORY) {
|
|
22
|
+
history.shift();
|
|
23
|
+
}
|
|
24
|
+
log.debug(`History: session=${sessionId}, entries=${history.length}`);
|
|
25
|
+
return history.length - 1;
|
|
26
|
+
}
|
|
27
|
+
export function getHistory(sessionId) {
|
|
28
|
+
return historyStore.get(sessionId) || [];
|
|
29
|
+
}
|
|
30
|
+
export function getHistoryEntry(sessionId, index) {
|
|
31
|
+
const history = historyStore.get(sessionId);
|
|
32
|
+
return history?.[index];
|
|
33
|
+
}
|
|
34
|
+
export function clearHistory(sessionId) {
|
|
35
|
+
historyStore.delete(sessionId);
|
|
36
|
+
}
|
|
37
|
+
export function updateLastHistorySvg(sessionId, svg) {
|
|
38
|
+
const history = historyStore.get(sessionId);
|
|
39
|
+
if (!history || history.length === 0)
|
|
40
|
+
return false;
|
|
41
|
+
const last = history[history.length - 1];
|
|
42
|
+
if (!last.svg) {
|
|
43
|
+
last.svg = svg;
|
|
44
|
+
return true;
|
|
45
|
+
}
|
|
46
|
+
return false;
|
|
47
|
+
}
|
|
48
|
+
//# sourceMappingURL=history.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"history.js","sourceRoot":"","sources":["../src/history.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,OAAO,EAAE,GAAG,EAAE,MAAM,aAAa,CAAA;AAEjC,MAAM,WAAW,GAAG,EAAE,CAAA;AACtB,MAAM,YAAY,GAAG,IAAI,GAAG,EAA+C,CAAA;AAE3E,MAAM,UAAU,UAAU,CAAC,SAAiB,EAAE,GAAW,EAAE,GAAG,GAAG,EAAE;IAC/D,IAAI,OAAO,GAAG,YAAY,CAAC,GAAG,CAAC,SAAS,CAAC,CAAA;IACzC,IAAI,CAAC,OAAO,EAAE,CAAC;QACX,OAAO,GAAG,EAAE,CAAA;QACZ,YAAY,CAAC,GAAG,CAAC,SAAS,EAAE,OAAO,CAAC,CAAA;IACxC,CAAC;IAED,qCAAqC;IACrC,MAAM,IAAI,GAAG,OAAO,CAAC,OAAO,CAAC,MAAM,GAAG,CAAC,CAAC,CAAA;IACxC,IAAI,IAAI,EAAE,GAAG,KAAK,GAAG,EAAE,CAAC;QACpB,OAAO,OAAO,CAAC,MAAM,GAAG,CAAC,CAAA;IAC7B,CAAC;IAED,OAAO,CAAC,IAAI,CAAC,EAAE,GAAG,EAAE,GAAG,EAAE,CAAC,CAAA;IAE1B,kBAAkB;IAClB,IAAI,OAAO,CAAC,MAAM,GAAG,WAAW,EAAE,CAAC;QAC/B,OAAO,CAAC,KAAK,EAAE,CAAA;IACnB,CAAC;IAED,GAAG,CAAC,KAAK,CAAC,oBAAoB,SAAS,aAAa,OAAO,CAAC,MAAM,EAAE,CAAC,CAAA;IACrE,OAAO,OAAO,CAAC,MAAM,GAAG,CAAC,CAAA;AAC7B,CAAC;AAED,MAAM,UAAU,UAAU,CACtB,SAAiB;IAEjB,OAAO,YAAY,CAAC,GAAG,CAAC,SAAS,CAAC,IAAI,EAAE,CAAA;AAC5C,CAAC;AAED,MAAM,UAAU,eAAe,CAC3B,SAAiB,EACjB,KAAa;IAEb,MAAM,OAAO,GAAG,YAAY,CAAC,GAAG,CAAC,SAAS,CAAC,CAAA;IAC3C,OAAO,OAAO,EAAE,CAAC,KAAK,CAAC,CAAA;AAC3B,CAAC;AAED,MAAM,UAAU,YAAY,CAAC,SAAiB;IAC1C,YAAY,CAAC,MAAM,CAAC,SAAS,CAAC,CAAA;AAClC,CAAC;AAED,MAAM,UAAU,oBAAoB,CAAC,SAAiB,EAAE,GAAW;IAC/D,MAAM,OAAO,GAAG,YAAY,CAAC,GAAG,CAAC,SAAS,CAAC,CAAA;IAC3C,IAAI,CAAC,OAAO,IAAI,OAAO,CAAC,MAAM,KAAK,CAAC;QAAE,OAAO,KAAK,CAAA;IAClD,MAAM,IAAI,GAAG,OAAO,CAAC,OAAO,CAAC,MAAM,GAAG,CAAC,CAAC,CAAA;IACxC,IAAI,CAAC,IAAI,CAAC,GAAG,EAAE,CAAC;QACZ,IAAI,CAAC,GAAG,GAAG,GAAG,CAAA;QACd,OAAO,IAAI,CAAA;IACf,CAAC;IACD,OAAO,KAAK,CAAA;AAChB,CAAC"}
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Embedded HTTP Server for MCP
|
|
3
|
+
* Serves draw.io embed with state sync and history UI
|
|
4
|
+
*/
|
|
5
|
+
interface SessionState {
|
|
6
|
+
xml: string;
|
|
7
|
+
version: number;
|
|
8
|
+
lastUpdated: Date;
|
|
9
|
+
svg?: string;
|
|
10
|
+
syncRequested?: number;
|
|
11
|
+
}
|
|
12
|
+
export declare const stateStore: Map<string, SessionState>;
|
|
13
|
+
export declare function getState(sessionId: string): SessionState | undefined;
|
|
14
|
+
export declare function setState(sessionId: string, xml: string, svg?: string): number;
|
|
15
|
+
export declare function requestSync(sessionId: string): boolean;
|
|
16
|
+
export declare function waitForSync(sessionId: string, timeoutMs?: number): Promise<boolean>;
|
|
17
|
+
export declare function startHttpServer(port?: number): Promise<number>;
|
|
18
|
+
export declare function stopHttpServer(): void;
|
|
19
|
+
export declare function shutdown(): void;
|
|
20
|
+
export declare function getServerPort(): number;
|
|
21
|
+
export {};
|
|
22
|
+
//# sourceMappingURL=http-server.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"http-server.d.ts","sourceRoot":"","sources":["../src/http-server.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAmDH,UAAU,YAAY;IAClB,GAAG,EAAE,MAAM,CAAA;IACX,OAAO,EAAE,MAAM,CAAA;IACf,WAAW,EAAE,IAAI,CAAA;IACjB,GAAG,CAAC,EAAE,MAAM,CAAA;IACZ,aAAa,CAAC,EAAE,MAAM,CAAA;CACzB;AAED,eAAO,MAAM,UAAU,2BAAkC,CAAA;AAOzD,wBAAgB,QAAQ,CAAC,SAAS,EAAE,MAAM,GAAG,YAAY,GAAG,SAAS,CAEpE;AAED,wBAAgB,QAAQ,CAAC,SAAS,EAAE,MAAM,EAAE,GAAG,EAAE,MAAM,EAAE,GAAG,CAAC,EAAE,MAAM,GAAG,MAAM,CAY7E;AAED,wBAAgB,WAAW,CAAC,SAAS,EAAE,MAAM,GAAG,OAAO,CAStD;AAED,wBAAsB,WAAW,CAC7B,SAAS,EAAE,MAAM,EACjB,SAAS,SAAO,GACjB,OAAO,CAAC,OAAO,CAAC,CASlB;AAED,wBAAgB,eAAe,CAAC,IAAI,SAAO,GAAG,OAAO,CAAC,MAAM,CAAC,CAoC5D;AAED,wBAAgB,cAAc,IAAI,IAAI,CAKrC;AAeD,wBAAgB,QAAQ,IAAI,IAAI,CAG/B;AAED,wBAAgB,aAAa,IAAI,MAAM,CAEtC"}
|