@paybond/kit 0.9.7 → 0.10.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.
Files changed (60) hide show
  1. package/dist/cli/audit-export.d.ts +7 -0
  2. package/dist/cli/audit-export.js +120 -0
  3. package/dist/cli/automation.d.ts +25 -0
  4. package/dist/cli/automation.js +297 -0
  5. package/dist/cli/body.d.ts +7 -0
  6. package/dist/cli/body.js +22 -0
  7. package/dist/cli/color.d.ts +15 -0
  8. package/dist/cli/color.js +39 -0
  9. package/dist/cli/command-spec.d.ts +12 -0
  10. package/dist/cli/command-spec.js +330 -0
  11. package/dist/cli/commands/discovery.d.ts +8 -0
  12. package/dist/cli/commands/discovery.js +194 -0
  13. package/dist/cli/commands/setup.d.ts +15 -0
  14. package/dist/cli/commands/setup.js +397 -0
  15. package/dist/cli/commands/workflows.d.ts +7 -0
  16. package/dist/cli/commands/workflows.js +209 -0
  17. package/dist/cli/config.d.ts +14 -0
  18. package/dist/cli/config.js +96 -0
  19. package/dist/cli/context.d.ts +22 -0
  20. package/dist/cli/context.js +109 -0
  21. package/dist/cli/credentials.d.ts +21 -0
  22. package/dist/cli/credentials.js +141 -0
  23. package/dist/cli/doctor-agent.d.ts +15 -0
  24. package/dist/cli/doctor-agent.js +311 -0
  25. package/dist/cli/envelope.d.ts +14 -0
  26. package/dist/cli/envelope.js +46 -0
  27. package/dist/cli/globals.d.ts +22 -0
  28. package/dist/cli/globals.js +238 -0
  29. package/dist/cli/help.d.ts +3 -0
  30. package/dist/cli/help.js +51 -0
  31. package/dist/cli/mcp-install.d.ts +41 -0
  32. package/dist/cli/mcp-install.js +95 -0
  33. package/dist/cli/mcp-policy.d.ts +23 -0
  34. package/dist/cli/mcp-policy.js +104 -0
  35. package/dist/cli/mcp-verify-config.d.ts +37 -0
  36. package/dist/cli/mcp-verify-config.js +174 -0
  37. package/dist/cli/redact.d.ts +4 -0
  38. package/dist/cli/redact.js +67 -0
  39. package/dist/cli/request-id.d.ts +2 -0
  40. package/dist/cli/request-id.js +5 -0
  41. package/dist/cli/router.d.ts +2 -0
  42. package/dist/cli/router.js +275 -0
  43. package/dist/cli/suggest.d.ts +4 -0
  44. package/dist/cli/suggest.js +58 -0
  45. package/dist/cli/support-diagnostics.d.ts +19 -0
  46. package/dist/cli/support-diagnostics.js +47 -0
  47. package/dist/cli/types.d.ts +72 -0
  48. package/dist/cli/types.js +60 -0
  49. package/dist/cli/ux.d.ts +8 -0
  50. package/dist/cli/ux.js +164 -0
  51. package/dist/cli.d.ts +2 -0
  52. package/dist/cli.js +38 -0
  53. package/dist/index.d.ts +46 -12
  54. package/dist/index.js +136 -47
  55. package/dist/init.js +9 -14
  56. package/dist/login.d.ts +14 -1
  57. package/dist/login.js +123 -63
  58. package/dist/mcp-server.d.ts +4 -0
  59. package/dist/mcp-server.js +204 -76
  60. package/package.json +5 -2
@@ -1,9 +1,14 @@
1
1
  #!/usr/bin/env node
2
- // @ts-ignore Node builtins are available in the published CLI runtime.
2
+ import { Buffer } from "node:buffer";
3
3
  import { readFileSync } from "node:fs";
