@receiz/mcp-server
Version:
MCP server for agents building and verifying Receiz proof-native applications through the canonical Receiz SDK rails.
248 lines • 18.2 kB
JavaScript
import { ArtifactInputError, readAuthorizedUploadedArtifact } from "./uploadedArtifact.js";
import { createHash } from "node:crypto";
import { readFile, realpath, open, mkdtemp } from "node:fs/promises";
import { homedir } from "node:os";
import { basename, dirname, isAbsolute, join, relative, resolve } from "node:path";
import { createReceizNodeOfflineSealer } from "@receiz/sdk/offline/node";
import { verifyReceizOfflineSealedFile } from "@receiz/sdk/offline";
import { createReceizNodeOfflineKaiProofFactory } from "@receiz/sdk/offline/kai/node";
import { admitReceizKksV1ProofCoordinate } from "@receiz/sdk";
import { RECEIZ_SEALED_OUTPUT_URI } from "./sealedArtifactOutput.js";
// One proof process per MCP host, retaining the live monotonic sampler across
// calls. A tool invocation must not leave an additional idle process behind.
let kaiProofFactory;
export const RECEIZ_OFFLINE_SEAL_TOOLS = [
{ name: "receiz_offline_kai_proof", description: "MCP is not authority. Create and verify a full live KaiSigil Groth16 coordinate locally. No pulse override. An optional predecessor must be a complete valid proof coordinate; the consuming primitive still checks its expected causal head.",
inputSchema: { type: "object", properties: { previousCoordinate: { type: "object" } }, additionalProperties: false } },
{ name: "receiz_offline_seal_status", description: "MCP is not authority. Check local canonical signer and packaged proof resources. No network access.",
inputSchema: { type: "object", properties: {}, additionalProperties: false } },
{ name: "receiz_offline_seal_enroll", description: "MCP is not authority. Explicit one-time online canonical device enrollment. The private key remains in host custody. No login required.",
inputSchema: { type: "object", properties: { confirmEnrollment: { type: "boolean", const: true } }, required: ["confirmEnrollment"], additionalProperties: false } },
{ name: "receiz_offline_seal_file", description: "MCP is not authority. Seal a workspace file, an authorized uploaded/generated file, or exact caller-supplied text with the device-held signer. Canonically verifies a new private proof object. File references are transport only; text does not prove authorship or chat completeness. Existing workspace paths still require inputPath and outputPath. Uploaded files and text use a new private generated output path. After enrollment, sealing itself requires no network; attachment retrieval requires the authorized platform URL.",
inputSchema: { type: "object", properties: {
inputPath: { type: "string" }, outputPath: { type: "string" }, mimeType: { type: "string" },
file: { type: "object", properties: { download_url: { type: "string" }, file_id: { type: "string" }, mime_type: { type: "string" }, file_name: { type: "string" } },
required: ["download_url", "file_id"], additionalProperties: false },
text: { type: "string" }, filename: { type: "string" }, contentKind: { type: "string", enum: ["response", "conversation", "text"] },
}, additionalProperties: false },
outputSchema: { type: "object", properties: { artifactReference: { type: "string" }, artifactSha256: { type: "string" },
suggestedFilename: { type: "string" }, mimeType: { type: "string" }, byteLength: { type: "integer" } },
required: ["artifactReference", "artifactSha256", "suggestedFilename", "mimeType", "byteLength"] },
_meta: { "openai/fileParams": ["file"], ui: { resourceUri: RECEIZ_SEALED_OUTPUT_URI },
"openai/outputTemplate": RECEIZ_SEALED_OUTPUT_URI } },
{ name: "receiz_offline_artifact_chunk", description: "MCP is not authority. App-only exact sealed output transport. Reopens a recently sealed device-held proof object, checks its exact digest, then returns a bounded byte segment to the component. When the host cannot download the file, the component may request a short-lived first-party Receiz download ticket for those exact chunks; the ticket conveys no proof authority.",
inputSchema: { type: "object", properties: { transferToken: { type: "string" }, artifactReference: { type: "string" },
artifactSha256: { type: "string" }, offset: { type: "integer", minimum: 0 },
prepareDownload: { type: "boolean" }, attemptIds: { type: "array", items: { type: "string" } },
byteLength: { type: "integer", minimum: 1 } }, additionalProperties: false },
outputSchema: { type: "object", properties: { offset: { type: "integer" }, nextOffset: { type: "integer" },
byteLength: { type: "integer" }, artifactSha256: { type: "string" }, filename: { type: "string" },
mimeType: { type: "string" }, mcpAuthority: { type: "boolean" }, bytesBase64: { type: "string" },
receizTransportAttemptId: { type: "string" }, downloadUrl: { type: "string" } },
required: ["offset", "nextOffset", "byteLength", "artifactSha256", "filename", "mimeType", "mcpAuthority"] },
_meta: { ui: { visibility: ["app"] }, "openai/visibility": "private", "openai/widgetAccessible": true } },
{ name: "receiz_offline_verify_file", description: "MCP is not authority. Verify complete workspace artifact bytes offline using the canonical SDK verifier.",
inputSchema: { type: "object", properties: { inputPath: { type: "string" } }, required: ["inputPath"], additionalProperties: false } },
];
/** A reusable application boundary: only exact source bytes enter the SDK sealer.
* The sealed file is authoritative; this result is a locator and projection. */
export async function sealReceizSourceBytes(input, options = {}) {
if (!(input.bytes instanceof Uint8Array) || !input.bytes.length || !input.filename.trim())
throw Error("offline_seal_input_invalid");
const workspace = await realpath(options.workspace ?? process.env.RECEIZ_OFFLINE_WORKSPACE ?? process.cwd());
const directory = resolve(options.directory ?? process.env.RECEIZ_OFFLINE_SEAL_DIRECTORY ?? join(homedir(), ".receiz", "offline-seal"));
async function canonicalPath(path) {
try {
return await realpath(path);
}
catch (error) {
if (error.code !== "ENOENT")
throw error;
const parent = dirname(path);
if (parent === path)
throw error;
return join(await canonicalPath(parent), basename(path));
}
}
const custodyRoot = await canonicalPath(directory);
const workspaceWithinCustody = relative(custodyRoot, workspace);
if (workspaceWithinCustody === "" || (!workspaceWithinCustody.startsWith("..") && !isAbsolute(workspaceWithinCustody))) {
throw Error("offline_seal_path_outside_workspace");
}
const identity = options.identity !== undefined ? options.identity
: process.env.RECEIZ_SUBJECT_IDENTITY_PATH ? { artifactPath: process.env.RECEIZ_SUBJECT_IDENTITY_PATH, passphrase: process.env.RECEIZ_SUBJECT_IDENTITY_PASSPHRASE ?? "" } : null;
const sealer = options.sealer ?? await createReceizNodeOfflineSealer({ directory,
...(identity ? { identityArtifactPath: identity.artifactPath, identityPassphrase: identity.passphrase ?? "" } : {}),
...(options.fetch ? { fetch: options.fetch } : {}) });
const safeName = basename(input.filename).replace(/[^a-zA-Z0-9._-]/g, "_").slice(0, 160);
if (!safeName || safeName === "." || safeName === "..")
throw Error("offline_seal_input_invalid");
const sealed = await sealer.seal({ bytes: input.bytes, filename: safeName,
...(input.mimeType ? { mimeType: input.mimeType } : {}) });
if (!sealed.verification.ok)
throw Error("offline_seal_output_verification_failed");
const outputDirectory = await mkdtemp(join(workspace, ".receiz-sealed-"));
const outputName = basename(sealed.filename);
if (!outputName || outputName === "." || outputName === "..")
throw Error("offline_seal_output_invalid");
const outputPath = join(outputDirectory, outputName);
const output = await open(outputPath, "wx", 0o600);
try {
await output.writeFile(sealed.artifactBytes);
await output.sync();
}
finally {
await output.close();
}
const artifactSha256 = createHash("sha256").update(sealed.artifactBytes).digest("hex");
// Device material host reopens this exact relative file and re-verifies the
// enclosing artifact. The reference is a locator, never proof authority.
const artifactReference = `receiz:file:${artifactSha256}:${relative(workspace, outputPath)}`;
return { outputPath, artifactReference, artifactSha256,
suggestedFilename: sealed.filename, mimeType: sealed.mimeType, byteLength: sealed.artifactBytes.length,
verification: sealed.verification, mcpAuthority: false, strongerTruth: "sealed-receiz-proof-object" };
}
export async function sealUploadedArtifact(raw, options = {}) {
const source = await readAuthorizedUploadedArtifact(raw, options);
// OpenAI may omit file_name. Preserve a native image carrier when its
// declared MIME gives an unambiguous extension; MIME is still only a hint.
const extension = source.mimeType === "image/png" ? ".png"
: source.mimeType === "image/jpeg" ? ".jpg"
: source.mimeType === "image/gif" ? ".gif"
: source.mimeType === "image/webp" ? ".webp"
: source.mimeType === "application/pdf" ? ".pdf" : "";
const filename = source.filename === "attachment" ? `attachment${extension}` : source.filename;
const sealed = await sealReceizSourceBytes({ bytes: source.bytes, filename,
...(source.mimeType ? { mimeType: source.mimeType } : {}) }, options);
return { ...sealed, sourceTransport: source.transport, sourceKind: "authorized-upload" };
}
export async function sealSuppliedText(raw, options = {}) {
if (!raw || typeof raw !== "object" || Array.isArray(raw))
throw Error("offline_seal_arguments_invalid");
const args = raw;
if (Object.keys(args).some(key => !["text", "filename", "contentKind", "mimeType"].includes(key))
|| (args.mimeType !== undefined && (typeof args.mimeType !== "string" || !args.mimeType.trim() || /[\r\n]/.test(args.mimeType)))
|| typeof args.text !== "string" || !args.text || Buffer.byteLength(args.text, "utf8") > 512 * 1024
|| !["response", "conversation", "text"].includes(String(args.contentKind))
|| (args.filename !== undefined && (typeof args.filename !== "string" || !/^[a-zA-Z0-9._-]{1,120}$/.test(args.filename)))) {
throw Error("offline_seal_arguments_invalid");
}
const filename = typeof args.filename === "string" ? args.filename : `${args.contentKind}.txt`;
const bytes = Buffer.from(args.text, "utf8");
const sealed = await sealReceizSourceBytes({ bytes, filename, mimeType: typeof args.mimeType === "string" ? args.mimeType : "text/plain" }, options);
return { ...sealed, sourceKind: "caller-supplied-text", contentKind: args.contentKind,
sourceTransport: { byteLength: bytes.length, sha256: createHash("sha256").update(bytes).digest("hex"), authority: false },
authorshipVerified: false, conversationCompletenessVerified: false };
}
export async function callReceizOfflineSealTool(name, raw, options = {}) {
if (!raw || typeof raw !== "object" || Array.isArray(raw))
throw new Error("offline_seal_arguments_invalid");
const args = raw;
const allowed = name === "receiz_offline_seal_enroll" ? ["confirmEnrollment"]
: name === "receiz_offline_kai_proof" ? ["previousCoordinate"]
: name === "receiz_offline_seal_file" ? ["inputPath", "outputPath", "mimeType", "file", "text", "filename", "contentKind"]
: name === "receiz_offline_verify_file" ? ["inputPath"] : [];
if (Object.keys(args).some(key => !allowed.includes(key)))
throw new Error("offline_seal_arguments_invalid");
if (name === "receiz_offline_seal_file" && Object.hasOwn(args, "file")) {
// ChatGPT may send these schema-advertised hints with its selected file.
// The authorized attachment carries the actual bytes, name, and MIME;
// caller hints never override that stronger source.
if (Object.keys(args).some(key => !["file", "filename", "mimeType"].includes(key))
|| (args.filename !== undefined && typeof args.filename !== "string")
|| (args.mimeType !== undefined && typeof args.mimeType !== "string"))
throw Error("offline_seal_arguments_invalid");
return sealUploadedArtifact({ file: args.file }, options);
}
if (name === "receiz_offline_seal_file" && Object.hasOwn(args, "text")) {
if (Object.keys(args).some(key => !["text", "filename", "contentKind", "mimeType"].includes(key)))
throw Error("offline_seal_arguments_invalid");
return sealSuppliedText(args, options);
}
if (name === "receiz_offline_seal_file" && Object.keys(args).some(key => !["inputPath", "outputPath", "mimeType"].includes(key))) {
throw Error("offline_seal_arguments_invalid");
}
if (name === "receiz_offline_kai_proof") {
const previous = args.previousCoordinate === undefined ? undefined : await admitReceizKksV1ProofCoordinate(args.previousCoordinate);
const createCoordinate = await (kaiProofFactory ??= createReceizNodeOfflineKaiProofFactory());
const coordinate = await createCoordinate({ previousKaiSigilProofHead: previous?.kaiSigil.proofHead ?? null });
await admitReceizKksV1ProofCoordinate(coordinate, {
expectedPreviousKaiSigilProofHead: previous?.kaiSigil.proofHead ?? null,
...(previous ? { minimumExclusiveKaiUpulse: previous.kaiUpulse } : {}),
});
return { coordinate, mcpAuthority: false, networkRequired: false };
}
const directory = resolve(options.directory ?? process.env.RECEIZ_OFFLINE_SEAL_DIRECTORY ?? join(homedir(), ".receiz", "offline-seal"));
// Resolve existing ancestors too: custody may not exist before enrollment.
async function canonicalPath(path) {
try {
return await realpath(path);
}
catch (error) {
if (error.code !== "ENOENT")
throw error;
const parent = dirname(path);
if (parent === path)
throw error;
return join(await canonicalPath(parent), basename(path));
}
}
const custodyRoot = await canonicalPath(directory);
const workspace = await realpath(options.workspace ?? process.env.RECEIZ_OFFLINE_WORKSPACE ?? process.cwd());
function inside(root, path) { const rel = relative(root, path); return rel === "" || (!rel.startsWith("..") && !isAbsolute(rel)); }
async function filePath(key, output = false) {
const value = args[key];
if (typeof value !== "string" || !value.trim())
throw new Error("offline_seal_path_required");
const candidate = resolve(workspace, value);
const path = output ? join(await realpath(dirname(candidate)), basename(candidate)) : await realpath(candidate);
if (!inside(workspace, path) || inside(custodyRoot, path))
throw new Error("offline_seal_path_outside_workspace");
return path;
}
if (name === "receiz_offline_verify_file") {
const inputPath = await filePath("inputPath");
const bytes = await readFile(inputPath);
try {
return { verification: await verifyReceizOfflineSealedFile({ bytes, filename: basename(inputPath) }), mcpAuthority: false };
}
catch {
throw new ArtifactInputError("artifact_verification_unavailable", "canonical_verification");
}
}
const identity = options.identity !== undefined ? options.identity
: process.env.RECEIZ_SUBJECT_IDENTITY_PATH ? { artifactPath: process.env.RECEIZ_SUBJECT_IDENTITY_PATH, passphrase: process.env.RECEIZ_SUBJECT_IDENTITY_PASSPHRASE ?? "" } : null;
const sealer = options.sealer ?? await createReceizNodeOfflineSealer({ directory,
...(identity ? { identityArtifactPath: identity.artifactPath, identityPassphrase: identity.passphrase ?? "" } : {}),
...(options.fetch ? { fetch: options.fetch } : {}) });
if (name === "receiz_offline_seal_status")
return { ready: await sealer.ready(), networkRequiredForSealing: false, mcpAuthority: false };
if (name === "receiz_offline_seal_enroll") {
if (args.confirmEnrollment !== true)
throw new Error("offline_seal_enrollment_confirmation_required");
await sealer.enroll();
return { ready: await sealer.ready(), privateKeyExposed: false, mcpAuthority: false };
}
if (name !== "receiz_offline_seal_file")
throw new Error("offline_seal_tool_unknown");
if (args.mimeType !== undefined && typeof args.mimeType !== "string")
throw new Error("offline_seal_arguments_invalid");
const inputPath = await filePath("inputPath");
const outputPath = await filePath("outputPath", true);
const sealed = await sealer.seal({ bytes: await readFile(inputPath), filename: basename(inputPath), ...(typeof args.mimeType === "string" ? { mimeType: args.mimeType } : {}) });
if (!sealed.verification.ok)
throw Error("offline_seal_output_verification_failed");
const output = await open(outputPath, "wx", 0o600);
try {
await output.writeFile(sealed.artifactBytes);
await output.sync();
}
finally {
await output.close();
}
const artifactSha256 = createHash("sha256").update(sealed.artifactBytes).digest("hex");
return { outputPath, artifactSha256, artifactReference: `receiz:file:${artifactSha256}:${relative(workspace, outputPath)}`,
suggestedFilename: sealed.filename, mimeType: sealed.mimeType, byteLength: sealed.artifactBytes.length,
verification: sealed.verification, mcpAuthority: false, strongerTruth: "sealed-receiz-proof-object" };
}
//# sourceMappingURL=offlineSealing.js.map