@peac/mcp-server 0.11.3 → 0.12.0-preview.2

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.mjs CHANGED
@@ -1,6 +1,6 @@
1
1
  import { McpServer } from '@modelcontextprotocol/sdk/server/mcp.js';
2
2
  import { ERRORS } from '@peac/kernel';
3
- import { verifyLocal, issue, IssueError } from '@peac/protocol';
3
+ import { verifyLocal, issueWire02, IssueError } from '@peac/protocol';
4
4
  import { base64urlDecode, decode, sha256Hex, sign, validateKeypair, derivePublicKey, base64urlEncode } from '@peac/crypto';
5
5
  import { readFile, mkdir, rename, rm, mkdtemp, writeFile, stat, lstat } from 'fs/promises';
6
6
  import { parseReceiptClaims } from '@peac/schema';
@@ -395,16 +395,15 @@ async function handleVerify(params) {
395
395
  const claims = result.claims;
396
396
  const claimsSummary = {
397
397
  iss: claims.iss,
398
- aud: claims.aud,
399
- rid: claims.rid,
400
- variant: result.variant
398
+ kind: claims.kind,
399
+ type: claims.type,
400
+ jti: claims.jti,
401
+ ...claims.sub !== void 0 && { sub: claims.sub },
402
+ variant: result.variant,
403
+ wireVersion: result.wireVersion
401
404
  };
402
- if (result.variant === "commerce") {
403
- claimsSummary.amt = claims.amt;
404
- claimsSummary.cur = claims.cur;
405
- }
406
405
  const tr = truncateResponse(
407
- `Verification PASSED (${result.variant} receipt, kid=${result.kid})`,
406
+ `Verification PASSED (${result.variant} receipt, kind=${claims.kind ?? "unknown"}, kid=${result.kid})`,
408
407
  policy
409
408
  );
410
409
  return {
@@ -637,49 +636,44 @@ async function handleIssue(params) {
637
636
  isError: true
638
637
  };
639
638
  }
640
- if (input.ttl_seconds !== void 0 && input.ttl_seconds > policy.limits.max_ttl_seconds) {
641
- return {
642
- text: `Input rejected: ttl_seconds ${input.ttl_seconds} exceeds max_ttl_seconds ${policy.limits.max_ttl_seconds}`,
643
- structured: {
644
- ok: false,
645
- code: "E_MCP_INVALID_INPUT",
646
- message: `ttl_seconds ${input.ttl_seconds} exceeds policy max of ${policy.limits.max_ttl_seconds}`
647
- },
648
- isError: true
649
- };
650
- }
651
639
  const keyPatterns = buildKeyPatterns(context.issuerKey.privateKey, context.issuerKey.publicKey);
652
- const now = Math.floor(Date.now() / 1e3);
653
- const exp = input.ttl_seconds !== void 0 ? now + input.ttl_seconds : void 0;
654
640
  try {
655
- const result = await issue({
641
+ if (input.policy && !input.policy.digest) {
642
+ return {
643
+ text: "Issue failed: policy.digest is required when policy block is provided",
644
+ structured: {
645
+ ok: false,
646
+ code: "E_MCP_ISSUE_FAILED",
647
+ message: "policy.digest is required when policy block is provided (uri/version alone is insufficient for binding)"
648
+ },
649
+ isError: true
650
+ };
651
+ }
652
+ const policyBlock = input.policy?.digest ? { digest: input.policy.digest, uri: input.policy.uri, version: input.policy.version } : void 0;
653
+ const result = await issueWire02({
656
654
  iss: context.issuerId,
657
- aud: input.aud,
658
- amt: input.amt,
659
- cur: input.cur,
660
- rail: input.rail,
661
- reference: input.reference,
662
- asset: input.asset,
663
- env: input.env,
664
- network: input.network,
665
- evidence: input.evidence,
666
- subject: input.subject,
667
- exp,
655
+ kind: input.kind,
656
+ type: input.type,
657
+ sub: input.sub,
658
+ pillars: input.pillars,
659
+ occurred_at: input.occurred_at,
660
+ extensions: input.extensions,
661
+ policy: policyBlock,
668
662
  privateKey: context.issuerKey.privateKey,
669
663
  kid: context.issuerKey.kid
670
664
  });
671
665
  const { payload } = decode(result.jws);
672
666
  const claimsSummary = {
673
667
  iss: payload.iss,
674
- aud: payload.aud,
668
+ kind: payload.kind,
669
+ type: payload.type,
675
670
  iat: payload.iat,
676
- ...payload.exp !== void 0 ? { exp: payload.exp } : {},
677
- rid: payload.rid,
678
- amt: payload.amt,
679
- cur: payload.cur
671
+ jti: payload.jti,
672
+ ...payload.sub !== void 0 ? { sub: payload.sub } : {},
673
+ ...payload.pillars !== void 0 ? { pillars: payload.pillars } : {}
680
674
  };
681
675
  const tr = truncateResponse(
682
- `Receipt issued: rid=${claimsSummary.rid}, ${claimsSummary.amt} ${claimsSummary.cur}`,
676
+ `Receipt issued: jti=${claimsSummary.jti}, kind=${claimsSummary.kind}, type=${claimsSummary.type}`,
683
677
  policy
684
678
  );
685
679
  const safeText = sanitizeOutput(tr.text, keyPatterns);
@@ -1119,18 +1113,41 @@ var DecodeOutputSchema = z.object({
1119
1113
  verified: z.literal(false)
1120
1114
  });
1121
1115
  var IssueInputSchema = z.object({
1122
- aud: z.string().url().describe("Audience / resource URI (https://)"),
1123
- amt: z.number().int().nonnegative().describe("Amount in smallest currency unit"),
1124
- cur: z.string().regex(/^[A-Z]{3}$/).describe("ISO 4217 currency code (uppercase, e.g. USD)"),
1125
- rail: z.string().describe("Payment rail identifier"),
1126
- reference: z.string().describe("Unique payment reference"),
1127
- asset: z.string().optional().describe("Asset transferred (e.g. USDC) -- defaults to currency"),
1128
- env: z.enum(["live", "test"]).default("test").describe("Environment"),
1129
- network: z.string().optional().describe("Network/chain identifier"),
1130
- evidence: z.unknown().optional().describe("Rail-specific evidence (JSON-safe)"),
1131
- subject: z.string().url().optional().describe("Subject URI (https://)"),
1132
- ttl_seconds: z.number().int().positive().optional().describe("Time-to-live in seconds (computes exp = iat + ttl)"),
1133
- kind: z.string().optional().describe("Receipt kind for policy filtering")
1116
+ kind: z.enum(["evidence", "challenge"]).describe("Structural kind: evidence (records interaction) or challenge (requests action)"),
1117
+ type: z.string().min(1).max(256).refine(
1118
+ (v) => /^https?:\/\//.test(v) || /^[a-zA-Z0-9][a-zA-Z0-9._-]*\.[a-zA-Z0-9._-]+\/[a-zA-Z0-9]/.test(v),
1119
+ {
1120
+ message: "type must be reverse-DNS (e.g. org.peacprotocol/payment) or absolute URI (https://...)"
1121
+ }
1122
+ ).describe("Semantic type in reverse-DNS or absolute URI form (e.g. org.peacprotocol/payment)"),
1123
+ sub: z.string().max(2048).optional().describe("Subject identifier (resource or interaction target)"),
1124
+ pillars: z.array(
1125
+ z.enum([
1126
+ "access",
1127
+ "attribution",
1128
+ "commerce",
1129
+ "compliance",
1130
+ "consent",
1131
+ "identity",
1132
+ "privacy",
1133
+ "provenance",
1134
+ "purpose",
1135
+ "safety"
1136
+ ])
1137
+ ).optional().refine(
1138
+ (arr) => !arr || new Set(arr).size === arr.length && [...arr].sort().every((v, i) => v === arr[i]),
1139
+ { message: "pillars must be unique and sorted ascending" }
1140
+ ).describe("Evidence pillars from closed 10-value taxonomy (sorted ascending)"),
1141
+ occurred_at: z.string().optional().refine((v) => !v || !isNaN(Date.parse(v)), {
1142
+ message: "occurred_at must be a valid ISO 8601 timestamp"
1143
+ }).describe("ISO 8601 timestamp when interaction occurred (evidence kind only)"),
1144
+ extensions: z.record(z.string(), z.unknown()).optional().describe("Extension groups keyed by reverse-DNS identifier"),
1145
+ policy: z.object({
1146
+ uri: z.string().url().max(2048).refine((v) => v.startsWith("https://"), { message: "policy.uri must use HTTPS" }).describe("Policy document URI (HTTPS only)"),
1147
+ version: z.string().max(256).optional().describe("Policy version"),
1148
+ digest: z.string().regex(/^sha256:[0-9a-f]{64}$/).optional().describe("Policy digest in sha256:<64 hex> format")
1149
+ }).optional().describe("Policy binding block"),
1150
+ ttl_seconds: z.number().int().positive().optional().describe("Reserved for future use (Wire 0.2 receipts do not expire)")
1134
1151
  });
1135
1152
  var MetaSchema4 = z.object({
1136
1153
  serverVersion: z.string(),
@@ -1139,12 +1156,12 @@ var MetaSchema4 = z.object({
1139
1156
  });
1140
1157
  var ClaimsSummarySchema = z.object({
1141
1158
  iss: z.string(),
1142
- aud: z.string(),
1159
+ kind: z.string(),
1160
+ type: z.string(),
1143
1161
  iat: z.number(),
1144
- exp: z.number().optional(),
1145
- rid: z.string(),
1146
- amt: z.number(),
1147
- cur: z.string()
1162
+ jti: z.string(),
1163
+ sub: z.string().optional(),
1164
+ pillars: z.array(z.string()).optional()
1148
1165
  });
1149
1166
  var IssueOutputSchema = z.object({
1150
1167
  _meta: MetaSchema4,
@@ -1180,7 +1197,8 @@ function makeMeta(ctx, serverName) {
1180
1197
  serverName,
1181
1198
  serverVersion: ctx.version,
1182
1199
  policyHash: ctx.policyHash,
1183
- protocolVersion: ctx.protocolVersion
1200
+ protocolVersion: ctx.protocolVersion,
1201
+ wireFormatVersion: "0.2"
1184
1202
  };
1185
1203
  }
1186
1204
  function handlerResultToCallToolResult(result, meta) {
@@ -1372,8 +1390,8 @@ function createPeacMcpServer(options) {
1372
1390
  register(
1373
1391
  "peac_issue",
1374
1392
  {
1375
- title: "Issue PEAC Receipt",
1376
- description: "Sign and return a new PEAC receipt JWS. Requires server configured with an Ed25519 issuer key (--issuer-key and --issuer-id).",
1393
+ title: "Issue Wire 0.2 PEAC Receipt",
1394
+ description: "Sign and return a Wire 0.2 PEAC receipt JWS. Accepts kind, type, pillars, extensions, and policy fields. Wire 0.2 only: Wire 0.1 fields are not accepted. Requires server configured with an Ed25519 issuer key (--issuer-key and --issuer-id).",
1377
1395
  inputSchema: IssueInputSchema,
1378
1396
  outputSchema: IssueOutputSchema,
1379
1397
  annotations: ISSUE_TOOL_ANNOTATIONS