@peac/mappings-mcp 0.11.1 → 0.11.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.cjs CHANGED
@@ -71,6 +71,7 @@ var META_KEY_RECEIPT_REF = "org.peacprotocol/receipt_ref";
71
71
  var META_KEY_RECEIPT_JWS = "org.peacprotocol/receipt_jws";
72
72
  var META_KEY_AGENT_ID = "org.peacprotocol/agent_id";
73
73
  var META_KEY_VERIFIED_AT = "org.peacprotocol/verified_at";
74
+ var META_KEY_RECEIPT_URL = "org.peacprotocol/receipt_url";
74
75
  var META_KEY_LEGACY_RECEIPT = "org.peacprotocol/receipt";
75
76
  var MCP_MAX_CARRIER_SIZE = schema.CARRIER_TRANSPORT_LIMITS.mcp;
76
77
  function attachReceiptToMeta(result, carrier, opts) {
@@ -95,6 +96,9 @@ function attachReceiptToMeta(result, carrier, opts) {
95
96
  if (carrier.receipt_jws) {
96
97
  result._meta[META_KEY_RECEIPT_JWS] = carrier.receipt_jws;
97
98
  }
99
+ if (carrier.receipt_url) {
100
+ result._meta[META_KEY_RECEIPT_URL] = carrier.receipt_url;
101
+ }
98
102
  }
99
103
  if (opts?.agentId) {
100
104
  result._meta[META_KEY_AGENT_ID] = opts.agentId;
@@ -118,6 +122,10 @@ function extractReceiptFromMeta(result) {
118
122
  if (typeof receiptJws === "string") {
119
123
  carrier.receipt_jws = receiptJws;
120
124
  }
125
+ const receiptUrl = result._meta[META_KEY_RECEIPT_URL];
126
+ if (typeof receiptUrl === "string") {
127
+ carrier.receipt_url = receiptUrl;
128
+ }
121
129
  const parsed = schema.PeacEvidenceCarrierSchema.safeParse(carrier);
122
130
  if (parsed.success) {
123
131
  return { receipts: [parsed.data], meta };
@@ -151,6 +159,10 @@ async function extractReceiptFromMetaAsync(result) {
151
159
  if (typeof receiptJws === "string") {
152
160
  carrier.receipt_jws = receiptJws;
153
161
  }
162
+ const receiptUrl = result._meta[META_KEY_RECEIPT_URL];
163
+ if (typeof receiptUrl === "string") {
164
+ carrier.receipt_url = receiptUrl;
165
+ }
154
166
  const parsed = schema.PeacEvidenceCarrierSchema.safeParse(carrier);
155
167
  if (parsed.success) {
156
168
  const validCarrier = parsed.data;
@@ -253,6 +265,7 @@ exports.META_KEY_AGENT_ID = META_KEY_AGENT_ID;
253
265
  exports.META_KEY_LEGACY_RECEIPT = META_KEY_LEGACY_RECEIPT;
254
266
  exports.META_KEY_RECEIPT_JWS = META_KEY_RECEIPT_JWS;
255
267
  exports.META_KEY_RECEIPT_REF = META_KEY_RECEIPT_REF;
268
+ exports.META_KEY_RECEIPT_URL = META_KEY_RECEIPT_URL;
256
269
  exports.META_KEY_VERIFIED_AT = META_KEY_VERIFIED_AT;
257
270
  exports.McpCarrierAdapter = McpCarrierAdapter;
258
271
  exports.assertNotMcpReservedKey = assertNotMcpReservedKey;
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/budget.ts","../src/meta.ts","../src/guard.ts","../src/index.ts"],"names":["CARRIER_TRANSPORT_LIMITS","validateCarrierConstraints","PeacEvidenceCarrierSchema","verifyReceiptRefConsistency","computeReceiptRef"],"mappings":"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","file":"index.cjs","sourcesContent":["/**\n * Budget enforcement utilities for MCP tool calls\n * Uses bigint for all currency calculations to avoid floating-point errors\n */\n\nexport interface BudgetConfig {\n /** Maximum cost per single call in minor currency units (e.g., cents for USD) */\n maxPerCallMinor?: bigint;\n /** Maximum total cost per day in minor currency units */\n maxDailyMinor?: bigint;\n /** Maximum total cost per month in minor currency units */\n maxMonthlyMinor?: bigint;\n /** Currency code (must match at runtime, e.g., 'USD', 'INR') */\n currency: string;\n}\n\nexport interface BudgetResult {\n /** Whether the cost is allowed within budget limits */\n allowed: boolean;\n /**\n * Remaining budget in minor units (after this operation).\n * - When allowed: the minimum remaining across all applicable limits\n * - When denied: 0n (never negative)\n * - When unbounded: undefined (check `unbounded` flag instead)\n */\n remainingMinor?: bigint;\n /**\n * True when no budget limits are configured.\n * In this case, remainingMinor is undefined.\n */\n unbounded?: boolean;\n /** Error code if not allowed */\n code?: 'budget_exceeded' | 'currency_mismatch';\n /** Human-readable reason if not allowed */\n reason?: string;\n}\n\n/**\n * Check if a cost is within budget.\n * Pure, deterministic function - caller tracks time windows externally.\n *\n * @param spentMinor - Amount already spent in minor units (e.g., cents)\n * @param costMinor - Cost of current operation in minor units\n * @param currency - Currency code (must match config.currency)\n * @param config - Budget configuration\n * @returns Result indicating whether cost is allowed and remaining budget\n *\n * @example\n * ```typescript\n * const config: BudgetConfig = {\n * maxPerCallMinor: 500n, // $5.00 max per call\n * maxDailyMinor: 10000n, // $100.00 max per day\n * currency: 'USD'\n * };\n *\n * const result = checkBudget(\n * 8500n, // Already spent $85.00 today\n * 1000n, // Current call costs $10.00\n * 'USD',\n * config\n * );\n *\n * if (result.allowed) {\n * console.log(`Allowed. Remaining: ${result.remainingMinor} cents`);\n * } else {\n * console.log(`Denied: ${result.reason}`);\n * }\n * ```\n */\nexport function checkBudget(\n spentMinor: bigint,\n costMinor: bigint,\n currency: string,\n config: BudgetConfig\n): BudgetResult {\n // Currency mismatch check\n if (currency !== config.currency) {\n return {\n allowed: false,\n remainingMinor: 0n,\n code: 'currency_mismatch',\n reason: `Currency mismatch: expected ${config.currency}, got ${currency}`,\n };\n }\n\n // Check per-call limit\n if (config.maxPerCallMinor !== undefined && costMinor > config.maxPerCallMinor) {\n return {\n allowed: false,\n remainingMinor: 0n, // Never negative - clamp to 0\n code: 'budget_exceeded',\n reason: `Per-call limit exceeded: cost ${costMinor} > limit ${config.maxPerCallMinor}`,\n };\n }\n\n // Check daily limit (if configured)\n if (config.maxDailyMinor !== undefined) {\n const newTotal = spentMinor + costMinor;\n if (newTotal > config.maxDailyMinor) {\n return {\n allowed: false,\n remainingMinor: config.maxDailyMinor - spentMinor,\n code: 'budget_exceeded',\n reason: `Daily limit exceeded: total ${newTotal} > limit ${config.maxDailyMinor}`,\n };\n }\n }\n\n // Check monthly limit (if configured)\n if (config.maxMonthlyMinor !== undefined) {\n const newTotal = spentMinor + costMinor;\n if (newTotal > config.maxMonthlyMinor) {\n return {\n allowed: false,\n remainingMinor: config.maxMonthlyMinor - spentMinor,\n code: 'budget_exceeded',\n reason: `Monthly limit exceeded: total ${newTotal} > limit ${config.maxMonthlyMinor}`,\n };\n }\n }\n\n // Calculate remaining budget (how much can be spent in future operations)\n // This is the minimum of:\n // 1. Per-call limit (max single operation)\n // 2. Remaining daily budget\n // 3. Remaining monthly budget\n const remainingCandidates: bigint[] = [];\n\n if (config.maxPerCallMinor !== undefined) {\n remainingCandidates.push(config.maxPerCallMinor);\n }\n\n if (config.maxDailyMinor !== undefined) {\n const dailyRemaining = config.maxDailyMinor - (spentMinor + costMinor);\n remainingCandidates.push(dailyRemaining);\n }\n\n if (config.maxMonthlyMinor !== undefined) {\n const monthlyRemaining = config.maxMonthlyMinor - (spentMinor + costMinor);\n remainingCandidates.push(monthlyRemaining);\n }\n\n // Return the most restrictive limit\n if (remainingCandidates.length === 0) {\n // No limits configured - unbounded\n return {\n allowed: true,\n unbounded: true,\n };\n }\n\n const remainingMinor = remainingCandidates.reduce((min, val) => (val < min ? val : min));\n\n return {\n allowed: true,\n remainingMinor,\n };\n}\n","/**\n * MCP _meta carrier format (DD-125).\n *\n * Attach and extract PEAC evidence carriers using MCP _meta keys.\n * Uses reverse-DNS keys under \"org.peacprotocol/\" prefix.\n *\n * New format (v0.11.1+):\n * _meta[\"org.peacprotocol/receipt_ref\"] = \"sha256:...\"\n * _meta[\"org.peacprotocol/receipt_jws\"] = \"eyJ...\"\n *\n * Legacy format (v0.10.13):\n * _meta[\"org.peacprotocol/receipt\"] = \"eyJ...\" (JWS only, no receipt_ref)\n */\n\nimport type {\n PeacEvidenceCarrier,\n CarrierMeta,\n CarrierValidationResult,\n CarrierAdapter,\n} from '@peac/kernel';\nimport {\n PeacEvidenceCarrierSchema,\n computeReceiptRef,\n validateCarrierConstraints,\n verifyReceiptRefConsistency,\n CARRIER_TRANSPORT_LIMITS,\n} from '@peac/schema';\n\n// ---------------------------------------------------------------------------\n// Constants\n// ---------------------------------------------------------------------------\n\n/** _meta key for receipt reference (v0.11.1+) */\nexport const META_KEY_RECEIPT_REF = 'org.peacprotocol/receipt_ref' as const;\n\n/** _meta key for receipt JWS (v0.11.1+) */\nexport const META_KEY_RECEIPT_JWS = 'org.peacprotocol/receipt_jws' as const;\n\n/** _meta key for agent ID (v0.10.13+, unchanged) */\nexport const META_KEY_AGENT_ID = 'org.peacprotocol/agent_id' as const;\n\n/** _meta key for verification timestamp (v0.10.13+, unchanged) */\nexport const META_KEY_VERIFIED_AT = 'org.peacprotocol/verified_at' as const;\n\n/** Legacy _meta key for receipt JWS (v0.10.13, DD-125) */\nexport const META_KEY_LEGACY_RECEIPT = 'org.peacprotocol/receipt' as const;\n\n/** Maximum carrier size for MCP _meta (64 KB, DD-127) */\nexport const MCP_MAX_CARRIER_SIZE = CARRIER_TRANSPORT_LIMITS.mcp;\n\n// ---------------------------------------------------------------------------\n// Types\n// ---------------------------------------------------------------------------\n\n/** MCP _meta object */\nexport type McpMeta = Record<string, unknown>;\n\n/** MCP JSON-RPC result with _meta */\nexport interface McpResultLike {\n _meta?: McpMeta;\n [key: string]: unknown;\n}\n\n/** Options for attachReceiptToMeta */\nexport interface AttachMetaOptions {\n /** Use legacy format (v0.10.13 peac_receipt key). Default: false */\n legacyFormat?: boolean;\n /** Agent ID to include in _meta */\n agentId?: string;\n /** Verification timestamp (ISO 8601) */\n verifiedAt?: string;\n}\n\n/** Result of extraction */\nexport interface McpExtractResult {\n receipts: PeacEvidenceCarrier[];\n meta: CarrierMeta;\n}\n\n/** Async extraction result with consistency violations */\nexport interface McpExtractAsyncResult extends McpExtractResult {\n violations: string[];\n}\n\n// ---------------------------------------------------------------------------\n// Attach\n// ---------------------------------------------------------------------------\n\n/**\n * Attach PEAC evidence carrier to MCP _meta.\n *\n * Default format (v0.11.1+): writes receipt_ref and receipt_jws as separate keys.\n * Legacy format (opts.legacyFormat): writes single \"receipt\" key (DD-125 phase 1).\n */\nexport function attachReceiptToMeta(\n result: McpResultLike,\n carrier: PeacEvidenceCarrier,\n opts?: AttachMetaOptions\n): McpResultLike {\n const meta: CarrierMeta = {\n transport: 'mcp',\n format: 'embed',\n max_size: MCP_MAX_CARRIER_SIZE,\n };\n\n const validation = validateCarrierConstraints(carrier, meta);\n if (!validation.valid) {\n throw new Error(`Carrier constraint violation: ${validation.violations.join('; ')}`);\n }\n\n if (!result._meta) {\n result._meta = {};\n }\n\n if (opts?.legacyFormat) {\n // DD-125 legacy format: single JWS string\n if (carrier.receipt_jws) {\n result._meta[META_KEY_LEGACY_RECEIPT] = carrier.receipt_jws;\n }\n } else {\n // v0.11.1+ carrier format\n result._meta[META_KEY_RECEIPT_REF] = carrier.receipt_ref;\n if (carrier.receipt_jws) {\n result._meta[META_KEY_RECEIPT_JWS] = carrier.receipt_jws;\n }\n }\n\n // Optional metadata fields (unchanged from v0.10.13)\n if (opts?.agentId) {\n result._meta[META_KEY_AGENT_ID] = opts.agentId;\n }\n if (opts?.verifiedAt) {\n result._meta[META_KEY_VERIFIED_AT] = opts.verifiedAt;\n }\n\n return result;\n}\n\n// ---------------------------------------------------------------------------\n// Extract (sync: structural validation only)\n// ---------------------------------------------------------------------------\n\n/**\n * Extract PEAC evidence carrier from MCP _meta (sync).\n *\n * Reads in order (DD-125):\n * 1. New carrier keys (receipt_ref + receipt_jws)\n * 2. Legacy key (org.peacprotocol/receipt, v0.10.13)\n *\n * For legacy format, computes receipt_ref from the JWS to return a proper\n * PeacEvidenceCarrier (Polish B). Note: this requires async for the hash,\n * so the sync version uses a placeholder receipt_ref for legacy and marks\n * it in the meta. Use extractReceiptFromMetaAsync for full validation.\n */\nexport function extractReceiptFromMeta(result: McpResultLike): McpExtractResult | null {\n if (!result._meta) return null;\n\n const meta: CarrierMeta = {\n transport: 'mcp',\n format: 'embed',\n max_size: MCP_MAX_CARRIER_SIZE,\n };\n\n // 1. Try new format (v0.11.1+)\n const receiptRef = result._meta[META_KEY_RECEIPT_REF];\n if (typeof receiptRef === 'string') {\n const carrier: Record<string, unknown> = { receipt_ref: receiptRef };\n const receiptJws = result._meta[META_KEY_RECEIPT_JWS];\n if (typeof receiptJws === 'string') {\n carrier.receipt_jws = receiptJws;\n }\n\n const parsed = PeacEvidenceCarrierSchema.safeParse(carrier);\n if (parsed.success) {\n return { receipts: [parsed.data as PeacEvidenceCarrier], meta };\n }\n }\n\n // 2. Try legacy format (v0.10.13, DD-125 + Polish B)\n const legacyReceipt = result._meta[META_KEY_LEGACY_RECEIPT];\n if (typeof legacyReceipt === 'string' && legacyReceipt.length > 0) {\n // Legacy format has JWS only; we can't compute receipt_ref synchronously.\n // Return the JWS in a carrier with a placeholder ref that extractAsync will fix.\n // For sync extraction, we skip schema validation of receipt_ref since we can't\n // compute it without async. Return the raw data and let async handle integrity.\n return {\n receipts: [\n {\n receipt_ref:\n 'sha256:0000000000000000000000000000000000000000000000000000000000000000' as PeacEvidenceCarrier['receipt_ref'],\n receipt_jws: legacyReceipt,\n },\n ],\n meta: { ...meta, redaction: ['legacy_receipt_ref_pending'] },\n };\n }\n\n return null;\n}\n\n/**\n * Extract PEAC evidence carrier from MCP _meta (async, DD-129).\n *\n * Performs structural validation AND receipt_ref consistency check.\n * For legacy format (v0.10.13), computes receipt_ref from JWS (Polish B).\n */\nexport async function extractReceiptFromMetaAsync(\n result: McpResultLike\n): Promise<McpExtractAsyncResult | null> {\n if (!result._meta) return null;\n\n const meta: CarrierMeta = {\n transport: 'mcp',\n format: 'embed',\n max_size: MCP_MAX_CARRIER_SIZE,\n };\n\n // 1. Try new format (v0.11.1+)\n const receiptRef = result._meta[META_KEY_RECEIPT_REF];\n if (typeof receiptRef === 'string') {\n const carrier: Record<string, unknown> = { receipt_ref: receiptRef };\n const receiptJws = result._meta[META_KEY_RECEIPT_JWS];\n if (typeof receiptJws === 'string') {\n carrier.receipt_jws = receiptJws;\n }\n\n const parsed = PeacEvidenceCarrierSchema.safeParse(carrier);\n if (parsed.success) {\n const validCarrier = parsed.data as PeacEvidenceCarrier;\n const error = await verifyReceiptRefConsistency(validCarrier);\n const violations = error ? [error] : [];\n return {\n receipts: error ? [] : [validCarrier],\n meta,\n violations,\n };\n }\n }\n\n // 2. Try legacy format (v0.10.13, DD-125 + Polish B)\n const legacyReceipt = result._meta[META_KEY_LEGACY_RECEIPT];\n if (typeof legacyReceipt === 'string' && legacyReceipt.length > 0) {\n // Compute receipt_ref from legacy JWS\n const computedRef = await computeReceiptRef(legacyReceipt);\n const carrier: PeacEvidenceCarrier = {\n receipt_ref: computedRef,\n receipt_jws: legacyReceipt,\n };\n return { receipts: [carrier], meta, violations: [] };\n }\n\n return null;\n}\n\n// ---------------------------------------------------------------------------\n// McpCarrierAdapter\n// ---------------------------------------------------------------------------\n\n/**\n * CarrierAdapter implementation for MCP _meta format.\n */\nexport class McpCarrierAdapter implements CarrierAdapter<McpResultLike, McpResultLike> {\n extract(input: McpResultLike): { receipts: PeacEvidenceCarrier[]; meta: CarrierMeta } | null {\n return extractReceiptFromMeta(input);\n }\n\n attach(\n output: McpResultLike,\n carriers: PeacEvidenceCarrier[],\n meta?: CarrierMeta\n ): McpResultLike {\n // Attach first carrier (MCP typically carries one receipt per response)\n if (carriers.length > 0) {\n attachReceiptToMeta(output, carriers[0]);\n }\n return output;\n }\n\n validateConstraints(carrier: PeacEvidenceCarrier, meta: CarrierMeta): CarrierValidationResult {\n return validateCarrierConstraints(carrier, meta);\n }\n}\n","/**\n * MCP _meta reserved key guard.\n *\n * Per MCP specification (2025-11-25), the reserved prefix rule is:\n * \"Any prefix where the second label is `modelcontextprotocol` or `mcp`\n * is reserved.\"\n *\n * The prefix is the segment before the first `/`, split by `.` into labels.\n * Only the second label (labels[1], 0-indexed) determines reservation.\n *\n * Examples:\n * \"dev.mcp/anything\" -> RESERVED (2nd label = mcp)\n * \"io.modelcontextprotocol/data\" -> RESERVED (2nd label = modelcontextprotocol)\n * \"com.mcp.tools/data\" -> RESERVED (2nd label = mcp)\n * \"tools.mcp.com/data\" -> RESERVED (2nd label = mcp)\n * \"mcp.dev/anything\" -> NOT reserved (2nd label = dev)\n * \"modelcontextprotocol.io/data\" -> NOT reserved (2nd label = io)\n * \"com.example.mcp/data\" -> NOT reserved (2nd label = example)\n * \"org.peacprotocol/receipt_ref\" -> NOT reserved (2nd label = peacprotocol)\n */\n\nconst MCP_RESERVED_SECOND_LABELS = ['modelcontextprotocol', 'mcp'];\n\n/**\n * Assert that a _meta key does not use an MCP-reserved prefix.\n *\n * A prefix is reserved when its second label (labels[1], 0-indexed)\n * equals \"mcp\" or \"modelcontextprotocol\" (case-insensitive).\n *\n * @throws Error if the key uses a reserved prefix\n */\nexport function assertNotMcpReservedKey(key: string): void {\n const slashIndex = key.indexOf('/');\n if (slashIndex === -1) return; // No prefix = not reserved\n\n const prefix = key.substring(0, slashIndex);\n const labels = prefix.split('.');\n\n if (labels.length < 2) return; // Single label = no second label = not reserved\n\n if (MCP_RESERVED_SECOND_LABELS.includes(labels[1].toLowerCase())) {\n throw new Error(\n `Reserved MCP _meta key prefix: ${key} (second label \"${labels[1]}\" is reserved per MCP spec)`\n );\n }\n}\n\n/**\n * Check if a _meta key uses an MCP-reserved prefix (non-throwing).\n */\nexport function isMcpReservedKey(key: string): boolean {\n try {\n assertNotMcpReservedKey(key);\n return false;\n } catch {\n return true;\n }\n}\n","/**\n * @peac/mappings-mcp\n *\n * Model Context Protocol (MCP) integration for PEAC.\n * Attach and extract PEAC evidence carriers via MCP _meta keys (DD-125).\n */\n\n// Budget enforcement\nexport * from './budget';\n\n// Carrier _meta format (v0.11.1+ Evidence Carrier Contract)\nexport type {\n McpMeta,\n McpResultLike,\n AttachMetaOptions,\n McpExtractResult,\n McpExtractAsyncResult,\n} from './meta';\n\nexport {\n attachReceiptToMeta,\n extractReceiptFromMeta,\n extractReceiptFromMetaAsync,\n McpCarrierAdapter,\n META_KEY_RECEIPT_REF,\n META_KEY_RECEIPT_JWS,\n META_KEY_AGENT_ID,\n META_KEY_VERIFIED_AT,\n META_KEY_LEGACY_RECEIPT,\n MCP_MAX_CARRIER_SIZE,\n} from './meta';\n\n// MCP _meta reserved key guard\nexport { assertNotMcpReservedKey, isMcpReservedKey } from './guard';\n\n// ---------------------------------------------------------------------------\n// Legacy API (backward compatible)\n// ---------------------------------------------------------------------------\n\n/**\n * MCP Tool Response\n */\nexport interface MCPToolResponse {\n tool: string;\n result: unknown;\n metadata?: Record<string, unknown>;\n [key: string]: unknown;\n}\n\n/**\n * MCP Tool Response with PEAC receipt (legacy format)\n */\nexport interface MCPToolResponseWithReceipt extends MCPToolResponse {\n peac_receipt?: string;\n}\n\n/**\n * Attach PEAC receipt to MCP tool response (legacy format).\n *\n * Uses `peac_receipt` top-level key. For new integrations, prefer\n * `attachReceiptToMeta()` which uses the _meta carrier format (DD-125).\n *\n * @param response - MCP tool response\n * @param receiptJWS - PEAC receipt JWS\n * @returns MCP tool response with PEAC receipt attached\n */\nexport function attachReceipt(\n response: MCPToolResponse,\n receiptJWS: string\n): MCPToolResponseWithReceipt {\n return {\n ...response,\n peac_receipt: receiptJWS,\n };\n}\n\n/**\n * Extract PEAC receipt from MCP tool response.\n *\n * Reads BOTH legacy `peac_receipt` field AND `_meta` carrier format (DD-125).\n * Prefers _meta format when both are present.\n *\n * @param response - MCP tool response (possibly with receipt)\n * @returns PEAC receipt JWS or null if not present\n */\nexport function extractReceipt(response: MCPToolResponseWithReceipt): string | null {\n // 1. Try _meta carrier format (v0.11.1+)\n if (response._meta) {\n const meta = response._meta as Record<string, unknown>;\n // New format: receipt_jws key\n const jws = meta['org.peacprotocol/receipt_jws'];\n if (typeof jws === 'string' && jws.length > 0) {\n return jws;\n }\n // Legacy _meta format: receipt key (v0.10.13)\n const legacyJws = meta['org.peacprotocol/receipt'];\n if (typeof legacyJws === 'string' && legacyJws.length > 0) {\n return legacyJws;\n }\n }\n\n // 2. Fall back to legacy peac_receipt field\n if (typeof response.peac_receipt === 'string' && response.peac_receipt.length > 0) {\n return response.peac_receipt;\n }\n return null;\n}\n\n/**\n * Check if MCP tool response has a PEAC receipt\n *\n * @param response - MCP tool response\n * @returns true if receipt is present\n */\nexport function hasReceipt(response: MCPToolResponseWithReceipt): boolean {\n return extractReceipt(response) !== null;\n}\n\n/**\n * Create MCP tool response with PEAC receipt for paid API calls\n *\n * @param tool - Tool name\n * @param result - Tool execution result\n * @param receiptJWS - PEAC receipt JWS\n * @param metadata - Optional metadata\n * @returns MCP tool response with receipt\n */\nexport function createPaidToolResponse(\n tool: string,\n result: unknown,\n receiptJWS: string,\n metadata?: Record<string, unknown>\n): MCPToolResponseWithReceipt {\n const response: MCPToolResponse = {\n tool,\n result,\n ...(metadata && { metadata }),\n };\n\n return attachReceipt(response, receiptJWS);\n}\n"]}
1
+ {"version":3,"sources":["../src/budget.ts","../src/meta.ts","../src/guard.ts","../src/index.ts"],"names":["CARRIER_TRANSPORT_LIMITS","validateCarrierConstraints","PeacEvidenceCarrierSchema","verifyReceiptRefConsistency","computeReceiptRef"],"mappings":"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","file":"index.cjs","sourcesContent":["/**\n * Budget enforcement utilities for MCP tool calls\n * Uses bigint for all currency calculations to avoid floating-point errors\n */\n\nexport interface BudgetConfig {\n /** Maximum cost per single call in minor currency units (e.g., cents for USD) */\n maxPerCallMinor?: bigint;\n /** Maximum total cost per day in minor currency units */\n maxDailyMinor?: bigint;\n /** Maximum total cost per month in minor currency units */\n maxMonthlyMinor?: bigint;\n /** Currency code (must match at runtime, e.g., 'USD', 'INR') */\n currency: string;\n}\n\nexport interface BudgetResult {\n /** Whether the cost is allowed within budget limits */\n allowed: boolean;\n /**\n * Remaining budget in minor units (after this operation).\n * - When allowed: the minimum remaining across all applicable limits\n * - When denied: 0n (never negative)\n * - When unbounded: undefined (check `unbounded` flag instead)\n */\n remainingMinor?: bigint;\n /**\n * True when no budget limits are configured.\n * In this case, remainingMinor is undefined.\n */\n unbounded?: boolean;\n /** Error code if not allowed */\n code?: 'budget_exceeded' | 'currency_mismatch';\n /** Human-readable reason if not allowed */\n reason?: string;\n}\n\n/**\n * Check if a cost is within budget.\n * Pure, deterministic function - caller tracks time windows externally.\n *\n * @param spentMinor - Amount already spent in minor units (e.g., cents)\n * @param costMinor - Cost of current operation in minor units\n * @param currency - Currency code (must match config.currency)\n * @param config - Budget configuration\n * @returns Result indicating whether cost is allowed and remaining budget\n *\n * @example\n * ```typescript\n * const config: BudgetConfig = {\n * maxPerCallMinor: 500n, // $5.00 max per call\n * maxDailyMinor: 10000n, // $100.00 max per day\n * currency: 'USD'\n * };\n *\n * const result = checkBudget(\n * 8500n, // Already spent $85.00 today\n * 1000n, // Current call costs $10.00\n * 'USD',\n * config\n * );\n *\n * if (result.allowed) {\n * console.log(`Allowed. Remaining: ${result.remainingMinor} cents`);\n * } else {\n * console.log(`Denied: ${result.reason}`);\n * }\n * ```\n */\nexport function checkBudget(\n spentMinor: bigint,\n costMinor: bigint,\n currency: string,\n config: BudgetConfig\n): BudgetResult {\n // Currency mismatch check\n if (currency !== config.currency) {\n return {\n allowed: false,\n remainingMinor: 0n,\n code: 'currency_mismatch',\n reason: `Currency mismatch: expected ${config.currency}, got ${currency}`,\n };\n }\n\n // Check per-call limit\n if (config.maxPerCallMinor !== undefined && costMinor > config.maxPerCallMinor) {\n return {\n allowed: false,\n remainingMinor: 0n, // Never negative - clamp to 0\n code: 'budget_exceeded',\n reason: `Per-call limit exceeded: cost ${costMinor} > limit ${config.maxPerCallMinor}`,\n };\n }\n\n // Check daily limit (if configured)\n if (config.maxDailyMinor !== undefined) {\n const newTotal = spentMinor + costMinor;\n if (newTotal > config.maxDailyMinor) {\n return {\n allowed: false,\n remainingMinor: config.maxDailyMinor - spentMinor,\n code: 'budget_exceeded',\n reason: `Daily limit exceeded: total ${newTotal} > limit ${config.maxDailyMinor}`,\n };\n }\n }\n\n // Check monthly limit (if configured)\n if (config.maxMonthlyMinor !== undefined) {\n const newTotal = spentMinor + costMinor;\n if (newTotal > config.maxMonthlyMinor) {\n return {\n allowed: false,\n remainingMinor: config.maxMonthlyMinor - spentMinor,\n code: 'budget_exceeded',\n reason: `Monthly limit exceeded: total ${newTotal} > limit ${config.maxMonthlyMinor}`,\n };\n }\n }\n\n // Calculate remaining budget (how much can be spent in future operations)\n // This is the minimum of:\n // 1. Per-call limit (max single operation)\n // 2. Remaining daily budget\n // 3. Remaining monthly budget\n const remainingCandidates: bigint[] = [];\n\n if (config.maxPerCallMinor !== undefined) {\n remainingCandidates.push(config.maxPerCallMinor);\n }\n\n if (config.maxDailyMinor !== undefined) {\n const dailyRemaining = config.maxDailyMinor - (spentMinor + costMinor);\n remainingCandidates.push(dailyRemaining);\n }\n\n if (config.maxMonthlyMinor !== undefined) {\n const monthlyRemaining = config.maxMonthlyMinor - (spentMinor + costMinor);\n remainingCandidates.push(monthlyRemaining);\n }\n\n // Return the most restrictive limit\n if (remainingCandidates.length === 0) {\n // No limits configured - unbounded\n return {\n allowed: true,\n unbounded: true,\n };\n }\n\n const remainingMinor = remainingCandidates.reduce((min, val) => (val < min ? val : min));\n\n return {\n allowed: true,\n remainingMinor,\n };\n}\n","/**\n * MCP _meta carrier format (DD-125).\n *\n * Attach and extract PEAC evidence carriers using MCP _meta keys.\n * Uses reverse-DNS keys under \"org.peacprotocol/\" prefix.\n *\n * New format (v0.11.1+):\n * _meta[\"org.peacprotocol/receipt_ref\"] = \"sha256:...\"\n * _meta[\"org.peacprotocol/receipt_jws\"] = \"eyJ...\"\n *\n * Legacy format (v0.10.13):\n * _meta[\"org.peacprotocol/receipt\"] = \"eyJ...\" (JWS only, no receipt_ref)\n */\n\nimport type {\n PeacEvidenceCarrier,\n CarrierMeta,\n CarrierValidationResult,\n CarrierAdapter,\n} from '@peac/kernel';\nimport {\n PeacEvidenceCarrierSchema,\n computeReceiptRef,\n validateCarrierConstraints,\n verifyReceiptRefConsistency,\n CARRIER_TRANSPORT_LIMITS,\n} from '@peac/schema';\n\n// ---------------------------------------------------------------------------\n// Constants\n// ---------------------------------------------------------------------------\n\n/** _meta key for receipt reference (v0.11.1+) */\nexport const META_KEY_RECEIPT_REF = 'org.peacprotocol/receipt_ref' as const;\n\n/** _meta key for receipt JWS (v0.11.1+) */\nexport const META_KEY_RECEIPT_JWS = 'org.peacprotocol/receipt_jws' as const;\n\n/** _meta key for agent ID (v0.10.13+, unchanged) */\nexport const META_KEY_AGENT_ID = 'org.peacprotocol/agent_id' as const;\n\n/** _meta key for verification timestamp (v0.10.13+, unchanged) */\nexport const META_KEY_VERIFIED_AT = 'org.peacprotocol/verified_at' as const;\n\n/** _meta key for receipt URL locator hint (v0.11.2+, DD-135) */\nexport const META_KEY_RECEIPT_URL = 'org.peacprotocol/receipt_url' as const;\n\n/** Legacy _meta key for receipt JWS (v0.10.13, DD-125) */\nexport const META_KEY_LEGACY_RECEIPT = 'org.peacprotocol/receipt' as const;\n\n/** Maximum carrier size for MCP _meta (64 KB, DD-127) */\nexport const MCP_MAX_CARRIER_SIZE = CARRIER_TRANSPORT_LIMITS.mcp;\n\n// ---------------------------------------------------------------------------\n// Types\n// ---------------------------------------------------------------------------\n\n/** MCP _meta object */\nexport type McpMeta = Record<string, unknown>;\n\n/** MCP JSON-RPC result with _meta */\nexport interface McpResultLike {\n _meta?: McpMeta;\n [key: string]: unknown;\n}\n\n/** Options for attachReceiptToMeta */\nexport interface AttachMetaOptions {\n /** Use legacy format (v0.10.13 peac_receipt key). Default: false */\n legacyFormat?: boolean;\n /** Agent ID to include in _meta */\n agentId?: string;\n /** Verification timestamp (ISO 8601) */\n verifiedAt?: string;\n}\n\n/** Result of extraction */\nexport interface McpExtractResult {\n receipts: PeacEvidenceCarrier[];\n meta: CarrierMeta;\n}\n\n/** Async extraction result with consistency violations */\nexport interface McpExtractAsyncResult extends McpExtractResult {\n violations: string[];\n}\n\n// ---------------------------------------------------------------------------\n// Attach\n// ---------------------------------------------------------------------------\n\n/**\n * Attach PEAC evidence carrier to MCP _meta.\n *\n * Default format (v0.11.1+): writes receipt_ref and receipt_jws as separate keys.\n * Legacy format (opts.legacyFormat): writes single \"receipt\" key (DD-125 phase 1).\n */\nexport function attachReceiptToMeta(\n result: McpResultLike,\n carrier: PeacEvidenceCarrier,\n opts?: AttachMetaOptions\n): McpResultLike {\n const meta: CarrierMeta = {\n transport: 'mcp',\n format: 'embed',\n max_size: MCP_MAX_CARRIER_SIZE,\n };\n\n const validation = validateCarrierConstraints(carrier, meta);\n if (!validation.valid) {\n throw new Error(`Carrier constraint violation: ${validation.violations.join('; ')}`);\n }\n\n if (!result._meta) {\n result._meta = {};\n }\n\n if (opts?.legacyFormat) {\n // DD-125 legacy format: single JWS string\n if (carrier.receipt_jws) {\n result._meta[META_KEY_LEGACY_RECEIPT] = carrier.receipt_jws;\n }\n } else {\n // v0.11.1+ carrier format\n result._meta[META_KEY_RECEIPT_REF] = carrier.receipt_ref;\n if (carrier.receipt_jws) {\n result._meta[META_KEY_RECEIPT_JWS] = carrier.receipt_jws;\n }\n if (carrier.receipt_url) {\n result._meta[META_KEY_RECEIPT_URL] = carrier.receipt_url;\n }\n }\n\n // Optional metadata fields (unchanged from v0.10.13)\n if (opts?.agentId) {\n result._meta[META_KEY_AGENT_ID] = opts.agentId;\n }\n if (opts?.verifiedAt) {\n result._meta[META_KEY_VERIFIED_AT] = opts.verifiedAt;\n }\n\n return result;\n}\n\n// ---------------------------------------------------------------------------\n// Extract (sync: structural validation only)\n// ---------------------------------------------------------------------------\n\n/**\n * Extract PEAC evidence carrier from MCP _meta (sync).\n *\n * Reads in order (DD-125):\n * 1. New carrier keys (receipt_ref + receipt_jws)\n * 2. Legacy key (org.peacprotocol/receipt, v0.10.13)\n *\n * For legacy format, computes receipt_ref from the JWS to return a proper\n * PeacEvidenceCarrier (Polish B). Note: this requires async for the hash,\n * so the sync version uses a placeholder receipt_ref for legacy and marks\n * it in the meta. Use extractReceiptFromMetaAsync for full validation.\n */\nexport function extractReceiptFromMeta(result: McpResultLike): McpExtractResult | null {\n if (!result._meta) return null;\n\n const meta: CarrierMeta = {\n transport: 'mcp',\n format: 'embed',\n max_size: MCP_MAX_CARRIER_SIZE,\n };\n\n // 1. Try new format (v0.11.1+)\n const receiptRef = result._meta[META_KEY_RECEIPT_REF];\n if (typeof receiptRef === 'string') {\n const carrier: Record<string, unknown> = { receipt_ref: receiptRef };\n const receiptJws = result._meta[META_KEY_RECEIPT_JWS];\n if (typeof receiptJws === 'string') {\n carrier.receipt_jws = receiptJws;\n }\n const receiptUrl = result._meta[META_KEY_RECEIPT_URL];\n if (typeof receiptUrl === 'string') {\n carrier.receipt_url = receiptUrl;\n }\n\n const parsed = PeacEvidenceCarrierSchema.safeParse(carrier);\n if (parsed.success) {\n return { receipts: [parsed.data as PeacEvidenceCarrier], meta };\n }\n }\n\n // 2. Try legacy format (v0.10.13, DD-125 + Polish B)\n const legacyReceipt = result._meta[META_KEY_LEGACY_RECEIPT];\n if (typeof legacyReceipt === 'string' && legacyReceipt.length > 0) {\n // Legacy format has JWS only; we can't compute receipt_ref synchronously.\n // Return the JWS in a carrier with a placeholder ref that extractAsync will fix.\n // For sync extraction, we skip schema validation of receipt_ref since we can't\n // compute it without async. Return the raw data and let async handle integrity.\n return {\n receipts: [\n {\n receipt_ref:\n 'sha256:0000000000000000000000000000000000000000000000000000000000000000' as PeacEvidenceCarrier['receipt_ref'],\n receipt_jws: legacyReceipt,\n },\n ],\n meta: { ...meta, redaction: ['legacy_receipt_ref_pending'] },\n };\n }\n\n return null;\n}\n\n/**\n * Extract PEAC evidence carrier from MCP _meta (async, DD-129).\n *\n * Performs structural validation AND receipt_ref consistency check.\n * For legacy format (v0.10.13), computes receipt_ref from JWS (Polish B).\n */\nexport async function extractReceiptFromMetaAsync(\n result: McpResultLike\n): Promise<McpExtractAsyncResult | null> {\n if (!result._meta) return null;\n\n const meta: CarrierMeta = {\n transport: 'mcp',\n format: 'embed',\n max_size: MCP_MAX_CARRIER_SIZE,\n };\n\n // 1. Try new format (v0.11.1+)\n const receiptRef = result._meta[META_KEY_RECEIPT_REF];\n if (typeof receiptRef === 'string') {\n const carrier: Record<string, unknown> = { receipt_ref: receiptRef };\n const receiptJws = result._meta[META_KEY_RECEIPT_JWS];\n if (typeof receiptJws === 'string') {\n carrier.receipt_jws = receiptJws;\n }\n const receiptUrl = result._meta[META_KEY_RECEIPT_URL];\n if (typeof receiptUrl === 'string') {\n carrier.receipt_url = receiptUrl;\n }\n\n const parsed = PeacEvidenceCarrierSchema.safeParse(carrier);\n if (parsed.success) {\n const validCarrier = parsed.data as PeacEvidenceCarrier;\n const error = await verifyReceiptRefConsistency(validCarrier);\n const violations = error ? [error] : [];\n return {\n receipts: error ? [] : [validCarrier],\n meta,\n violations,\n };\n }\n }\n\n // 2. Try legacy format (v0.10.13, DD-125 + Polish B)\n const legacyReceipt = result._meta[META_KEY_LEGACY_RECEIPT];\n if (typeof legacyReceipt === 'string' && legacyReceipt.length > 0) {\n // Compute receipt_ref from legacy JWS\n const computedRef = await computeReceiptRef(legacyReceipt);\n const carrier: PeacEvidenceCarrier = {\n receipt_ref: computedRef,\n receipt_jws: legacyReceipt,\n };\n return { receipts: [carrier], meta, violations: [] };\n }\n\n return null;\n}\n\n// ---------------------------------------------------------------------------\n// McpCarrierAdapter\n// ---------------------------------------------------------------------------\n\n/**\n * CarrierAdapter implementation for MCP _meta format.\n */\nexport class McpCarrierAdapter implements CarrierAdapter<McpResultLike, McpResultLike> {\n extract(input: McpResultLike): { receipts: PeacEvidenceCarrier[]; meta: CarrierMeta } | null {\n return extractReceiptFromMeta(input);\n }\n\n attach(\n output: McpResultLike,\n carriers: PeacEvidenceCarrier[],\n meta?: CarrierMeta\n ): McpResultLike {\n // Attach first carrier (MCP typically carries one receipt per response)\n if (carriers.length > 0) {\n attachReceiptToMeta(output, carriers[0]);\n }\n return output;\n }\n\n validateConstraints(carrier: PeacEvidenceCarrier, meta: CarrierMeta): CarrierValidationResult {\n return validateCarrierConstraints(carrier, meta);\n }\n}\n","/**\n * MCP _meta reserved key guard.\n *\n * Per MCP specification (2025-11-25), the reserved prefix rule is:\n * \"Any prefix where the second label is `modelcontextprotocol` or `mcp`\n * is reserved.\"\n *\n * The prefix is the segment before the first `/`, split by `.` into labels.\n * Only the second label (labels[1], 0-indexed) determines reservation.\n *\n * Examples:\n * \"dev.mcp/anything\" -> RESERVED (2nd label = mcp)\n * \"io.modelcontextprotocol/data\" -> RESERVED (2nd label = modelcontextprotocol)\n * \"com.mcp.tools/data\" -> RESERVED (2nd label = mcp)\n * \"tools.mcp.com/data\" -> RESERVED (2nd label = mcp)\n * \"mcp.dev/anything\" -> NOT reserved (2nd label = dev)\n * \"modelcontextprotocol.io/data\" -> NOT reserved (2nd label = io)\n * \"com.example.mcp/data\" -> NOT reserved (2nd label = example)\n * \"org.peacprotocol/receipt_ref\" -> NOT reserved (2nd label = peacprotocol)\n */\n\nconst MCP_RESERVED_SECOND_LABELS = ['modelcontextprotocol', 'mcp'];\n\n/**\n * Assert that a _meta key does not use an MCP-reserved prefix.\n *\n * A prefix is reserved when its second label (labels[1], 0-indexed)\n * equals \"mcp\" or \"modelcontextprotocol\" (case-insensitive).\n *\n * @throws Error if the key uses a reserved prefix\n */\nexport function assertNotMcpReservedKey(key: string): void {\n const slashIndex = key.indexOf('/');\n if (slashIndex === -1) return; // No prefix = not reserved\n\n const prefix = key.substring(0, slashIndex);\n const labels = prefix.split('.');\n\n if (labels.length < 2) return; // Single label = no second label = not reserved\n\n if (MCP_RESERVED_SECOND_LABELS.includes(labels[1].toLowerCase())) {\n throw new Error(\n `Reserved MCP _meta key prefix: ${key} (second label \"${labels[1]}\" is reserved per MCP spec)`\n );\n }\n}\n\n/**\n * Check if a _meta key uses an MCP-reserved prefix (non-throwing).\n */\nexport function isMcpReservedKey(key: string): boolean {\n try {\n assertNotMcpReservedKey(key);\n return false;\n } catch {\n return true;\n }\n}\n","/**\n * @peac/mappings-mcp\n *\n * Model Context Protocol (MCP) integration for PEAC.\n * Attach and extract PEAC evidence carriers via MCP _meta keys (DD-125).\n */\n\n// Budget enforcement\nexport * from './budget';\n\n// Carrier _meta format (v0.11.1+ Evidence Carrier Contract)\nexport type {\n McpMeta,\n McpResultLike,\n AttachMetaOptions,\n McpExtractResult,\n McpExtractAsyncResult,\n} from './meta';\n\nexport {\n attachReceiptToMeta,\n extractReceiptFromMeta,\n extractReceiptFromMetaAsync,\n McpCarrierAdapter,\n META_KEY_RECEIPT_REF,\n META_KEY_RECEIPT_JWS,\n META_KEY_RECEIPT_URL,\n META_KEY_AGENT_ID,\n META_KEY_VERIFIED_AT,\n META_KEY_LEGACY_RECEIPT,\n MCP_MAX_CARRIER_SIZE,\n} from './meta';\n\n// MCP _meta reserved key guard\nexport { assertNotMcpReservedKey, isMcpReservedKey } from './guard';\n\n// ---------------------------------------------------------------------------\n// Legacy API (backward compatible)\n// ---------------------------------------------------------------------------\n\n/**\n * MCP Tool Response\n */\nexport interface MCPToolResponse {\n tool: string;\n result: unknown;\n metadata?: Record<string, unknown>;\n [key: string]: unknown;\n}\n\n/**\n * MCP Tool Response with PEAC receipt (legacy format)\n */\nexport interface MCPToolResponseWithReceipt extends MCPToolResponse {\n peac_receipt?: string;\n}\n\n/**\n * Attach PEAC receipt to MCP tool response (legacy format).\n *\n * Uses `peac_receipt` top-level key. For new integrations, prefer\n * `attachReceiptToMeta()` which uses the _meta carrier format (DD-125).\n *\n * @param response - MCP tool response\n * @param receiptJWS - PEAC receipt JWS\n * @returns MCP tool response with PEAC receipt attached\n */\nexport function attachReceipt(\n response: MCPToolResponse,\n receiptJWS: string\n): MCPToolResponseWithReceipt {\n return {\n ...response,\n peac_receipt: receiptJWS,\n };\n}\n\n/**\n * Extract PEAC receipt from MCP tool response.\n *\n * Reads BOTH legacy `peac_receipt` field AND `_meta` carrier format (DD-125).\n * Prefers _meta format when both are present.\n *\n * @param response - MCP tool response (possibly with receipt)\n * @returns PEAC receipt JWS or null if not present\n */\nexport function extractReceipt(response: MCPToolResponseWithReceipt): string | null {\n // 1. Try _meta carrier format (v0.11.1+)\n if (response._meta) {\n const meta = response._meta as Record<string, unknown>;\n // New format: receipt_jws key\n const jws = meta['org.peacprotocol/receipt_jws'];\n if (typeof jws === 'string' && jws.length > 0) {\n return jws;\n }\n // Legacy _meta format: receipt key (v0.10.13)\n const legacyJws = meta['org.peacprotocol/receipt'];\n if (typeof legacyJws === 'string' && legacyJws.length > 0) {\n return legacyJws;\n }\n }\n\n // 2. Fall back to legacy peac_receipt field\n if (typeof response.peac_receipt === 'string' && response.peac_receipt.length > 0) {\n return response.peac_receipt;\n }\n return null;\n}\n\n/**\n * Check if MCP tool response has a PEAC receipt\n *\n * @param response - MCP tool response\n * @returns true if receipt is present\n */\nexport function hasReceipt(response: MCPToolResponseWithReceipt): boolean {\n return extractReceipt(response) !== null;\n}\n\n/**\n * Create MCP tool response with PEAC receipt for paid API calls\n *\n * @param tool - Tool name\n * @param result - Tool execution result\n * @param receiptJWS - PEAC receipt JWS\n * @param metadata - Optional metadata\n * @returns MCP tool response with receipt\n */\nexport function createPaidToolResponse(\n tool: string,\n result: unknown,\n receiptJWS: string,\n metadata?: Record<string, unknown>\n): MCPToolResponseWithReceipt {\n const response: MCPToolResponse = {\n tool,\n result,\n ...(metadata && { metadata }),\n };\n\n return attachReceipt(response, receiptJWS);\n}\n"]}
package/dist/index.d.ts CHANGED
@@ -6,7 +6,7 @@
6
6
  */
7
7
  export * from './budget';
8
8
  export type { McpMeta, McpResultLike, AttachMetaOptions, McpExtractResult, McpExtractAsyncResult, } from './meta';
9
- export { attachReceiptToMeta, extractReceiptFromMeta, extractReceiptFromMetaAsync, McpCarrierAdapter, META_KEY_RECEIPT_REF, META_KEY_RECEIPT_JWS, META_KEY_AGENT_ID, META_KEY_VERIFIED_AT, META_KEY_LEGACY_RECEIPT, MCP_MAX_CARRIER_SIZE, } from './meta';
9
+ export { attachReceiptToMeta, extractReceiptFromMeta, extractReceiptFromMetaAsync, McpCarrierAdapter, META_KEY_RECEIPT_REF, META_KEY_RECEIPT_JWS, META_KEY_RECEIPT_URL, META_KEY_AGENT_ID, META_KEY_VERIFIED_AT, META_KEY_LEGACY_RECEIPT, MCP_MAX_CARRIER_SIZE, } from './meta';
10
10
  export { assertNotMcpReservedKey, isMcpReservedKey } from './guard';
11
11
  /**
12
12
  * MCP Tool Response
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAGH,cAAc,UAAU,CAAC;AAGzB,YAAY,EACV,OAAO,EACP,aAAa,EACb,iBAAiB,EACjB,gBAAgB,EAChB,qBAAqB,GACtB,MAAM,QAAQ,CAAC;AAEhB,OAAO,EACL,mBAAmB,EACnB,sBAAsB,EACtB,2BAA2B,EAC3B,iBAAiB,EACjB,oBAAoB,EACpB,oBAAoB,EACpB,iBAAiB,EACjB,oBAAoB,EACpB,uBAAuB,EACvB,oBAAoB,GACrB,MAAM,QAAQ,CAAC;AAGhB,OAAO,EAAE,uBAAuB,EAAE,gBAAgB,EAAE,MAAM,SAAS,CAAC;AAMpE;;GAEG;AACH,MAAM,WAAW,eAAe;IAC9B,IAAI,EAAE,MAAM,CAAC;IACb,MAAM,EAAE,OAAO,CAAC;IAChB,QAAQ,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;IACnC,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC;CACxB;AAED;;GAEG;AACH,MAAM,WAAW,0BAA2B,SAAQ,eAAe;IACjE,YAAY,CAAC,EAAE,MAAM,CAAC;CACvB;AAED;;;;;;;;;GASG;AACH,wBAAgB,aAAa,CAC3B,QAAQ,EAAE,eAAe,EACzB,UAAU,EAAE,MAAM,GACjB,0BAA0B,CAK5B;AAED;;;;;;;;GAQG;AACH,wBAAgB,cAAc,CAAC,QAAQ,EAAE,0BAA0B,GAAG,MAAM,GAAG,IAAI,CAqBlF;AAED;;;;;GAKG;AACH,wBAAgB,UAAU,CAAC,QAAQ,EAAE,0BAA0B,GAAG,OAAO,CAExE;AAED;;;;;;;;GAQG;AACH,wBAAgB,sBAAsB,CACpC,IAAI,EAAE,MAAM,EACZ,MAAM,EAAE,OAAO,EACf,UAAU,EAAE,MAAM,EAClB,QAAQ,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GACjC,0BAA0B,CAQ5B"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAGH,cAAc,UAAU,CAAC;AAGzB,YAAY,EACV,OAAO,EACP,aAAa,EACb,iBAAiB,EACjB,gBAAgB,EAChB,qBAAqB,GACtB,MAAM,QAAQ,CAAC;AAEhB,OAAO,EACL,mBAAmB,EACnB,sBAAsB,EACtB,2BAA2B,EAC3B,iBAAiB,EACjB,oBAAoB,EACpB,oBAAoB,EACpB,oBAAoB,EACpB,iBAAiB,EACjB,oBAAoB,EACpB,uBAAuB,EACvB,oBAAoB,GACrB,MAAM,QAAQ,CAAC;AAGhB,OAAO,EAAE,uBAAuB,EAAE,gBAAgB,EAAE,MAAM,SAAS,CAAC;AAMpE;;GAEG;AACH,MAAM,WAAW,eAAe;IAC9B,IAAI,EAAE,MAAM,CAAC;IACb,MAAM,EAAE,OAAO,CAAC;IAChB,QAAQ,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;IACnC,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC;CACxB;AAED;;GAEG;AACH,MAAM,WAAW,0BAA2B,SAAQ,eAAe;IACjE,YAAY,CAAC,EAAE,MAAM,CAAC;CACvB;AAED;;;;;;;;;GASG;AACH,wBAAgB,aAAa,CAC3B,QAAQ,EAAE,eAAe,EACzB,UAAU,EAAE,MAAM,GACjB,0BAA0B,CAK5B;AAED;;;;;;;;GAQG;AACH,wBAAgB,cAAc,CAAC,QAAQ,EAAE,0BAA0B,GAAG,MAAM,GAAG,IAAI,CAqBlF;AAED;;;;;GAKG;AACH,wBAAgB,UAAU,CAAC,QAAQ,EAAE,0BAA0B,GAAG,OAAO,CAExE;AAED;;;;;;;;GAQG;AACH,wBAAgB,sBAAsB,CACpC,IAAI,EAAE,MAAM,EACZ,MAAM,EAAE,OAAO,EACf,UAAU,EAAE,MAAM,EAClB,QAAQ,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GACjC,0BAA0B,CAQ5B"}
package/dist/index.mjs CHANGED
@@ -69,6 +69,7 @@ var META_KEY_RECEIPT_REF = "org.peacprotocol/receipt_ref";
69
69
  var META_KEY_RECEIPT_JWS = "org.peacprotocol/receipt_jws";
70
70
  var META_KEY_AGENT_ID = "org.peacprotocol/agent_id";
71
71
  var META_KEY_VERIFIED_AT = "org.peacprotocol/verified_at";
72
+ var META_KEY_RECEIPT_URL = "org.peacprotocol/receipt_url";
72
73
  var META_KEY_LEGACY_RECEIPT = "org.peacprotocol/receipt";
73
74
  var MCP_MAX_CARRIER_SIZE = CARRIER_TRANSPORT_LIMITS.mcp;
74
75
  function attachReceiptToMeta(result, carrier, opts) {
@@ -93,6 +94,9 @@ function attachReceiptToMeta(result, carrier, opts) {
93
94
  if (carrier.receipt_jws) {
94
95
  result._meta[META_KEY_RECEIPT_JWS] = carrier.receipt_jws;
95
96
  }
97
+ if (carrier.receipt_url) {
98
+ result._meta[META_KEY_RECEIPT_URL] = carrier.receipt_url;
99
+ }
96
100
  }
97
101
  if (opts?.agentId) {
98
102
  result._meta[META_KEY_AGENT_ID] = opts.agentId;
@@ -116,6 +120,10 @@ function extractReceiptFromMeta(result) {
116
120
  if (typeof receiptJws === "string") {
117
121
  carrier.receipt_jws = receiptJws;
118
122
  }
123
+ const receiptUrl = result._meta[META_KEY_RECEIPT_URL];
124
+ if (typeof receiptUrl === "string") {
125
+ carrier.receipt_url = receiptUrl;
126
+ }
119
127
  const parsed = PeacEvidenceCarrierSchema.safeParse(carrier);
120
128
  if (parsed.success) {
121
129
  return { receipts: [parsed.data], meta };
@@ -149,6 +157,10 @@ async function extractReceiptFromMetaAsync(result) {
149
157
  if (typeof receiptJws === "string") {
150
158
  carrier.receipt_jws = receiptJws;
151
159
  }
160
+ const receiptUrl = result._meta[META_KEY_RECEIPT_URL];
161
+ if (typeof receiptUrl === "string") {
162
+ carrier.receipt_url = receiptUrl;
163
+ }
152
164
  const parsed = PeacEvidenceCarrierSchema.safeParse(carrier);
153
165
  if (parsed.success) {
154
166
  const validCarrier = parsed.data;
@@ -246,6 +258,6 @@ function createPaidToolResponse(tool, result, receiptJWS, metadata) {
246
258
  return attachReceipt(response, receiptJWS);
247
259
  }
248
260
 
249
- export { MCP_MAX_CARRIER_SIZE, META_KEY_AGENT_ID, META_KEY_LEGACY_RECEIPT, META_KEY_RECEIPT_JWS, META_KEY_RECEIPT_REF, META_KEY_VERIFIED_AT, McpCarrierAdapter, assertNotMcpReservedKey, attachReceipt, attachReceiptToMeta, checkBudget, createPaidToolResponse, extractReceipt, extractReceiptFromMeta, extractReceiptFromMetaAsync, hasReceipt, isMcpReservedKey };
261
+ export { MCP_MAX_CARRIER_SIZE, META_KEY_AGENT_ID, META_KEY_LEGACY_RECEIPT, META_KEY_RECEIPT_JWS, META_KEY_RECEIPT_REF, META_KEY_RECEIPT_URL, META_KEY_VERIFIED_AT, McpCarrierAdapter, assertNotMcpReservedKey, attachReceipt, attachReceiptToMeta, checkBudget, createPaidToolResponse, extractReceipt, extractReceiptFromMeta, extractReceiptFromMetaAsync, hasReceipt, isMcpReservedKey };
250
262
  //# sourceMappingURL=index.mjs.map
251
263
  //# sourceMappingURL=index.mjs.map
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/budget.ts","../src/meta.ts","../src/guard.ts","../src/index.ts"],"names":[],"mappings":";;;AAqEO,SAAS,WAAA,CACd,UAAA,EACA,SAAA,EACA,QAAA,EACA,MAAA,EACc;AAEd,EAAA,IAAI,QAAA,KAAa,OAAO,QAAA,EAAU;AAChC,IAAA,OAAO;AAAA,MACL,OAAA,EAAS,KAAA;AAAA,MACT,cAAA,EAAgB,EAAA;AAAA,MAChB,IAAA,EAAM,mBAAA;AAAA,MACN,MAAA,EAAQ,CAAA,4BAAA,EAA+B,MAAA,CAAO,QAAQ,SAAS,QAAQ,CAAA;AAAA,KACzE;AAAA,EACF;AAGA,EAAA,IAAI,MAAA,CAAO,eAAA,KAAoB,MAAA,IAAa,SAAA,GAAY,OAAO,eAAA,EAAiB;AAC9E,IAAA,OAAO;AAAA,MACL,OAAA,EAAS,KAAA;AAAA,MACT,cAAA,EAAgB,EAAA;AAAA;AAAA,MAChB,IAAA,EAAM,iBAAA;AAAA,MACN,MAAA,EAAQ,CAAA,8BAAA,EAAiC,SAAS,CAAA,SAAA,EAAY,OAAO,eAAe,CAAA;AAAA,KACtF;AAAA,EACF;AAGA,EAAA,IAAI,MAAA,CAAO,kBAAkB,MAAA,EAAW;AACtC,IAAA,MAAM,WAAW,UAAA,GAAa,SAAA;AAC9B,IAAA,IAAI,QAAA,GAAW,OAAO,aAAA,EAAe;AACnC,MAAA,OAAO;AAAA,QACL,OAAA,EAAS,KAAA;AAAA,QACT,cAAA,EAAgB,OAAO,aAAA,GAAgB,UAAA;AAAA,QACvC,IAAA,EAAM,iBAAA;AAAA,QACN,MAAA,EAAQ,CAAA,4BAAA,EAA+B,QAAQ,CAAA,SAAA,EAAY,OAAO,aAAa,CAAA;AAAA,OACjF;AAAA,IACF;AAAA,EACF;AAGA,EAAA,IAAI,MAAA,CAAO,oBAAoB,MAAA,EAAW;AACxC,IAAA,MAAM,WAAW,UAAA,GAAa,SAAA;AAC9B,IAAA,IAAI,QAAA,GAAW,OAAO,eAAA,EAAiB;AACrC,MAAA,OAAO;AAAA,QACL,OAAA,EAAS,KAAA;AAAA,QACT,cAAA,EAAgB,OAAO,eAAA,GAAkB,UAAA;AAAA,QACzC,IAAA,EAAM,iBAAA;AAAA,QACN,MAAA,EAAQ,CAAA,8BAAA,EAAiC,QAAQ,CAAA,SAAA,EAAY,OAAO,eAAe,CAAA;AAAA,OACrF;AAAA,IACF;AAAA,EACF;AAOA,EAAA,MAAM,sBAAgC,EAAC;AAEvC,EAAA,IAAI,MAAA,CAAO,oBAAoB,MAAA,EAAW;AACxC,IAAA,mBAAA,CAAoB,IAAA,CAAK,OAAO,eAAe,CAAA;AAAA,EACjD;AAEA,EAAA,IAAI,MAAA,CAAO,kBAAkB,MAAA,EAAW;AACtC,IAAA,MAAM,cAAA,GAAiB,MAAA,CAAO,aAAA,IAAiB,UAAA,GAAa,SAAA,CAAA;AAC5D,IAAA,mBAAA,CAAoB,KAAK,cAAc,CAAA;AAAA,EACzC;AAEA,EAAA,IAAI,MAAA,CAAO,oBAAoB,MAAA,EAAW;AACxC,IAAA,MAAM,gBAAA,GAAmB,MAAA,CAAO,eAAA,IAAmB,UAAA,GAAa,SAAA,CAAA;AAChE,IAAA,mBAAA,CAAoB,KAAK,gBAAgB,CAAA;AAAA,EAC3C;AAGA,EAAA,IAAI,mBAAA,CAAoB,WAAW,CAAA,EAAG;AAEpC,IAAA,OAAO;AAAA,MACL,OAAA,EAAS,IAAA;AAAA,MACT,SAAA,EAAW;AAAA,KACb;AAAA,EACF;AAEA,EAAA,MAAM,cAAA,GAAiB,oBAAoB,MAAA,CAAO,CAAC,KAAK,GAAA,KAAS,GAAA,GAAM,GAAA,GAAM,GAAA,GAAM,GAAI,CAAA;AAEvF,EAAA,OAAO;AAAA,IACL,OAAA,EAAS,IAAA;AAAA,IACT;AAAA,GACF;AACF;AC5HO,IAAM,oBAAA,GAAuB;AAG7B,IAAM,oBAAA,GAAuB;AAG7B,IAAM,iBAAA,GAAoB;AAG1B,IAAM,oBAAA,GAAuB;AAG7B,IAAM,uBAAA,GAA0B;AAGhC,IAAM,uBAAuB,wBAAA,CAAyB;AA8CtD,SAAS,mBAAA,CACd,MAAA,EACA,OAAA,EACA,IAAA,EACe;AACf,EAAA,MAAM,IAAA,GAAoB;AAAA,IACxB,SAAA,EAAW,KAAA;AAAA,IACX,MAAA,EAAQ,OAAA;AAAA,IACR,QAAA,EAAU;AAAA,GACZ;AAEA,EAAA,MAAM,UAAA,GAAa,0BAAA,CAA2B,OAAA,EAAS,IAAI,CAAA;AAC3D,EAAA,IAAI,CAAC,WAAW,KAAA,EAAO;AACrB,IAAA,MAAM,IAAI,MAAM,CAAA,8BAAA,EAAiC,UAAA,CAAW,WAAW,IAAA,CAAK,IAAI,CAAC,CAAA,CAAE,CAAA;AAAA,EACrF;AAEA,EAAA,IAAI,CAAC,OAAO,KAAA,EAAO;AACjB,IAAA,MAAA,CAAO,QAAQ,EAAC;AAAA,EAClB;AAEA,EAAA,IAAI,MAAM,YAAA,EAAc;AAEtB,IAAA,IAAI,QAAQ,WAAA,EAAa;AACvB,MAAA,MAAA,CAAO,KAAA,CAAM,uBAAuB,CAAA,GAAI,OAAA,CAAQ,WAAA;AAAA,IAClD;AAAA,EACF,CAAA,MAAO;AAEL,IAAA,MAAA,CAAO,KAAA,CAAM,oBAAoB,CAAA,GAAI,OAAA,CAAQ,WAAA;AAC7C,IAAA,IAAI,QAAQ,WAAA,EAAa;AACvB,MAAA,MAAA,CAAO,KAAA,CAAM,oBAAoB,CAAA,GAAI,OAAA,CAAQ,WAAA;AAAA,IAC/C;AAAA,EACF;AAGA,EAAA,IAAI,MAAM,OAAA,EAAS;AACjB,IAAA,MAAA,CAAO,KAAA,CAAM,iBAAiB,CAAA,GAAI,IAAA,CAAK,OAAA;AAAA,EACzC;AACA,EAAA,IAAI,MAAM,UAAA,EAAY;AACpB,IAAA,MAAA,CAAO,KAAA,CAAM,oBAAoB,CAAA,GAAI,IAAA,CAAK,UAAA;AAAA,EAC5C;AAEA,EAAA,OAAO,MAAA;AACT;AAkBO,SAAS,uBAAuB,MAAA,EAAgD;AACrF,EAAA,IAAI,CAAC,MAAA,CAAO,KAAA,EAAO,OAAO,IAAA;AAE1B,EAAA,MAAM,IAAA,GAAoB;AAAA,IACxB,SAAA,EAAW,KAAA;AAAA,IACX,MAAA,EAAQ,OAAA;AAAA,IACR,QAAA,EAAU;AAAA,GACZ;AAGA,EAAA,MAAM,UAAA,GAAa,MAAA,CAAO,KAAA,CAAM,oBAAoB,CAAA;AACpD,EAAA,IAAI,OAAO,eAAe,QAAA,EAAU;AAClC,IAAA,MAAM,OAAA,GAAmC,EAAE,WAAA,EAAa,UAAA,EAAW;AACnE,IAAA,MAAM,UAAA,GAAa,MAAA,CAAO,KAAA,CAAM,oBAAoB,CAAA;AACpD,IAAA,IAAI,OAAO,eAAe,QAAA,EAAU;AAClC,MAAA,OAAA,CAAQ,WAAA,GAAc,UAAA;AAAA,IACxB;AAEA,IAAA,MAAM,MAAA,GAAS,yBAAA,CAA0B,SAAA,CAAU,OAAO,CAAA;AAC1D,IAAA,IAAI,OAAO,OAAA,EAAS;AAClB,MAAA,OAAO,EAAE,QAAA,EAAU,CAAC,MAAA,CAAO,IAA2B,GAAG,IAAA,EAAK;AAAA,IAChE;AAAA,EACF;AAGA,EAAA,MAAM,aAAA,GAAgB,MAAA,CAAO,KAAA,CAAM,uBAAuB,CAAA;AAC1D,EAAA,IAAI,OAAO,aAAA,KAAkB,QAAA,IAAY,aAAA,CAAc,SAAS,CAAA,EAAG;AAKjE,IAAA,OAAO;AAAA,MACL,QAAA,EAAU;AAAA,QACR;AAAA,UACE,WAAA,EACE,yEAAA;AAAA,UACF,WAAA,EAAa;AAAA;AACf,OACF;AAAA,MACA,MAAM,EAAE,GAAG,MAAM,SAAA,EAAW,CAAC,4BAA4B,CAAA;AAAE,KAC7D;AAAA,EACF;AAEA,EAAA,OAAO,IAAA;AACT;AAQA,eAAsB,4BACpB,MAAA,EACuC;AACvC,EAAA,IAAI,CAAC,MAAA,CAAO,KAAA,EAAO,OAAO,IAAA;AAE1B,EAAA,MAAM,IAAA,GAAoB;AAAA,IACxB,SAAA,EAAW,KAAA;AAAA,IACX,MAAA,EAAQ,OAAA;AAAA,IACR,QAAA,EAAU;AAAA,GACZ;AAGA,EAAA,MAAM,UAAA,GAAa,MAAA,CAAO,KAAA,CAAM,oBAAoB,CAAA;AACpD,EAAA,IAAI,OAAO,eAAe,QAAA,EAAU;AAClC,IAAA,MAAM,OAAA,GAAmC,EAAE,WAAA,EAAa,UAAA,EAAW;AACnE,IAAA,MAAM,UAAA,GAAa,MAAA,CAAO,KAAA,CAAM,oBAAoB,CAAA;AACpD,IAAA,IAAI,OAAO,eAAe,QAAA,EAAU;AAClC,MAAA,OAAA,CAAQ,WAAA,GAAc,UAAA;AAAA,IACxB;AAEA,IAAA,MAAM,MAAA,GAAS,yBAAA,CAA0B,SAAA,CAAU,OAAO,CAAA;AAC1D,IAAA,IAAI,OAAO,OAAA,EAAS;AAClB,MAAA,MAAM,eAAe,MAAA,CAAO,IAAA;AAC5B,MAAA,MAAM,KAAA,GAAQ,MAAM,2BAAA,CAA4B,YAAY,CAAA;AAC5D,MAAA,MAAM,UAAA,GAAa,KAAA,GAAQ,CAAC,KAAK,IAAI,EAAC;AACtC,MAAA,OAAO;AAAA,QACL,QAAA,EAAU,KAAA,GAAQ,EAAC,GAAI,CAAC,YAAY,CAAA;AAAA,QACpC,IAAA;AAAA,QACA;AAAA,OACF;AAAA,IACF;AAAA,EACF;AAGA,EAAA,MAAM,aAAA,GAAgB,MAAA,CAAO,KAAA,CAAM,uBAAuB,CAAA;AAC1D,EAAA,IAAI,OAAO,aAAA,KAAkB,QAAA,IAAY,aAAA,CAAc,SAAS,CAAA,EAAG;AAEjE,IAAA,MAAM,WAAA,GAAc,MAAM,iBAAA,CAAkB,aAAa,CAAA;AACzD,IAAA,MAAM,OAAA,GAA+B;AAAA,MACnC,WAAA,EAAa,WAAA;AAAA,MACb,WAAA,EAAa;AAAA,KACf;AACA,IAAA,OAAO,EAAE,UAAU,CAAC,OAAO,GAAG,IAAA,EAAM,UAAA,EAAY,EAAC,EAAE;AAAA,EACrD;AAEA,EAAA,OAAO,IAAA;AACT;AASO,IAAM,oBAAN,MAAgF;AAAA,EACrF,QAAQ,KAAA,EAAqF;AAC3F,IAAA,OAAO,uBAAuB,KAAK,CAAA;AAAA,EACrC;AAAA,EAEA,MAAA,CACE,MAAA,EACA,QAAA,EACA,IAAA,EACe;AAEf,IAAA,IAAI,QAAA,CAAS,SAAS,CAAA,EAAG;AACvB,MAAA,mBAAA,CAAoB,MAAA,EAAQ,QAAA,CAAS,CAAC,CAAC,CAAA;AAAA,IACzC;AACA,IAAA,OAAO,MAAA;AAAA,EACT;AAAA,EAEA,mBAAA,CAAoB,SAA8B,IAAA,EAA4C;AAC5F,IAAA,OAAO,0BAAA,CAA2B,SAAS,IAAI,CAAA;AAAA,EACjD;AACF;;;ACpQA,IAAM,0BAAA,GAA6B,CAAC,sBAAA,EAAwB,KAAK,CAAA;AAU1D,SAAS,wBAAwB,GAAA,EAAmB;AACzD,EAAA,MAAM,UAAA,GAAa,GAAA,CAAI,OAAA,CAAQ,GAAG,CAAA;AAClC,EAAA,IAAI,eAAe,EAAA,EAAI;AAEvB,EAAA,MAAM,MAAA,GAAS,GAAA,CAAI,SAAA,CAAU,CAAA,EAAG,UAAU,CAAA;AAC1C,EAAA,MAAM,MAAA,GAAS,MAAA,CAAO,KAAA,CAAM,GAAG,CAAA;AAE/B,EAAA,IAAI,MAAA,CAAO,SAAS,CAAA,EAAG;AAEvB,EAAA,IAAI,2BAA2B,QAAA,CAAS,MAAA,CAAO,CAAC,CAAA,CAAE,WAAA,EAAa,CAAA,EAAG;AAChE,IAAA,MAAM,IAAI,KAAA;AAAA,MACR,CAAA,+BAAA,EAAkC,GAAG,CAAA,gBAAA,EAAmB,MAAA,CAAO,CAAC,CAAC,CAAA,2BAAA;AAAA,KACnE;AAAA,EACF;AACF;AAKO,SAAS,iBAAiB,GAAA,EAAsB;AACrD,EAAA,IAAI;AACF,IAAA,uBAAA,CAAwB,GAAG,CAAA;AAC3B,IAAA,OAAO,KAAA;AAAA,EACT,CAAA,CAAA,MAAQ;AACN,IAAA,OAAO,IAAA;AAAA,EACT;AACF;;;ACSO,SAAS,aAAA,CACd,UACA,UAAA,EAC4B;AAC5B,EAAA,OAAO;AAAA,IACL,GAAG,QAAA;AAAA,IACH,YAAA,EAAc;AAAA,GAChB;AACF;AAWO,SAAS,eAAe,QAAA,EAAqD;AAElF,EAAA,IAAI,SAAS,KAAA,EAAO;AAClB,IAAA,MAAM,OAAO,QAAA,CAAS,KAAA;AAEtB,IAAA,MAAM,GAAA,GAAM,KAAK,8BAA8B,CAAA;AAC/C,IAAA,IAAI,OAAO,GAAA,KAAQ,QAAA,IAAY,GAAA,CAAI,SAAS,CAAA,EAAG;AAC7C,MAAA,OAAO,GAAA;AAAA,IACT;AAEA,IAAA,MAAM,SAAA,GAAY,KAAK,0BAA0B,CAAA;AACjD,IAAA,IAAI,OAAO,SAAA,KAAc,QAAA,IAAY,SAAA,CAAU,SAAS,CAAA,EAAG;AACzD,MAAA,OAAO,SAAA;AAAA,IACT;AAAA,EACF;AAGA,EAAA,IAAI,OAAO,QAAA,CAAS,YAAA,KAAiB,YAAY,QAAA,CAAS,YAAA,CAAa,SAAS,CAAA,EAAG;AACjF,IAAA,OAAO,QAAA,CAAS,YAAA;AAAA,EAClB;AACA,EAAA,OAAO,IAAA;AACT;AAQO,SAAS,WAAW,QAAA,EAA+C;AACxE,EAAA,OAAO,cAAA,CAAe,QAAQ,CAAA,KAAM,IAAA;AACtC;AAWO,SAAS,sBAAA,CACd,IAAA,EACA,MAAA,EACA,UAAA,EACA,QAAA,EAC4B;AAC5B,EAAA,MAAM,QAAA,GAA4B;AAAA,IAChC,IAAA;AAAA,IACA,MAAA;AAAA,IACA,GAAI,QAAA,IAAY,EAAE,QAAA;AAAS,GAC7B;AAEA,EAAA,OAAO,aAAA,CAAc,UAAU,UAAU,CAAA;AAC3C","file":"index.mjs","sourcesContent":["/**\n * Budget enforcement utilities for MCP tool calls\n * Uses bigint for all currency calculations to avoid floating-point errors\n */\n\nexport interface BudgetConfig {\n /** Maximum cost per single call in minor currency units (e.g., cents for USD) */\n maxPerCallMinor?: bigint;\n /** Maximum total cost per day in minor currency units */\n maxDailyMinor?: bigint;\n /** Maximum total cost per month in minor currency units */\n maxMonthlyMinor?: bigint;\n /** Currency code (must match at runtime, e.g., 'USD', 'INR') */\n currency: string;\n}\n\nexport interface BudgetResult {\n /** Whether the cost is allowed within budget limits */\n allowed: boolean;\n /**\n * Remaining budget in minor units (after this operation).\n * - When allowed: the minimum remaining across all applicable limits\n * - When denied: 0n (never negative)\n * - When unbounded: undefined (check `unbounded` flag instead)\n */\n remainingMinor?: bigint;\n /**\n * True when no budget limits are configured.\n * In this case, remainingMinor is undefined.\n */\n unbounded?: boolean;\n /** Error code if not allowed */\n code?: 'budget_exceeded' | 'currency_mismatch';\n /** Human-readable reason if not allowed */\n reason?: string;\n}\n\n/**\n * Check if a cost is within budget.\n * Pure, deterministic function - caller tracks time windows externally.\n *\n * @param spentMinor - Amount already spent in minor units (e.g., cents)\n * @param costMinor - Cost of current operation in minor units\n * @param currency - Currency code (must match config.currency)\n * @param config - Budget configuration\n * @returns Result indicating whether cost is allowed and remaining budget\n *\n * @example\n * ```typescript\n * const config: BudgetConfig = {\n * maxPerCallMinor: 500n, // $5.00 max per call\n * maxDailyMinor: 10000n, // $100.00 max per day\n * currency: 'USD'\n * };\n *\n * const result = checkBudget(\n * 8500n, // Already spent $85.00 today\n * 1000n, // Current call costs $10.00\n * 'USD',\n * config\n * );\n *\n * if (result.allowed) {\n * console.log(`Allowed. Remaining: ${result.remainingMinor} cents`);\n * } else {\n * console.log(`Denied: ${result.reason}`);\n * }\n * ```\n */\nexport function checkBudget(\n spentMinor: bigint,\n costMinor: bigint,\n currency: string,\n config: BudgetConfig\n): BudgetResult {\n // Currency mismatch check\n if (currency !== config.currency) {\n return {\n allowed: false,\n remainingMinor: 0n,\n code: 'currency_mismatch',\n reason: `Currency mismatch: expected ${config.currency}, got ${currency}`,\n };\n }\n\n // Check per-call limit\n if (config.maxPerCallMinor !== undefined && costMinor > config.maxPerCallMinor) {\n return {\n allowed: false,\n remainingMinor: 0n, // Never negative - clamp to 0\n code: 'budget_exceeded',\n reason: `Per-call limit exceeded: cost ${costMinor} > limit ${config.maxPerCallMinor}`,\n };\n }\n\n // Check daily limit (if configured)\n if (config.maxDailyMinor !== undefined) {\n const newTotal = spentMinor + costMinor;\n if (newTotal > config.maxDailyMinor) {\n return {\n allowed: false,\n remainingMinor: config.maxDailyMinor - spentMinor,\n code: 'budget_exceeded',\n reason: `Daily limit exceeded: total ${newTotal} > limit ${config.maxDailyMinor}`,\n };\n }\n }\n\n // Check monthly limit (if configured)\n if (config.maxMonthlyMinor !== undefined) {\n const newTotal = spentMinor + costMinor;\n if (newTotal > config.maxMonthlyMinor) {\n return {\n allowed: false,\n remainingMinor: config.maxMonthlyMinor - spentMinor,\n code: 'budget_exceeded',\n reason: `Monthly limit exceeded: total ${newTotal} > limit ${config.maxMonthlyMinor}`,\n };\n }\n }\n\n // Calculate remaining budget (how much can be spent in future operations)\n // This is the minimum of:\n // 1. Per-call limit (max single operation)\n // 2. Remaining daily budget\n // 3. Remaining monthly budget\n const remainingCandidates: bigint[] = [];\n\n if (config.maxPerCallMinor !== undefined) {\n remainingCandidates.push(config.maxPerCallMinor);\n }\n\n if (config.maxDailyMinor !== undefined) {\n const dailyRemaining = config.maxDailyMinor - (spentMinor + costMinor);\n remainingCandidates.push(dailyRemaining);\n }\n\n if (config.maxMonthlyMinor !== undefined) {\n const monthlyRemaining = config.maxMonthlyMinor - (spentMinor + costMinor);\n remainingCandidates.push(monthlyRemaining);\n }\n\n // Return the most restrictive limit\n if (remainingCandidates.length === 0) {\n // No limits configured - unbounded\n return {\n allowed: true,\n unbounded: true,\n };\n }\n\n const remainingMinor = remainingCandidates.reduce((min, val) => (val < min ? val : min));\n\n return {\n allowed: true,\n remainingMinor,\n };\n}\n","/**\n * MCP _meta carrier format (DD-125).\n *\n * Attach and extract PEAC evidence carriers using MCP _meta keys.\n * Uses reverse-DNS keys under \"org.peacprotocol/\" prefix.\n *\n * New format (v0.11.1+):\n * _meta[\"org.peacprotocol/receipt_ref\"] = \"sha256:...\"\n * _meta[\"org.peacprotocol/receipt_jws\"] = \"eyJ...\"\n *\n * Legacy format (v0.10.13):\n * _meta[\"org.peacprotocol/receipt\"] = \"eyJ...\" (JWS only, no receipt_ref)\n */\n\nimport type {\n PeacEvidenceCarrier,\n CarrierMeta,\n CarrierValidationResult,\n CarrierAdapter,\n} from '@peac/kernel';\nimport {\n PeacEvidenceCarrierSchema,\n computeReceiptRef,\n validateCarrierConstraints,\n verifyReceiptRefConsistency,\n CARRIER_TRANSPORT_LIMITS,\n} from '@peac/schema';\n\n// ---------------------------------------------------------------------------\n// Constants\n// ---------------------------------------------------------------------------\n\n/** _meta key for receipt reference (v0.11.1+) */\nexport const META_KEY_RECEIPT_REF = 'org.peacprotocol/receipt_ref' as const;\n\n/** _meta key for receipt JWS (v0.11.1+) */\nexport const META_KEY_RECEIPT_JWS = 'org.peacprotocol/receipt_jws' as const;\n\n/** _meta key for agent ID (v0.10.13+, unchanged) */\nexport const META_KEY_AGENT_ID = 'org.peacprotocol/agent_id' as const;\n\n/** _meta key for verification timestamp (v0.10.13+, unchanged) */\nexport const META_KEY_VERIFIED_AT = 'org.peacprotocol/verified_at' as const;\n\n/** Legacy _meta key for receipt JWS (v0.10.13, DD-125) */\nexport const META_KEY_LEGACY_RECEIPT = 'org.peacprotocol/receipt' as const;\n\n/** Maximum carrier size for MCP _meta (64 KB, DD-127) */\nexport const MCP_MAX_CARRIER_SIZE = CARRIER_TRANSPORT_LIMITS.mcp;\n\n// ---------------------------------------------------------------------------\n// Types\n// ---------------------------------------------------------------------------\n\n/** MCP _meta object */\nexport type McpMeta = Record<string, unknown>;\n\n/** MCP JSON-RPC result with _meta */\nexport interface McpResultLike {\n _meta?: McpMeta;\n [key: string]: unknown;\n}\n\n/** Options for attachReceiptToMeta */\nexport interface AttachMetaOptions {\n /** Use legacy format (v0.10.13 peac_receipt key). Default: false */\n legacyFormat?: boolean;\n /** Agent ID to include in _meta */\n agentId?: string;\n /** Verification timestamp (ISO 8601) */\n verifiedAt?: string;\n}\n\n/** Result of extraction */\nexport interface McpExtractResult {\n receipts: PeacEvidenceCarrier[];\n meta: CarrierMeta;\n}\n\n/** Async extraction result with consistency violations */\nexport interface McpExtractAsyncResult extends McpExtractResult {\n violations: string[];\n}\n\n// ---------------------------------------------------------------------------\n// Attach\n// ---------------------------------------------------------------------------\n\n/**\n * Attach PEAC evidence carrier to MCP _meta.\n *\n * Default format (v0.11.1+): writes receipt_ref and receipt_jws as separate keys.\n * Legacy format (opts.legacyFormat): writes single \"receipt\" key (DD-125 phase 1).\n */\nexport function attachReceiptToMeta(\n result: McpResultLike,\n carrier: PeacEvidenceCarrier,\n opts?: AttachMetaOptions\n): McpResultLike {\n const meta: CarrierMeta = {\n transport: 'mcp',\n format: 'embed',\n max_size: MCP_MAX_CARRIER_SIZE,\n };\n\n const validation = validateCarrierConstraints(carrier, meta);\n if (!validation.valid) {\n throw new Error(`Carrier constraint violation: ${validation.violations.join('; ')}`);\n }\n\n if (!result._meta) {\n result._meta = {};\n }\n\n if (opts?.legacyFormat) {\n // DD-125 legacy format: single JWS string\n if (carrier.receipt_jws) {\n result._meta[META_KEY_LEGACY_RECEIPT] = carrier.receipt_jws;\n }\n } else {\n // v0.11.1+ carrier format\n result._meta[META_KEY_RECEIPT_REF] = carrier.receipt_ref;\n if (carrier.receipt_jws) {\n result._meta[META_KEY_RECEIPT_JWS] = carrier.receipt_jws;\n }\n }\n\n // Optional metadata fields (unchanged from v0.10.13)\n if (opts?.agentId) {\n result._meta[META_KEY_AGENT_ID] = opts.agentId;\n }\n if (opts?.verifiedAt) {\n result._meta[META_KEY_VERIFIED_AT] = opts.verifiedAt;\n }\n\n return result;\n}\n\n// ---------------------------------------------------------------------------\n// Extract (sync: structural validation only)\n// ---------------------------------------------------------------------------\n\n/**\n * Extract PEAC evidence carrier from MCP _meta (sync).\n *\n * Reads in order (DD-125):\n * 1. New carrier keys (receipt_ref + receipt_jws)\n * 2. Legacy key (org.peacprotocol/receipt, v0.10.13)\n *\n * For legacy format, computes receipt_ref from the JWS to return a proper\n * PeacEvidenceCarrier (Polish B). Note: this requires async for the hash,\n * so the sync version uses a placeholder receipt_ref for legacy and marks\n * it in the meta. Use extractReceiptFromMetaAsync for full validation.\n */\nexport function extractReceiptFromMeta(result: McpResultLike): McpExtractResult | null {\n if (!result._meta) return null;\n\n const meta: CarrierMeta = {\n transport: 'mcp',\n format: 'embed',\n max_size: MCP_MAX_CARRIER_SIZE,\n };\n\n // 1. Try new format (v0.11.1+)\n const receiptRef = result._meta[META_KEY_RECEIPT_REF];\n if (typeof receiptRef === 'string') {\n const carrier: Record<string, unknown> = { receipt_ref: receiptRef };\n const receiptJws = result._meta[META_KEY_RECEIPT_JWS];\n if (typeof receiptJws === 'string') {\n carrier.receipt_jws = receiptJws;\n }\n\n const parsed = PeacEvidenceCarrierSchema.safeParse(carrier);\n if (parsed.success) {\n return { receipts: [parsed.data as PeacEvidenceCarrier], meta };\n }\n }\n\n // 2. Try legacy format (v0.10.13, DD-125 + Polish B)\n const legacyReceipt = result._meta[META_KEY_LEGACY_RECEIPT];\n if (typeof legacyReceipt === 'string' && legacyReceipt.length > 0) {\n // Legacy format has JWS only; we can't compute receipt_ref synchronously.\n // Return the JWS in a carrier with a placeholder ref that extractAsync will fix.\n // For sync extraction, we skip schema validation of receipt_ref since we can't\n // compute it without async. Return the raw data and let async handle integrity.\n return {\n receipts: [\n {\n receipt_ref:\n 'sha256:0000000000000000000000000000000000000000000000000000000000000000' as PeacEvidenceCarrier['receipt_ref'],\n receipt_jws: legacyReceipt,\n },\n ],\n meta: { ...meta, redaction: ['legacy_receipt_ref_pending'] },\n };\n }\n\n return null;\n}\n\n/**\n * Extract PEAC evidence carrier from MCP _meta (async, DD-129).\n *\n * Performs structural validation AND receipt_ref consistency check.\n * For legacy format (v0.10.13), computes receipt_ref from JWS (Polish B).\n */\nexport async function extractReceiptFromMetaAsync(\n result: McpResultLike\n): Promise<McpExtractAsyncResult | null> {\n if (!result._meta) return null;\n\n const meta: CarrierMeta = {\n transport: 'mcp',\n format: 'embed',\n max_size: MCP_MAX_CARRIER_SIZE,\n };\n\n // 1. Try new format (v0.11.1+)\n const receiptRef = result._meta[META_KEY_RECEIPT_REF];\n if (typeof receiptRef === 'string') {\n const carrier: Record<string, unknown> = { receipt_ref: receiptRef };\n const receiptJws = result._meta[META_KEY_RECEIPT_JWS];\n if (typeof receiptJws === 'string') {\n carrier.receipt_jws = receiptJws;\n }\n\n const parsed = PeacEvidenceCarrierSchema.safeParse(carrier);\n if (parsed.success) {\n const validCarrier = parsed.data as PeacEvidenceCarrier;\n const error = await verifyReceiptRefConsistency(validCarrier);\n const violations = error ? [error] : [];\n return {\n receipts: error ? [] : [validCarrier],\n meta,\n violations,\n };\n }\n }\n\n // 2. Try legacy format (v0.10.13, DD-125 + Polish B)\n const legacyReceipt = result._meta[META_KEY_LEGACY_RECEIPT];\n if (typeof legacyReceipt === 'string' && legacyReceipt.length > 0) {\n // Compute receipt_ref from legacy JWS\n const computedRef = await computeReceiptRef(legacyReceipt);\n const carrier: PeacEvidenceCarrier = {\n receipt_ref: computedRef,\n receipt_jws: legacyReceipt,\n };\n return { receipts: [carrier], meta, violations: [] };\n }\n\n return null;\n}\n\n// ---------------------------------------------------------------------------\n// McpCarrierAdapter\n// ---------------------------------------------------------------------------\n\n/**\n * CarrierAdapter implementation for MCP _meta format.\n */\nexport class McpCarrierAdapter implements CarrierAdapter<McpResultLike, McpResultLike> {\n extract(input: McpResultLike): { receipts: PeacEvidenceCarrier[]; meta: CarrierMeta } | null {\n return extractReceiptFromMeta(input);\n }\n\n attach(\n output: McpResultLike,\n carriers: PeacEvidenceCarrier[],\n meta?: CarrierMeta\n ): McpResultLike {\n // Attach first carrier (MCP typically carries one receipt per response)\n if (carriers.length > 0) {\n attachReceiptToMeta(output, carriers[0]);\n }\n return output;\n }\n\n validateConstraints(carrier: PeacEvidenceCarrier, meta: CarrierMeta): CarrierValidationResult {\n return validateCarrierConstraints(carrier, meta);\n }\n}\n","/**\n * MCP _meta reserved key guard.\n *\n * Per MCP specification (2025-11-25), the reserved prefix rule is:\n * \"Any prefix where the second label is `modelcontextprotocol` or `mcp`\n * is reserved.\"\n *\n * The prefix is the segment before the first `/`, split by `.` into labels.\n * Only the second label (labels[1], 0-indexed) determines reservation.\n *\n * Examples:\n * \"dev.mcp/anything\" -> RESERVED (2nd label = mcp)\n * \"io.modelcontextprotocol/data\" -> RESERVED (2nd label = modelcontextprotocol)\n * \"com.mcp.tools/data\" -> RESERVED (2nd label = mcp)\n * \"tools.mcp.com/data\" -> RESERVED (2nd label = mcp)\n * \"mcp.dev/anything\" -> NOT reserved (2nd label = dev)\n * \"modelcontextprotocol.io/data\" -> NOT reserved (2nd label = io)\n * \"com.example.mcp/data\" -> NOT reserved (2nd label = example)\n * \"org.peacprotocol/receipt_ref\" -> NOT reserved (2nd label = peacprotocol)\n */\n\nconst MCP_RESERVED_SECOND_LABELS = ['modelcontextprotocol', 'mcp'];\n\n/**\n * Assert that a _meta key does not use an MCP-reserved prefix.\n *\n * A prefix is reserved when its second label (labels[1], 0-indexed)\n * equals \"mcp\" or \"modelcontextprotocol\" (case-insensitive).\n *\n * @throws Error if the key uses a reserved prefix\n */\nexport function assertNotMcpReservedKey(key: string): void {\n const slashIndex = key.indexOf('/');\n if (slashIndex === -1) return; // No prefix = not reserved\n\n const prefix = key.substring(0, slashIndex);\n const labels = prefix.split('.');\n\n if (labels.length < 2) return; // Single label = no second label = not reserved\n\n if (MCP_RESERVED_SECOND_LABELS.includes(labels[1].toLowerCase())) {\n throw new Error(\n `Reserved MCP _meta key prefix: ${key} (second label \"${labels[1]}\" is reserved per MCP spec)`\n );\n }\n}\n\n/**\n * Check if a _meta key uses an MCP-reserved prefix (non-throwing).\n */\nexport function isMcpReservedKey(key: string): boolean {\n try {\n assertNotMcpReservedKey(key);\n return false;\n } catch {\n return true;\n }\n}\n","/**\n * @peac/mappings-mcp\n *\n * Model Context Protocol (MCP) integration for PEAC.\n * Attach and extract PEAC evidence carriers via MCP _meta keys (DD-125).\n */\n\n// Budget enforcement\nexport * from './budget';\n\n// Carrier _meta format (v0.11.1+ Evidence Carrier Contract)\nexport type {\n McpMeta,\n McpResultLike,\n AttachMetaOptions,\n McpExtractResult,\n McpExtractAsyncResult,\n} from './meta';\n\nexport {\n attachReceiptToMeta,\n extractReceiptFromMeta,\n extractReceiptFromMetaAsync,\n McpCarrierAdapter,\n META_KEY_RECEIPT_REF,\n META_KEY_RECEIPT_JWS,\n META_KEY_AGENT_ID,\n META_KEY_VERIFIED_AT,\n META_KEY_LEGACY_RECEIPT,\n MCP_MAX_CARRIER_SIZE,\n} from './meta';\n\n// MCP _meta reserved key guard\nexport { assertNotMcpReservedKey, isMcpReservedKey } from './guard';\n\n// ---------------------------------------------------------------------------\n// Legacy API (backward compatible)\n// ---------------------------------------------------------------------------\n\n/**\n * MCP Tool Response\n */\nexport interface MCPToolResponse {\n tool: string;\n result: unknown;\n metadata?: Record<string, unknown>;\n [key: string]: unknown;\n}\n\n/**\n * MCP Tool Response with PEAC receipt (legacy format)\n */\nexport interface MCPToolResponseWithReceipt extends MCPToolResponse {\n peac_receipt?: string;\n}\n\n/**\n * Attach PEAC receipt to MCP tool response (legacy format).\n *\n * Uses `peac_receipt` top-level key. For new integrations, prefer\n * `attachReceiptToMeta()` which uses the _meta carrier format (DD-125).\n *\n * @param response - MCP tool response\n * @param receiptJWS - PEAC receipt JWS\n * @returns MCP tool response with PEAC receipt attached\n */\nexport function attachReceipt(\n response: MCPToolResponse,\n receiptJWS: string\n): MCPToolResponseWithReceipt {\n return {\n ...response,\n peac_receipt: receiptJWS,\n };\n}\n\n/**\n * Extract PEAC receipt from MCP tool response.\n *\n * Reads BOTH legacy `peac_receipt` field AND `_meta` carrier format (DD-125).\n * Prefers _meta format when both are present.\n *\n * @param response - MCP tool response (possibly with receipt)\n * @returns PEAC receipt JWS or null if not present\n */\nexport function extractReceipt(response: MCPToolResponseWithReceipt): string | null {\n // 1. Try _meta carrier format (v0.11.1+)\n if (response._meta) {\n const meta = response._meta as Record<string, unknown>;\n // New format: receipt_jws key\n const jws = meta['org.peacprotocol/receipt_jws'];\n if (typeof jws === 'string' && jws.length > 0) {\n return jws;\n }\n // Legacy _meta format: receipt key (v0.10.13)\n const legacyJws = meta['org.peacprotocol/receipt'];\n if (typeof legacyJws === 'string' && legacyJws.length > 0) {\n return legacyJws;\n }\n }\n\n // 2. Fall back to legacy peac_receipt field\n if (typeof response.peac_receipt === 'string' && response.peac_receipt.length > 0) {\n return response.peac_receipt;\n }\n return null;\n}\n\n/**\n * Check if MCP tool response has a PEAC receipt\n *\n * @param response - MCP tool response\n * @returns true if receipt is present\n */\nexport function hasReceipt(response: MCPToolResponseWithReceipt): boolean {\n return extractReceipt(response) !== null;\n}\n\n/**\n * Create MCP tool response with PEAC receipt for paid API calls\n *\n * @param tool - Tool name\n * @param result - Tool execution result\n * @param receiptJWS - PEAC receipt JWS\n * @param metadata - Optional metadata\n * @returns MCP tool response with receipt\n */\nexport function createPaidToolResponse(\n tool: string,\n result: unknown,\n receiptJWS: string,\n metadata?: Record<string, unknown>\n): MCPToolResponseWithReceipt {\n const response: MCPToolResponse = {\n tool,\n result,\n ...(metadata && { metadata }),\n };\n\n return attachReceipt(response, receiptJWS);\n}\n"]}
1
+ {"version":3,"sources":["../src/budget.ts","../src/meta.ts","../src/guard.ts","../src/index.ts"],"names":[],"mappings":"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","file":"index.mjs","sourcesContent":["/**\n * Budget enforcement utilities for MCP tool calls\n * Uses bigint for all currency calculations to avoid floating-point errors\n */\n\nexport interface BudgetConfig {\n /** Maximum cost per single call in minor currency units (e.g., cents for USD) */\n maxPerCallMinor?: bigint;\n /** Maximum total cost per day in minor currency units */\n maxDailyMinor?: bigint;\n /** Maximum total cost per month in minor currency units */\n maxMonthlyMinor?: bigint;\n /** Currency code (must match at runtime, e.g., 'USD', 'INR') */\n currency: string;\n}\n\nexport interface BudgetResult {\n /** Whether the cost is allowed within budget limits */\n allowed: boolean;\n /**\n * Remaining budget in minor units (after this operation).\n * - When allowed: the minimum remaining across all applicable limits\n * - When denied: 0n (never negative)\n * - When unbounded: undefined (check `unbounded` flag instead)\n */\n remainingMinor?: bigint;\n /**\n * True when no budget limits are configured.\n * In this case, remainingMinor is undefined.\n */\n unbounded?: boolean;\n /** Error code if not allowed */\n code?: 'budget_exceeded' | 'currency_mismatch';\n /** Human-readable reason if not allowed */\n reason?: string;\n}\n\n/**\n * Check if a cost is within budget.\n * Pure, deterministic function - caller tracks time windows externally.\n *\n * @param spentMinor - Amount already spent in minor units (e.g., cents)\n * @param costMinor - Cost of current operation in minor units\n * @param currency - Currency code (must match config.currency)\n * @param config - Budget configuration\n * @returns Result indicating whether cost is allowed and remaining budget\n *\n * @example\n * ```typescript\n * const config: BudgetConfig = {\n * maxPerCallMinor: 500n, // $5.00 max per call\n * maxDailyMinor: 10000n, // $100.00 max per day\n * currency: 'USD'\n * };\n *\n * const result = checkBudget(\n * 8500n, // Already spent $85.00 today\n * 1000n, // Current call costs $10.00\n * 'USD',\n * config\n * );\n *\n * if (result.allowed) {\n * console.log(`Allowed. Remaining: ${result.remainingMinor} cents`);\n * } else {\n * console.log(`Denied: ${result.reason}`);\n * }\n * ```\n */\nexport function checkBudget(\n spentMinor: bigint,\n costMinor: bigint,\n currency: string,\n config: BudgetConfig\n): BudgetResult {\n // Currency mismatch check\n if (currency !== config.currency) {\n return {\n allowed: false,\n remainingMinor: 0n,\n code: 'currency_mismatch',\n reason: `Currency mismatch: expected ${config.currency}, got ${currency}`,\n };\n }\n\n // Check per-call limit\n if (config.maxPerCallMinor !== undefined && costMinor > config.maxPerCallMinor) {\n return {\n allowed: false,\n remainingMinor: 0n, // Never negative - clamp to 0\n code: 'budget_exceeded',\n reason: `Per-call limit exceeded: cost ${costMinor} > limit ${config.maxPerCallMinor}`,\n };\n }\n\n // Check daily limit (if configured)\n if (config.maxDailyMinor !== undefined) {\n const newTotal = spentMinor + costMinor;\n if (newTotal > config.maxDailyMinor) {\n return {\n allowed: false,\n remainingMinor: config.maxDailyMinor - spentMinor,\n code: 'budget_exceeded',\n reason: `Daily limit exceeded: total ${newTotal} > limit ${config.maxDailyMinor}`,\n };\n }\n }\n\n // Check monthly limit (if configured)\n if (config.maxMonthlyMinor !== undefined) {\n const newTotal = spentMinor + costMinor;\n if (newTotal > config.maxMonthlyMinor) {\n return {\n allowed: false,\n remainingMinor: config.maxMonthlyMinor - spentMinor,\n code: 'budget_exceeded',\n reason: `Monthly limit exceeded: total ${newTotal} > limit ${config.maxMonthlyMinor}`,\n };\n }\n }\n\n // Calculate remaining budget (how much can be spent in future operations)\n // This is the minimum of:\n // 1. Per-call limit (max single operation)\n // 2. Remaining daily budget\n // 3. Remaining monthly budget\n const remainingCandidates: bigint[] = [];\n\n if (config.maxPerCallMinor !== undefined) {\n remainingCandidates.push(config.maxPerCallMinor);\n }\n\n if (config.maxDailyMinor !== undefined) {\n const dailyRemaining = config.maxDailyMinor - (spentMinor + costMinor);\n remainingCandidates.push(dailyRemaining);\n }\n\n if (config.maxMonthlyMinor !== undefined) {\n const monthlyRemaining = config.maxMonthlyMinor - (spentMinor + costMinor);\n remainingCandidates.push(monthlyRemaining);\n }\n\n // Return the most restrictive limit\n if (remainingCandidates.length === 0) {\n // No limits configured - unbounded\n return {\n allowed: true,\n unbounded: true,\n };\n }\n\n const remainingMinor = remainingCandidates.reduce((min, val) => (val < min ? val : min));\n\n return {\n allowed: true,\n remainingMinor,\n };\n}\n","/**\n * MCP _meta carrier format (DD-125).\n *\n * Attach and extract PEAC evidence carriers using MCP _meta keys.\n * Uses reverse-DNS keys under \"org.peacprotocol/\" prefix.\n *\n * New format (v0.11.1+):\n * _meta[\"org.peacprotocol/receipt_ref\"] = \"sha256:...\"\n * _meta[\"org.peacprotocol/receipt_jws\"] = \"eyJ...\"\n *\n * Legacy format (v0.10.13):\n * _meta[\"org.peacprotocol/receipt\"] = \"eyJ...\" (JWS only, no receipt_ref)\n */\n\nimport type {\n PeacEvidenceCarrier,\n CarrierMeta,\n CarrierValidationResult,\n CarrierAdapter,\n} from '@peac/kernel';\nimport {\n PeacEvidenceCarrierSchema,\n computeReceiptRef,\n validateCarrierConstraints,\n verifyReceiptRefConsistency,\n CARRIER_TRANSPORT_LIMITS,\n} from '@peac/schema';\n\n// ---------------------------------------------------------------------------\n// Constants\n// ---------------------------------------------------------------------------\n\n/** _meta key for receipt reference (v0.11.1+) */\nexport const META_KEY_RECEIPT_REF = 'org.peacprotocol/receipt_ref' as const;\n\n/** _meta key for receipt JWS (v0.11.1+) */\nexport const META_KEY_RECEIPT_JWS = 'org.peacprotocol/receipt_jws' as const;\n\n/** _meta key for agent ID (v0.10.13+, unchanged) */\nexport const META_KEY_AGENT_ID = 'org.peacprotocol/agent_id' as const;\n\n/** _meta key for verification timestamp (v0.10.13+, unchanged) */\nexport const META_KEY_VERIFIED_AT = 'org.peacprotocol/verified_at' as const;\n\n/** _meta key for receipt URL locator hint (v0.11.2+, DD-135) */\nexport const META_KEY_RECEIPT_URL = 'org.peacprotocol/receipt_url' as const;\n\n/** Legacy _meta key for receipt JWS (v0.10.13, DD-125) */\nexport const META_KEY_LEGACY_RECEIPT = 'org.peacprotocol/receipt' as const;\n\n/** Maximum carrier size for MCP _meta (64 KB, DD-127) */\nexport const MCP_MAX_CARRIER_SIZE = CARRIER_TRANSPORT_LIMITS.mcp;\n\n// ---------------------------------------------------------------------------\n// Types\n// ---------------------------------------------------------------------------\n\n/** MCP _meta object */\nexport type McpMeta = Record<string, unknown>;\n\n/** MCP JSON-RPC result with _meta */\nexport interface McpResultLike {\n _meta?: McpMeta;\n [key: string]: unknown;\n}\n\n/** Options for attachReceiptToMeta */\nexport interface AttachMetaOptions {\n /** Use legacy format (v0.10.13 peac_receipt key). Default: false */\n legacyFormat?: boolean;\n /** Agent ID to include in _meta */\n agentId?: string;\n /** Verification timestamp (ISO 8601) */\n verifiedAt?: string;\n}\n\n/** Result of extraction */\nexport interface McpExtractResult {\n receipts: PeacEvidenceCarrier[];\n meta: CarrierMeta;\n}\n\n/** Async extraction result with consistency violations */\nexport interface McpExtractAsyncResult extends McpExtractResult {\n violations: string[];\n}\n\n// ---------------------------------------------------------------------------\n// Attach\n// ---------------------------------------------------------------------------\n\n/**\n * Attach PEAC evidence carrier to MCP _meta.\n *\n * Default format (v0.11.1+): writes receipt_ref and receipt_jws as separate keys.\n * Legacy format (opts.legacyFormat): writes single \"receipt\" key (DD-125 phase 1).\n */\nexport function attachReceiptToMeta(\n result: McpResultLike,\n carrier: PeacEvidenceCarrier,\n opts?: AttachMetaOptions\n): McpResultLike {\n const meta: CarrierMeta = {\n transport: 'mcp',\n format: 'embed',\n max_size: MCP_MAX_CARRIER_SIZE,\n };\n\n const validation = validateCarrierConstraints(carrier, meta);\n if (!validation.valid) {\n throw new Error(`Carrier constraint violation: ${validation.violations.join('; ')}`);\n }\n\n if (!result._meta) {\n result._meta = {};\n }\n\n if (opts?.legacyFormat) {\n // DD-125 legacy format: single JWS string\n if (carrier.receipt_jws) {\n result._meta[META_KEY_LEGACY_RECEIPT] = carrier.receipt_jws;\n }\n } else {\n // v0.11.1+ carrier format\n result._meta[META_KEY_RECEIPT_REF] = carrier.receipt_ref;\n if (carrier.receipt_jws) {\n result._meta[META_KEY_RECEIPT_JWS] = carrier.receipt_jws;\n }\n if (carrier.receipt_url) {\n result._meta[META_KEY_RECEIPT_URL] = carrier.receipt_url;\n }\n }\n\n // Optional metadata fields (unchanged from v0.10.13)\n if (opts?.agentId) {\n result._meta[META_KEY_AGENT_ID] = opts.agentId;\n }\n if (opts?.verifiedAt) {\n result._meta[META_KEY_VERIFIED_AT] = opts.verifiedAt;\n }\n\n return result;\n}\n\n// ---------------------------------------------------------------------------\n// Extract (sync: structural validation only)\n// ---------------------------------------------------------------------------\n\n/**\n * Extract PEAC evidence carrier from MCP _meta (sync).\n *\n * Reads in order (DD-125):\n * 1. New carrier keys (receipt_ref + receipt_jws)\n * 2. Legacy key (org.peacprotocol/receipt, v0.10.13)\n *\n * For legacy format, computes receipt_ref from the JWS to return a proper\n * PeacEvidenceCarrier (Polish B). Note: this requires async for the hash,\n * so the sync version uses a placeholder receipt_ref for legacy and marks\n * it in the meta. Use extractReceiptFromMetaAsync for full validation.\n */\nexport function extractReceiptFromMeta(result: McpResultLike): McpExtractResult | null {\n if (!result._meta) return null;\n\n const meta: CarrierMeta = {\n transport: 'mcp',\n format: 'embed',\n max_size: MCP_MAX_CARRIER_SIZE,\n };\n\n // 1. Try new format (v0.11.1+)\n const receiptRef = result._meta[META_KEY_RECEIPT_REF];\n if (typeof receiptRef === 'string') {\n const carrier: Record<string, unknown> = { receipt_ref: receiptRef };\n const receiptJws = result._meta[META_KEY_RECEIPT_JWS];\n if (typeof receiptJws === 'string') {\n carrier.receipt_jws = receiptJws;\n }\n const receiptUrl = result._meta[META_KEY_RECEIPT_URL];\n if (typeof receiptUrl === 'string') {\n carrier.receipt_url = receiptUrl;\n }\n\n const parsed = PeacEvidenceCarrierSchema.safeParse(carrier);\n if (parsed.success) {\n return { receipts: [parsed.data as PeacEvidenceCarrier], meta };\n }\n }\n\n // 2. Try legacy format (v0.10.13, DD-125 + Polish B)\n const legacyReceipt = result._meta[META_KEY_LEGACY_RECEIPT];\n if (typeof legacyReceipt === 'string' && legacyReceipt.length > 0) {\n // Legacy format has JWS only; we can't compute receipt_ref synchronously.\n // Return the JWS in a carrier with a placeholder ref that extractAsync will fix.\n // For sync extraction, we skip schema validation of receipt_ref since we can't\n // compute it without async. Return the raw data and let async handle integrity.\n return {\n receipts: [\n {\n receipt_ref:\n 'sha256:0000000000000000000000000000000000000000000000000000000000000000' as PeacEvidenceCarrier['receipt_ref'],\n receipt_jws: legacyReceipt,\n },\n ],\n meta: { ...meta, redaction: ['legacy_receipt_ref_pending'] },\n };\n }\n\n return null;\n}\n\n/**\n * Extract PEAC evidence carrier from MCP _meta (async, DD-129).\n *\n * Performs structural validation AND receipt_ref consistency check.\n * For legacy format (v0.10.13), computes receipt_ref from JWS (Polish B).\n */\nexport async function extractReceiptFromMetaAsync(\n result: McpResultLike\n): Promise<McpExtractAsyncResult | null> {\n if (!result._meta) return null;\n\n const meta: CarrierMeta = {\n transport: 'mcp',\n format: 'embed',\n max_size: MCP_MAX_CARRIER_SIZE,\n };\n\n // 1. Try new format (v0.11.1+)\n const receiptRef = result._meta[META_KEY_RECEIPT_REF];\n if (typeof receiptRef === 'string') {\n const carrier: Record<string, unknown> = { receipt_ref: receiptRef };\n const receiptJws = result._meta[META_KEY_RECEIPT_JWS];\n if (typeof receiptJws === 'string') {\n carrier.receipt_jws = receiptJws;\n }\n const receiptUrl = result._meta[META_KEY_RECEIPT_URL];\n if (typeof receiptUrl === 'string') {\n carrier.receipt_url = receiptUrl;\n }\n\n const parsed = PeacEvidenceCarrierSchema.safeParse(carrier);\n if (parsed.success) {\n const validCarrier = parsed.data as PeacEvidenceCarrier;\n const error = await verifyReceiptRefConsistency(validCarrier);\n const violations = error ? [error] : [];\n return {\n receipts: error ? [] : [validCarrier],\n meta,\n violations,\n };\n }\n }\n\n // 2. Try legacy format (v0.10.13, DD-125 + Polish B)\n const legacyReceipt = result._meta[META_KEY_LEGACY_RECEIPT];\n if (typeof legacyReceipt === 'string' && legacyReceipt.length > 0) {\n // Compute receipt_ref from legacy JWS\n const computedRef = await computeReceiptRef(legacyReceipt);\n const carrier: PeacEvidenceCarrier = {\n receipt_ref: computedRef,\n receipt_jws: legacyReceipt,\n };\n return { receipts: [carrier], meta, violations: [] };\n }\n\n return null;\n}\n\n// ---------------------------------------------------------------------------\n// McpCarrierAdapter\n// ---------------------------------------------------------------------------\n\n/**\n * CarrierAdapter implementation for MCP _meta format.\n */\nexport class McpCarrierAdapter implements CarrierAdapter<McpResultLike, McpResultLike> {\n extract(input: McpResultLike): { receipts: PeacEvidenceCarrier[]; meta: CarrierMeta } | null {\n return extractReceiptFromMeta(input);\n }\n\n attach(\n output: McpResultLike,\n carriers: PeacEvidenceCarrier[],\n meta?: CarrierMeta\n ): McpResultLike {\n // Attach first carrier (MCP typically carries one receipt per response)\n if (carriers.length > 0) {\n attachReceiptToMeta(output, carriers[0]);\n }\n return output;\n }\n\n validateConstraints(carrier: PeacEvidenceCarrier, meta: CarrierMeta): CarrierValidationResult {\n return validateCarrierConstraints(carrier, meta);\n }\n}\n","/**\n * MCP _meta reserved key guard.\n *\n * Per MCP specification (2025-11-25), the reserved prefix rule is:\n * \"Any prefix where the second label is `modelcontextprotocol` or `mcp`\n * is reserved.\"\n *\n * The prefix is the segment before the first `/`, split by `.` into labels.\n * Only the second label (labels[1], 0-indexed) determines reservation.\n *\n * Examples:\n * \"dev.mcp/anything\" -> RESERVED (2nd label = mcp)\n * \"io.modelcontextprotocol/data\" -> RESERVED (2nd label = modelcontextprotocol)\n * \"com.mcp.tools/data\" -> RESERVED (2nd label = mcp)\n * \"tools.mcp.com/data\" -> RESERVED (2nd label = mcp)\n * \"mcp.dev/anything\" -> NOT reserved (2nd label = dev)\n * \"modelcontextprotocol.io/data\" -> NOT reserved (2nd label = io)\n * \"com.example.mcp/data\" -> NOT reserved (2nd label = example)\n * \"org.peacprotocol/receipt_ref\" -> NOT reserved (2nd label = peacprotocol)\n */\n\nconst MCP_RESERVED_SECOND_LABELS = ['modelcontextprotocol', 'mcp'];\n\n/**\n * Assert that a _meta key does not use an MCP-reserved prefix.\n *\n * A prefix is reserved when its second label (labels[1], 0-indexed)\n * equals \"mcp\" or \"modelcontextprotocol\" (case-insensitive).\n *\n * @throws Error if the key uses a reserved prefix\n */\nexport function assertNotMcpReservedKey(key: string): void {\n const slashIndex = key.indexOf('/');\n if (slashIndex === -1) return; // No prefix = not reserved\n\n const prefix = key.substring(0, slashIndex);\n const labels = prefix.split('.');\n\n if (labels.length < 2) return; // Single label = no second label = not reserved\n\n if (MCP_RESERVED_SECOND_LABELS.includes(labels[1].toLowerCase())) {\n throw new Error(\n `Reserved MCP _meta key prefix: ${key} (second label \"${labels[1]}\" is reserved per MCP spec)`\n );\n }\n}\n\n/**\n * Check if a _meta key uses an MCP-reserved prefix (non-throwing).\n */\nexport function isMcpReservedKey(key: string): boolean {\n try {\n assertNotMcpReservedKey(key);\n return false;\n } catch {\n return true;\n }\n}\n","/**\n * @peac/mappings-mcp\n *\n * Model Context Protocol (MCP) integration for PEAC.\n * Attach and extract PEAC evidence carriers via MCP _meta keys (DD-125).\n */\n\n// Budget enforcement\nexport * from './budget';\n\n// Carrier _meta format (v0.11.1+ Evidence Carrier Contract)\nexport type {\n McpMeta,\n McpResultLike,\n AttachMetaOptions,\n McpExtractResult,\n McpExtractAsyncResult,\n} from './meta';\n\nexport {\n attachReceiptToMeta,\n extractReceiptFromMeta,\n extractReceiptFromMetaAsync,\n McpCarrierAdapter,\n META_KEY_RECEIPT_REF,\n META_KEY_RECEIPT_JWS,\n META_KEY_RECEIPT_URL,\n META_KEY_AGENT_ID,\n META_KEY_VERIFIED_AT,\n META_KEY_LEGACY_RECEIPT,\n MCP_MAX_CARRIER_SIZE,\n} from './meta';\n\n// MCP _meta reserved key guard\nexport { assertNotMcpReservedKey, isMcpReservedKey } from './guard';\n\n// ---------------------------------------------------------------------------\n// Legacy API (backward compatible)\n// ---------------------------------------------------------------------------\n\n/**\n * MCP Tool Response\n */\nexport interface MCPToolResponse {\n tool: string;\n result: unknown;\n metadata?: Record<string, unknown>;\n [key: string]: unknown;\n}\n\n/**\n * MCP Tool Response with PEAC receipt (legacy format)\n */\nexport interface MCPToolResponseWithReceipt extends MCPToolResponse {\n peac_receipt?: string;\n}\n\n/**\n * Attach PEAC receipt to MCP tool response (legacy format).\n *\n * Uses `peac_receipt` top-level key. For new integrations, prefer\n * `attachReceiptToMeta()` which uses the _meta carrier format (DD-125).\n *\n * @param response - MCP tool response\n * @param receiptJWS - PEAC receipt JWS\n * @returns MCP tool response with PEAC receipt attached\n */\nexport function attachReceipt(\n response: MCPToolResponse,\n receiptJWS: string\n): MCPToolResponseWithReceipt {\n return {\n ...response,\n peac_receipt: receiptJWS,\n };\n}\n\n/**\n * Extract PEAC receipt from MCP tool response.\n *\n * Reads BOTH legacy `peac_receipt` field AND `_meta` carrier format (DD-125).\n * Prefers _meta format when both are present.\n *\n * @param response - MCP tool response (possibly with receipt)\n * @returns PEAC receipt JWS or null if not present\n */\nexport function extractReceipt(response: MCPToolResponseWithReceipt): string | null {\n // 1. Try _meta carrier format (v0.11.1+)\n if (response._meta) {\n const meta = response._meta as Record<string, unknown>;\n // New format: receipt_jws key\n const jws = meta['org.peacprotocol/receipt_jws'];\n if (typeof jws === 'string' && jws.length > 0) {\n return jws;\n }\n // Legacy _meta format: receipt key (v0.10.13)\n const legacyJws = meta['org.peacprotocol/receipt'];\n if (typeof legacyJws === 'string' && legacyJws.length > 0) {\n return legacyJws;\n }\n }\n\n // 2. Fall back to legacy peac_receipt field\n if (typeof response.peac_receipt === 'string' && response.peac_receipt.length > 0) {\n return response.peac_receipt;\n }\n return null;\n}\n\n/**\n * Check if MCP tool response has a PEAC receipt\n *\n * @param response - MCP tool response\n * @returns true if receipt is present\n */\nexport function hasReceipt(response: MCPToolResponseWithReceipt): boolean {\n return extractReceipt(response) !== null;\n}\n\n/**\n * Create MCP tool response with PEAC receipt for paid API calls\n *\n * @param tool - Tool name\n * @param result - Tool execution result\n * @param receiptJWS - PEAC receipt JWS\n * @param metadata - Optional metadata\n * @returns MCP tool response with receipt\n */\nexport function createPaidToolResponse(\n tool: string,\n result: unknown,\n receiptJWS: string,\n metadata?: Record<string, unknown>\n): MCPToolResponseWithReceipt {\n const response: MCPToolResponse = {\n tool,\n result,\n ...(metadata && { metadata }),\n };\n\n return attachReceipt(response, receiptJWS);\n}\n"]}
package/dist/meta.d.ts CHANGED
@@ -20,6 +20,8 @@ export declare const META_KEY_RECEIPT_JWS: "org.peacprotocol/receipt_jws";
20
20
  export declare const META_KEY_AGENT_ID: "org.peacprotocol/agent_id";
21
21
  /** _meta key for verification timestamp (v0.10.13+, unchanged) */
22
22
  export declare const META_KEY_VERIFIED_AT: "org.peacprotocol/verified_at";
23
+ /** _meta key for receipt URL locator hint (v0.11.2+, DD-135) */
24
+ export declare const META_KEY_RECEIPT_URL: "org.peacprotocol/receipt_url";
23
25
  /** Legacy _meta key for receipt JWS (v0.10.13, DD-125) */
24
26
  export declare const META_KEY_LEGACY_RECEIPT: "org.peacprotocol/receipt";
25
27
  /** Maximum carrier size for MCP _meta (64 KB, DD-127) */
@@ -1 +1 @@
1
- {"version":3,"file":"meta.d.ts","sourceRoot":"","sources":["../src/meta.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;GAYG;AAEH,OAAO,KAAK,EACV,mBAAmB,EACnB,WAAW,EACX,uBAAuB,EACvB,cAAc,EACf,MAAM,cAAc,CAAC;AAatB,iDAAiD;AACjD,eAAO,MAAM,oBAAoB,EAAG,8BAAuC,CAAC;AAE5E,2CAA2C;AAC3C,eAAO,MAAM,oBAAoB,EAAG,8BAAuC,CAAC;AAE5E,oDAAoD;AACpD,eAAO,MAAM,iBAAiB,EAAG,2BAAoC,CAAC;AAEtE,kEAAkE;AAClE,eAAO,MAAM,oBAAoB,EAAG,8BAAuC,CAAC;AAE5E,0DAA0D;AAC1D,eAAO,MAAM,uBAAuB,EAAG,0BAAmC,CAAC;AAE3E,yDAAyD;AACzD,eAAO,MAAM,oBAAoB,OAA+B,CAAC;AAMjE,uBAAuB;AACvB,MAAM,MAAM,OAAO,GAAG,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;AAE9C,qCAAqC;AACrC,MAAM,WAAW,aAAa;IAC5B,KAAK,CAAC,EAAE,OAAO,CAAC;IAChB,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC;CACxB;AAED,sCAAsC;AACtC,MAAM,WAAW,iBAAiB;IAChC,oEAAoE;IACpE,YAAY,CAAC,EAAE,OAAO,CAAC;IACvB,mCAAmC;IACnC,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,wCAAwC;IACxC,UAAU,CAAC,EAAE,MAAM,CAAC;CACrB;AAED,2BAA2B;AAC3B,MAAM,WAAW,gBAAgB;IAC/B,QAAQ,EAAE,mBAAmB,EAAE,CAAC;IAChC,IAAI,EAAE,WAAW,CAAC;CACnB;AAED,0DAA0D;AAC1D,MAAM,WAAW,qBAAsB,SAAQ,gBAAgB;IAC7D,UAAU,EAAE,MAAM,EAAE,CAAC;CACtB;AAMD;;;;;GAKG;AACH,wBAAgB,mBAAmB,CACjC,MAAM,EAAE,aAAa,EACrB,OAAO,EAAE,mBAAmB,EAC5B,IAAI,CAAC,EAAE,iBAAiB,GACvB,aAAa,CAsCf;AAMD;;;;;;;;;;;GAWG;AACH,wBAAgB,sBAAsB,CAAC,MAAM,EAAE,aAAa,GAAG,gBAAgB,GAAG,IAAI,CA4CrF;AAED;;;;;GAKG;AACH,wBAAsB,2BAA2B,CAC/C,MAAM,EAAE,aAAa,GACpB,OAAO,CAAC,qBAAqB,GAAG,IAAI,CAAC,CA4CvC;AAMD;;GAEG;AACH,qBAAa,iBAAkB,YAAW,cAAc,CAAC,aAAa,EAAE,aAAa,CAAC;IACpF,OAAO,CAAC,KAAK,EAAE,aAAa,GAAG;QAAE,QAAQ,EAAE,mBAAmB,EAAE,CAAC;QAAC,IAAI,EAAE,WAAW,CAAA;KAAE,GAAG,IAAI;IAI5F,MAAM,CACJ,MAAM,EAAE,aAAa,EACrB,QAAQ,EAAE,mBAAmB,EAAE,EAC/B,IAAI,CAAC,EAAE,WAAW,GACjB,aAAa;IAQhB,mBAAmB,CAAC,OAAO,EAAE,mBAAmB,EAAE,IAAI,EAAE,WAAW,GAAG,uBAAuB;CAG9F"}
1
+ {"version":3,"file":"meta.d.ts","sourceRoot":"","sources":["../src/meta.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;GAYG;AAEH,OAAO,KAAK,EACV,mBAAmB,EACnB,WAAW,EACX,uBAAuB,EACvB,cAAc,EACf,MAAM,cAAc,CAAC;AAatB,iDAAiD;AACjD,eAAO,MAAM,oBAAoB,EAAG,8BAAuC,CAAC;AAE5E,2CAA2C;AAC3C,eAAO,MAAM,oBAAoB,EAAG,8BAAuC,CAAC;AAE5E,oDAAoD;AACpD,eAAO,MAAM,iBAAiB,EAAG,2BAAoC,CAAC;AAEtE,kEAAkE;AAClE,eAAO,MAAM,oBAAoB,EAAG,8BAAuC,CAAC;AAE5E,gEAAgE;AAChE,eAAO,MAAM,oBAAoB,EAAG,8BAAuC,CAAC;AAE5E,0DAA0D;AAC1D,eAAO,MAAM,uBAAuB,EAAG,0BAAmC,CAAC;AAE3E,yDAAyD;AACzD,eAAO,MAAM,oBAAoB,OAA+B,CAAC;AAMjE,uBAAuB;AACvB,MAAM,MAAM,OAAO,GAAG,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;AAE9C,qCAAqC;AACrC,MAAM,WAAW,aAAa;IAC5B,KAAK,CAAC,EAAE,OAAO,CAAC;IAChB,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC;CACxB;AAED,sCAAsC;AACtC,MAAM,WAAW,iBAAiB;IAChC,oEAAoE;IACpE,YAAY,CAAC,EAAE,OAAO,CAAC;IACvB,mCAAmC;IACnC,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,wCAAwC;IACxC,UAAU,CAAC,EAAE,MAAM,CAAC;CACrB;AAED,2BAA2B;AAC3B,MAAM,WAAW,gBAAgB;IAC/B,QAAQ,EAAE,mBAAmB,EAAE,CAAC;IAChC,IAAI,EAAE,WAAW,CAAC;CACnB;AAED,0DAA0D;AAC1D,MAAM,WAAW,qBAAsB,SAAQ,gBAAgB;IAC7D,UAAU,EAAE,MAAM,EAAE,CAAC;CACtB;AAMD;;;;;GAKG;AACH,wBAAgB,mBAAmB,CACjC,MAAM,EAAE,aAAa,EACrB,OAAO,EAAE,mBAAmB,EAC5B,IAAI,CAAC,EAAE,iBAAiB,GACvB,aAAa,CAyCf;AAMD;;;;;;;;;;;GAWG;AACH,wBAAgB,sBAAsB,CAAC,MAAM,EAAE,aAAa,GAAG,gBAAgB,GAAG,IAAI,CAgDrF;AAED;;;;;GAKG;AACH,wBAAsB,2BAA2B,CAC/C,MAAM,EAAE,aAAa,GACpB,OAAO,CAAC,qBAAqB,GAAG,IAAI,CAAC,CAgDvC;AAMD;;GAEG;AACH,qBAAa,iBAAkB,YAAW,cAAc,CAAC,aAAa,EAAE,aAAa,CAAC;IACpF,OAAO,CAAC,KAAK,EAAE,aAAa,GAAG;QAAE,QAAQ,EAAE,mBAAmB,EAAE,CAAC;QAAC,IAAI,EAAE,WAAW,CAAA;KAAE,GAAG,IAAI;IAI5F,MAAM,CACJ,MAAM,EAAE,aAAa,EACrB,QAAQ,EAAE,mBAAmB,EAAE,EAC/B,IAAI,CAAC,EAAE,WAAW,GACjB,aAAa;IAQhB,mBAAmB,CAAC,OAAO,EAAE,mBAAmB,EAAE,IAAI,EAAE,WAAW,GAAG,uBAAuB;CAG9F"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@peac/mappings-mcp",
3
- "version": "0.11.1",
3
+ "version": "0.11.2",
4
4
  "description": "Model Context Protocol (MCP) integration for PEAC",
5
5
  "main": "dist/index.cjs",
6
6
  "types": "dist/index.d.ts",
@@ -23,8 +23,8 @@
23
23
  "access": "public"
24
24
  },
25
25
  "dependencies": {
26
- "@peac/kernel": "0.11.1",
27
- "@peac/schema": "0.11.1"
26
+ "@peac/kernel": "0.11.2",
27
+ "@peac/schema": "0.11.2"
28
28
  },
29
29
  "devDependencies": {
30
30
  "@types/node": "^22.19.11",