MCP Server
APISign provides a Model Context Protocol (MCP) server that enables AI agents to manage templates and send contracts programmatically.
Overview
The MCP server uses the Streamable HTTP transport, which works with any MCP-compatible client including Claude Desktop, Cursor, and custom implementations.
Connection Details
| Property | Value |
|---|---|
| Endpoint | POST /mcp |
| Transport | Streamable HTTP |
| Authentication | API Key (x-api-key header) |
Getting an API Key
- Log into the APISign dashboard
- Navigate to Account > API Keys
- Click Create API Key
- Copy the key (it won't be shown again)
Key permissions
The permission you pick when creating the key decides which tools it can use.
| Permission | Tools available |
|---|---|
| Read Only | template_list, template_get, contract_list, contract_get |
| Read & Write | All tools |
A Read Only key does not see the write tools at all — they are left out of the
tools/list response, so an agent connected with that key has no way to
discover them. Calling one anyway returns
This API key does not have write permission.
If your agent only ever needs to look things up, use a Read Only key. It cannot create, send, cancel, or archive anything.
Client Configuration
Quick Setup
The easiest way to add APISign MCP to your AI assistant is using the add-mcp command:
npx add-mcp https://apisign.io/mcp --header '{"x-api-key": "your-api-key-here"}'
This command works with Claude Desktop, Cursor, ChatGPT, and other MCP-compatible AI assistants.
Manual Configuration
If you prefer to configure manually, add the following to your client's MCP configuration:
{
"mcpServers": {
"apisign": {
"url": "https://apisign.io/mcp",
"headers": {
"x-api-key": "your-api-key-here"
}
}
}
}
Configuration file locations:
- Claude Desktop (macOS):
~/Library/Application Support/Claude/claude_desktop_config.json - Claude Desktop (Windows):
%APPDATA%\Claude\claude_desktop_config.json - Cursor:
~/.cursor/mcp.json(macOS) or%USERPROFILE%\.cursor\mcp.json(Windows) - ChatGPT: Add via Settings → Features → MCP servers → Add MCP server
Local Development
When running locally, use:
npx add-mcp http://localhost:3553/mcp --header '{"x-api-key": "your-api-key-here"}'
Or manually configure:
{
"mcpServers": {
"apisign": {
"url": "http://localhost:3553/mcp",
"headers": {
"x-api-key": "your-api-key-here"
}
}
}
}
Available Tools
Template Tools
template_list
List all templates in your organization.
Parameters: None
Returns:
{
"templates": [
{
"id": "clx...",
"name": "NDA Template",
"created_at": "2024-01-15T10:30:00Z",
"updated_at": "2024-01-15T10:30:00Z"
}
]
}
template_get
Get a specific template with its content and field definitions.
Parameters:
| Name | Type | Required | Description |
|---|---|---|---|
id | string | Yes | Template ID (CUID format) |
Returns:
{
"template": {
"id": "clx...",
"name": "NDA Template",
"content": "# Non-Disclosure Agreement\n\nThis agreement...",
"fields": {
"fields": [
{ "name": "company_name", "type": "text", "completedBy": "creator" },
{ "name": "signature", "type": "signature", "completedBy": "signer" }
]
}
}
}
template_create
Create a new blank template.
Parameters:
| Name | Type | Required | Description |
|---|---|---|---|
name | string | Yes | Template name (min 3 characters) |
content | string | No | Markdown content |
Example:
{
"name": "Service Agreement",
"content": "# Service Agreement\n\nBetween {{company_name}} and {{client_name}}..."
}
template_update
Update an existing template.
Parameters:
| Name | Type | Required | Description |
|---|---|---|---|
id | string | Yes | Template ID |
name | string | No | New name |
content | string | No | New markdown content |
fields | array | No | Field definitions |
Fields array format:
{
"fields": [
{
"name": "company_name",
"type": "text",
"completedBy": "creator"
},
{
"name": "signature",
"type": "signature",
"completedBy": "signer"
}
]
}
template_upload
Upload a DOCX or DOC file and convert it to a template.
Parameters:
| Name | Type | Required | Description |
|---|---|---|---|
filename | string | Yes | Original filename (must end in .doc or .docx) |
fileData | string | Yes | Base64-encoded file content |
template_archive
Archive (soft delete) a template.
Parameters:
| Name | Type | Required | Description |
|---|---|---|---|
id | string | Yes | Template ID |
Contract Tools
contract_list
List contracts in your organization.
Parameters:
| Name | Type | Required | Description |
|---|---|---|---|
status | string | No | Filter by status: draft, queued, sent, signed, cancelled, expired |
Returns:
{
"contracts": [
{
"id": "clx...",
"name": "NDA - Acme Corp",
"status": "sent",
"created_at": "2024-01-15T10:30:00Z",
"sent_at": "2024-01-15T11:00:00Z",
"expires_at": "2024-02-14T11:00:00Z"
}
]
}
contract_get
Get a contract with its signers.
Parameters:
| Name | Type | Required | Description |
|---|---|---|---|
id | string | Yes | Contract ID |
Returns:
{
"contract": {
"id": "clx...",
"name": "NDA - Acme Corp",
"status": "sent",
"content": { "markdown": "..." }
},
"signers": [
{
"id": "clx...",
"name": "John Doe",
"email": "john@example.com",
"status": "pending",
"signing_order": 1
}
]
}
contract_create
Create a new contract from a template or custom content.
Parameters:
| Name | Type | Required | Description |
|---|---|---|---|
name | string | Yes | Contract name |
template_id | string | No | Template ID (if using a template) |
content | string | No | Markdown content (required if no template_id) |
variables | object | No | Variables to substitute (for template-based contracts) |
expires_in_days | number | No | Days until expiration (default: 30, max: 365) |
signers | array | Yes | List of signers (at least one) |
Signers array format:
{
"signers": [
{
"email": "john@example.com",
"name": "John Doe",
"company": "Acme Corp",
"signing_order": 1
},
{
"email": "jane@example.com",
"name": "Jane Smith",
"signing_order": 2
}
]
}
Example - From template:
{
"name": "NDA - Acme Corp",
"template_id": "clx...",
"variables": {
"company_name": "Acme Corporation",
"effective_date": "January 15, 2024"
},
"signers": [
{
"email": "john@acme.com",
"name": "John Doe",
"signing_order": 1
}
]
}
Example - Custom content:
{
"name": "Simple Agreement",
"content": "# Agreement\n\nI, {{signer_name}}, agree to the terms.\n\n{{signature}}",
"signers": [
{
"email": "john@example.com",
"name": "John Doe",
"signing_order": 1
}
]
}
contract_update
Update a draft contract. Only contracts with draft status can be updated.
Parameters:
| Name | Type | Required | Description |
|---|---|---|---|
contract_id | string | Yes | Contract ID |
name | string | No | New name |
content | object | No | New content object |
signers | array | No | Replace signers list |
contract_send
Send a contract to signers for signing. This:
- Changes status to
sent - Charges your organization balance
- Sends email notifications to all signers
Parameters:
| Name | Type | Required | Description |
|---|---|---|---|
contract_id | string | Yes | Contract ID |
Returns:
{
"success": true,
"contract_id": "clx...",
"signers_notified": 2,
"cost_charged": 0.25,
"message": "Contract sent successfully"
}
contract_cancel
Cancel a contract. Only draft and sent contracts can be cancelled.
Parameters:
| Name | Type | Required | Description |
|---|---|---|---|
contract_id | string | Yes | Contract ID |
Template Variables
Templates use handlebar-style variables: {{variable_name}}
Variable Types
| completedBy | Description |
|---|---|
creator | Filled when creating the contract |
signer | Filled by the signer when signing |
Common Variables
{{company_name}}- Company name (creator){{client_name}}- Client name (creator){{effective_date}}- Contract effective date (creator){{signer_name}}- Signer's name (signer){{signature}}- Signature field (signer){{date}}- Signing date (signer)
Error Handling
All tools return errors in a consistent format:
{
"error": "Error message here",
"details": [
{ "field": "name", "message": "Name is required" }
]
}
Common Errors
| Error | Description |
|---|---|
Missing x-api-key header | No API key provided |
Invalid or disabled API key | API key not found or disabled |
API key has expired | API key past expiration date |
This API key does not have write permission | Read Only key called a write tool |
Template not found | Template ID doesn't exist or is archived |
Contract not found | Contract ID doesn't exist |
Insufficient balance | Organization needs to add funds |
Only draft contracts can be updated | Cannot update sent/signed contracts |
Usage Examples
Create and Send a Contract
1. Use template_list to find available templates
2. Use template_get to view template content and fields
3. Use contract_create with template_id and variables
4. Use contract_send to send to signers
Upload a Document Template
1. Read document file and base64 encode it
2. Use template_upload with filename and fileData
3. Use template_update to set field definitions
Check Contract Status
1. Use contract_list with status filter
2. Use contract_get for detailed signer status
Rate Limits
We do not currently enforce per-API-key rate limits. There is no published
quota to plan against and no RateLimit-* headers on API responses.
Some unauthenticated endpoints — the support contact form, for example — are rate limited to stop abuse. Authenticated API keys are not.
Planning for high volume?
If we add per-key limits, they will be documented here with their numbers before they are enforced. Until then, be a good citizen and retry with backoff.