@drawpro/mcp 0.4.1 → 0.6.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 +14 -2
- package/dist/server.js +122 -4
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -3,13 +3,25 @@
|
|
|
3
3
|
Local MCP server for DrawPro. Lets Claude read and create diagrams in your
|
|
4
4
|
account from Claude Code, Claude Desktop, or any MCP client.
|
|
5
5
|
|
|
6
|
+
Full documentation:
|
|
7
|
+
[setup](https://github.com/deBilla/drawpro/blob/main/docs/connect-claude-code.md) ·
|
|
8
|
+
[tools](https://github.com/deBilla/drawpro/blob/main/docs/mcp-tools.md) ·
|
|
9
|
+
[diagram specs](https://github.com/deBilla/drawpro/blob/main/docs/diagram-specs.md) ·
|
|
10
|
+
[privacy](https://github.com/deBilla/drawpro/blob/main/docs/privacy.md)
|
|
11
|
+
|
|
6
12
|
## Setup
|
|
7
13
|
|
|
8
14
|
```bash
|
|
9
|
-
|
|
15
|
+
npx -y @drawpro/mcp connect dp_live_...
|
|
10
16
|
```
|
|
11
17
|
|
|
12
|
-
Mint the token in DrawPro under **Connect to Claude Code**.
|
|
18
|
+
Mint the token in DrawPro under **Connect to Claude Code**. One command: it
|
|
19
|
+
verifies the token, registers the server with Claude Code for all projects, and
|
|
20
|
+
offers to unlock reading. Re-run it with a new token to rotate. Nothing changes
|
|
21
|
+
if the token is rejected.
|
|
22
|
+
|
|
23
|
+
`auth`, `login`, and `claude mcp add` remain available separately if you would
|
|
24
|
+
rather do the steps yourself.
|
|
13
25
|
|
|
14
26
|
`--scope user` registers it for every project on your machine. The scope
|
|
15
27
|
otherwise defaults to `local`, which loads the server only in the directory the
|
package/dist/server.js
CHANGED
|
@@ -24,6 +24,7 @@ var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__ge
|
|
|
24
24
|
));
|
|
25
25
|
|
|
26
26
|
// src/server.ts
|
|
27
|
+
var import_node_child_process2 = require("node:child_process");
|
|
27
28
|
var import_node_fs3 = require("node:fs");
|
|
28
29
|
var import_node_os3 = require("node:os");
|
|
29
30
|
var import_node_path3 = require("node:path");
|
|
@@ -430,6 +431,9 @@ function installId() {
|
|
|
430
431
|
function telemetryEnabled() {
|
|
431
432
|
return readConfig().telemetry === "on";
|
|
432
433
|
}
|
|
434
|
+
function resolveToken() {
|
|
435
|
+
return process.env.DRAWPRO_TOKEN || readConfig().token;
|
|
436
|
+
}
|
|
433
437
|
|
|
434
438
|
// ../diagram/src/ids.ts
|
|
435
439
|
var import_fractional_indexing = require("fractional-indexing");
|
|
@@ -1396,10 +1400,10 @@ var ConfigError = class extends Error {
|
|
|
1396
1400
|
var clientInstance = null;
|
|
1397
1401
|
function api() {
|
|
1398
1402
|
if (!clientInstance) {
|
|
1399
|
-
const token =
|
|
1403
|
+
const token = resolveToken();
|
|
1400
1404
|
if (!token) {
|
|
1401
1405
|
throw new ConfigError(
|
|
1402
|
-
'
|
|
1406
|
+
'No API token. Create one in DrawPro under "Connect to Claude Code", then:\n npx -y @drawpro/mcp connect dp_live_...\n\nOr supply it through the environment when registering the server:\n claude mcp add drawpro --scope user -e DRAWPRO_TOKEN="dp_live_..." -- npx -y @drawpro/mcp'
|
|
1403
1407
|
);
|
|
1404
1408
|
}
|
|
1405
1409
|
clientInstance = new DrawProClient(BASE_URL, token, (t) => inFlight.push(t));
|
|
@@ -1407,7 +1411,7 @@ function api() {
|
|
|
1407
1411
|
return clientInstance;
|
|
1408
1412
|
}
|
|
1409
1413
|
var SESSION_ID = Math.random().toString(36).slice(2, 10);
|
|
1410
|
-
var VERSION = "0.
|
|
1414
|
+
var VERSION = "0.6.0";
|
|
1411
1415
|
var inFlight = [];
|
|
1412
1416
|
var cachedUser = null;
|
|
1413
1417
|
async function currentUser() {
|
|
@@ -1960,12 +1964,126 @@ function maybeSendInBackground() {
|
|
|
1960
1964
|
if (ok) writeConfig({ lastReportAt: (/* @__PURE__ */ new Date()).toISOString() });
|
|
1961
1965
|
});
|
|
1962
1966
|
}
|
|
1967
|
+
async function auth(arg) {
|
|
1968
|
+
if (arg === "--forget") {
|
|
1969
|
+
writeConfig({ token: void 0 });
|
|
1970
|
+
console.log("Token cleared.");
|
|
1971
|
+
return;
|
|
1972
|
+
}
|
|
1973
|
+
if (!arg) {
|
|
1974
|
+
const current = readConfig().token;
|
|
1975
|
+
const fromEnv = Boolean(process.env.DRAWPRO_TOKEN);
|
|
1976
|
+
if (fromEnv) {
|
|
1977
|
+
console.log("Using DRAWPRO_TOKEN from the environment, which takes precedence.");
|
|
1978
|
+
} else if (current) {
|
|
1979
|
+
console.log(`Stored token: ${current.slice(0, 16)}\u2026`);
|
|
1980
|
+
} else {
|
|
1981
|
+
console.log("No token stored.");
|
|
1982
|
+
}
|
|
1983
|
+
console.log("\n drawpro-mcp auth dp_live_... store or replace it");
|
|
1984
|
+
console.log(" drawpro-mcp auth --forget clear it");
|
|
1985
|
+
return;
|
|
1986
|
+
}
|
|
1987
|
+
if (!arg.startsWith("dp_live_")) {
|
|
1988
|
+
throw new ConfigError("That does not look like a DrawPro token \u2014 they begin with dp_live_.");
|
|
1989
|
+
}
|
|
1990
|
+
const probe = new DrawProClient(BASE_URL, arg);
|
|
1991
|
+
let email;
|
|
1992
|
+
try {
|
|
1993
|
+
email = (await probe.me()).email;
|
|
1994
|
+
} catch (err) {
|
|
1995
|
+
throw new ConfigError(
|
|
1996
|
+
`That token was rejected, so it has not been saved: ${err.message}`
|
|
1997
|
+
);
|
|
1998
|
+
}
|
|
1999
|
+
writeConfig({ token: arg });
|
|
2000
|
+
console.log(`Token saved for ${email}.`);
|
|
2001
|
+
if (process.env.DRAWPRO_TOKEN) {
|
|
2002
|
+
console.log(
|
|
2003
|
+
"\nNote: DRAWPRO_TOKEN is also set in this environment and takes precedence.\nRemove it from the MCP registration for the stored token to be used."
|
|
2004
|
+
);
|
|
2005
|
+
}
|
|
2006
|
+
}
|
|
2007
|
+
function claudeAvailable() {
|
|
2008
|
+
try {
|
|
2009
|
+
(0, import_node_child_process2.execFileSync)("claude", ["--version"], { stdio: "ignore" });
|
|
2010
|
+
return true;
|
|
2011
|
+
} catch {
|
|
2012
|
+
return false;
|
|
2013
|
+
}
|
|
2014
|
+
}
|
|
2015
|
+
async function connect(token) {
|
|
2016
|
+
if (!token) {
|
|
2017
|
+
throw new ConfigError(
|
|
2018
|
+
'Usage: drawpro-mcp connect dp_live_...\nCreate a token in DrawPro under "Connect to Claude Code".'
|
|
2019
|
+
);
|
|
2020
|
+
}
|
|
2021
|
+
if (!token.startsWith("dp_live_")) {
|
|
2022
|
+
throw new ConfigError("That does not look like a DrawPro token \u2014 they begin with dp_live_.");
|
|
2023
|
+
}
|
|
2024
|
+
process.stdout.write("Checking the token... ");
|
|
2025
|
+
let user;
|
|
2026
|
+
try {
|
|
2027
|
+
user = await new DrawProClient(BASE_URL, token).me();
|
|
2028
|
+
} catch (err) {
|
|
2029
|
+
console.log("");
|
|
2030
|
+
throw new ConfigError(`rejected, nothing has been changed: ${err.message}`);
|
|
2031
|
+
}
|
|
2032
|
+
console.log(`ok \u2014 ${user.email}`);
|
|
2033
|
+
writeConfig({ token });
|
|
2034
|
+
if (!claudeAvailable()) {
|
|
2035
|
+
console.log("\nToken saved, but the `claude` command was not found, so the server could not");
|
|
2036
|
+
console.log("be registered. Register it yourself, without -e DRAWPRO_TOKEN:");
|
|
2037
|
+
console.log("\n claude mcp add drawpro --scope user -- npx -y @drawpro/mcp");
|
|
2038
|
+
return;
|
|
2039
|
+
}
|
|
2040
|
+
try {
|
|
2041
|
+
(0, import_node_child_process2.execFileSync)("claude", ["mcp", "remove", "drawpro", "-s", "user"], { stdio: "ignore" });
|
|
2042
|
+
} catch {
|
|
2043
|
+
}
|
|
2044
|
+
try {
|
|
2045
|
+
(0, import_node_child_process2.execFileSync)("claude", ["mcp", "add", "drawpro", "-s", "user", "--", "npx", "-y", "@drawpro/mcp"], {
|
|
2046
|
+
stdio: "ignore"
|
|
2047
|
+
});
|
|
2048
|
+
} catch (err) {
|
|
2049
|
+
throw new ConfigError(
|
|
2050
|
+
`Token saved, but registering with Claude Code failed: ${err.message}
|
|
2051
|
+
Register it yourself: claude mcp add drawpro --scope user -- npx -y @drawpro/mcp`
|
|
2052
|
+
);
|
|
2053
|
+
}
|
|
2054
|
+
console.log("Registered with Claude Code for all your projects.");
|
|
2055
|
+
if (user.encryptedPrivateKey && !loadKey(user.email)) {
|
|
2056
|
+
console.log("\nCreating diagrams will work now. Reading them needs your passcode, which");
|
|
2057
|
+
console.log("unwraps your private key on this machine \u2014 it is never sent anywhere.");
|
|
2058
|
+
console.log("Unlock now, or skip and run `npx -y @drawpro/mcp login` later.\n");
|
|
2059
|
+
const passcode = await askHidden("passcode (or press enter to skip): ");
|
|
2060
|
+
if (passcode) {
|
|
2061
|
+
process.stdout.write("unlocking... ");
|
|
2062
|
+
try {
|
|
2063
|
+
const key = await decryptPrivateKey(user.encryptedPrivateKey, passcode, user.salt);
|
|
2064
|
+
const { location } = storeKey(user.email, key);
|
|
2065
|
+
console.log(`done, stored in the ${location}.`);
|
|
2066
|
+
} catch {
|
|
2067
|
+
console.log("incorrect passcode. Run `npx -y @drawpro/mcp login` when ready.");
|
|
2068
|
+
}
|
|
2069
|
+
}
|
|
2070
|
+
}
|
|
2071
|
+
console.log("\nRestart Claude Code, then ask it to list your DrawPro workspaces.");
|
|
2072
|
+
}
|
|
1963
2073
|
async function main() {
|
|
1964
2074
|
const command = process.argv[2];
|
|
1965
2075
|
if (command === "login") {
|
|
1966
2076
|
await login(process.argv.includes("--forget"));
|
|
1967
2077
|
return;
|
|
1968
2078
|
}
|
|
2079
|
+
if (command === "connect") {
|
|
2080
|
+
await connect(process.argv[3]);
|
|
2081
|
+
return;
|
|
2082
|
+
}
|
|
2083
|
+
if (command === "auth") {
|
|
2084
|
+
await auth(process.argv[3]);
|
|
2085
|
+
return;
|
|
2086
|
+
}
|
|
1969
2087
|
if (command === "telemetry") {
|
|
1970
2088
|
await telemetry(process.argv[3]);
|
|
1971
2089
|
return;
|
|
@@ -1981,7 +2099,7 @@ async function main() {
|
|
|
1981
2099
|
}
|
|
1982
2100
|
if (command && command !== "serve") {
|
|
1983
2101
|
console.error(
|
|
1984
|
-
`Unknown command "${command}". Use: drawpro-mcp [serve|login|stats|telemetry|report]`
|
|
2102
|
+
`Unknown command "${command}". Use: drawpro-mcp [serve|connect|auth|login|stats|telemetry|report]`
|
|
1985
2103
|
);
|
|
1986
2104
|
process.exit(2);
|
|
1987
2105
|
}
|