@drawpro/mcp 0.2.1 → 0.3.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 +11 -2
- package/dist/server.js +44 -3
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -76,6 +76,7 @@ passcode itself.
|
|
|
76
76
|
| `create_diagram` | no | returns a link to the new sheet |
|
|
77
77
|
| `update_diagram` | no | replaces the sheet wholesale — regenerates layout |
|
|
78
78
|
| `edit_sheet_text` | yes | rewrites named text in place, preserving every other element |
|
|
79
|
+
| `import_sheet` | no | writes a local .excalidraw file into a sheet, coordinates verbatim |
|
|
79
80
|
|
|
80
81
|
### Editing a sheet a person drew
|
|
81
82
|
|
|
@@ -97,8 +98,16 @@ and nothing else moves — reflowing neighbours would be the wholesale rewrite
|
|
|
97
98
|
this tool exists to avoid. Any box it grows is named in the result, so overlap
|
|
98
99
|
with a neighbour is easy to spot and one drag to fix.
|
|
99
100
|
|
|
100
|
-
It cannot add elements. A correction that needs a new box
|
|
101
|
-
|
|
101
|
+
It cannot add elements or move anything. A correction that needs a new box, a
|
|
102
|
+
repositioned column, or a re-anchored arrow is a geometry change, and no spec or
|
|
103
|
+
text edit can express one.
|
|
104
|
+
|
|
105
|
+
`import_sheet` covers that case. Point it at a local `.excalidraw` file and it
|
|
106
|
+
writes the scene in verbatim — every coordinate exactly as in the file. Because
|
|
107
|
+
the server runs on your machine it can simply read the file, so a geometry pass
|
|
108
|
+
can be done with a real editor, or by a model editing the file directly, and
|
|
109
|
+
then pushed without a clipboard round trip. The file's contents go into the
|
|
110
|
+
encrypted blob, never into the model's context.
|
|
102
111
|
|
|
103
112
|
`update_diagram` remains the right tool for sheets this package generated, where
|
|
104
113
|
regenerating the layout is the point.
|
package/dist/server.js
CHANGED
|
@@ -24,6 +24,8 @@ var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__ge
|
|
|
24
24
|
));
|
|
25
25
|
|
|
26
26
|
// src/server.ts
|
|
27
|
+
var import_node_fs2 = require("node:fs");
|
|
28
|
+
var import_node_path2 = require("node:path");
|
|
27
29
|
var import_mcp = require("@modelcontextprotocol/sdk/server/mcp.js");
|
|
28
30
|
var import_stdio = require("@modelcontextprotocol/sdk/server/stdio.js");
|
|
29
31
|
var import_zod = require("zod");
|
|
@@ -338,7 +340,7 @@ function forgetKey(email) {
|
|
|
338
340
|
|
|
339
341
|
// ../client/src/prompt.ts
|
|
340
342
|
function askHidden(question) {
|
|
341
|
-
return new Promise((
|
|
343
|
+
return new Promise((resolve2) => {
|
|
342
344
|
const input = process.stdin;
|
|
343
345
|
process.stdout.write(question);
|
|
344
346
|
if (!input.isTTY) {
|
|
@@ -347,7 +349,7 @@ function askHidden(question) {
|
|
|
347
349
|
input.on("data", (chunk) => {
|
|
348
350
|
buffered += chunk;
|
|
349
351
|
});
|
|
350
|
-
input.on("end", () =>
|
|
352
|
+
input.on("end", () => resolve2(buffered.split("\n")[0].trim()));
|
|
351
353
|
return;
|
|
352
354
|
}
|
|
353
355
|
const wasRaw = input.isRaw;
|
|
@@ -363,7 +365,7 @@ function askHidden(question) {
|
|
|
363
365
|
if (result === null) {
|
|
364
366
|
process.exit(130);
|
|
365
367
|
}
|
|
366
|
-
|
|
368
|
+
resolve2(result);
|
|
367
369
|
};
|
|
368
370
|
const onData = (chunk) => {
|
|
369
371
|
for (const ch of chunk) {
|
|
@@ -1638,6 +1640,45 @@ ${sheetUrl(workspace_id, sheet_id)}`
|
|
|
1638
1640
|
);
|
|
1639
1641
|
}
|
|
1640
1642
|
);
|
|
1643
|
+
server.tool(
|
|
1644
|
+
"import_sheet",
|
|
1645
|
+
"Write a local .excalidraw file into a sheet, exactly as it is. Use this when geometry has to change \u2014 repositioning, resizing, re-anchoring arrows \u2014 which no spec can express and edit_sheet_text will not touch. Every coordinate in the file is preserved verbatim.",
|
|
1646
|
+
{
|
|
1647
|
+
workspace_id: import_zod.z.string(),
|
|
1648
|
+
file_path: import_zod.z.string().describe("Path to a .excalidraw file on this machine"),
|
|
1649
|
+
name: import_zod.z.string().describe("Sheet name"),
|
|
1650
|
+
sheet_id: import_zod.z.string().optional().describe("Omit to create a new sheet; supply it to replace an existing one")
|
|
1651
|
+
},
|
|
1652
|
+
async ({ workspace_id, file_path, name, sheet_id }) => {
|
|
1653
|
+
let parsed;
|
|
1654
|
+
try {
|
|
1655
|
+
parsed = JSON.parse((0, import_node_fs2.readFileSync)((0, import_node_path2.resolve)(file_path), "utf8"));
|
|
1656
|
+
} catch (err) {
|
|
1657
|
+
return text(`Could not read ${file_path}: ${err.message}`);
|
|
1658
|
+
}
|
|
1659
|
+
const elements = parsed.elements;
|
|
1660
|
+
if (!Array.isArray(elements) || elements.length === 0) {
|
|
1661
|
+
return text(`${file_path} has no "elements" array \u2014 is it an .excalidraw file?`);
|
|
1662
|
+
}
|
|
1663
|
+
const issues = validateScene(elements);
|
|
1664
|
+
const noted = issues.length ? `
|
|
1665
|
+
|
|
1666
|
+
${issues.length} thing(s) worth a look (imported anyway):
|
|
1667
|
+
` + issues.slice(0, 5).map((i) => ` ${i.level}: ${i.message}`).join("\n") : "";
|
|
1668
|
+
const user = await currentUser();
|
|
1669
|
+
const payload = {
|
|
1670
|
+
name,
|
|
1671
|
+
elements,
|
|
1672
|
+
appState: parsed.appState ?? {}
|
|
1673
|
+
};
|
|
1674
|
+
const sheet = sheet_id ? await api().updateSheet(workspace_id, sheet_id, payload, user.publicKey) : await api().createSheet(workspace_id, payload, user.publicKey);
|
|
1675
|
+
const id = sheet_id ?? sheet.id;
|
|
1676
|
+
return text(
|
|
1677
|
+
`${sheet_id ? "Replaced" : "Created"} "${name}" from ${file_path} \u2014 ${elements.length} elements, every coordinate as in the file.
|
|
1678
|
+
${sheetUrl(workspace_id, id)}${noted}`
|
|
1679
|
+
);
|
|
1680
|
+
}
|
|
1681
|
+
);
|
|
1641
1682
|
async function main() {
|
|
1642
1683
|
const command = process.argv[2];
|
|
1643
1684
|
if (command === "login") {
|