MCP server
Let an AI agent send documents for signature and track them — Claude Code, Claude Desktop, Cursor, VS Code or your own agent, with your API key. The agent sends and tracks; every signer signs themselves.
wesign.now runs a remote Model Context Protocol server. Connect an AI agent to it and the agent can send a PDF or a template for signature, follow every signer, remind or withdraw, and fetch the links to the sealed PDF and its audit trail — on the same contract as the REST API: the same keys, monthly caps, rate limit, errors and API log.
https://www.wesign.now/api/mcpStreamable HTTP, one endpoint, an API key on every request
(Authorization: Bearer wsk_live_…). The same server also answers at
https://api.wesign.now/mcp.
The agent sends; people sign. No tool signs anything. Each signer signs
themselves from the personal link wesign.now emails them — a simple
electronic signature (SES) — or with an SMS code to their phone as well, an
advanced electronic signature (AES). The agent never receives a signing link
unless you ask to deliver the links yourself (send_emails: false).
1 · Get your API key
- 1. Sign up free.
- 2. Settings → Company → Developer settings → Turn on (on a personal account: Settings → Profile).
- 3. Settings → Developers → Create API key.
- 4. Call
GET /v1/mewith the key. It sends nothing and shows the key works.
Create one key per agent and name it after the client ("Claude Code — Anna"):
the API log then shows which agent made each call, and
revoking one key stops one agent. Keep the key out of files you commit: the
setups below read it from the environment variable WESIGN_API_KEY or ask
for it (VS Code).
export WESIGN_API_KEY="wsk_live_…" # paste the whole key here2 · Connect your client
Claude Code
claude mcp add --transport http wesign https://www.wesign.now/api/mcp \
--header "Authorization: Bearer $WESIGN_API_KEY"Add --scope user to use it in every project. To share the setup with your
team without sharing a key, put it in the project's .mcp.json, which reads
each person's own variable:
{
"mcpServers": {
"wesign": {
"type": "http",
"url": "https://www.wesign.now/api/mcp",
"headers": { "Authorization": "Bearer ${WESIGN_API_KEY}" }
}
}
}Claude Desktop
Claude Desktop's own connector settings sign in with OAuth, which this
server does not offer yet. Connect it through
mcp-remote, a community bridge
that passes your key as a header. In claude_desktop_config.json:
{
"mcpServers": {
"wesign": {
"command": "npx",
"args": [
"-y",
"mcp-remote",
"https://www.wesign.now/api/mcp",
"--header",
"Authorization:${WESIGN_AUTH_HEADER}"
],
"env": { "WESIGN_AUTH_HEADER": "Bearer wsk_live_…" }
}
}
}The header is written without a space after the colon on purpose: on
Windows, Claude Desktop does not escape spaces inside args. Restart Claude
Desktop after saving.
Cursor
In .cursor/mcp.json (one project) or ~/.cursor/mcp.json (every project):
{
"mcpServers": {
"wesign": {
"url": "https://www.wesign.now/api/mcp",
"headers": { "Authorization": "Bearer ${env:WESIGN_API_KEY}" }
}
}
}VS Code
In .vscode/mcp.json. VS Code asks for the key when the server first
starts, so it is not written into the file:
{
"inputs": [
{ "type": "promptString", "id": "wesign-key", "description": "wesign.now API key", "password": true }
],
"servers": {
"wesign": {
"type": "http",
"url": "https://www.wesign.now/api/mcp",
"headers": { "Authorization": "Bearer ${input:wesign-key}" }
}
}
}Your own agent
Any MCP client that speaks Streamable HTTP and can send a header connects
with the URL and Authorization: Bearer <key>. The server is stateless: no
session id, every request stands alone, answers are JSON (no event stream).
GET and DELETE answer 405.
Then ask the agent to call whoami: it sends nothing and shows the
workspace, the plan and this month's API documents.
Tools
| Tool | What it does | REST equivalent |
|---|---|---|
whoami | The key's workspace, plan, capabilities, SMS allowance and this month's API documents against the cap. Sends nothing, costs no rate-limit token. | GET /v1/me |
list_templates | The workspace's templates; instantiable: true ones can be sent. | GET /v1/templates |
get_template | A template's input schema: recipient slots and field_values. | GET /v1/templates/{id} |
send_for_signature | Sends a PDF (file_url or file_base64) to 1–20 signers. placement auto_append (default) adds a signature page; anchors uses markers in the PDF. A signer with phone_e164 also gets an SMS code (AES). | POST /v1/signing-requests |
send_from_template | Fills a locked template and sends it; review: true stages it for a person to send from the app, validate_only: true only checks. Enterprise. | POST /v1/templates/{id}/instantiate |
list_signing_requests | One row per signer, newest first, filtered by status, signer email, document or date. | — |
get_signing_request | A document's overall status and every signer's (document_id), or one signer with recent events (signing_request_id). | GET /v1/documents/{id}, GET /v1/signing-requests/{id} |
send_reminder | Emails one signer their link again. | POST /v1/signing-requests/{id}/remind |
withdraw_signing_request | Withdraws one signer's request; their link stops working. Cannot be undone. | POST /v1/signing-requests/{id}/withdraw |
get_signed_document | Once everyone has signed: signed_pdf_url and audit_trail_url, fetched with the same key. No file content. | GET /v1/documents/{id}/signed, /audit-trail |
A signing request is one signer: to remind or withdraw a whole document, the
agent calls the tool once per signer (get_signing_request with the
document_id lists them).
The send, withdraw and reminder tools carry MCP annotations that mark them
as acting outside the conversation (destructiveHint / openWorldHint), so
a client that honours them asks you before each call.
Limits and caps
-
Monthly cap. A document sent by an agent counts like one sent over REST, once per document whatever the number of signers:
- Free: 10 documents a month, the plan's own cap
- Branded: 100 documents a month through the API
- Enterprise: no cap
Past the cap, a send answers
402 api_monthly_limit(ortier_required, the plan's overall cap) withmeta: { tier, cap, used }. -
Rate limit. Every tool call except
whoamitakes one token from the key's 60 requests a minute, the same bucket as the key's REST calls. A refusal is429 rate_limitedwithretry_after_sec. Connecting and listing the tools take no token. -
Per address. Before any key is read, one IP address may send 120 requests a minute to the MCP server, every message counted (connecting and listing included). Over it, the HTTP answer is
429 rate_limitedwith aRetry-After; see Rate limits. -
Templates.
send_from_templateneeds the Enterprise plan and answers402 enterprise-requiredon the others.list_templatesandget_templatework on every plan. -
The PDF.
file_url(https, a plain GET that answers the PDF itself) up to 25 MB, as on REST.file_base64suits small files: the whole request is capped at 4.5 MB, so about 3 MB of PDF; send larger files by URL. -
Retries. A send without
idempotency_keygets one derived from its exact content, so an identical call within 24 hours answers the first result withreplayed: trueand sends nothing again (see Idempotency). To send the same content twice on purpose, pass a newidempotency_key.
Errors
A key that is missing, unknown, revoked or limited to the embedded scope
is refused before any tool runs: HTTP 401 invalid_key with a
WWW-Authenticate: Bearer challenge; a key used from an address its IP
allowlist does not hold is 403 ip_not_allowed
(Authentication).
Every other refusal is a tool result with isError: true whose content is
the REST error plus its HTTP status and the request id:
{
"error": "Monthly API limit reached (100 documents/month through the API on the branded tier). Upgrade to send more.",
"code": "api_monthly_limit",
"status": 402,
"meta": { "tier": "branded", "cap": 100, "used": 100 },
"request_id": "fra1::…"
}Branch on code; the codes are the REST API's (Errors).
Quote request_id to support with the time of the call.
Safety
- No signing, no signing links. No tool signs, and results carry no
signing link (a link is the signer's own credential). The one exception
is the result of a send with
send_emails: false, where you asked to deliver the links yourself: hand each link to its own signer. - Results are data. Document names, template names, signer names, metadata and audit events are written by other people. The server tells the agent to treat them as data, never as instructions, and returns them as JSON fields only.
- One key per agent. A key can do over MCP exactly what it can do over REST. Revoke it in Settings → Developers and the agent is cut off at once.
The API log
Every tool call appears in Settings → Developers → API log, kept 30 days:
POST /mcp/send_for_signature with its status, error code, key and
request id, the same id the response's X-Request-Id header carries. A
refused key appears as /mcp. No request or response body is stored.
Integrator FAQ
Short answers an integrating app, or its AI assistant, can quote — where to start, the sandbox, SDK and the MCP server, signing-link hosts, observers, AES by SMS, the SMS allowance, checking phone numbers, languages, signer names, parallel signing, field keys and dates, webhooks and key scopes, and how to reach us.
API overview
Base URL, authentication, versioning policy, and the full map of v1 resources.
