@calca/mcp 0.7.3
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 +24 -0
- package/dist/cli.d.mts +1 -0
- package/dist/cli.mjs +24 -0
- package/dist/cli.mjs.map +1 -0
- package/dist/index.d.mts +14 -0
- package/dist/index.d.mts.map +1 -0
- package/dist/index.mjs +3 -0
- package/dist/install-BU23djTa.mjs +107 -0
- package/dist/install-BU23djTa.mjs.map +1 -0
- package/dist/mcp-BiGdJaoN.mjs +38 -0
- package/dist/mcp-BiGdJaoN.mjs.map +1 -0
- package/dist/open-BTc5qKY_.mjs +32 -0
- package/dist/open-BTc5qKY_.mjs.map +1 -0
- package/dist/package-BbsUrmrv.mjs +6 -0
- package/dist/package-BbsUrmrv.mjs.map +1 -0
- package/dist/session-DhX_7S8U.mjs +81 -0
- package/dist/session-DhX_7S8U.mjs.map +1 -0
- package/package.json +49 -0
package/README.md
ADDED
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
# @calca/mcp
|
|
2
|
+
|
|
3
|
+
The `calca` CLI — Layer 2 of the Calca stack: an MCP playground that lets AI agents read and edit a canvas board over the Model Context Protocol.
|
|
4
|
+
|
|
5
|
+
The pure tool surface (session, commands, leases, proposals, idempotency) lives in [`@calca/mcp-core`](../mcp-core) and is runtime-neutral; this package is the Node-facing binding: stdio transport, board-file persistence, host config installers.
|
|
6
|
+
|
|
7
|
+
## Install / run
|
|
8
|
+
|
|
9
|
+
```bash
|
|
10
|
+
npx -y @calca/mcp mcp # run the MCP server over stdio
|
|
11
|
+
npx -y @calca/mcp mcp --file board.json # load a board, autosave on change
|
|
12
|
+
npx -y @calca/mcp open board.json # inspect a board snapshot
|
|
13
|
+
npx -y @calca/mcp mcp install claude-code # write host config (prints with --print)
|
|
14
|
+
```
|
|
15
|
+
|
|
16
|
+
## Commands
|
|
17
|
+
|
|
18
|
+
- `calca mcp` — serve the canvas tool contract over stdio (`canvas.read`, `canvas.propose`, `canvas.apply`, `canvas.lease`, `canvas.release`, `canvas.comment`, `canvas.arrange`). `--file` loads/saves a JSON snapshot; `--agent` sets the principal id used for command origins and leases.
|
|
19
|
+
- `calca mcp install <host>` — merge `calca` into the host's MCP config. Hosts: `claude-code`, `cursor`, `gemini-cli`, `opencode`, `codex`.
|
|
20
|
+
- `calca open <file>` — board summary (record counts by type). Full visual open lands with the web build (Phase 3).
|
|
21
|
+
|
|
22
|
+
## License
|
|
23
|
+
|
|
24
|
+
Apache-2.0
|
package/dist/cli.d.mts
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {}
|
package/dist/cli.mjs
ADDED
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
import { t as version } from "./package-BbsUrmrv.mjs";
|
|
3
|
+
import { defineCommand, runMain } from "citty";
|
|
4
|
+
|
|
5
|
+
//#region src/main.ts
|
|
6
|
+
const main = defineCommand({
|
|
7
|
+
meta: {
|
|
8
|
+
name: "calca",
|
|
9
|
+
version,
|
|
10
|
+
description: "Calca — agent playground CLI (MCP canvas tools)"
|
|
11
|
+
},
|
|
12
|
+
subCommands: {
|
|
13
|
+
mcp: () => import("./mcp-BiGdJaoN.mjs").then((r) => r.mcpCommand),
|
|
14
|
+
open: () => import("./open-BTc5qKY_.mjs").then((r) => r.openCommand)
|
|
15
|
+
}
|
|
16
|
+
});
|
|
17
|
+
|
|
18
|
+
//#endregion
|
|
19
|
+
//#region src/cli.ts
|
|
20
|
+
runMain(main);
|
|
21
|
+
|
|
22
|
+
//#endregion
|
|
23
|
+
export { };
|
|
24
|
+
//# sourceMappingURL=cli.mjs.map
|
package/dist/cli.mjs.map
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"cli.mjs","names":[],"sources":["../src/main.ts","../src/cli.ts"],"sourcesContent":["import { defineCommand } from \"citty\";\n\nimport { version } from \"../package.json\" with { type: \"json\" };\n\nexport const main = defineCommand({\n meta: {\n name: \"calca\",\n version,\n description: \"Calca — agent playground CLI (MCP canvas tools)\",\n },\n subCommands: {\n mcp: () => import(\"./commands/mcp\").then((r) => r.mcpCommand),\n open: () => import(\"./commands/open\").then((r) => r.openCommand),\n },\n});\n","#!/usr/bin/env node\nimport { runMain } from \"citty\";\n\nimport { main } from \"./main\";\n\nrunMain(main);\n"],"mappings":";;;;;AAIA,MAAa,OAAO,cAAc;CAChC,MAAM;EACJ,MAAM;EACN;EACA,aAAa;CACf;CACA,aAAa;EACX,WAAW,OAAO,qBAAiB,CAAC,MAAM,MAAM,EAAE,UAAU;EAC5D,YAAY,OAAO,sBAAkB,CAAC,MAAM,MAAM,EAAE,WAAW;CACjE;AACF,CAAC;;;;ACTD,QAAQ,IAAI"}
|
package/dist/index.d.mts
ADDED
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
import { CanvasSession } from "@calca/mcp-core";
|
|
2
|
+
import { Server } from "@modelcontextprotocol/sdk/server/index.js";
|
|
3
|
+
//#region src/server.d.ts
|
|
4
|
+
export declare function createCalcaMcpServer(session: CanvasSession): Server;
|
|
5
|
+
//#endregion
|
|
6
|
+
//#region src/session.d.ts
|
|
7
|
+
interface LoadSessionOptions {
|
|
8
|
+
file?: string;
|
|
9
|
+
agentId: string;
|
|
10
|
+
}
|
|
11
|
+
export declare function loadSession(options: LoadSessionOptions): Promise<CanvasSession>;
|
|
12
|
+
//#endregion
|
|
13
|
+
export type { LoadSessionOptions };
|
|
14
|
+
//# sourceMappingURL=index.d.mts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.mts","names":[],"sources":["../src/server.ts","../src/session.ts"],"mappings":";;;wBAQgB,qBAAqB,SAAS,gBAAgB;;;UCF7C;EACf;EACA;;wBAGoB,YAAY,SAAS,qBAAqB,QAAQ"}
|
package/dist/index.mjs
ADDED
|
@@ -0,0 +1,107 @@
|
|
|
1
|
+
import { mkdir, readFile, writeFile } from "node:fs/promises";
|
|
2
|
+
import { consola } from "consola";
|
|
3
|
+
import { defineCommand } from "citty";
|
|
4
|
+
import { existsSync } from "node:fs";
|
|
5
|
+
import { homedir } from "node:os";
|
|
6
|
+
import { dirname, join } from "pathe";
|
|
7
|
+
|
|
8
|
+
//#region src/install.ts
|
|
9
|
+
const SERVER_ENTRY = {
|
|
10
|
+
command: "npx",
|
|
11
|
+
args: [
|
|
12
|
+
"-y",
|
|
13
|
+
"@calca/mcp@latest",
|
|
14
|
+
"mcp"
|
|
15
|
+
]
|
|
16
|
+
};
|
|
17
|
+
const TOML_ENTRY = `[mcp_servers.calca]
|
|
18
|
+
command = "npx"
|
|
19
|
+
args = ["-y", "@calca/mcp@latest", "mcp"]
|
|
20
|
+
`;
|
|
21
|
+
const HOSTS = {
|
|
22
|
+
"claude-code": {
|
|
23
|
+
configPath: () => join(homedir(), ".claude.json"),
|
|
24
|
+
format: "json",
|
|
25
|
+
mcpServersKey: ["mcpServers"]
|
|
26
|
+
},
|
|
27
|
+
cursor: {
|
|
28
|
+
configPath: () => join(homedir(), ".cursor", "mcp.json"),
|
|
29
|
+
format: "json",
|
|
30
|
+
mcpServersKey: ["mcpServers"]
|
|
31
|
+
},
|
|
32
|
+
"gemini-cli": {
|
|
33
|
+
configPath: () => join(homedir(), ".gemini", "settings.json"),
|
|
34
|
+
format: "json",
|
|
35
|
+
mcpServersKey: ["mcpServers"]
|
|
36
|
+
},
|
|
37
|
+
opencode: {
|
|
38
|
+
configPath: () => join(homedir(), ".config", "opencode", "opencode.json"),
|
|
39
|
+
format: "json",
|
|
40
|
+
mcpServersKey: ["mcp"]
|
|
41
|
+
},
|
|
42
|
+
codex: {
|
|
43
|
+
configPath: () => join(homedir(), ".codex", "config.toml"),
|
|
44
|
+
format: "toml"
|
|
45
|
+
}
|
|
46
|
+
};
|
|
47
|
+
const installCommand = defineCommand({
|
|
48
|
+
meta: {
|
|
49
|
+
name: "install",
|
|
50
|
+
description: "Write the calca MCP server into an agent host's config (claude-code, cursor, gemini-cli, opencode, codex)"
|
|
51
|
+
},
|
|
52
|
+
args: {
|
|
53
|
+
host: {
|
|
54
|
+
type: "positional",
|
|
55
|
+
description: `agent host (${Object.keys(HOSTS).join(", ")})`,
|
|
56
|
+
required: true
|
|
57
|
+
},
|
|
58
|
+
print: {
|
|
59
|
+
type: "boolean",
|
|
60
|
+
description: "Print the config fragment instead of writing"
|
|
61
|
+
}
|
|
62
|
+
},
|
|
63
|
+
async run({ args }) {
|
|
64
|
+
const host = HOSTS[args.host];
|
|
65
|
+
if (!host) {
|
|
66
|
+
consola.error(`unknown host "${args.host}" — expected one of: ${Object.keys(HOSTS).join(", ")}`);
|
|
67
|
+
process.exit(1);
|
|
68
|
+
}
|
|
69
|
+
const path = host.configPath();
|
|
70
|
+
if (args.print) {
|
|
71
|
+
if (host.format === "toml") consola.log(TOML_ENTRY);
|
|
72
|
+
else consola.log(JSON.stringify({ calca: SERVER_ENTRY }, null, 2));
|
|
73
|
+
return;
|
|
74
|
+
}
|
|
75
|
+
await installHost(host, path);
|
|
76
|
+
}
|
|
77
|
+
});
|
|
78
|
+
async function installHost(host, path) {
|
|
79
|
+
await mkdir(dirname(path), { recursive: true });
|
|
80
|
+
if (host.format === "toml") {
|
|
81
|
+
const existing = existsSync(path) ? await readFile(path, "utf8") : "";
|
|
82
|
+
if (existing.includes("[mcp_servers.calca]")) {
|
|
83
|
+
consola.info(`calca already configured in ${path}`);
|
|
84
|
+
return;
|
|
85
|
+
}
|
|
86
|
+
await writeFile(path, `${existing.trimEnd()}\n\n${TOML_ENTRY}`.trimStart());
|
|
87
|
+
consola.success(`added calca MCP server to ${path}`);
|
|
88
|
+
return;
|
|
89
|
+
}
|
|
90
|
+
const existing = existsSync(path) ? JSON.parse(await readFile(path, "utf8")) : {};
|
|
91
|
+
const key = host.mcpServersKey ?? ["mcpServers"];
|
|
92
|
+
let target = existing;
|
|
93
|
+
for (const segment of key.slice(0, -1)) target = target[segment] ??= {};
|
|
94
|
+
const leaf = key[key.length - 1];
|
|
95
|
+
const servers = target[leaf] ??= {};
|
|
96
|
+
if (servers.calca) {
|
|
97
|
+
consola.info(`calca already configured in ${path}`);
|
|
98
|
+
return;
|
|
99
|
+
}
|
|
100
|
+
servers.calca = SERVER_ENTRY;
|
|
101
|
+
await writeFile(path, JSON.stringify(existing, null, 2) + "\n");
|
|
102
|
+
consola.success(`added calca MCP server to ${path}`);
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
//#endregion
|
|
106
|
+
export { installCommand };
|
|
107
|
+
//# sourceMappingURL=install-BU23djTa.mjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"install-BU23djTa.mjs","names":[],"sources":["../src/install.ts"],"sourcesContent":["import { existsSync } from \"node:fs\";\nimport { mkdir, readFile, writeFile } from \"node:fs/promises\";\nimport { homedir } from \"node:os\";\n\nimport { defineCommand } from \"citty\";\nimport { consola } from \"consola\";\nimport { dirname, join } from \"pathe\";\n\nconst SERVER_ENTRY = {\n command: \"npx\",\n args: [\"-y\", \"@calca/mcp@latest\", \"mcp\"],\n};\n\nconst TOML_ENTRY = `[mcp_servers.calca]\ncommand = \"npx\"\nargs = [\"-y\", \"@calca/mcp@latest\", \"mcp\"]\n`;\n\ninterface HostConfig {\n configPath: () => string;\n format: \"json\" | \"toml\";\n mcpServersKey?: string[];\n}\n\nconst HOSTS: Record<string, HostConfig> = {\n \"claude-code\": {\n configPath: () => join(homedir(), \".claude.json\"),\n format: \"json\",\n mcpServersKey: [\"mcpServers\"],\n },\n cursor: {\n configPath: () => join(homedir(), \".cursor\", \"mcp.json\"),\n format: \"json\",\n mcpServersKey: [\"mcpServers\"],\n },\n \"gemini-cli\": {\n configPath: () => join(homedir(), \".gemini\", \"settings.json\"),\n format: \"json\",\n mcpServersKey: [\"mcpServers\"],\n },\n opencode: {\n configPath: () => join(homedir(), \".config\", \"opencode\", \"opencode.json\"),\n format: \"json\",\n mcpServersKey: [\"mcp\"],\n },\n codex: {\n configPath: () => join(homedir(), \".codex\", \"config.toml\"),\n format: \"toml\",\n },\n};\n\nexport const installCommand = defineCommand({\n meta: {\n name: \"install\",\n description:\n \"Write the calca MCP server into an agent host's config (claude-code, cursor, gemini-cli, opencode, codex)\",\n },\n args: {\n host: {\n type: \"positional\",\n description: `agent host (${Object.keys(HOSTS).join(\", \")})`,\n required: true,\n },\n print: {\n type: \"boolean\",\n description: \"Print the config fragment instead of writing\",\n },\n },\n async run({ args }) {\n const host = HOSTS[args.host];\n if (!host) {\n consola.error(\n `unknown host \"${args.host}\" — expected one of: ${Object.keys(HOSTS).join(\", \")}`,\n );\n process.exit(1);\n }\n const path = host.configPath();\n if (args.print) {\n if (host.format === \"toml\") {\n consola.log(TOML_ENTRY);\n } else {\n consola.log(JSON.stringify({ calca: SERVER_ENTRY }, null, 2));\n }\n return;\n }\n await installHost(host, path);\n },\n});\n\nasync function installHost(host: HostConfig, path: string): Promise<void> {\n await mkdir(dirname(path), { recursive: true });\n\n if (host.format === \"toml\") {\n const existing = existsSync(path) ? await readFile(path, \"utf8\") : \"\";\n if (existing.includes(\"[mcp_servers.calca]\")) {\n consola.info(`calca already configured in ${path}`);\n return;\n }\n await writeFile(path, `${existing.trimEnd()}\\n\\n${TOML_ENTRY}`.trimStart());\n consola.success(`added calca MCP server to ${path}`);\n return;\n }\n\n const existing: Record<string, unknown> = existsSync(path)\n ? JSON.parse(await readFile(path, \"utf8\"))\n : {};\n const key = host.mcpServersKey ?? [\"mcpServers\"];\n let target = existing;\n for (const segment of key.slice(0, -1)) {\n target = (target[segment] ??= {}) as Record<string, unknown>;\n }\n const leaf = key[key.length - 1];\n const servers = (target[leaf] ??= {}) as Record<string, unknown>;\n if (servers.calca) {\n consola.info(`calca already configured in ${path}`);\n return;\n }\n servers.calca = SERVER_ENTRY;\n await writeFile(path, JSON.stringify(existing, null, 2) + \"\\n\");\n consola.success(`added calca MCP server to ${path}`);\n}\n"],"mappings":";;;;;;;;AAQA,MAAM,eAAe;CACnB,SAAS;CACT,MAAM;EAAC;EAAM;EAAqB;CAAK;AACzC;AAEA,MAAM,aAAa;;;;AAWnB,MAAM,QAAoC;CACxC,eAAe;EACb,kBAAkB,KAAK,QAAQ,GAAG,cAAc;EAChD,QAAQ;EACR,eAAe,CAAC,YAAY;CAC9B;CACA,QAAQ;EACN,kBAAkB,KAAK,QAAQ,GAAG,WAAW,UAAU;EACvD,QAAQ;EACR,eAAe,CAAC,YAAY;CAC9B;CACA,cAAc;EACZ,kBAAkB,KAAK,QAAQ,GAAG,WAAW,eAAe;EAC5D,QAAQ;EACR,eAAe,CAAC,YAAY;CAC9B;CACA,UAAU;EACR,kBAAkB,KAAK,QAAQ,GAAG,WAAW,YAAY,eAAe;EACxE,QAAQ;EACR,eAAe,CAAC,KAAK;CACvB;CACA,OAAO;EACL,kBAAkB,KAAK,QAAQ,GAAG,UAAU,aAAa;EACzD,QAAQ;CACV;AACF;AAEA,MAAa,iBAAiB,cAAc;CAC1C,MAAM;EACJ,MAAM;EACN,aACE;CACJ;CACA,MAAM;EACJ,MAAM;GACJ,MAAM;GACN,aAAa,eAAe,OAAO,KAAK,KAAK,CAAC,CAAC,KAAK,IAAI,EAAE;GAC1D,UAAU;EACZ;EACA,OAAO;GACL,MAAM;GACN,aAAa;EACf;CACF;CACA,MAAM,IAAI,EAAE,QAAQ;EAClB,MAAM,OAAO,MAAM,KAAK;EACxB,IAAI,CAAC,MAAM;GACT,QAAQ,MACN,iBAAiB,KAAK,KAAK,uBAAuB,OAAO,KAAK,KAAK,CAAC,CAAC,KAAK,IAAI,GAChF;GACA,QAAQ,KAAK,CAAC;EAChB;EACA,MAAM,OAAO,KAAK,WAAW;EAC7B,IAAI,KAAK,OAAO;GACd,IAAI,KAAK,WAAW,QAClB,QAAQ,IAAI,UAAU;QAEtB,QAAQ,IAAI,KAAK,UAAU,EAAE,OAAO,aAAa,GAAG,MAAM,CAAC,CAAC;GAE9D;EACF;EACA,MAAM,YAAY,MAAM,IAAI;CAC9B;AACF,CAAC;AAED,eAAe,YAAY,MAAkB,MAA6B;CACxE,MAAM,MAAM,QAAQ,IAAI,GAAG,EAAE,WAAW,KAAK,CAAC;CAE9C,IAAI,KAAK,WAAW,QAAQ;EAC1B,MAAM,WAAW,WAAW,IAAI,IAAI,MAAM,SAAS,MAAM,MAAM,IAAI;EACnE,IAAI,SAAS,SAAS,qBAAqB,GAAG;GAC5C,QAAQ,KAAK,+BAA+B,MAAM;GAClD;EACF;EACA,MAAM,UAAU,MAAM,GAAG,SAAS,QAAQ,EAAE,MAAM,aAAa,UAAU,CAAC;EAC1E,QAAQ,QAAQ,6BAA6B,MAAM;EACnD;CACF;CAEA,MAAM,WAAoC,WAAW,IAAI,IACrD,KAAK,MAAM,MAAM,SAAS,MAAM,MAAM,CAAC,IACvC,CAAC;CACL,MAAM,MAAM,KAAK,iBAAiB,CAAC,YAAY;CAC/C,IAAI,SAAS;CACb,KAAK,MAAM,WAAW,IAAI,MAAM,GAAG,EAAE,GACnC,SAAU,OAAO,aAAa,CAAC;CAEjC,MAAM,OAAO,IAAI,IAAI,SAAS;CAC9B,MAAM,UAAW,OAAO,UAAU,CAAC;CACnC,IAAI,QAAQ,OAAO;EACjB,QAAQ,KAAK,+BAA+B,MAAM;EAClD;CACF;CACA,QAAQ,QAAQ;CAChB,MAAM,UAAU,MAAM,KAAK,UAAU,UAAU,MAAM,CAAC,IAAI,IAAI;CAC9D,QAAQ,QAAQ,6BAA6B,MAAM;AACrD"}
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
import { n as createCalcaMcpServer, t as loadSession } from "./session-DhX_7S8U.mjs";
|
|
2
|
+
import { consola } from "consola";
|
|
3
|
+
import { defineCommand } from "citty";
|
|
4
|
+
import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio.js";
|
|
5
|
+
|
|
6
|
+
//#region src/commands/mcp.ts
|
|
7
|
+
const mcpCommand = defineCommand({
|
|
8
|
+
meta: {
|
|
9
|
+
name: "mcp",
|
|
10
|
+
description: "Run the calca MCP server over stdio"
|
|
11
|
+
},
|
|
12
|
+
args: {
|
|
13
|
+
file: {
|
|
14
|
+
type: "string",
|
|
15
|
+
description: "Board file to load (JSON snapshot). Autosaves on change."
|
|
16
|
+
},
|
|
17
|
+
agent: {
|
|
18
|
+
type: "string",
|
|
19
|
+
description: "Agent principal id for command origins and leases",
|
|
20
|
+
default: "mcp-agent"
|
|
21
|
+
}
|
|
22
|
+
},
|
|
23
|
+
subCommands: { install: () => import("./install-BU23djTa.mjs").then((r) => r.installCommand) },
|
|
24
|
+
async run({ args }) {
|
|
25
|
+
const session = await loadSession({
|
|
26
|
+
file: args.file,
|
|
27
|
+
agentId: args.agent
|
|
28
|
+
});
|
|
29
|
+
const server = createCalcaMcpServer(session);
|
|
30
|
+
const transport = new StdioServerTransport();
|
|
31
|
+
await server.connect(transport);
|
|
32
|
+
consola.debug("calca mcp server listening on stdio");
|
|
33
|
+
}
|
|
34
|
+
});
|
|
35
|
+
|
|
36
|
+
//#endregion
|
|
37
|
+
export { mcpCommand };
|
|
38
|
+
//# sourceMappingURL=mcp-BiGdJaoN.mjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"mcp-BiGdJaoN.mjs","names":[],"sources":["../src/commands/mcp.ts"],"sourcesContent":["import { StdioServerTransport } from \"@modelcontextprotocol/sdk/server/stdio.js\";\nimport { defineCommand } from \"citty\";\nimport { consola } from \"consola\";\n\nimport { createCalcaMcpServer } from \"../server\";\nimport { loadSession } from \"../session\";\n\nexport const mcpCommand = defineCommand({\n meta: {\n name: \"mcp\",\n description: \"Run the calca MCP server over stdio\",\n },\n args: {\n file: {\n type: \"string\",\n description: \"Board file to load (JSON snapshot). Autosaves on change.\",\n },\n agent: {\n type: \"string\",\n description: \"Agent principal id for command origins and leases\",\n default: \"mcp-agent\",\n },\n },\n subCommands: {\n install: () => import(\"../install\").then((r) => r.installCommand),\n },\n async run({ args }) {\n const session = await loadSession({ file: args.file, agentId: args.agent });\n const server = createCalcaMcpServer(session);\n const transport = new StdioServerTransport();\n await server.connect(transport);\n consola.debug(\"calca mcp server listening on stdio\");\n },\n});\n"],"mappings":";;;;;;AAOA,MAAa,aAAa,cAAc;CACtC,MAAM;EACJ,MAAM;EACN,aAAa;CACf;CACA,MAAM;EACJ,MAAM;GACJ,MAAM;GACN,aAAa;EACf;EACA,OAAO;GACL,MAAM;GACN,aAAa;GACb,SAAS;EACX;CACF;CACA,aAAa,EACX,eAAe,OAAO,yBAAa,CAAC,MAAM,MAAM,EAAE,cAAc,EAClE;CACA,MAAM,IAAI,EAAE,QAAQ;EAClB,MAAM,UAAU,MAAM,YAAY;GAAE,MAAM,KAAK;GAAM,SAAS,KAAK;EAAM,CAAC;EAC1E,MAAM,SAAS,qBAAqB,OAAO;EAC3C,MAAM,YAAY,IAAI,qBAAqB;EAC3C,MAAM,OAAO,QAAQ,SAAS;EAC9B,QAAQ,MAAM,qCAAqC;CACrD;AACF,CAAC"}
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
import { createCanvasSession } from "@calca/mcp-core";
|
|
2
|
+
import { readFile } from "node:fs/promises";
|
|
3
|
+
import { consola } from "consola";
|
|
4
|
+
import { defineCommand } from "citty";
|
|
5
|
+
|
|
6
|
+
//#region src/commands/open.ts
|
|
7
|
+
const openCommand = defineCommand({
|
|
8
|
+
meta: {
|
|
9
|
+
name: "open",
|
|
10
|
+
description: "Inspect a board file (JSON snapshot). Full visual open lands with the web build (Phase 3)."
|
|
11
|
+
},
|
|
12
|
+
args: { file: {
|
|
13
|
+
type: "positional",
|
|
14
|
+
description: "board file to open",
|
|
15
|
+
required: true
|
|
16
|
+
} },
|
|
17
|
+
async run({ args }) {
|
|
18
|
+
const snapshot = JSON.parse(await readFile(args.file, "utf8"));
|
|
19
|
+
const records = createCanvasSession({
|
|
20
|
+
snapshot,
|
|
21
|
+
agentId: "cli"
|
|
22
|
+
}).store.all();
|
|
23
|
+
const byType = /* @__PURE__ */ new Map();
|
|
24
|
+
for (const record of records) byType.set(record.type, (byType.get(record.type) ?? 0) + 1);
|
|
25
|
+
consola.info(`${args.file}: ${records.length} record(s)`);
|
|
26
|
+
for (const [type, count] of [...byType].toSorted()) consola.log(` ${type}: ${count}`);
|
|
27
|
+
}
|
|
28
|
+
});
|
|
29
|
+
|
|
30
|
+
//#endregion
|
|
31
|
+
export { openCommand };
|
|
32
|
+
//# sourceMappingURL=open-BTc5qKY_.mjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"open-BTc5qKY_.mjs","names":[],"sources":["../src/commands/open.ts"],"sourcesContent":["import { readFile } from \"node:fs/promises\";\n\nimport { createCanvasSession } from \"@calca/mcp-core\";\nimport { defineCommand } from \"citty\";\nimport { consola } from \"consola\";\n\nexport const openCommand = defineCommand({\n meta: {\n name: \"open\",\n description:\n \"Inspect a board file (JSON snapshot). Full visual open lands with the web build (Phase 3).\",\n },\n args: {\n file: {\n type: \"positional\",\n description: \"board file to open\",\n required: true,\n },\n },\n async run({ args }) {\n const snapshot = JSON.parse(await readFile(args.file, \"utf8\"));\n const session = createCanvasSession({ snapshot, agentId: \"cli\" });\n const records = session.store.all();\n const byType = new Map<string, number>();\n for (const record of records) {\n byType.set(record.type, (byType.get(record.type) ?? 0) + 1);\n }\n consola.info(`${args.file}: ${records.length} record(s)`);\n for (const [type, count] of [...byType].toSorted()) {\n consola.log(` ${type}: ${count}`);\n }\n },\n});\n"],"mappings":";;;;;;AAMA,MAAa,cAAc,cAAc;CACvC,MAAM;EACJ,MAAM;EACN,aACE;CACJ;CACA,MAAM,EACJ,MAAM;EACJ,MAAM;EACN,aAAa;EACb,UAAU;CACZ,EACF;CACA,MAAM,IAAI,EAAE,QAAQ;EAClB,MAAM,WAAW,KAAK,MAAM,MAAM,SAAS,KAAK,MAAM,MAAM,CAAC;EAE7D,MAAM,UADU,oBAAoB;GAAE;GAAU,SAAS;EAAM,CACzC,CAAC,CAAC,MAAM,IAAI;EAClC,MAAM,yBAAS,IAAI,IAAoB;EACvC,KAAK,MAAM,UAAU,SACnB,OAAO,IAAI,OAAO,OAAO,OAAO,IAAI,OAAO,IAAI,KAAK,KAAK,CAAC;EAE5D,QAAQ,KAAK,GAAG,KAAK,KAAK,IAAI,QAAQ,OAAO,WAAW;EACxD,KAAK,MAAM,CAAC,MAAM,UAAU,CAAC,GAAG,MAAM,CAAC,CAAC,SAAS,GAC/C,QAAQ,IAAI,KAAK,KAAK,IAAI,OAAO;CAErC;AACF,CAAC"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"package-BbsUrmrv.mjs","names":[],"sources":["../package.json"],"sourcesContent":[""],"mappings":""}
|
|
@@ -0,0 +1,81 @@
|
|
|
1
|
+
import { t as version } from "./package-BbsUrmrv.mjs";
|
|
2
|
+
import { createCanvasSession, toolContract } from "@calca/mcp-core";
|
|
3
|
+
import { Server } from "@modelcontextprotocol/sdk/server/index.js";
|
|
4
|
+
import { CallToolRequestSchema, ListToolsRequestSchema } from "@modelcontextprotocol/sdk/types.js";
|
|
5
|
+
import { readFile, writeFile } from "node:fs/promises";
|
|
6
|
+
import { consola } from "consola";
|
|
7
|
+
|
|
8
|
+
//#region src/server.ts
|
|
9
|
+
const contractByName = new Map(toolContract.map((t) => [t.name, t]));
|
|
10
|
+
function createCalcaMcpServer(session) {
|
|
11
|
+
const server = new Server({
|
|
12
|
+
name: "calca",
|
|
13
|
+
version
|
|
14
|
+
}, { capabilities: { tools: {} } });
|
|
15
|
+
server.setRequestHandler(ListToolsRequestSchema, () => ({ tools: toolContract.map((t) => ({
|
|
16
|
+
name: t.name,
|
|
17
|
+
description: t.description,
|
|
18
|
+
inputSchema: t.inputSchema,
|
|
19
|
+
annotations: t.annotations
|
|
20
|
+
})) }));
|
|
21
|
+
server.setRequestHandler(CallToolRequestSchema, async (request) => {
|
|
22
|
+
const tool = contractByName.get(request.params.name);
|
|
23
|
+
if (!tool) return {
|
|
24
|
+
isError: true,
|
|
25
|
+
content: [{
|
|
26
|
+
type: "text",
|
|
27
|
+
text: `unknown tool: ${request.params.name}`
|
|
28
|
+
}]
|
|
29
|
+
};
|
|
30
|
+
try {
|
|
31
|
+
const result = await tool.handler(session, request.params.arguments ?? {});
|
|
32
|
+
return {
|
|
33
|
+
...typeof result === "object" && result !== null ? { structuredContent: result } : {},
|
|
34
|
+
content: [{
|
|
35
|
+
type: "text",
|
|
36
|
+
text: JSON.stringify(result, null, 2)
|
|
37
|
+
}]
|
|
38
|
+
};
|
|
39
|
+
} catch (error) {
|
|
40
|
+
return {
|
|
41
|
+
isError: true,
|
|
42
|
+
content: [{
|
|
43
|
+
type: "text",
|
|
44
|
+
text: error instanceof Error ? error.message : String(error)
|
|
45
|
+
}]
|
|
46
|
+
};
|
|
47
|
+
}
|
|
48
|
+
});
|
|
49
|
+
return server;
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
//#endregion
|
|
53
|
+
//#region src/session.ts
|
|
54
|
+
async function loadSession(options) {
|
|
55
|
+
let snapshot;
|
|
56
|
+
if (options.file) try {
|
|
57
|
+
snapshot = JSON.parse(await readFile(options.file, "utf8"));
|
|
58
|
+
} catch (error) {
|
|
59
|
+
if (error.code === "ENOENT") consola.warn(`board file not found, starting empty: ${options.file}`);
|
|
60
|
+
else throw error;
|
|
61
|
+
}
|
|
62
|
+
const session = createCanvasSession({
|
|
63
|
+
snapshot,
|
|
64
|
+
agentId: options.agentId
|
|
65
|
+
});
|
|
66
|
+
if (options.file) {
|
|
67
|
+
const file = options.file;
|
|
68
|
+
let pending;
|
|
69
|
+
session.store.addEventListener("change", () => {
|
|
70
|
+
clearTimeout(pending);
|
|
71
|
+
pending = setTimeout(() => {
|
|
72
|
+
writeFile(file, JSON.stringify(session.store.snapshot(), null, 2)).catch((error) => consola.warn(`autosave failed: ${error}`));
|
|
73
|
+
}, 250);
|
|
74
|
+
});
|
|
75
|
+
}
|
|
76
|
+
return session;
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
//#endregion
|
|
80
|
+
export { createCalcaMcpServer as n, loadSession as t };
|
|
81
|
+
//# sourceMappingURL=session-DhX_7S8U.mjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"session-DhX_7S8U.mjs","names":[],"sources":["../src/server.ts","../src/session.ts"],"sourcesContent":["import { toolContract, type CanvasSession } from \"@calca/mcp-core\";\nimport { Server } from \"@modelcontextprotocol/sdk/server/index.js\";\nimport { CallToolRequestSchema, ListToolsRequestSchema } from \"@modelcontextprotocol/sdk/types.js\";\n\nimport { version } from \"../package.json\" with { type: \"json\" };\n\nconst contractByName = new Map(toolContract.map((t) => [t.name, t]));\n\nexport function createCalcaMcpServer(session: CanvasSession): Server {\n const server = new Server({ name: \"calca\", version }, { capabilities: { tools: {} } });\n\n server.setRequestHandler(ListToolsRequestSchema, () => ({\n tools: toolContract.map((t) => ({\n name: t.name,\n description: t.description,\n inputSchema: t.inputSchema,\n annotations: t.annotations,\n })),\n }));\n\n server.setRequestHandler(CallToolRequestSchema, async (request) => {\n const tool = contractByName.get(request.params.name);\n if (!tool) {\n return {\n isError: true,\n content: [{ type: \"text\", text: `unknown tool: ${request.params.name}` }],\n };\n }\n try {\n const result = await tool.handler(session, request.params.arguments ?? {});\n return {\n ...(typeof result === \"object\" && result !== null\n ? { structuredContent: result as Record<string, unknown> }\n : {}),\n content: [{ type: \"text\", text: JSON.stringify(result, null, 2) }],\n };\n } catch (error) {\n return {\n isError: true,\n content: [\n {\n type: \"text\",\n text: error instanceof Error ? error.message : String(error),\n },\n ],\n };\n }\n });\n\n return server;\n}\n","import { readFile, writeFile } from \"node:fs/promises\";\n\nimport type { CanvasSnapshot } from \"@calca/canvas-base\";\nimport { createCanvasSession, type CanvasSession } from \"@calca/mcp-core\";\nimport { consola } from \"consola\";\n\nexport interface LoadSessionOptions {\n file?: string;\n agentId: string;\n}\n\nexport async function loadSession(options: LoadSessionOptions): Promise<CanvasSession> {\n let snapshot: CanvasSnapshot | undefined;\n if (options.file) {\n try {\n snapshot = JSON.parse(await readFile(options.file, \"utf8\"));\n } catch (error) {\n if ((error as NodeJS.ErrnoException).code === \"ENOENT\") {\n consola.warn(`board file not found, starting empty: ${options.file}`);\n } else {\n throw error;\n }\n }\n }\n\n const session = createCanvasSession({ snapshot, agentId: options.agentId });\n\n if (options.file) {\n const file = options.file;\n let pending: ReturnType<typeof setTimeout> | undefined;\n session.store.addEventListener(\"change\", () => {\n clearTimeout(pending);\n pending = setTimeout(() => {\n writeFile(file, JSON.stringify(session.store.snapshot(), null, 2)).catch((error) =>\n consola.warn(`autosave failed: ${error}`),\n );\n }, 250);\n });\n }\n\n return session;\n}\n"],"mappings":";;;;;;;;AAMA,MAAM,iBAAiB,IAAI,IAAI,aAAa,KAAK,MAAM,CAAC,EAAE,MAAM,CAAC,CAAC,CAAC;AAEnE,SAAgB,qBAAqB,SAAgC;CACnE,MAAM,SAAS,IAAI,OAAO;EAAE,MAAM;EAAS;CAAQ,GAAG,EAAE,cAAc,EAAE,OAAO,CAAC,EAAE,EAAE,CAAC;CAErF,OAAO,kBAAkB,+BAA+B,EACtD,OAAO,aAAa,KAAK,OAAO;EAC9B,MAAM,EAAE;EACR,aAAa,EAAE;EACf,aAAa,EAAE;EACf,aAAa,EAAE;CACjB,EAAE,EACJ,EAAE;CAEF,OAAO,kBAAkB,uBAAuB,OAAO,YAAY;EACjE,MAAM,OAAO,eAAe,IAAI,QAAQ,OAAO,IAAI;EACnD,IAAI,CAAC,MACH,OAAO;GACL,SAAS;GACT,SAAS,CAAC;IAAE,MAAM;IAAQ,MAAM,iBAAiB,QAAQ,OAAO;GAAO,CAAC;EAC1E;EAEF,IAAI;GACF,MAAM,SAAS,MAAM,KAAK,QAAQ,SAAS,QAAQ,OAAO,aAAa,CAAC,CAAC;GACzE,OAAO;IACL,GAAI,OAAO,WAAW,YAAY,WAAW,OACzC,EAAE,mBAAmB,OAAkC,IACvD,CAAC;IACL,SAAS,CAAC;KAAE,MAAM;KAAQ,MAAM,KAAK,UAAU,QAAQ,MAAM,CAAC;IAAE,CAAC;GACnE;EACF,SAAS,OAAO;GACd,OAAO;IACL,SAAS;IACT,SAAS,CACP;KACE,MAAM;KACN,MAAM,iBAAiB,QAAQ,MAAM,UAAU,OAAO,KAAK;IAC7D,CACF;GACF;EACF;CACF,CAAC;CAED,OAAO;AACT;;;;ACvCA,eAAsB,YAAY,SAAqD;CACrF,IAAI;CACJ,IAAI,QAAQ,MACV,IAAI;EACF,WAAW,KAAK,MAAM,MAAM,SAAS,QAAQ,MAAM,MAAM,CAAC;CAC5D,SAAS,OAAO;EACd,IAAK,MAAgC,SAAS,UAC5C,QAAQ,KAAK,yCAAyC,QAAQ,MAAM;OAEpE,MAAM;CAEV;CAGF,MAAM,UAAU,oBAAoB;EAAE;EAAU,SAAS,QAAQ;CAAQ,CAAC;CAE1E,IAAI,QAAQ,MAAM;EAChB,MAAM,OAAO,QAAQ;EACrB,IAAI;EACJ,QAAQ,MAAM,iBAAiB,gBAAgB;GAC7C,aAAa,OAAO;GACpB,UAAU,iBAAiB;IACzB,UAAU,MAAM,KAAK,UAAU,QAAQ,MAAM,SAAS,GAAG,MAAM,CAAC,CAAC,CAAC,CAAC,OAAO,UACxE,QAAQ,KAAK,oBAAoB,OAAO,CAC1C;GACF,GAAG,GAAG;EACR,CAAC;CACH;CAEA,OAAO;AACT"}
|
package/package.json
ADDED
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@calca/mcp",
|
|
3
|
+
"version": "0.7.3",
|
|
4
|
+
"private": false,
|
|
5
|
+
"description": "calca CLI — MCP playground server for AI agents",
|
|
6
|
+
"license": "Apache-2.0",
|
|
7
|
+
"bin": {
|
|
8
|
+
"calca": "./dist/cli.mjs"
|
|
9
|
+
},
|
|
10
|
+
"files": [
|
|
11
|
+
"dist"
|
|
12
|
+
],
|
|
13
|
+
"type": "module",
|
|
14
|
+
"exports": {
|
|
15
|
+
".": {
|
|
16
|
+
"types": "./dist/index.d.mts",
|
|
17
|
+
"import": "./dist/index.mjs"
|
|
18
|
+
}
|
|
19
|
+
},
|
|
20
|
+
"publishConfig": {
|
|
21
|
+
"access": "public"
|
|
22
|
+
},
|
|
23
|
+
"scripts": {
|
|
24
|
+
"build": "tsdown",
|
|
25
|
+
"typecheck": "bunx tsc --noEmit",
|
|
26
|
+
"lint": "oxlint --fix .",
|
|
27
|
+
"format": "oxfmt --write .",
|
|
28
|
+
"test": "vitest run",
|
|
29
|
+
"clean": "rm -rf dist",
|
|
30
|
+
"validate": "bun ../../scripts/validate.ts --cwd $INIT_CWD",
|
|
31
|
+
"check:pack": "publint && attw --pack . --profile esm-only"
|
|
32
|
+
},
|
|
33
|
+
"dependencies": {
|
|
34
|
+
"@calca/canvas-base": "0.7.3",
|
|
35
|
+
"@calca/mcp-core": "0.7.3",
|
|
36
|
+
"@modelcontextprotocol/sdk": "^1.32.0",
|
|
37
|
+
"citty": "^0.1.6",
|
|
38
|
+
"consola": "^3.4.2",
|
|
39
|
+
"pathe": "^2.0.3"
|
|
40
|
+
},
|
|
41
|
+
"devDependencies": {
|
|
42
|
+
"@arethetypeswrong/cli": "^0.18.0",
|
|
43
|
+
"@types/node": "^25.2.3",
|
|
44
|
+
"publint": "^0.3.0",
|
|
45
|
+
"tsdown": "^0.23.0",
|
|
46
|
+
"typescript": "^6.0.3",
|
|
47
|
+
"vitest": "^4.1.5"
|
|
48
|
+
}
|
|
49
|
+
}
|