Why this exists

Generating a PDF is reversible. Sending it for signature is not. ReleaseGate puts a visible checkpoint between those two actions.

What it does

A user starts with a plain-language request. ReleaseGate checks that the document is nonbinding, creates a versioned preview, and prepares the PDF through Foxit's official MCP server. The app shows the exact PDF SHA-256 before anything can move to eSign.

The signer must review that document and approve the matching hash. ReleaseGate then calls the Foxit eSign API directly and opens a short-lived handoff to Foxit's signing page. The signing URL never appears in logs or project artifacts.

After the person signs, ReleaseGate downloads the signed output with a strict size limit, accepts only PDF or ZIP bytes, hashes the result, clears the local bytes, and permanently deletes the remote envelope. The demo run reached EXECUTED and completed that cleanup path.

How it was built

The app runs on Node.js 22 and uses @foxitsoftware/foxit-pdf-api-mcp-server for PDF preparation. Signing uses Foxit's unified eSign REST API because the sponsor intentionally left signing outside the MCP tool catalog.

The local service listens only on loopback. It checks Host and Origin, bounds request and upstream response sizes, coalesces duplicate PDF and signing work, and keeps capability URLs behind expiring one-time paths. Temporary MCP documents and eSign envelopes have explicit cleanup paths.

The hard part

The difficult part was state, not PDF layout. Approval had to stay attached to the exact bytes while asynchronous MCP jobs, browser handoff, signing status, retries, and deletion happened at different times. Treating the PDF hash as the approval boundary made those transitions testable.

What I learned

A useful agent boundary is concrete: reversible document work can stay in the tool loop, while signature authority remains with the person who can inspect the final bytes.

Built With

Share this project:

Updates