spotdraft-mcp
MCP server that gives Claude safety-gated access to SpotDraft contracts, enabling querying and managing contracts, templates, counterparties, obligations, and analytics through natural language.
README
SpotDraft MCP Server
Give Claude direct, safety-gated access to your SpotDraft contracts.
This is a locally-hosted MCP (Model Context Protocol) server that wraps the SpotDraft Public API so you can query and drive your SpotDraft workspace -- contracts, templates, counterparties, obligations, analytics -- conversationally from Claude, instead of clicking through the UI or writing one-off scripts.
It ships as two separate servers built from one codebase:
spotdraft-read-- every read-only operation. Safe to blanket-allow; nothing here has side effects.spotdraft-write-- every mutating operation (create/send/void/invite/etc.). Every single tool requires your explicit approval on every call -- it cannot be pre-approved or run unattended.
That split exists so you can tell your MCP client "always allow reads, always ask before writes" in one line each, instead of trusting a single server's internal judgment about what's safe.
What can you do with this?
Once connected, ask Claude things like:
- "List all contracts pending signature from Acme Corp"
- "What's the status of contract T-4821?"
- "Show me the obligations tracked on H-102"
- "Draft a new NDA from the Standard NDA template for this counterparty" (write -- will prompt for approval)
- "Void contract T-991, it was created by mistake" (write + destructive -- will prompt for approval)
- "Run an analytics query for all contracts executed last quarter by contract type"
Claude figures out which SpotDraft API call(s) to make; you approve anything that changes data.
Coverage
This server covers the v2.1 SpotDraft API family (the current/latest version) plus the small
set of v1-only endpoints that have no v2.1 successor (legal intake, native integrations,
obligation types, view-email, webhook-sample) -- 114 operations total. Superseded v2 and
old-v1 endpoints with a v2.1 replacement are intentionally excluded.
Coverage is delivered two ways:
- Curated tools (~15 read + ~13 write) for the most common contract-lifecycle workflows -- listing/searching contracts, checking status, downloading, creating from a template, sending to counterparties, voiding, managing counterparties and users, etc. Tight, well-described input schemas.
- A search + execute fallback, so nothing is out of reach even if it doesn't have a curated
tool:
search_actions(intent, access?)-- keyword-search the full 114-operation catalog.execute_read_request(operationId, ...)-- call any read-classified operation by ID.execute_write_request(operationId, ...)-- call any write-classified operation by ID (write server only; force-gated like every other write tool).
Re-vendoring a newer OpenAPI spec and re-running npm run gen:catalog keeps this catalog current
without hand-editing generated code.
Quick start
What you'll need
- Node.js 20+ and git.
- A SpotDraft API credential (Client ID + Client Secret): in SpotDraft, go to Settings -> Developer Settings -> Generate API Credential. If you don't have access to that page, ask whoever administers your SpotDraft workspace to generate one for you.
- An MCP-capable client (e.g. Claude Code).
1. Clone and build
git clone <this-repo-url> spotdraft-mcp
cd spotdraft-mcp
npm install
npm run build
This produces dist/index.js, which both server modes run.
2. Configure your MCP client
Add two server entries -- one per mode -- pointing at the same built file, with
SPOTDRAFT_MODE as the only thing that differs:
{
"mcpServers": {
"spotdraft-read": {
"command": "node",
"args": ["/absolute/path/to/spotdraft-mcp/dist/index.js"],
"env": {
"SPOTDRAFT_MODE": "read",
"SPOTDRAFT_CLIENT_ID": "your-client-id",
"SPOTDRAFT_CLIENT_SECRET": "your-client-secret",
"SPOTDRAFT_REGION": "us"
}
},
"spotdraft-write": {
"command": "node",
"args": ["/absolute/path/to/spotdraft-mcp/dist/index.js"],
"env": {
"SPOTDRAFT_MODE": "write",
"SPOTDRAFT_CLIENT_ID": "your-client-id",
"SPOTDRAFT_CLIENT_SECRET": "your-client-secret",
"SPOTDRAFT_REGION": "us"
}
}
}
}
On Windows, double the backslashes in the path (C:\\Users\\you\\...).
If you only ever need read access, register just spotdraft-read.
3. Set your approval rules
In your MCP client's permission settings, add:
{
"permissions": {
"allow": ["mcp__spotdraft-read__*"],
"ask": ["mcp__spotdraft-write__*"]
}
}
This blanket-allows every read tool and requires per-call approval for every write tool. Every
write tool also sets _meta["anthropic/requiresUserInteraction"] = true, which forces approval on
supporting clients even if a broader "don't ask again" rule is in effect.
4. Verify
Ask Claude to "list SpotDraft users" (calls list_users, a good connectivity check) and confirm it
returns your workspace roster without any approval prompt. Then ask it to do something mutating
(e.g. draft a contract note) and confirm it does prompt for approval.
Configuration reference
| Env var | Required | Purpose |
|---|---|---|
SPOTDRAFT_MODE |
yes | read or write. Selects which tool set this server instance registers. |
SPOTDRAFT_CLIENT_ID |
yes | SpotDraft API client-id. |
SPOTDRAFT_CLIENT_SECRET |
yes | SpotDraft API client-secret. Treat like a password -- never logged, never echoed in tool output. |
SPOTDRAFT_REGION |
no (default us) |
us, eu, in, or me -- selects the regional API host. |
SPOTDRAFT_USER_EMAIL |
no | Optional user-email header for per-user attribution. |
SPOTDRAFT_BASE_URL |
no | Escape hatch to override the computed base URL entirely. |
Region -> base URL mapping: us -> api.us.spotdraft.com, eu -> api.eu.spotdraft.com,
in -> api.in.spotdraft.com, me -> api.me.spotdraft.com.
Curated tools
Read (spotdraft-read) -- always safe, never prompts
| Tool | What it does |
|---|---|
list_contracts |
Paginated contract search/list with common filters. |
get_contract_status |
Display status + name for one contract by composite ID. |
get_contract_content |
The contract's text (as plain text, structured segments, or HTML). |
get_contract_download_link |
A temporary signed download URL (PDF/DOCX) -- not the file bytes. |
list_contract_notes |
Notes/comments on a contract's activity log. |
get_contract_obligations |
Obligations (renewal, payment, deliverable reminders) tracked on a contract. |
get_contract_key_pointers |
Structured metadata fields recorded on a contract. |
list_templates |
Contract templates available in the workspace. |
get_template_metadata |
A template's field definitions (for building create_contract payloads). |
list_contract_types |
Configured contract types and their IDs. |
list_counterparties |
Counterparty organizations/individuals, paginated. |
get_counterparty |
Full detail for one counterparty. |
list_users |
Workspace users (also the recommended connectivity self-test). |
get_analytics_catalog |
Tables/columns available to run_analytics_query. |
run_analytics_query |
Runs a read-only GoogleSQL query against SpotDraft's analytics tables. |
search_actions |
Keyword-search the full 114-op catalog (on both servers). |
execute_read_request |
Call any read-classified operation by ID (full-coverage fallback). |
Write (spotdraft-write) -- every call requires approval
| Tool | What it does |
|---|---|
create_contract |
Creates a contract from a template + contract_data + counterparties. |
send_contract_to_counterparties |
Emails a contract to its counterparties. |
upload_contract_for_signing |
Uploads an existing document as a new contract headed for signature. |
upload_contract_for_review |
Uploads an existing document as a new contract headed for review/redlining. |
mark_contract_for_execution |
Advances a contract to the execution/signature stage. |
void_contract |
Destructive. Permanently voids a contract. |
invite_user_to_contract |
Invites a role/user/new-email to a contract with a specific permission level. |
create_contract_note |
Adds a note/comment to a contract's activity log. |
set_contract_key_pointers |
Creates/updates structured metadata fields on a contract, in bulk. |
create_counterparty |
Creates a new counterparty (organization or individual). |
add_counterparty_contact |
Adds a contact person to an existing counterparty. |
create_webhook |
Registers a webhook subscription for contract/counterparty activity. |
create_user |
Invites a new user to the workspace. |
execute_write_request |
Call any write-classified operation by ID (full-coverage fallback). |
Security model
- Two servers, not one with internal flags. Approval tooling in MCP clients keys off the tool
name
mcp__<server-name>__<tool-name>, so splitting read/write into two server names is what makes "always allow reads, always ask on writes" expressible as two simple rules. - Every write tool force-gates. In addition to the two-server split, every write tool sets
_meta["anthropic/requiresUserInteraction"] = trueandreadOnlyHint: false;void_contractadditionally setsdestructiveHint: true. Read tools setreadOnlyHint: trueand never force-gate. This is belt-and-suspenders: the server split is the primary control, the tool annotations are a second, client-enforced layer that can't be bypassed by a broad allow rule. Any operation reachable throughexecute_read_request/execute_write_requestis checked against the same catalogaccessflag server-side, so the fallback path can't be used to sneak a write through the read server or vice versa. - Semantic, not just HTTP-method-based, classification. A handful of
POSTendpoints with no side effects (analytics query, contract preview, sidebar query, clickwrap agreement preview, contract-download-link generation) are classified as read. Everything else that isn't aGETis write. - Credentials never leave your machine and are never logged.
SPOTDRAFT_CLIENT_SECRET/SPOTDRAFT_CLIENT_IDare read from environment variables supplied by your MCP client, and are redacted from any error message or log line before it can be printed or returned to the model. - Composite IDs are never mutated. SpotDraft composite contract IDs (
T-123,H-45) are sent to the API exactly as given -- never re-prefixed, re-cased, or reformatted.
How it works
You -> Claude -> spotdraft-read / spotdraft-write (this server, on your machine) -> SpotDraft API -> Your workspace
Both server modes are built from the same dist/index.js; SPOTDRAFT_MODE decides which tool set
gets registered at startup (see src/server.ts). The operation catalog
(src/generated/catalog.ts) is generated from a vendored copy of SpotDraft's own OpenAPI spec
(openapi/spotdraft-openapi.json) by scripts/gen-catalog.ts -- re-run npm run gen:catalog after
re-vendoring a newer spec to pick up new operations.
Project structure
spotdraft-mcp/
├── package.json # bin: spotdraft-mcp-read / spotdraft-mcp-write; scripts: build/dev/gen:catalog/test
├── tsconfig.json
├── openapi/
│ ├── spotdraft-openapi.json # vendored OpenAPI spec (source of truth for coverage)
│ └── FETCHED.md # provenance / fetch date for the vendored spec
├── scripts/
│ ├── gen-catalog.ts # parses the vendored spec -> src/generated/catalog.ts
│ └── run-tests.mjs # cross-shell test runner (see "Development" below)
├── src/
│ ├── index.ts # entry point for both bin commands
│ ├── server.ts # builds the McpServer per SPOTDRAFT_MODE
│ ├── config.ts # env parsing, region resolution, validation
│ ├── http.ts # SpotDraft HTTP client: auth, retries, redaction
│ ├── generated/catalog.ts # generated operation catalog (do not hand-edit)
│ ├── tools/
│ │ ├── read/ # curated read tool modules
│ │ ├── write/ # curated write tool modules
│ │ ├── shared.ts # registration helper (annotations, error handling, pagination)
│ │ └── fallback.ts # search_actions + execute_read_request + execute_write_request
│ └── util/ (ids.ts, format.ts, errors.ts)
└── test/ # unit tests (node:test)
Development
npm install # install dependencies
npm run gen:catalog # regenerate src/generated/catalog.ts from openapi/spotdraft-openapi.json
npm run build # compile TypeScript -> dist/
npm test # run the unit test suite
npm run dev # run src/index.ts directly via tsx (no build step)
npm test runs scripts/run-tests.mjs, which enumerates test/*.test.ts and passes them
explicitly to Node's built-in test runner -- letting the test runner glob-scan the test/
directory itself conflicts with the tsx ESM loader hook on some Node versions.
License
MIT.
Recommended Servers
playwright-mcp
A Model Context Protocol server that enables LLMs to interact with web pages through structured accessibility snapshots without requiring vision models or screenshots.
Magic Component Platform (MCP)
An AI-powered tool that generates modern UI components from natural language descriptions, integrating with popular IDEs to streamline UI development workflow.
Audiense Insights MCP Server
Enables interaction with Audiense Insights accounts via the Model Context Protocol, facilitating the extraction and analysis of marketing insights and audience data including demographics, behavior, and influencer engagement.
VeyraX MCP
Single MCP tool to connect all your favorite tools: Gmail, Calendar and 40 more.
graphlit-mcp-server
The Model Context Protocol (MCP) Server enables integration between MCP clients and the Graphlit service. Ingest anything from Slack to Gmail to podcast feeds, in addition to web crawling, into a Graphlit project - and then retrieve relevant contents from the MCP client.
Kagi MCP Server
An MCP server that integrates Kagi search capabilities with Claude AI, enabling Claude to perform real-time web searches when answering questions that require up-to-date information.
E2B
Using MCP to run code via e2b.
Neon Database
MCP server for interacting with Neon Management API and databases
Exa Search
A Model Context Protocol (MCP) server lets AI assistants like Claude use the Exa AI Search API for web searches. This setup allows AI models to get real-time web information in a safe and controlled way.
Qdrant Server
This repository is an example of how to create a MCP server for Qdrant, a vector search engine.