turbosign-mcp
Enables sending PDFs for e-signature via the TurboSign API, with tools for sending, reviewing, tracking status, downloading signed documents, voiding, resending, and managing credentials.
README
turbosign-mcp
Send PDFs out for signature by asking for it.
> send ~/contracts/nda.pdf to Bob Smith <bob@example.com> for signature
A thin MCP server over the TurboSign e-signature API. It speaks stdio, so any MCP client can launch it — Claude Code, Hermes Agent, anything else — with no container, no port, and no daemon.
What it does
| Tool | |
|---|---|
turbosign_send |
Send a document for signature. Emails the recipients. |
turbosign_review |
Same, but emails nobody and returns a preview URL. |
turbosign_status |
Has anyone signed yet? |
turbosign_download |
Fetch the completed signed PDF. |
turbosign_void |
Cancel a request that has not completed. |
turbosign_resend |
Chase a recipient. |
turbosign_audit_trail |
Hash-chained history — prepared, sent, viewed, signed. |
turbosign_setup / turbosign_configure / turbosign_whoami |
Getting a machine credentialled. |
Install
git clone https://github.com/disciplin-run-org/turbosign-mcp
cd turbosign-mcp
python3 -m venv .venv
.venv/bin/pip install -e .
Then point your MCP client at it. For Claude Code, the bundled .mcp.json
already does this:
{
"mcpServers": {
"turbosign": { "command": ".venv/bin/turbosign-mcp" }
}
}
Use an absolute path to .venv/bin/turbosign-mcp if your client does not
resolve relative commands from the project directory.
Getting credentialled
Ask the agent where to start:
> turbosign_setup()
It reports what is missing and gives you the URL to create a TurboDocx account and the navigation to the API key. Then save the key one of two ways.
From a terminal — the key never enters the conversation:
.venv/bin/turbosign-mcp configure
Prompts for the key with the echo off, verifies it against the live API, and
writes it owner-only to ~/.turbosign-mcp/credentials.json. Nothing is printed
but a masked fingerprint. Use this for any key you would mind seeing in a log.
There is deliberately no --api-key flag: a secret on a command line is
recorded in your shell history and is visible to every other user on the
machine via ps. Passing one is refused with an explanation rather than
silently ignored. For automated provisioning use --api-key-file, and
--org-id / --sender-email to skip the prompts.
Or through the agent, if convenience wins:
> turbosign_configure(api_key="...", org_id="...", sender_email="you@example.com")
Same verification, same store. The trade-off is that the key travels through the agent's context and lands in that conversation's transcript on disk — fine for a scoped key on a test account, not fine for a long-lived one or for a session token that can do everything your user can.
Either way the credentials are checked against the live API before they are saved, so a mistyped key fails at setup rather than on your first real send. The server re-reads the store on every call, so there is nothing to restart.
turbosign_whoami() shows which account a machine is sending as — worth having
when the server is installed on several machines with different accounts.
Credentials never live in this repo
The store is at ~/.turbosign-mcp/credentials.json — outside the working
tree, so a credential cannot be committed by accident even if .gitignore
were wrong. .gitignore covers credentials.json, .env, *.pem and *.key
anyway, for the case where someone puts one in the tree deliberately. The test
suite needs no credentials, and its fixtures are obviously fake.
As a backstop that does not depend on anyone being careful, this repo has GitHub secret scanning and push protection enabled — a push carrying a recognised key pattern is rejected rather than published.
Credentials resolve in this order
TURBODOCX_*environment variables~/.turbosign-mcp/credentials.json- Neither — the server still runs and still offers the setup tools
The environment always wins. On an unattended box where the harness injects
the key, it never passes through the agent's context and no tool call can
overwrite it. turbosign_configure is the interactive path for a machine
someone is sitting at.
The trade-off, stated plainly: anything you pass to turbosign_configure
travels through the agent's context and, on a supervised agent, across its
approval surface. That is fine for interactive setup. For unattended
instances, prefer the environment.
Testing: there is no sandbox
TurboSign has exactly one environment, and it is production. There is no test
host, no sandbox key and no dry-run flag — the "free sandbox" on the vendor's
marketing page means the free tier (5 signatures a month) on the live API. Every
turbosign_send reaches a real inbox, lands in a real audit trail, and cannot
be recalled, only voided.
So the server provides the rehearsal the API does not. Work up this ladder on any new machine, new document layout, or new account:
| Emails anyone? | ||
|---|---|---|
| 1 | turbosign_whoami(verify=True) — credentials work, API reachable |
No |
| 2 | turbosign_review(...) — same code path as send, preview URL back |
No |
| 3 | turbosign_send(...) to your own address first |
Yes |
Rung 2 is the important one: it uploads the document, parses the recipients, places the fields and passes the API's own validation — everything a send does except the send. Open the preview URL and look at where the boxes landed.
These instructions ship inside the server, so any MCP client that reads
get_instructions() gets them too, not just readers of this file.
If you are embedding this server in an agent host, gate turbosign_send
behind human approval, and consider gating turbosign_void as well —
cancelling someone's pending signature request is equally irreversible. Leave
turbosign_review ungated: it is the safe rehearsal, and gating it removes the
reason to prefer it.
Where the signature boxes go
By default (placement="auto") the server reads the PDF and decides:
- Anchors, if the document has them. Text like
{Signature1},{Date1}or{Initial2}is replaced in place by TurboSign. The trailing digit picks the recipient. Exact placement, no geometry involved. - Geometry, if it does not. A signature and date box per recipient at the foot of the last page.
So a document authored with anchors gets exact placement for free, and an arbitrary PDF still works. The response always reports which strategy was used.
Override with placement="anchor" (fail rather than fall back),
placement="coordinates", or pass a fields array for full control.
turbosign_review() takes the same arguments as turbosign_send() but emails
nobody and hands back a preview URL. Worth doing the first time you send a new
kind of document.
Configuration
Every setting is optional; the three credentials are needed before a send.
| Variable | Default | |
|---|---|---|
TURBODOCX_API_KEY |
— | Bearer token |
TURBODOCX_ORG_ID |
— | x-rapiddocx-org-id header |
TURBODOCX_SENDER_EMAIL |
— | Reply-to; the API rejects sends without it |
TURBODOCX_SENDER_NAME |
API key's name | Shown in the request emails |
TURBODOCX_BASE_URL |
https://api.turbodocx.com |
|
TURBODOCX_APP_URL |
https://app.turbodocx.com |
Console, for turbosign_setup |
TURBODOCX_SIGNUP_URL |
https://www.turbodocx.com |
|
TURBOSIGN_HOME |
~/.turbosign-mcp |
Credential store location |
TURBOSIGN_ALLOWED_DIRS |
$HOME |
Roots documents may be sent from |
TURBOSIGN_MAX_FILE_MB |
10 |
Upload cap |
TURBOSIGN_TIMEOUT |
90 |
Per-request timeout, seconds |
Health
Stdio servers have no health endpoint, so:
.venv/bin/turbosign-mcp --selftest
It lists the registered tools and reports how the machine is configured. A machine with no credentials exits 0 — that is the normal state before setup, not a fault.
Notes for the curious
Why stdio and not HTTP. TurboSign is a stateless request/response API. There is no long-lived session to keep warm, so a container, a port and a health check would be pure overhead. The client launches the process; when it exits, nothing is left behind.
Why httpx directly and not turbodocx-sdk. This server is the thin
wrapper. Stacking it on a second wrapper buys drift protection at the price of
a pre-1.0 dependency and someone else's error messages — and error messages are
most of the value here, because an agent recovers from a sentence and cannot
recover from a stack trace.
Why the tools are synchronous. The usual MCP advice for a call to an external service is a background task the client polls. Stdio clients like Hermes do not poll the MCP task protocol, so that would make the primary consumer worse. Instead the calls are synchronous with a bounded timeout (90s, inside Hermes' 300s per-tool budget) and a 10 MB upload cap that keeps a typical send well inside the tighter ~60s budget of other clients.
One thing about the API is not documented: whether y is measured from the
top or the bottom of the page. The published reference gives only the
validation rule, which holds either way. It is top-left — verified against the
live API on 2026-08-01, not inferred — and isolated to a single constant in
placement.py so a future change stays a one-line fix. The record, and how to
re-run the check, is in docs/VERIFICATION.md.
Development
.venv/bin/pip install -e ".[dev]"
.venv/bin/python -m pytest
The suite runs without network access or credentials — HTTP is mocked with
respx, and PDF fixtures are generated in code rather than committed, so
nothing in this public repo can carry a real name or address.
Licence
MIT.
推荐服务器
Baidu Map
百度地图核心API现已全面兼容MCP协议,是国内首家兼容MCP协议的地图服务商。
Playwright MCP Server
一个模型上下文协议服务器,它使大型语言模型能够通过结构化的可访问性快照与网页进行交互,而无需视觉模型或屏幕截图。
Magic Component Platform (MCP)
一个由人工智能驱动的工具,可以从自然语言描述生成现代化的用户界面组件,并与流行的集成开发环境(IDE)集成,从而简化用户界面开发流程。
Audiense Insights MCP Server
通过模型上下文协议启用与 Audiense Insights 账户的交互,从而促进营销洞察和受众数据的提取和分析,包括人口统计信息、行为和影响者互动。
VeyraX
一个单一的 MCP 工具,连接你所有喜爱的工具:Gmail、日历以及其他 40 多个工具。
graphlit-mcp-server
模型上下文协议 (MCP) 服务器实现了 MCP 客户端与 Graphlit 服务之间的集成。 除了网络爬取之外,还可以将任何内容(从 Slack 到 Gmail 再到播客订阅源)导入到 Graphlit 项目中,然后从 MCP 客户端检索相关内容。
Kagi MCP Server
一个 MCP 服务器,集成了 Kagi 搜索功能和 Claude AI,使 Claude 能够在回答需要最新信息的问题时执行实时网络搜索。
e2b-mcp-server
使用 MCP 通过 e2b 运行代码。
Neon MCP Server
用于与 Neon 管理 API 和数据库交互的 MCP 服务器
Exa MCP Server
模型上下文协议(MCP)服务器允许像 Claude 这样的 AI 助手使用 Exa AI 搜索 API 进行网络搜索。这种设置允许 AI 模型以安全和受控的方式获取实时的网络信息。