UNPKG

@receiz/mcp-server

Version:

MCP server for agents building and verifying Receiz proof-native applications through the canonical Receiz SDK rails.

173 lines • 9.48 kB
import { isReceizV125TrustMcpHost, assertReceizV125TrustMcpHostScope } from "./v125TrustHost.js"; const object = (properties, required = []) => ({ type: "object", additionalProperties: false, properties, required, }); const text = (description) => ({ type: "string", description }); export const RECEIZ_V125_TRUST_MCP_TOOL_NAMES = Object.freeze([ "receiz_v125_attestation_domain_resolve", "receiz_v125_attestation_application_plan", "receiz_v125_attestation_application_apply", "receiz_v125_attestation_workflow_plan", "receiz_v125_attestation_workflow_apply", "receiz_v125_attestation_evidence_plan", "receiz_v125_attestation_evidence_apply", "receiz_v125_attestation_evaluation_plan", "receiz_v125_attestation_evaluation_apply", "receiz_v125_attestation_review_plan", "receiz_v125_attestation_review_apply", "receiz_v125_attestation_approval_plan", "receiz_v125_attestation_approval_apply", "receiz_v125_credential_issue_plan", "receiz_v125_credential_issue_apply", "receiz_v125_credential_lifecycle_plan", "receiz_v125_credential_lifecycle_apply", "receiz_v125_credential_currentness_resolve", "receiz_v125_pbi_ceremony_challenge_create", "receiz_v125_pbi_ceremony_approve", "receiz_v125_pbi_ceremony_receipt_issue", "receiz_v125_pbi_ceremony_receipt_verify", "receiz_v125_pbi_ceremony_challenge_redeem", "receiz_v125_credential_presentation_create", "receiz_v125_credential_presentation_verify", "receiz_v125_credential_presentation_handoff_resolve", "receiz_v125_subject_relationship_plan", "receiz_v125_subject_relationship_apply", "receiz_v125_subject_introduction_plan", "receiz_v125_subject_introduction_apply", "receiz_v125_subject_message_plan", "receiz_v125_subject_message_apply", "receiz_v125_subject_presence_plan", "receiz_v125_subject_presence_apply", "receiz_v125_subject_discovery_resolve", "receiz_v125_external_execution_plan", "receiz_v125_external_execution_execute", "receiz_v125_external_execution_resolve", "receiz_v125_external_execution_verify", ]); const READ_ONLY_SUFFIXES = ["_resolve", "_verify"]; const isReadOnly = (name) => READ_ONLY_SUFFIXES.some((suffix) => name.endsWith(suffix)); export const RECEIZ_V125_TRUST_MCP_REQUIRED_SCOPES = Object.freeze(Object.fromEntries(RECEIZ_V125_TRUST_MCP_TOOL_NAMES.map((name) => [ name, Object.freeze([isReadOnly(name) ? "receiz:proof.read" : "receiz:proof.write"]), ]))); function inputSchema(name) { const properties = { proofReference: text("Opaque trusted-host proof Reference; sealed bytes and private claims never enter model context."), selectedKai: text("Optional exact KKS uPulse selected for currentness or expiry evaluation."), }; if (!isReadOnly(name)) { properties.idempotencyKey = text("Stable semantic retry identity bound by the trusted host."); properties.confirmationDigest = text("Exact preview confirmation digest required before trusted-host execution."); } return object(properties, ["proofReference", ...(!isReadOnly(name) ? ["idempotencyKey"] : [])]); } const projectionAuthority = Object.freeze({ mcpIsProofAuthority: false, strongerTruth: "sealed-receiz-proof-object" }); const RESULT_REFERENCE_FIELDS = ["planReference", "proofReference", "resultReference", "sourceFamilyReference"]; const RESULT_DIGEST_FIELDS = ["confirmationDigest", "acceptedHead"]; const RESULT_TOKEN_FIELDS = ["status", "code", "missingBoundary"]; const RESULT_FIELDS = new Set([ ...RESULT_REFERENCE_FIELDS, ...RESULT_DIGEST_FIELDS, ...RESULT_TOKEN_FIELDS, "writesPerformed", "confirmationRequired", "authority", ]); const resultSchema = object({ ...Object.fromEntries(RESULT_REFERENCE_FIELDS.map((key) => [key, { type: "string", minLength: 1, maxLength: 512 }])), ...Object.fromEntries(RESULT_DIGEST_FIELDS.map((key) => [key, { type: "string", pattern: "^[0-9a-f]{64}$" }])), ...Object.fromEntries(RESULT_TOKEN_FIELDS.map((key) => [key, { type: "string", pattern: "^[A-Za-z][A-Za-z0-9_-]{0,127}$" }])), writesPerformed: { enum: [0, 1] }, confirmationRequired: { type: "boolean" }, authority: { const: projectionAuthority }, }, ["status", "writesPerformed", "authority"]); export const RECEIZ_V125_TRUST_MCP_TOOLS = Object.freeze(RECEIZ_V125_TRUST_MCP_TOOL_NAMES.map((name) => Object.freeze({ name, description: (name.startsWith("receiz_v125_subject_message_") ? "Supported thread effect: close only; encrypted message effects are rejected. " : "") + "Invoke one generic Receiz v125 proof operation through opaque trusted-host Reference custody. MCP is not authority; the enclosing sealed Receiz proof object, exact accepted heads, Receiz-ID/PBI authorship, and verified appends remain authority.", inputSchema: inputSchema(name), outputSchema: isReadOnly(name) ? { ...resultSchema, properties: { ...resultSchema.properties, writesPerformed: { const: 0 } } } : resultSchema, }))); function canonical(value) { if (value === null || typeof value === "string" || typeof value === "boolean" || typeof value === "number") return JSON.stringify(value); if (Array.isArray(value)) return `[${value.map(canonical).join(",")}]`; if (value && typeof value === "object") { const record = value; return `{${Object.keys(record).sort().map((key) => `${JSON.stringify(key)}:${canonical(record[key])}`).join(",")}}`; } throw new TypeError("V125_TRUST_MCP_CANONICAL_INPUT_INVALID"); } function requiredText(value, code) { if (typeof value !== "string" || value.length < 1 || value.length > 512 || value !== value.trim()) throw new TypeError(code); return value; } function optionalText(value, code) { return value === undefined ? null : requiredText(value, code); } export function assertReceizV125TrustMcpProjection(value, readOnly) { if (!value || typeof value !== "object" || Array.isArray(value) || Object.keys(value).some((key) => !RESULT_FIELDS.has(key))) { throw new TypeError("V125_TRUST_MCP_RESULT_INVALID"); } if (value.writesPerformed !== 0 && value.writesPerformed !== 1) throw new TypeError("V125_TRUST_MCP_RESULT_INVALID"); if (typeof value.status !== "string") throw new TypeError("V125_TRUST_MCP_RESULT_INVALID"); if (readOnly && value.writesPerformed !== 0) throw new TypeError("V125_TRUST_MCP_READ_ONLY_WRITES_FORBIDDEN"); for (const key of RESULT_REFERENCE_FIELDS) { if (key in value) requiredText(value[key], "V125_TRUST_MCP_RESULT_INVALID"); } for (const key of RESULT_DIGEST_FIELDS) { if (key in value && (typeof value[key] !== "string" || !/^[0-9a-f]{64}$/u.test(value[key]))) { throw new TypeError("V125_TRUST_MCP_RESULT_INVALID"); } } for (const key of RESULT_TOKEN_FIELDS) { if (key in value && (typeof value[key] !== "string" || !/^[A-Za-z][A-Za-z0-9_-]{0,127}$/u.test(value[key]))) { throw new TypeError("V125_TRUST_MCP_RESULT_INVALID"); } } if (("confirmationRequired" in value && typeof value.confirmationRequired !== "boolean") || ("authority" in value && canonical(value.authority) !== canonical(projectionAuthority))) { throw new TypeError("V125_TRUST_MCP_RESULT_INVALID"); } } export async function callReceizV125TrustMcpOperation(input) { if (!RECEIZ_V125_TRUST_MCP_TOOL_NAMES.includes(input.name)) { throw new TypeError("V125_TRUST_MCP_TOOL_UNKNOWN"); } const operation = input.name; const allowedFields = new Set(isReadOnly(operation) ? ["proofReference", "selectedKai"] : ["proofReference", "selectedKai", "idempotencyKey", "confirmationDigest"]); if (!input.args || typeof input.args !== "object" || Array.isArray(input.args) || Object.keys(input.args).some((key) => !allowedFields.has(key))) throw new TypeError("V125_TRUST_MCP_INPUT_INVALID"); const proofReference = requiredText(input.args.proofReference, "V125_TRUST_MCP_PROOF_REFERENCE_REQUIRED"); const selectedKai = optionalText(input.args.selectedKai, "V125_TRUST_MCP_KAI_INVALID"); if (selectedKai !== null && !/^(0|[1-9][0-9]*)$/u.test(selectedKai)) throw new TypeError("V125_TRUST_MCP_KAI_INVALID"); const idempotencyKey = isReadOnly(operation) ? null : requiredText(input.args.idempotencyKey, "V125_TRUST_MCP_IDEMPOTENCY_REQUIRED"); if (!input.host) { return Object.freeze({ status: "unavailable", code: "V125_TRUST_HOST_REQUIRED", missingBoundary: "trusted-host-proof-custody", writesPerformed: 0, authority: projectionAuthority, }); } if (!isReceizV125TrustMcpHost(input.host)) throw new TypeError("V125_TRUST_MCP_CANONICAL_HOST_REQUIRED"); if (input.runtimeScope) assertReceizV125TrustMcpHostScope(input.host, input.runtimeScope); const confirmationDigest = optionalText(input.args.confirmationDigest, "V125_TRUST_MCP_CONFIRMATION_INVALID"); const result = await input.host({ operation, proofReference, selectedKai, idempotencyKey, confirmationDigest }); assertReceizV125TrustMcpProjection(result, isReadOnly(operation)); return Object.freeze({ ...structuredClone(result), authority: projectionAuthority }); } //# sourceMappingURL=v125TrustOperations.js.map