MCP server
The agent drives. You approve.
The whole suite is designed for an agent-first workflow. sign-cli is the most concrete expression of that: every CLI command worth automating is exposed as an MCP tool over stdio, so any MCP-aware client (Claude Code, Cursor, Codex) can drive sending, tracking, detection, stamping, and verification — while the actual signing remains gated behind a per-signer human gesture.
Start the server
# Boots the MCP server on stdio. Wire it into any MCP-aware client.
sign mcp serve
# Or via npx, no install required:
npx sign-cli mcp serve
# Discover the catalog without spinning up the server:
sign mcp tools --format markdown Wire it into Claude Code
Add to your ~/.config/claude-code/settings.json (or the project-level .claude/settings.json):
{
"mcpServers": {
"sign-cli": {
"command": "npx",
"args": ["-y", "sign-cli", "mcp", "serve"]
}
}
} After that, every sign-cli MCP tool shows up inside Claude Code. Ask the agent to "detect the signature field on contract.pdf and send it to alice@acme.com and bob@beta.com via SignWell" and it will call the right tools with the right arguments.
Wire it into Cursor
Cursor's MCP config lives at ~/.cursor/mcp.json:
{
"mcpServers": {
"sign-cli": {
"command": "npx",
"args": ["-y", "sign-cli", "mcp", "serve"],
"env": {}
}
}
} Read-only mode for sandboxed agents
Run with --read-only true to block every mutating tool with a
FORBIDDEN_READ_ONLY error. Useful for letting an agent inspect and
track without any side effects. Pair with --tool to allow-list a
specific subset, or --capability to disable resources/prompts.
sign mcp serve --read-only true \
--tool request_show --tool audit_verify --tool pdf_detect_signature_field \
--emit-events ./mcp-events.ndjson \
--emit-events-redact true Available tools — 19 in total
Every tool ships with an inputSchema and (where applicable) an
outputSchema. request_watch also streams
notifications/progress when the client supplies a
progressToken. Don't hardcode this list — call
sign mcp tools for the live catalog.
Read-only (safe to call without approval)
| Tool | What it does |
|---|---|
| signer_list | List pending local-provider requests where the signer is a recipient. |
| signer_fetch_document | Read (and optionally save) the unsigned PDF for a request. Requires the per-signer token. |
| request_show | Enriched snapshot: approvals, signedBy[], declinedBy, and a nextSteps[] hint array. |
| request_status | Poll the provider for the latest status of a request. |
| request_watch | Poll until terminal (completed/declined/canceled/timeout). Streams progress notifications. |
| audit_verify | Verify the hash-chained audit log for a request; reports any break. |
| audit_scan | Cross-request audit search with filters (request id, event type, time window). |
| pdf_detect_signature_field | Ranked signature-field candidates (AcroForm /Sig + anchor text). Read-only. |
| pdf_detect_date_field | Date-anchor candidates with an alreadyFilled flag to avoid overwrites. |
| pdf_inspect_signatures | Parse a signed PDF's PKCS#7: /ByteRange digest match, signer certs, trust label. |
| profile_list | List named profiles (provider, dbPath, credentials bundle) and the active one. |
| profile_show | Show resolved profile state. Credentials redacted by default; show_secrets: true to reveal. |
Mutating (gated by --read-only true)
| Tool | What it does |
|---|---|
| sign | Sign a local request as the holder of a per-signer token. Requires --provider local. |
| signer_decline | Decline a local request as the token holder. Records a request.signer_declined event. |
| signer_reissue_token | Mint a fresh token in place of an expired/lost one. Tied to the original signer email. |
| pdf_stamp_text | Stamp plain text (dates, names) onto a PDF without producing a PAdES envelope. |
| preview | Stamp a signature image or rendered name onto a PDF — no envelope, no audit mutation. Iterate before committing. |
| document | One-shot DOCX|PDF → sealed PDF: convert, auto-place, stamp, PAdES-seal, verify chain. |
| request_receipt | Export a cryptographically-signed receipt bundle (manifest + detached signature + cert chain). |
HTTP API for non-MCP clients
Every MCP tool has a 1:1 HTTP equivalent under /v1/*, served by
sign serve. Same input shape, same path-traversal guards, same
read-only gating. Useful for agents and integrations that speak REST rather than MCP.
# Boot the HTTP API. Auth via SIGN_HTTP_BEARER_TOKEN.
sign serve --read-only true --rate-limit 5
# Discover the route catalog:
curl http://localhost:8787/v1/openapi.json Profiles for credential isolation
Named profiles bundle provider, dbPath,
strictProvider, and a credentials block
(with {{env:VAR}} references that point at shell-managed
secrets). The agent never holds API keys — it activates a profile by name; the credentials
resolve from environment variables at call time.
# Create a profile that reads its API key from the shell environment
sign profile init --name prod \
--provider signwell --db "~/.sign-cli/prod.db" \
--strict-provider true
sign profile set --name prod \
--key credentials.SIGNWELL_API_KEY --value "{{env:SIGNWELL_API_KEY}}"
# Activate per-call
sign --profile prod request show --request-id req_abc
# Or implicitly via a project-level sign-profile.json (git/npm-style discovery) What the agent can't do
- Sign on a human's behalf. The
signtool requires an explicit per-signer token. Tokens are scoped to one signer's email and expire after a configurable TTL. - Modify past audit events. The audit chain is hash-chained with append-only triggers; tampering breaks
audit_verify. - Bypass the timestamp anchor. RFC 3161 anchors are external — the agent can't forge one.
- Read or write paths outside the working directory. Every input/output path runs through
validateDocumentPath/validateOutputPath. Opt out withSIGN_ALLOW_ABSOLUTE_DOCS=1. - Leak its credentials. Profile-injected secrets flow through the error-message redactor — even custom keys never show up in stack traces.
Why this matters
Most "agent-friendly" SaaS products are agent-friendly in the sense that they have an API. They aren't agent-safe. The MCP boundary here is designed so an agent can do all the operational work (detecting, sending, stamping previews, tracking, verifying, reporting) while the actual legal commitment — the signature — stays gated behind a human gesture.
That's a meaningful architectural choice for anyone deploying agents into ops workflows. You get the productivity wins of automation without the legal liability of a hallucinating model accidentally executing a contract.