@arbiterai/cli 0.1.0 → 0.1.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/dist/index.js +194 -42
- package/package.json +8 -9
package/dist/index.js
CHANGED
|
@@ -31,7 +31,7 @@ var require_package = __commonJS({
|
|
|
31
31
|
"package.json"(exports2, module2) {
|
|
32
32
|
module2.exports = {
|
|
33
33
|
name: "@arbiterai/cli",
|
|
34
|
-
version: "0.1.
|
|
34
|
+
version: "0.1.1",
|
|
35
35
|
description: "Official CLI for Arbiter \u2014 the developer-first MCP gateway",
|
|
36
36
|
license: "MIT",
|
|
37
37
|
keywords: [
|
|
@@ -305,9 +305,6 @@ function printError(msg) {
|
|
|
305
305
|
console.error(import_chalk.default.red("\u2717") + " " + msg);
|
|
306
306
|
process.exit(1);
|
|
307
307
|
}
|
|
308
|
-
function printWarning(msg) {
|
|
309
|
-
console.warn(import_chalk.default.yellow("\u26A0") + " " + msg);
|
|
310
|
-
}
|
|
311
308
|
|
|
312
309
|
// src/commands/login.ts
|
|
313
310
|
function registerLogin(program2) {
|
|
@@ -502,6 +499,44 @@ function registerAgentCommands(program2) {
|
|
|
502
499
|
registerAgentDelete(agentCmd);
|
|
503
500
|
}
|
|
504
501
|
|
|
502
|
+
// src/commands/mcp-servers/list.ts
|
|
503
|
+
function registerMcpServersList(mcpServersCmd) {
|
|
504
|
+
mcpServersCmd.command("list").description("List registered MCP servers").option("--json", "Output raw JSON").action(async (opts) => {
|
|
505
|
+
requireAuth();
|
|
506
|
+
let page;
|
|
507
|
+
try {
|
|
508
|
+
page = await get("/api/v1/mcp-servers", { skip: 0, limit: 200 });
|
|
509
|
+
} catch (err) {
|
|
510
|
+
if (err instanceof ApiError) {
|
|
511
|
+
printError(`API error: ${err.detail}`);
|
|
512
|
+
}
|
|
513
|
+
throw err;
|
|
514
|
+
}
|
|
515
|
+
if (opts.json) {
|
|
516
|
+
console.log(JSON.stringify(page, null, 2));
|
|
517
|
+
return;
|
|
518
|
+
}
|
|
519
|
+
if (page.items.length === 0) {
|
|
520
|
+
printTable(["Name", "Base URL", "Cache", "Active"], []);
|
|
521
|
+
console.log("No MCP servers registered.");
|
|
522
|
+
return;
|
|
523
|
+
}
|
|
524
|
+
const rows = page.items.map((s) => [
|
|
525
|
+
s.name,
|
|
526
|
+
s.base_url,
|
|
527
|
+
s.cache_enabled ? "yes" : "no",
|
|
528
|
+
s.is_active ? "yes" : "no"
|
|
529
|
+
]);
|
|
530
|
+
printTable(["Name", "Base URL", "Cache", "Active"], rows);
|
|
531
|
+
});
|
|
532
|
+
}
|
|
533
|
+
|
|
534
|
+
// src/commands/mcp-servers/index.ts
|
|
535
|
+
function registerMcpServersCommands(program2) {
|
|
536
|
+
const mcpServersCmd = program2.command("mcp-servers").description("Manage registered MCP servers");
|
|
537
|
+
registerMcpServersList(mcpServersCmd);
|
|
538
|
+
}
|
|
539
|
+
|
|
505
540
|
// src/commands/permissions/grant.ts
|
|
506
541
|
function registerPermissionsGrant(permissionsCmd) {
|
|
507
542
|
permissionsCmd.command("grant").description("Grant a tool permission to an agent").requiredOption("--agent <id>", "Agent ID").requiredOption("--tool <tool>", "Tool name (e.g. read_file, or * for all tools)").requiredOption("--server <name>", "MCP server name").option("--json", "Output raw JSON").action(async (opts) => {
|
|
@@ -578,57 +613,116 @@ function formatDate2(iso) {
|
|
|
578
613
|
return d.toISOString().replace("T", " ").slice(0, 16);
|
|
579
614
|
}
|
|
580
615
|
|
|
616
|
+
// src/commands/permissions/revoke.ts
|
|
617
|
+
function registerPermissionsRevoke(permissionsCmd) {
|
|
618
|
+
permissionsCmd.command("revoke").description("Revoke a tool permission from an agent").requiredOption("--agent <id>", "Agent ID").requiredOption("--tool <tool>", "Tool name (e.g. read_file, or * for wildcard)").requiredOption("--server <name>", "MCP server name").action(async (opts) => {
|
|
619
|
+
requireAuth();
|
|
620
|
+
const serverPage = await get("/api/v1/mcp-servers", { skip: 0, limit: 200 });
|
|
621
|
+
const server = serverPage.items.find(
|
|
622
|
+
(s) => s.name.toLowerCase() === opts.server.toLowerCase()
|
|
623
|
+
);
|
|
624
|
+
if (!server) {
|
|
625
|
+
printError(`MCP server '${opts.server}' not found.`);
|
|
626
|
+
}
|
|
627
|
+
let page;
|
|
628
|
+
try {
|
|
629
|
+
page = await get(`/api/v1/agents/${opts.agent}/permissions`);
|
|
630
|
+
} catch (err) {
|
|
631
|
+
if (err instanceof ApiError && err.status === 404) {
|
|
632
|
+
printError("Agent not found.");
|
|
633
|
+
}
|
|
634
|
+
throw err;
|
|
635
|
+
}
|
|
636
|
+
const permission = page.items.find(
|
|
637
|
+
(p) => p.mcp_server_id === server.id && p.tool_name === opts.tool
|
|
638
|
+
);
|
|
639
|
+
if (!permission) {
|
|
640
|
+
printError(`No permission found for tool '${opts.tool}' on server '${opts.server}'.`);
|
|
641
|
+
}
|
|
642
|
+
try {
|
|
643
|
+
await del(`/api/v1/agents/${opts.agent}/permissions/${permission.id}`);
|
|
644
|
+
} catch (err) {
|
|
645
|
+
if (err instanceof ApiError) {
|
|
646
|
+
printError(`API error: ${err.detail}`);
|
|
647
|
+
}
|
|
648
|
+
throw err;
|
|
649
|
+
}
|
|
650
|
+
printSuccess(`Permission revoked: ${opts.agent} \u2192 ${opts.server}/${opts.tool}`);
|
|
651
|
+
});
|
|
652
|
+
}
|
|
653
|
+
|
|
581
654
|
// src/commands/permissions/index.ts
|
|
582
655
|
function registerPermissionsCommands(program2) {
|
|
583
656
|
const permissionsCmd = program2.command("permissions").description("Manage agent tool permissions");
|
|
584
657
|
registerPermissionsGrant(permissionsCmd);
|
|
585
658
|
registerPermissionsList(permissionsCmd);
|
|
659
|
+
registerPermissionsRevoke(permissionsCmd);
|
|
586
660
|
}
|
|
587
661
|
|
|
588
662
|
// src/commands/vault/set.ts
|
|
663
|
+
var readline2 = __toESM(require("readline"));
|
|
589
664
|
var SECRET_NAME_RE = /^[A-Za-z0-9_]+$/;
|
|
665
|
+
function promptSecret(prompt) {
|
|
666
|
+
return new Promise((resolve) => {
|
|
667
|
+
const rl = readline2.createInterface({ input: process.stdin, output: process.stdout });
|
|
668
|
+
process.stdout.write(prompt);
|
|
669
|
+
rl.output.write = () => true;
|
|
670
|
+
rl.question("", (answer) => {
|
|
671
|
+
rl.close();
|
|
672
|
+
process.stdout.write("\n");
|
|
673
|
+
resolve(answer);
|
|
674
|
+
});
|
|
675
|
+
});
|
|
676
|
+
}
|
|
590
677
|
function registerVaultSet(vaultCmd) {
|
|
591
|
-
vaultCmd.command("set").description("Store a secret in the vault").
|
|
592
|
-
|
|
593
|
-
|
|
594
|
-
|
|
595
|
-
|
|
596
|
-
);
|
|
597
|
-
|
|
598
|
-
|
|
599
|
-
|
|
600
|
-
|
|
601
|
-
|
|
602
|
-
|
|
603
|
-
|
|
604
|
-
|
|
605
|
-
|
|
606
|
-
|
|
607
|
-
|
|
608
|
-
|
|
609
|
-
|
|
610
|
-
|
|
611
|
-
|
|
612
|
-
|
|
613
|
-
|
|
614
|
-
|
|
615
|
-
|
|
616
|
-
|
|
617
|
-
|
|
618
|
-
|
|
619
|
-
|
|
620
|
-
|
|
678
|
+
vaultCmd.command("set").description("Store a secret in the vault").option("--agent <id>", "Agent ID to scope the secret to (omit for org-level secrets)").requiredOption("--key <key>", "Secret key name (e.g. OPENAI_API_KEY)").option(
|
|
679
|
+
"--value <value>",
|
|
680
|
+
"Secret value (omit to be prompted with masked input \u2014 keeps value out of ps aux)"
|
|
681
|
+
).option("--json", "Output raw JSON").action(
|
|
682
|
+
async (opts) => {
|
|
683
|
+
requireAuth();
|
|
684
|
+
if (!SECRET_NAME_RE.test(opts.key)) {
|
|
685
|
+
printError(
|
|
686
|
+
"Secret key must contain only letters, numbers, and underscores (A-Za-z0-9_)."
|
|
687
|
+
);
|
|
688
|
+
}
|
|
689
|
+
let secretValue;
|
|
690
|
+
if (opts.value !== void 0) {
|
|
691
|
+
secretValue = opts.value;
|
|
692
|
+
} else if (process.stdin.isTTY) {
|
|
693
|
+
secretValue = await promptSecret(`Secret value for ${opts.key}: `);
|
|
694
|
+
if (!secretValue) printError("Secret value cannot be empty.");
|
|
695
|
+
} else {
|
|
696
|
+
secretValue = await new Promise((resolve) => {
|
|
697
|
+
let data = "";
|
|
698
|
+
process.stdin.on("data", (chunk) => data += chunk);
|
|
699
|
+
process.stdin.on("end", () => resolve(data.trim()));
|
|
700
|
+
});
|
|
701
|
+
}
|
|
702
|
+
let secret;
|
|
703
|
+
try {
|
|
704
|
+
secret = await post("/api/v1/vault/secrets", {
|
|
705
|
+
name: opts.key,
|
|
706
|
+
value: secretValue,
|
|
707
|
+
agent_id: opts.agent ?? null
|
|
708
|
+
});
|
|
709
|
+
} catch (err) {
|
|
710
|
+
if (err instanceof ApiError) {
|
|
711
|
+
if (err.status === 404) printError("Agent not found.");
|
|
712
|
+
if (err.status === 402)
|
|
713
|
+
printError("Plan limit reached. Upgrade at https://arbiterai.dev/pricing");
|
|
714
|
+
printError(`API error: ${err.detail}`);
|
|
621
715
|
}
|
|
622
|
-
|
|
716
|
+
throw err;
|
|
623
717
|
}
|
|
624
|
-
|
|
625
|
-
|
|
626
|
-
|
|
627
|
-
|
|
628
|
-
|
|
718
|
+
if (opts.json) {
|
|
719
|
+
console.log(JSON.stringify(secret, null, 2));
|
|
720
|
+
return;
|
|
721
|
+
}
|
|
722
|
+
const scope = opts.agent ? `agent ${opts.agent}` : "org-level";
|
|
723
|
+
printSuccess(`Secret '${opts.key}' set (${scope}).`);
|
|
629
724
|
}
|
|
630
|
-
|
|
631
|
-
});
|
|
725
|
+
);
|
|
632
726
|
}
|
|
633
727
|
|
|
634
728
|
// src/commands/vault/index.ts
|
|
@@ -637,6 +731,62 @@ function registerVaultCommands(program2) {
|
|
|
637
731
|
registerVaultSet(vaultCmd);
|
|
638
732
|
}
|
|
639
733
|
|
|
734
|
+
// src/commands/test-call.ts
|
|
735
|
+
var import_axios3 = __toESM(require("axios"));
|
|
736
|
+
function registerTestCall(program2) {
|
|
737
|
+
program2.command("test-call").description("Fire a tool call through the gateway from the terminal").requiredOption("--server <name>", "MCP server name").requiredOption("--tool <tool>", "Tool name to invoke").option("--params <json>", "Tool arguments as a JSON string (default: {})", "{}").option("--agent-key <key>", "Agent API key (overrides config)").option("--json", "Output raw JSON response").action(
|
|
738
|
+
async (opts) => {
|
|
739
|
+
requireAuth();
|
|
740
|
+
const serverPage = await get("/api/v1/mcp-servers", { skip: 0, limit: 200 });
|
|
741
|
+
const server = serverPage.items.find(
|
|
742
|
+
(s) => s.name.toLowerCase() === opts.server.toLowerCase()
|
|
743
|
+
);
|
|
744
|
+
if (!server) {
|
|
745
|
+
printError(`MCP server '${opts.server}' not found.`);
|
|
746
|
+
}
|
|
747
|
+
let params;
|
|
748
|
+
try {
|
|
749
|
+
params = JSON.parse(opts.params);
|
|
750
|
+
} catch {
|
|
751
|
+
printError(`--params must be valid JSON, e.g. '{"path": "/tmp/test.txt"}'`);
|
|
752
|
+
}
|
|
753
|
+
const cfg = getConfig();
|
|
754
|
+
const apiKey = opts.agentKey;
|
|
755
|
+
if (!apiKey) {
|
|
756
|
+
printError(
|
|
757
|
+
"An agent API key is required for proxy calls.\nPass --agent-key <key> or create an agent with `arbiter agent create`."
|
|
758
|
+
);
|
|
759
|
+
}
|
|
760
|
+
const baseUrl = (process.env["ARBITER_API_URL"] ?? cfg?.api_url ?? "https://api.arbiterai.dev").replace(/\/$/, "");
|
|
761
|
+
let result;
|
|
762
|
+
try {
|
|
763
|
+
const res = await import_axios3.default.post(
|
|
764
|
+
`${baseUrl}/api/v1/proxy/tool-call`,
|
|
765
|
+
{ server_name: opts.server, tool_name: opts.tool, params },
|
|
766
|
+
{ headers: { Authorization: `Bearer ${apiKey}`, "Content-Type": "application/json" } }
|
|
767
|
+
);
|
|
768
|
+
result = res.data;
|
|
769
|
+
} catch (err) {
|
|
770
|
+
if (import_axios3.default.isAxiosError(err)) {
|
|
771
|
+
const detail = err.response?.data?.detail ?? err.message;
|
|
772
|
+
printError(`Tool call failed (HTTP ${err.response?.status ?? 0}): ${detail}`);
|
|
773
|
+
}
|
|
774
|
+
throw err;
|
|
775
|
+
}
|
|
776
|
+
if (opts.json) {
|
|
777
|
+
console.log(JSON.stringify(result, null, 2));
|
|
778
|
+
return;
|
|
779
|
+
}
|
|
780
|
+
const cacheTag = result.cache_hit ? " [cached]" : "";
|
|
781
|
+
console.log(`
|
|
782
|
+
\u2713 ${opts.tool} on ${opts.server}${cacheTag} \u2014 ${result.duration_ms}ms
|
|
783
|
+
`);
|
|
784
|
+
console.log(JSON.stringify(result.result, null, 2));
|
|
785
|
+
console.log();
|
|
786
|
+
}
|
|
787
|
+
);
|
|
788
|
+
}
|
|
789
|
+
|
|
640
790
|
// src/index.ts
|
|
641
791
|
var pkg = require_package();
|
|
642
792
|
var program = new import_commander.Command();
|
|
@@ -648,8 +798,10 @@ registerLogin(program);
|
|
|
648
798
|
registerLogout(program);
|
|
649
799
|
registerStatus(program);
|
|
650
800
|
registerAgentCommands(program);
|
|
801
|
+
registerMcpServersCommands(program);
|
|
651
802
|
registerPermissionsCommands(program);
|
|
652
803
|
registerVaultCommands(program);
|
|
804
|
+
registerTestCall(program);
|
|
653
805
|
program.parseAsync(process.argv).catch((err) => {
|
|
654
806
|
if (err instanceof Error) {
|
|
655
807
|
console.error(err.message);
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@arbiterai/cli",
|
|
3
|
-
"version": "0.1.
|
|
3
|
+
"version": "0.1.1",
|
|
4
4
|
"description": "Official CLI for Arbiter — the developer-first MCP gateway",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"keywords": [
|
|
@@ -25,13 +25,6 @@
|
|
|
25
25
|
"engines": {
|
|
26
26
|
"node": ">=18.0.0"
|
|
27
27
|
},
|
|
28
|
-
"scripts": {
|
|
29
|
-
"build": "tsup",
|
|
30
|
-
"dev": "tsup --watch",
|
|
31
|
-
"lint": "eslint src --max-warnings 0",
|
|
32
|
-
"type-check": "tsc --noEmit",
|
|
33
|
-
"prepublishOnly": "npm run build"
|
|
34
|
-
},
|
|
35
28
|
"dependencies": {
|
|
36
29
|
"axios": "^1.7.7",
|
|
37
30
|
"chalk": "^5.3.0",
|
|
@@ -47,5 +40,11 @@
|
|
|
47
40
|
"tsup": "^8.3.0",
|
|
48
41
|
"typescript": "^5.6.3",
|
|
49
42
|
"typescript-eslint": "^8.57.2"
|
|
43
|
+
},
|
|
44
|
+
"scripts": {
|
|
45
|
+
"build": "tsup",
|
|
46
|
+
"dev": "tsup --watch",
|
|
47
|
+
"lint": "eslint src --max-warnings 0",
|
|
48
|
+
"type-check": "tsc --noEmit"
|
|
50
49
|
}
|
|
51
|
-
}
|
|
50
|
+
}
|