4
+ import fs from "node:fs/promises";
5
+ import path from "node:path";
6
+ import { fileURLToPath, pathToFileURL } from "node:url";
7
+ import { runCli } from "./cli/router.js";
8
+ import { MCP_TOOL_ALLOWLIST_ENV, MCP_TOOL_POLICY_ENV, mergeMcpToolPolicy, parseMcpToolAllowlist, parseMcpToolPolicy, toolAllowedByPolicy, } from "./cli/mcp-policy.js";
4
9
  import { GatewayAuthError, GatewayFraudClient, GatewaySignalClient, SignalHttpError, DEFAULT_PAYBOND_GATEWAY_BASE_URL, } from "./index.js";
5
10
  const SERVER_NAME = "Paybond MCP";
6
- const SERVER_VERSION = "0.9.7";
11
+ const SERVER_VERSION = "0.10.0";
7
12
  const MCP_PROTOCOL_VERSION = "2025-11-25";
8
13
  const DEFAULT_PRINCIPAL_PATH = "/v1/auth/principal";
9
14
  const DEFAULT_RECOGNITION_VERIFIER_ID = "paybond-gateway";
@@ -14,7 +19,10 @@ const TOOL_SELECTION_METADATA = {
14
19
  title: "Get Paybond Principal",
15
20
  annotations: readOnlyToolAnnotations("Get Paybond Principal"),
16
21
  outputSchema: outputObjectSchema({
17
- tenant_id: { type: "string", description: "Tenant bound to the configured Paybond API key." },
22
+ tenant_id: {
23
+ type: "string",
24
+ description: "Tenant bound to the configured Paybond API key.",
25
+ },
18
26
  subject: { type: "string" },
19
27
  roles: { type: "array", items: { type: "string" } },
20
28
  }),
@@ -25,10 +33,22 @@ const TOOL_SELECTION_METADATA = {
25
33
  "Do not use this to create, fund, or modify intents; use paybond_authorize_agent_spend as the clearer gate before side-effecting agent tools.",
26
34
  annotations: additiveMutationToolAnnotations("Verify Paybond Capability"),
27
35
  outputSchema: outputObjectSchema({
28
- allow: { type: "boolean", description: "Whether the requested operation is allowed." },
29
- tenant: { type: "string", description: "Tenant echoed by the gateway." },
30
- intent_id: { type: "string", description: "Verified Harbor intent UUID." },
31
- audit_id: { type: "string", description: "Gateway audit identifier when available." },
36
+ allow: {
37
+ type: "boolean",
38
+ description: "Whether the requested operation is allowed.",
39
+ },
40
+ tenant: {
41
+ type: "string",
42
+ description: "Tenant echoed by the gateway.",
43
+ },
44
+ intent_id: {
45
+ type: "string",
46
+ description: "Verified Harbor intent UUID.",
47
+ },
48
+ audit_id: {
49
+ type: "string",
50
+ description: "Gateway audit identifier when available.",
51
+ },
32
52
  }, ["tenant", "intent_id"]),
33
53
  },
34
54
  paybond_authorize_agent_spend: {
@@ -37,10 +57,22 @@ const TOOL_SELECTION_METADATA = {
37
57
  "Do not use this for creating, funding, or changing intents; call paybond_create_spend_intent or paybond_fund_intent first when no funded capability token exists.",
38
58
  annotations: additiveMutationToolAnnotations("Authorize Agent Spend"),
39
59
  outputSchema: outputObjectSchema({
40
- allow: { type: "boolean", description: "Whether the requested operation is allowed." },
41
- tenant: { type: "string", description: "Tenant echoed by the gateway." },
42
- intent_id: { type: "string", description: "Verified Harbor intent UUID." },
43
- audit_id: { type: "string", description: "Gateway audit identifier when available." },
60
+ allow: {
61
+ type: "boolean",
62
+ description: "Whether the requested operation is allowed.",
63
+ },
64
+ tenant: {
65
+ type: "string",
66
+ description: "Tenant echoed by the gateway.",
67
+ },
68
+ intent_id: {
69
+ type: "string",
70
+ description: "Verified Harbor intent UUID.",
71
+ },
72
+ audit_id: {
73
+ type: "string",
74
+ description: "Gateway audit identifier when available.",
75
+ },
44
76
  }, ["tenant", "intent_id"]),
45
77
  },
46
78
  paybond_bootstrap_sandbox_guardrail: {
@@ -57,7 +89,14 @@ const TOOL_SELECTION_METADATA = {
57
89
  sandbox_lifecycle_status: { type: "string" },
58
90
  settlement_rail: { type: "string" },
59
91
  settlement_mode: { type: "string" },
60
- }, ["tenant_id", "intent_id", "capability_token", "operation", "requested_spend_cents", "sandbox_lifecycle_status"]),
92
+ }, [
93
+ "tenant_id",
94
+ "intent_id",
95
+ "capability_token",
96
+ "operation",
97
+ "requested_spend_cents",
98
+ "sandbox_lifecycle_status",
99
+ ]),
61
100
  },
