@plutojl/mcp 0.1.0 → 0.2.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/dist/cli.cjs +209 -6
- package/package.json +1 -1
package/dist/cli.cjs
CHANGED
|
@@ -39340,7 +39340,9 @@ Usage:
|
|
|
39340
39340
|
|
|
39341
39341
|
Commands:
|
|
39342
39342
|
run Start the MCP server (and Pluto server if needed)
|
|
39343
|
-
install Add MCP config to .
|
|
39343
|
+
install Add MCP config to .mcp.json or mcp.json
|
|
39344
|
+
tools List available MCP tools on a running server
|
|
39345
|
+
call Call an MCP tool on a running server
|
|
39344
39346
|
|
|
39345
39347
|
Run options:
|
|
39346
39348
|
--mcp-port <port> MCP server port (default: ${DEFAULTS.mcpPort})
|
|
@@ -39355,13 +39357,26 @@ Install options:
|
|
|
39355
39357
|
--dry-run Print config without writing
|
|
39356
39358
|
--force Overwrite existing config without prompting
|
|
39357
39359
|
|
|
39360
|
+
Call options:
|
|
39361
|
+
npx @plutojl/mcp call <tool_name> [json_args]
|
|
39362
|
+
--mcp-port <port> MCP server port (default: ${DEFAULTS.mcpPort})
|
|
39363
|
+
--raw Output raw JSON response
|
|
39364
|
+
|
|
39365
|
+
Tools options:
|
|
39366
|
+
--mcp-port <port> MCP server port (default: ${DEFAULTS.mcpPort})
|
|
39367
|
+
|
|
39358
39368
|
Examples:
|
|
39359
39369
|
npx @plutojl/mcp run
|
|
39360
39370
|
npx @plutojl/mcp run --pluto-url http://localhost:1234
|
|
39361
39371
|
npx @plutojl/mcp install
|
|
39362
39372
|
npx @plutojl/mcp install --target all --global
|
|
39373
|
+
npx @plutojl/mcp tools
|
|
39374
|
+
npx @plutojl/mcp call get_notebook_status
|
|
39375
|
+
npx @plutojl/mcp call start_pluto_server '{"port": 1234}'
|
|
39376
|
+
npx @plutojl/mcp call open_notebook '{"path": "/tmp/nb.pluto.jl"}'
|
|
39363
39377
|
`);
|
|
39364
39378
|
}
|
|
39379
|
+
var COMMANDS = /* @__PURE__ */ new Set(["run", "install", "call", "tools", "help"]);
|
|
39365
39380
|
function parseArgs(argv) {
|
|
39366
39381
|
const args = { command: "help" };
|
|
39367
39382
|
let i = 0;
|
|
@@ -39374,7 +39389,7 @@ function parseArgs(argv) {
|
|
|
39374
39389
|
}
|
|
39375
39390
|
if (i < argv.length) {
|
|
39376
39391
|
const cmd = argv[i];
|
|
39377
|
-
if (cmd
|
|
39392
|
+
if (COMMANDS.has(cmd)) {
|
|
39378
39393
|
args.command = cmd;
|
|
39379
39394
|
} else {
|
|
39380
39395
|
console.error(`Unknown command: ${cmd}`);
|
|
@@ -39383,6 +39398,16 @@ function parseArgs(argv) {
|
|
|
39383
39398
|
}
|
|
39384
39399
|
i++;
|
|
39385
39400
|
}
|
|
39401
|
+
if (args.command === "call") {
|
|
39402
|
+
while (i < argv.length && !argv[i].startsWith("-")) {
|
|
39403
|
+
if (!args.toolName) {
|
|
39404
|
+
args.toolName = argv[i];
|
|
39405
|
+
} else if (!args.toolArgs) {
|
|
39406
|
+
args.toolArgs = argv[i];
|
|
39407
|
+
}
|
|
39408
|
+
i++;
|
|
39409
|
+
}
|
|
39410
|
+
}
|
|
39386
39411
|
while (i < argv.length) {
|
|
39387
39412
|
const flag = argv[i];
|
|
39388
39413
|
if (flag === "--help" || flag === "-h") {
|
|
@@ -39413,6 +39438,8 @@ function parseArgs(argv) {
|
|
|
39413
39438
|
args.dryRun = true;
|
|
39414
39439
|
} else if (flag === "--force") {
|
|
39415
39440
|
args.force = true;
|
|
39441
|
+
} else if (flag === "--raw") {
|
|
39442
|
+
args.raw = true;
|
|
39416
39443
|
} else {
|
|
39417
39444
|
console.warn(`Unknown flag: ${flag}`);
|
|
39418
39445
|
}
|
|
@@ -63662,10 +63689,8 @@ async function run(config) {
|
|
|
63662
63689
|
console.log(`[cli] Health check: http://localhost:${config.mcpPort}/health`);
|
|
63663
63690
|
console.log(`[cli] Press Ctrl+C to stop
|
|
63664
63691
|
`);
|
|
63665
|
-
console.log(
|
|
63666
|
-
|
|
63667
|
-
`
|
|
63668
|
-
);
|
|
63692
|
+
console.log(`Tip: Run 'npx @plutojl/mcp install' to configure Claude Code
|
|
63693
|
+
`);
|
|
63669
63694
|
const shutdown = async () => {
|
|
63670
63695
|
console.log("\n[cli] Shutting down...");
|
|
63671
63696
|
try {
|
|
@@ -63759,9 +63784,170 @@ async function installMcpConfig(args) {
|
|
|
63759
63784
|
}
|
|
63760
63785
|
}
|
|
63761
63786
|
|
|
63787
|
+
// ../../src/cli/call.ts
|
|
63788
|
+
async function mcpRequest(port, method, params = {}) {
|
|
63789
|
+
const sseUrl = `http://localhost:${port}/mcp`;
|
|
63790
|
+
const sseResponse = await fetch(sseUrl, {
|
|
63791
|
+
headers: { Accept: "text/event-stream" }
|
|
63792
|
+
});
|
|
63793
|
+
if (!sseResponse.ok || !sseResponse.body) {
|
|
63794
|
+
throw new Error(
|
|
63795
|
+
`Failed to connect to MCP server at ${sseUrl} (${sseResponse.status})`
|
|
63796
|
+
);
|
|
63797
|
+
}
|
|
63798
|
+
const reader = sseResponse.body.getReader();
|
|
63799
|
+
const decoder = new TextDecoder();
|
|
63800
|
+
let buffer2 = "";
|
|
63801
|
+
let sessionUrl;
|
|
63802
|
+
while (!sessionUrl) {
|
|
63803
|
+
const { done, value } = await reader.read();
|
|
63804
|
+
if (done) throw new Error("SSE stream ended before receiving endpoint");
|
|
63805
|
+
buffer2 += decoder.decode(value, { stream: true });
|
|
63806
|
+
const lines = buffer2.split("\n");
|
|
63807
|
+
for (let i = 0; i < lines.length - 1; i++) {
|
|
63808
|
+
const line = lines[i];
|
|
63809
|
+
if (line.startsWith("data: ") && !sessionUrl) {
|
|
63810
|
+
sessionUrl = line.slice(6).trim();
|
|
63811
|
+
}
|
|
63812
|
+
}
|
|
63813
|
+
buffer2 = lines[lines.length - 1];
|
|
63814
|
+
}
|
|
63815
|
+
const messagesUrl = `http://localhost:${port}${sessionUrl}`;
|
|
63816
|
+
const requestId = 1;
|
|
63817
|
+
await fetch(messagesUrl, {
|
|
63818
|
+
method: "POST",
|
|
63819
|
+
headers: { "Content-Type": "application/json" },
|
|
63820
|
+
body: JSON.stringify({
|
|
63821
|
+
jsonrpc: "2.0",
|
|
63822
|
+
id: 0,
|
|
63823
|
+
method: "initialize",
|
|
63824
|
+
params: {
|
|
63825
|
+
protocolVersion: "2024-11-05",
|
|
63826
|
+
capabilities: {},
|
|
63827
|
+
clientInfo: { name: "plutojl-mcp-cli", version: "0.1.0" }
|
|
63828
|
+
}
|
|
63829
|
+
})
|
|
63830
|
+
});
|
|
63831
|
+
let initDone = false;
|
|
63832
|
+
while (!initDone) {
|
|
63833
|
+
const { done, value } = await reader.read();
|
|
63834
|
+
if (done) break;
|
|
63835
|
+
buffer2 += decoder.decode(value, { stream: true });
|
|
63836
|
+
if (buffer2.includes('"initialize"') || buffer2.includes('"id":0')) {
|
|
63837
|
+
initDone = true;
|
|
63838
|
+
}
|
|
63839
|
+
}
|
|
63840
|
+
await fetch(messagesUrl, {
|
|
63841
|
+
method: "POST",
|
|
63842
|
+
headers: { "Content-Type": "application/json" },
|
|
63843
|
+
body: JSON.stringify({
|
|
63844
|
+
jsonrpc: "2.0",
|
|
63845
|
+
method: "notifications/initialized"
|
|
63846
|
+
})
|
|
63847
|
+
});
|
|
63848
|
+
await fetch(messagesUrl, {
|
|
63849
|
+
method: "POST",
|
|
63850
|
+
headers: { "Content-Type": "application/json" },
|
|
63851
|
+
body: JSON.stringify({
|
|
63852
|
+
jsonrpc: "2.0",
|
|
63853
|
+
id: requestId,
|
|
63854
|
+
method,
|
|
63855
|
+
params
|
|
63856
|
+
})
|
|
63857
|
+
});
|
|
63858
|
+
buffer2 = "";
|
|
63859
|
+
const timeout2 = setTimeout(() => {
|
|
63860
|
+
reader.cancel().catch(() => {
|
|
63861
|
+
});
|
|
63862
|
+
}, 3e4);
|
|
63863
|
+
try {
|
|
63864
|
+
while (true) {
|
|
63865
|
+
const { done, value } = await reader.read();
|
|
63866
|
+
if (done) break;
|
|
63867
|
+
buffer2 += decoder.decode(value, { stream: true });
|
|
63868
|
+
const parts = buffer2.split("\n\n");
|
|
63869
|
+
buffer2 = parts.pop() ?? "";
|
|
63870
|
+
for (const part of parts) {
|
|
63871
|
+
let eventData = "";
|
|
63872
|
+
for (const line of part.split("\n")) {
|
|
63873
|
+
if (line.startsWith("data: ")) {
|
|
63874
|
+
eventData += line.slice(6);
|
|
63875
|
+
}
|
|
63876
|
+
}
|
|
63877
|
+
if (eventData) {
|
|
63878
|
+
try {
|
|
63879
|
+
const parsed = JSON.parse(eventData);
|
|
63880
|
+
if (parsed.id === requestId) {
|
|
63881
|
+
if (parsed.error) {
|
|
63882
|
+
throw new Error(
|
|
63883
|
+
`MCP error ${parsed.error.code}: ${parsed.error.message}`
|
|
63884
|
+
);
|
|
63885
|
+
}
|
|
63886
|
+
return parsed.result;
|
|
63887
|
+
}
|
|
63888
|
+
} catch (e) {
|
|
63889
|
+
if (e instanceof SyntaxError) continue;
|
|
63890
|
+
throw e;
|
|
63891
|
+
}
|
|
63892
|
+
}
|
|
63893
|
+
}
|
|
63894
|
+
}
|
|
63895
|
+
} finally {
|
|
63896
|
+
clearTimeout(timeout2);
|
|
63897
|
+
reader.cancel().catch(() => {
|
|
63898
|
+
});
|
|
63899
|
+
}
|
|
63900
|
+
throw new Error("No response received from MCP server");
|
|
63901
|
+
}
|
|
63902
|
+
async function listTools(port) {
|
|
63903
|
+
const result = await mcpRequest(port, "tools/list");
|
|
63904
|
+
const tools = result?.tools ?? [];
|
|
63905
|
+
if (tools.length === 0) {
|
|
63906
|
+
console.log("No tools available.");
|
|
63907
|
+
return;
|
|
63908
|
+
}
|
|
63909
|
+
const maxLen = Math.max(...tools.map((t) => t.name.length));
|
|
63910
|
+
for (const tool of tools) {
|
|
63911
|
+
const params = tool.inputSchema?.properties ? Object.keys(tool.inputSchema.properties) : [];
|
|
63912
|
+
const paramStr = params.length > 0 ? ` (${params.join(", ")})` : "";
|
|
63913
|
+
console.log(
|
|
63914
|
+
` ${tool.name.padEnd(maxLen)} ${tool.description ?? ""}${paramStr}`
|
|
63915
|
+
);
|
|
63916
|
+
}
|
|
63917
|
+
}
|
|
63918
|
+
async function callTool(port, toolName, argsJson, raw2) {
|
|
63919
|
+
let args;
|
|
63920
|
+
try {
|
|
63921
|
+
args = JSON.parse(argsJson);
|
|
63922
|
+
} catch {
|
|
63923
|
+
console.error(`Invalid JSON arguments: ${argsJson}`);
|
|
63924
|
+
process.exit(1);
|
|
63925
|
+
}
|
|
63926
|
+
const result = await mcpRequest(port, "tools/call", {
|
|
63927
|
+
name: toolName,
|
|
63928
|
+
arguments: args
|
|
63929
|
+
});
|
|
63930
|
+
if (raw2) {
|
|
63931
|
+
console.log(JSON.stringify(result, null, 2));
|
|
63932
|
+
return;
|
|
63933
|
+
}
|
|
63934
|
+
const content = result?.content;
|
|
63935
|
+
if (content) {
|
|
63936
|
+
for (const item of content) {
|
|
63937
|
+
if (item.type === "text" && item.text) {
|
|
63938
|
+
console.log(item.text);
|
|
63939
|
+
}
|
|
63940
|
+
}
|
|
63941
|
+
}
|
|
63942
|
+
if (result?.isError) {
|
|
63943
|
+
process.exit(1);
|
|
63944
|
+
}
|
|
63945
|
+
}
|
|
63946
|
+
|
|
63762
63947
|
// ../../src/cli/index.ts
|
|
63763
63948
|
async function main() {
|
|
63764
63949
|
const args = parseArgs(process.argv.slice(2));
|
|
63950
|
+
const mcpPort = args.mcpPort ?? DEFAULTS.mcpPort;
|
|
63765
63951
|
switch (args.command) {
|
|
63766
63952
|
case "run": {
|
|
63767
63953
|
const config = resolveRunConfig(args);
|
|
@@ -63773,6 +63959,23 @@ async function main() {
|
|
|
63773
63959
|
await installMcpConfig(installArgs);
|
|
63774
63960
|
break;
|
|
63775
63961
|
}
|
|
63962
|
+
case "tools": {
|
|
63963
|
+
await listTools(mcpPort);
|
|
63964
|
+
break;
|
|
63965
|
+
}
|
|
63966
|
+
case "call": {
|
|
63967
|
+
if (!args.toolName) {
|
|
63968
|
+
console.error("Usage: npx @plutojl/mcp call <tool_name> [json_args]");
|
|
63969
|
+
process.exit(1);
|
|
63970
|
+
}
|
|
63971
|
+
await callTool(
|
|
63972
|
+
mcpPort,
|
|
63973
|
+
args.toolName,
|
|
63974
|
+
args.toolArgs ?? "{}",
|
|
63975
|
+
args.raw ?? false
|
|
63976
|
+
);
|
|
63977
|
+
break;
|
|
63978
|
+
}
|
|
63776
63979
|
}
|
|
63777
63980
|
}
|
|
63778
63981
|
main().catch((err) => {
|