62
101
  paybond_submit_sandbox_guardrail_evidence: {
63
102
  title: "Submit Sandbox Guardrail Evidence",
@@ -72,13 +111,22 @@ const TOOL_SELECTION_METADATA = {
72
111
  sandbox_lifecycle_status: { type: "string" },
73
112
  predicate_passed: { type: "boolean" },
74
113
  payload_digest: { type: "string" },
75
- }, ["tenant_id", "intent_id", "operation", "requested_spend_cents", "sandbox_lifecycle_status"]),
114
+ }, [
115
+ "tenant_id",
116
+ "intent_id",
117
+ "operation",
118
+ "requested_spend_cents",
119
+ "sandbox_lifecycle_status",
120
+ ]),
76
121
  },
77
122
  paybond_list_intents: {
78
123
  title: "List Harbor Intents",
79
124
  annotations: readOnlyToolAnnotations("List Harbor Intents"),
80
125
  outputSchema: outputObjectSchema({
81
- items: { type: "array", items: { type: "object", additionalProperties: true } },
126
+ items: {
127
+ type: "array",
128
+ items: { type: "object", additionalProperties: true },
129
+ },
82
130
  next_cursor: { type: "string" },
83
131
  }),
84
132
  },
@@ -106,7 +154,10 @@ const TOOL_SELECTION_METADATA = {
106
154
  outputSchema: outputObjectSchema({
107
155
  tenant_id: { type: "string" },
108
156
  score_model_version: { type: "string" },
109
- operators: { type: "array", items: { type: "object", additionalProperties: true } },
157
+ operators: {
158
+ type: "array",
159
+ items: { type: "object", additionalProperties: true },
160
+ },
110
161
  }),
111
162
  },
112
163
  paybond_get_signed_portfolio_artifact: {
@@ -144,14 +195,20 @@ const TOOL_SELECTION_METADATA = {
144
195
  outputSchema: outputObjectSchema({
145
196
  name: { type: "string" },
146
197
  version: { type: "string" },
147
- skills: { type: "array", items: { type: "object", additionalProperties: true } },
198
+ skills: {
199
+ type: "array",
200
+ items: { type: "object", additionalProperties: true },
201
+ },
148
202
  }),
149
203
  },
150
204
  paybond_list_a2a_task_contracts: {
151
205
  title: "List A2A Task Contracts",
152
206
  annotations: readOnlyToolAnnotations("List A2A Task Contracts"),
153
207
  outputSchema: outputObjectSchema({
154
- contracts: { type: "array", items: { type: "object", additionalProperties: true } },
208
+ contracts: {
209
+ type: "array",
210
+ items: { type: "object", additionalProperties: true },
211
+ },
155
212
  }),
156
213
  },
157
214
  paybond_get_a2a_task_contract: {
@@ -327,8 +384,12 @@ function parseGatewayErrorEnvelope(text) {
327
384
  if (body === null || Array.isArray(body) || typeof body !== "object") {
328
385
  return {};
329
386
  }
330
- const errorCode = typeof body.error === "string" && body.error.trim() ? body.error.trim() : undefined;
331
- const errorMessage = typeof body.message === "string" && body.message.trim() ? body.message.trim() : undefined;
387
+ const errorCode = typeof body.error === "string" && body.error.trim()
388
+ ? body.error.trim()
389
+ : undefined;
390
+ const errorMessage = typeof body.message === "string" && body.message.trim()
391
+ ? body.message.trim()
392
+ : undefined;
332
393
  return { errorCode, errorMessage };
333
394
  }
334
395
  catch {
@@ -369,7 +430,9 @@ class GatewayAPIClient {
369
430
  accept: "application/json",
370
431
  authorization: `Bearer ${this.apiKey}`,
371
432
  ...(extraHeaders ?? {}),
372
- ...(payload === undefined ? {} : { "content-type": "application/json" }),
433
+ ...(payload === undefined
434
+ ? {}
435
+ : { "content-type": "application/json" }),
373
436
  },
374
437
  ...(payload === undefined ? {} : { body: JSON.stringify(payload) }),
375
438
  });
@@ -382,7 +445,8 @@ class GatewayAPIClient {
382
445
  await delay(backoffMs(attempt));
383
446
  continue;
384
447
  }
385
- if ([429, 500, 502, 503, 504].includes(res.status) && attempt + 1 < this.maxRetries) {
448
+ if ([429, 500, 502, 503, 504].includes(res.status) &&
449
+ attempt + 1 < this.maxRetries) {
386
450
  const retryAfter = parseRetryAfterSeconds(res.headers.get("retry-after"));
387
451
  await delay(retryAfter != null ? retryAfter * 1000 : backoffMs(attempt));
388
452
  continue;
@@ -620,7 +684,9 @@ class PaybondMCPRuntime {
620
684
  async fundHarborIntent(init) {
621
685
  return this.gateway.postJSON(`/harbor/intents/${encodeURIComponent(init.intentId)}/fund`, {}, gatewayMutationHeaders(await this.tenantId(), init.recognitionProof, {
622
686
  ...optionalMutationHeaders(init.idempotencyKey),
623
- ...(init.paymentSignature?.trim() ? { "payment-signature": init.paymentSignature.trim() } : {}),
687
+ ...(init.paymentSignature?.trim()
688
+ ? { "payment-signature": init.paymentSignature.trim() }
689
+ : {}),
624
690
  }));
625
691
  }
626
692
  async submitHarborEvidence(init) {
@@ -643,16 +709,22 @@ function gatewayMutationHeaders(tenantId, recognitionProof, extraHeaders) {
643
709
  [agentRecognitionProofHeader]: encodeRecognitionProofHeader(recognitionProof),
644
710
  };
645
711
  }
712
+ export function formatMcpStdioFrame(response) {
713
+ const body = JSON.stringify(response);
714
+ return `Content-Length: ${Buffer.byteLength(body, "utf8")}\r\n\r\n${body}`;
715
+ }
646
716
  export class PaybondMCPServer {
647
717
  runtime;
648
718
  tools;
719
+ toolPolicy;
649
720
  initialized = false;
650
721
  constructor(settings) {
651
722
  if (!settings.apiKey.trim()) {
652
723
  throw new Error("PAYBOND_API_KEY is required");
653
724
  }
725
+ this.toolPolicy = settings.toolPolicy ?? { policy: null, allowlist: [] };
654
726
  this.runtime = new PaybondMCPRuntime(settings);
655
- this.tools = this.buildTools(settings);
727
+ this.tools = this.buildTools(settings).filter((tool) => toolAllowedByPolicy(tool.name, tool.annotations, this.toolPolicy));
656
728
  }
657
729
  listTools() {
658
730
  return this.tools.map((tool) => ({
@@ -660,8 +732,12 @@ export class PaybondMCPServer {
660
732
  title: tool.title,
661
733
  description: tool.description,
662
734
  inputSchema: tool.inputSchema,
663
- ...(tool.outputSchema === undefined ? {} : { outputSchema: tool.outputSchema }),
664
- ...(tool.annotations === undefined ? {} : { annotations: tool.annotations }),
735
+ ...(tool.outputSchema === undefined
736
+ ? {}
737
+ : { outputSchema: tool.outputSchema }),
738
+ ...(tool.annotations === undefined
739
+ ? {}
740
+ : { annotations: tool.annotations }),
665
741
  }));
666
742
  }
667
743
  async callTool(name, args = {}) {
@@ -672,6 +748,17 @@ export class PaybondMCPServer {
672
748
  isError: true,
673
749
  };
674
750
  }
751
+ if (!toolAllowedByPolicy(name, tool.annotations, this.toolPolicy)) {
752
+ return {
753
+ content: [
754
+ {
755
+ type: "text",
756
+ text: `Tool blocked by ${MCP_TOOL_POLICY_ENV}=${this.toolPolicy.policy ?? "unset"}: ${name}`,
757
+ },
758
+ ],
759
+ isError: true,
760
+ };
761
+ }
675
762
  try {
676
763
  const value = await tool.call(args);
677
764
  return toToolResult(value);
@@ -740,7 +827,9 @@ export class PaybondMCPServer {
740
827
  case "tools/call": {
741
828
  const params = ensureObject(message.params, "tools/call params");
742
829
  const name = stringArg(params.name, "name");
743
- const args = params.arguments === undefined ? {} : ensureObject(params.arguments, "arguments");
830
+ const args = params.arguments === undefined
831
+ ? {}
832
+ : ensureObject(params.arguments, "arguments");
744
833
  return {
745
834
  jsonrpc: "2.0",
746
835
  id: message.id,
@@ -752,26 +841,36 @@ export class PaybondMCPServer {
752
841
  }
753
842
  }
754
843
  runStdio() {
755
- let buffer = "";
756
- process.stdin.setEncoding("utf8");
844
+ let buffer = Buffer.alloc(0);
757
845
  process.stdin.on("data", (chunk) => {
758
- buffer += chunk;
846
+ buffer = Buffer.concat([buffer, Buffer.isBuffer(chunk) ? chunk : Buffer.from(chunk, "utf8")]);
759
847
  while (true) {
760
- const newlineIndex = buffer.indexOf("\n");
761
- if (newlineIndex < 0) {
848
+ const headerEnd = buffer.indexOf("\r\n\r\n");
849
+ if (headerEnd < 0) {
762
850
  break;
763
851
  }
764
- const line = buffer.slice(0, newlineIndex).trim();
765
- buffer = buffer.slice(newlineIndex + 1);
766
- if (!line) {
767
- continue;
852
+ const headerText = buffer.subarray(0, headerEnd).toString("ascii");
853
+ const contentLength = Number.parseInt(headerText
854
+ .split("\r\n")
855
+ .find((line) => line.toLowerCase().startsWith("content-length:"))
856
+ ?.split(":", 2)[1]
857
+ ?.trim() ?? "", 10);
858
+ if (!Number.isFinite(contentLength) || contentLength <= 0) {
859
+ break;
768
860
  }
769
- void this.handleLine(line);
861
+ const bodyStart = headerEnd + 4;
862
+ const frameEnd = bodyStart + contentLength;
863
+ if (buffer.length < frameEnd) {
864
+ break;
865
+ }
866
+ const body = buffer.subarray(bodyStart, frameEnd).toString("utf8");
867
+ buffer = buffer.subarray(frameEnd);
868
+ void this.handleLine(body);
770
869
  }
771
870
  });
772
871
  process.stdin.on("end", () => {
773
- if (buffer.trim()) {
774
- void this.handleLine(buffer.trim());
872
+ if (buffer.length > 0) {
873
+ void this.handleLine(buffer.toString("utf8"));
775
874
  }
776
875
  });
777
876
  process.stdin.resume();
@@ -791,7 +890,7 @@ export class PaybondMCPServer {
791
890
  }
792
891
  }
793
892
  writeResponse(response) {
794
- process.stdout.write(`${JSON.stringify(response)}\n`);
893
+ process.stdout.write(formatMcpStdioFrame(response));
795
894
  }
796
895
  buildTools(settings) {
797
896
  const tools = [
@@ -805,12 +904,18 @@ export class PaybondMCPServer {
805
904
  name: "paybond_verify_capability",
806
905
  description: "Verify a capability token returned by a created or funded Paybond intent for one tenant-bound Harbor intent.",
807
906
  inputSchema: objectSchema({
808
- intent_id: { type: "string", description: "Canonical Harbor intent UUID." },
907
+ intent_id: {
908
+ type: "string",
909
+ description: "Canonical Harbor intent UUID.",
910
+ },
809
911
  token: {
810
912
  type: "string",
811
913
  description: "Capability token returned by paybond_create_spend_intent or paybond_fund_intent.",
812
914
  },
813
- operation: { type: "string", description: "Delegated operation or tool name." },
915
+ operation: {
916
+ type: "string",
917
+ description: "Delegated operation or tool name.",
918
+ },
814
919
  requested_spend_cents: {
815
920
  type: "integer",
816
921
  description: "Optional requested spend in cents for this tool call.",
@@ -829,12 +934,18 @@ export class PaybondMCPServer {
829
934
  name: "paybond_authorize_agent_spend",
830
935
  description: "Provider-agnostic spend gate: verify the funded intent's capability token before a side-effecting tool, paid API, vendor action, or settlement workflow executes.",
831
936
  inputSchema: objectSchema({
832
- intent_id: { type: "string", description: "Canonical Harbor intent UUID." },
937
+ intent_id: {
938
+ type: "string",
939
+ description: "Canonical Harbor intent UUID.",
940
+ },
833
941
  token: {
834
942
  type: "string",
835
943
  description: "Capability token returned by paybond_create_spend_intent or paybond_fund_intent.",
836
944
  },
837
- operation: { type: "string", description: "Delegated operation or tool name." },
945
+ operation: {
946
+ type: "string",
947
+ description: "Delegated operation or tool name.",
948
+ },
838
949
  requested_spend_cents: {
839
950
  type: "integer",
840
951
  description: "Optional requested spend in cents for this tool call.",
@@ -853,12 +964,18 @@ export class PaybondMCPServer {
853
964
  name: "paybond_bootstrap_sandbox_guardrail",
854
965
  description: "Bootstrap a sandbox-only Paybond guardrail intent for a first paid-tool integration. Tenant scope is derived from the configured service-account API key and the route never touches live settlement rails.",
855
966
  inputSchema: objectSchema({
856
- operation: { type: "string", description: "Delegated operation or paid tool name." },
967
+ operation: {
968
+ type: "string",
969
+ description: "Delegated operation or paid tool name.",
970
+ },
857
971
  requested_spend_cents: {
858
972
  type: "integer",
859
973
  description: "Sandbox spend amount in cents to authorize for the sample tool call.",
860
974
  },
861
- currency: { type: "string", description: "Optional ISO currency code; defaults at the gateway." },
975
+ currency: {
976
+ type: "string",
977
+ description: "Optional ISO currency code; defaults at the gateway.",
978
+ },
862
979
  evidence_schema: { type: "object", additionalProperties: true },
863
980
  metadata: { type: "object", additionalProperties: true },
864
981
  idempotency_key: { type: "string" },
@@ -867,8 +984,12 @@ export class PaybondMCPServer {
867
984
  operation: stringArg(args.operation, "operation"),
868
985
  requestedSpendCents: intArg(args.requested_spend_cents, "requested_spend_cents"),
869
986
  currency: optionalString(args.currency),
870
- evidenceSchema: args.evidence_schema === undefined ? undefined : ensureObject(args.evidence_schema, "evidence_schema"),
871
- metadata: args.metadata === undefined ? undefined : ensureObject(args.metadata, "metadata"),
987
+ evidenceSchema: args.evidence_schema === undefined
988
+ ? undefined
989
+ : ensureObject(args.evidence_schema, "evidence_schema"),
990
+ metadata: args.metadata === undefined
991
+ ? undefined
992
+ : ensureObject(args.metadata, "metadata"),
872
993
  idempotencyKey: optionalString(args.idempotency_key),
873
994
  }),
874
995
  },
@@ -876,10 +997,16 @@ export class PaybondMCPServer {
876
997
  name: "paybond_submit_sandbox_guardrail_evidence",
877
998
  description: "Submit evidence for a sandbox-only Paybond guardrail intent. Tenant scope is derived from the configured service-account API key and simulator settlement remains sandbox-only.",
878
999
  inputSchema: objectSchema({
879
- intent_id: { type: "string", description: "Sandbox guardrail intent UUID." },
1000
+ intent_id: {
1001
+ type: "string",
1002
+ description: "Sandbox guardrail intent UUID.",
1003
+ },
880
1004
  payload: { type: "object", additionalProperties: true },
881
1005
  artifacts: { type: "array", items: { type: "string" } },
882
- operation: { type: "string", description: "Optional operation override for the evidence record." },
1006
+ operation: {
1007
+ type: "string",
1008
+ description: "Optional operation override for the evidence record.",
1009
+ },
883
1010
  requested_spend_cents: {
884
1011
  type: "integer",
885
1012
  description: "Optional sandbox spend amount override for the evidence record.",
@@ -889,13 +1016,19 @@ export class PaybondMCPServer {
889
1016
  }, ["intent_id"]),
890
1017
  call: async (args) => this.runtime.submitSandboxGuardrailEvidence({
891
1018
  intentId: uuidArg(args.intent_id, "intent_id"),
892
- payload: args.payload === undefined ? undefined : ensureObject(args.payload, "payload"),
893
- artifacts: args.artifacts === undefined ? undefined : stringArrayArg(args.artifacts, "artifacts"),
1019
+ payload: args.payload === undefined
1020
+ ? undefined
1021
+ : ensureObject(args.payload, "payload"),
1022
+ artifacts: args.artifacts === undefined
1023
+ ? undefined
1024
+ : stringArrayArg(args.artifacts, "artifacts"),
894
1025
  operation: optionalString(args.operation),
895
1026
  requestedSpendCents: args.requested_spend_cents === undefined
896
1027
  ? undefined
897
1028
  : intArg(args.requested_spend_cents, "requested_spend_cents"),
898
- metadata: args.metadata === undefined ? undefined : ensureObject(args.metadata, "metadata"),
1029
+ metadata: args.metadata === undefined
1030
+ ? undefined
1031
+ : ensureObject(args.metadata, "metadata"),
899
1032
  idempotencyKey: optionalString(args.idempotency_key),
900
1033
  }),
901
1034
  },
@@ -919,7 +1052,10 @@ export class PaybondMCPServer {
919
1052
  name: "paybond_get_intent",
920
1053
  description: "Fetch one tenant-scoped Harbor intent detail through the gateway operator view.",
921
1054
  inputSchema: objectSchema({
922
- intent_id: { type: "string", description: "Canonical Harbor intent UUID." },
1055
+ intent_id: {
1056
+ type: "string",
1057
+ description: "Canonical Harbor intent UUID.",
1058
+ },
923
1059
  }, ["intent_id"]),
924
1060
  call: async (args) => this.runtime.getIntent(uuidArg(args.intent_id, "intent_id")),
925
1061
  },
@@ -1160,6 +1296,7 @@ export function settingsFromEnv(env = process.env) {
1160
1296
  maxRetries: optionalEnv(env.PAYBOND_MCP_MAX_RETRIES)
1161
1297
  ? intArg(optionalEnv(env.PAYBOND_MCP_MAX_RETRIES), "PAYBOND_MCP_MAX_RETRIES")
1162
1298
  : 3,
1299
+ toolPolicy: mergeMcpToolPolicy(parseMcpToolPolicy(optionalEnv(env[MCP_TOOL_POLICY_ENV])), parseMcpToolAllowlist(optionalEnv(env[MCP_TOOL_ALLOWLIST_ENV]))),
1163
1300
  };
1164
1301
  }
1165
1302
  export function main(argv = process.argv.slice(2)) {
@@ -1314,18 +1451,6 @@ function toToolResult(value) {
1314
1451
  structuredContent: value,
1315
1452
  };
1316
1453
  }
1317
- function jsonObjectFromValue(value) {
1318
- if (value === null) {
1319
- return {};
1320
- }
1321
- if (Array.isArray(value)) {
1322
- return { items: value };
1323
- }
1324
- if (typeof value !== "object") {
1325
- return { value };
1326
- }
1327
- return JSON.parse(JSON.stringify(value));
1328
- }
1329
1454
  function responseError(id, code, message) {
1330
1455
  return {
1331
1456
  jsonrpc: "2.0",
@@ -1365,19 +1490,15 @@ function formatError(err) {
1365
1490
  return String(err);
1366
1491
  }
1367
1492
  function normalizeFileURL(url) {
1368
- return url.startsWith("file:///var/") ? url.replace("file:///var/", "file:///private/var/") : url;
1493
+ return url.startsWith("file:///var/")
1494
+ ? url.replace("file:///var/", "file:///private/var/")
1495
+ : url;
1369
1496
  }
1370
1497
  async function invokedFromCLI() {
1371
1498
  const scriptPath = process.argv[1];
1372
1499
  if (!scriptPath) {
1373
1500
  return false;
1374
1501
  }
1375
- // @ts-ignore Node builtins are available in the published CLI runtime.
1376
- const fs = (await import("node:fs/promises"));
1377
- // @ts-ignore Node builtins are available in the published CLI runtime.
1378
- const path = (await import("node:path"));
1379
- // @ts-ignore Node builtins are available in the published CLI runtime.
1380
- const url = (await import("node:url"));
1381
1502
  async function realFileURL(filePath) {
1382
1503
  let resolved = path.resolve(filePath);
1383
1504
  try {
@@ -1387,14 +1508,21 @@ async function invokedFromCLI() {
1387
1508
  // If realpath fails, compare the absolute path. This keeps direct execution
1388
1509
  // working even when the script path disappears during process startup.
1389
1510
  }
1390
- return normalizeFileURL(url.pathToFileURL(resolved).href);
1511
+ return normalizeFileURL(pathToFileURL(resolved).href);
1391
1512
  }
1392
- return (await realFileURL(scriptPath)) === (await realFileURL(url.fileURLToPath(import.meta.url)));
1513
+ return ((await realFileURL(scriptPath)) ===
1514
+ (await realFileURL(fileURLToPath(import.meta.url))));
1393
1515
  }
1394
1516
  invokedFromCLI().then((invoked) => {
1395
- if (invoked && main() !== 0) {
1396
- process.exitCode = 1;
1517
+ if (!invoked) {
1518
+ return;
1397
1519
  }
1520
+ runCli(["mcp", "serve", ...process.argv.slice(2)]).then((code) => {
1521
+ process.exitCode = code;
1522
+ }, (err) => {
1523
+ process.stderr.write(`${formatError(err)}\n`);
1524
+ process.exitCode = 1;
1525
+ });
1398
1526
  }, (err) => {
1399
1527
  process.stderr.write(`${formatError(err)}\n`);
1400
1528
  process.exitCode = 1;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@paybond/kit",
3
- "version": "0.9.7",
3
+ "version": "0.10.0",
4
4
  "mcpName": "io.github.nonameuserd/paybond",
5
5
  "description": "Paybond Kit for TypeScript: agent spend governance for paid tool calls with spend authorization, evidence receipts, refunds, disputes, hosted Gateway sessions, and settlement.",
6
6
  "license": "Apache-2.0",
@@ -8,7 +8,8 @@
8
8
  "main": "dist/index.js",
9
9
  "types": "dist/index.d.ts",
10
10
  "bin": {
11
- "paybond": "dist/login.js",
11
+ "paybond": "dist/cli.js",
12
+ "paybond-kit-login": "dist/login.js",
12
13
  "paybond-init": "dist/init.js",
13
14
  "paybond-mcp-server": "dist/mcp-server.js"
14
15
  },
@@ -77,6 +78,7 @@
77
78
  "scripts": {
78
79
  "clean": "node ./scripts/clean-dist.mjs",
79
80
  "build": "npm run clean && tsc -p tsconfig.json",
81
+ "generate:cli-contract": "node ../cli-parity/generate.mjs",
80
82
  "test": "vitest run",
81
83
  "pack:dry-run": "npm pack --dry-run",
82
84
  "verify:release": "node ./scripts/verify-release.mjs",
@@ -88,6 +90,7 @@
88
90
  "uuid": "^14.0.0"
89
91
  },
90
92
  "devDependencies": {
93
+ "@types/node": "^22.10.0",
91
94
  "typescript": "^5.7.2",
92
95
  "vitest": "^4.1.8"
93
96
  }