docura-mcp 1.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +170 -0
- package/dist/client.d.ts +6 -0
- package/dist/client.js +35 -0
- package/dist/index.d.ts +2 -0
- package/dist/index.js +59 -0
- package/dist/tools/audit.d.ts +3 -0
- package/dist/tools/audit.js +45 -0
- package/dist/tools/submissions.d.ts +3 -0
- package/dist/tools/submissions.js +124 -0
- package/dist/tools/templates.d.ts +3 -0
- package/dist/tools/templates.js +39 -0
- package/dist/tools/webhooks.d.ts +3 -0
- package/dist/tools/webhooks.js +34 -0
- package/package.json +41 -0
package/README.md
ADDED
|
@@ -0,0 +1,170 @@
|
|
|
1
|
+
# docura-mcp
|
|
2
|
+
|
|
3
|
+
A [Model Context Protocol (MCP)](https://modelcontextprotocol.io/) server for the Docura e-signature platform. Connect Claude Code, Cursor, or any MCP-compatible AI client to your Docura account and manage documents via natural language.
|
|
4
|
+
|
|
5
|
+
No build step required — `npx` downloads and runs it automatically.
|
|
6
|
+
|
|
7
|
+
## What you can do
|
|
8
|
+
|
|
9
|
+
Once connected, ask your AI assistant things like:
|
|
10
|
+
|
|
11
|
+
- *"List all my templates"*
|
|
12
|
+
- *"Send the Master Services Agreement to alice@company.com and bob@company.com for signing"*
|
|
13
|
+
- *"What's the status of submission abc123? Has everyone signed?"*
|
|
14
|
+
- *"Resend the invitation to the second signer on the Smith contract"*
|
|
15
|
+
- *"Void the Q3 NDA submission"*
|
|
16
|
+
- *"Get the full audit trail for submission xyz"*
|
|
17
|
+
- *"How do I download the signed PDF for the Johnson agreement?"*
|
|
18
|
+
- *"List all our registered webhooks and test the production one"*
|
|
19
|
+
|
|
20
|
+
## Prerequisites
|
|
21
|
+
|
|
22
|
+
- Node.js 18+
|
|
23
|
+
- A Docura API key (`sk_live_*`) — generate one at **Settings → API Keys** in the dashboard
|
|
24
|
+
|
|
25
|
+
## Setup
|
|
26
|
+
|
|
27
|
+
### Step 1 — Get an API key
|
|
28
|
+
|
|
29
|
+
Log in to your Docura dashboard → **Settings → API Keys** → create a new key. It starts with `sk_live_`.
|
|
30
|
+
|
|
31
|
+
### Step 2 — Add to Claude Code
|
|
32
|
+
|
|
33
|
+
Add the server to `.claude/settings.local.json` in your project:
|
|
34
|
+
|
|
35
|
+
```json
|
|
36
|
+
{
|
|
37
|
+
"mcpServers": {
|
|
38
|
+
"docura": {
|
|
39
|
+
"command": "npx",
|
|
40
|
+
"args": ["-y", "docura-mcp"],
|
|
41
|
+
"env": {
|
|
42
|
+
"DOCURA_API_KEY": "sk_live_your_key_here",
|
|
43
|
+
"DOCURA_BASE_URL": "https://app.docura.com"
|
|
44
|
+
}
|
|
45
|
+
}
|
|
46
|
+
}
|
|
47
|
+
}
|
|
48
|
+
```
|
|
49
|
+
|
|
50
|
+
Restart Claude Code. The `docura` server appears in the MCP panel.
|
|
51
|
+
|
|
52
|
+
### Add to Cursor
|
|
53
|
+
|
|
54
|
+
Go to **Cursor Settings → MCP** and add the same block above.
|
|
55
|
+
|
|
56
|
+
### Install globally (optional — skips the npx download delay)
|
|
57
|
+
|
|
58
|
+
```bash
|
|
59
|
+
npm install -g docura-mcp
|
|
60
|
+
```
|
|
61
|
+
|
|
62
|
+
Then use `"command": "docura-mcp"` (no `args`) in your MCP config instead of the `npx` form.
|
|
63
|
+
|
|
64
|
+
## Environment variables
|
|
65
|
+
|
|
66
|
+
| Variable | Required | Default | Description |
|
|
67
|
+
|----------|----------|---------|-------------|
|
|
68
|
+
| `DOCURA_API_KEY` | Yes | — | API key from Docura Settings → API Keys |
|
|
69
|
+
| `DOCURA_BASE_URL` | No | `http://localhost:3000` | Base URL of your Docura instance |
|
|
70
|
+
|
|
71
|
+
Set `DOCURA_BASE_URL` to your deployed URL (e.g. `https://app.docura.com`) for production use.
|
|
72
|
+
|
|
73
|
+
## Available tools
|
|
74
|
+
|
|
75
|
+
### Templates
|
|
76
|
+
|
|
77
|
+
| Tool | Description |
|
|
78
|
+
|------|-------------|
|
|
79
|
+
| `list_templates` | List all PDF templates in your organization |
|
|
80
|
+
| `get_template` | Get a template's details, fields, and signer roles |
|
|
81
|
+
|
|
82
|
+
### Submissions
|
|
83
|
+
|
|
84
|
+
| Tool | Description |
|
|
85
|
+
|------|-------------|
|
|
86
|
+
| `list_submissions` | List submissions, optionally filtered by status |
|
|
87
|
+
| `get_submission` | Get status and signer progress for a submission |
|
|
88
|
+
| `create_submission` | Send a template to one or more signers |
|
|
89
|
+
| `void_submission` | Cancel a pending submission |
|
|
90
|
+
| `resend_invitation` | Resend the signing email to a specific signer |
|
|
91
|
+
|
|
92
|
+
### Audit & download
|
|
93
|
+
|
|
94
|
+
| Tool | Description |
|
|
95
|
+
|------|-------------|
|
|
96
|
+
| `get_audit_trail` | Full cryptographic event log (timestamps, IPs, hashes) |
|
|
97
|
+
| `get_download_url` | Get the URL + curl command to download a completed signed PDF |
|
|
98
|
+
|
|
99
|
+
### Webhooks
|
|
100
|
+
|
|
101
|
+
| Tool | Description |
|
|
102
|
+
|------|-------------|
|
|
103
|
+
| `list_webhooks` | List all registered webhook endpoints |
|
|
104
|
+
| `test_webhook` | Send a test event to verify a webhook is reachable |
|
|
105
|
+
|
|
106
|
+
## Tool reference
|
|
107
|
+
|
|
108
|
+
### `create_submission`
|
|
109
|
+
|
|
110
|
+
Sends a document to signers. The `signers` array must contain one entry per signer role defined in the template. Use `get_template` first to see the available role names.
|
|
111
|
+
|
|
112
|
+
```json
|
|
113
|
+
{
|
|
114
|
+
"templateId": "tmpl_abc123",
|
|
115
|
+
"signers": [
|
|
116
|
+
{ "email": "alice@company.com", "name": "Alice", "roleName": "Client" },
|
|
117
|
+
{ "email": "bob@company.com", "name": "Bob", "roleName": "Vendor" }
|
|
118
|
+
],
|
|
119
|
+
"message": "Please review and sign at your earliest convenience.",
|
|
120
|
+
"expiresAt": "2025-12-31T23:59:59Z"
|
|
121
|
+
}
|
|
122
|
+
```
|
|
123
|
+
|
|
124
|
+
### `resend_invitation`
|
|
125
|
+
|
|
126
|
+
Resends the signing email to a signer who hasn't signed yet. Get the `signerId` from `get_submission`.
|
|
127
|
+
|
|
128
|
+
```json
|
|
129
|
+
{
|
|
130
|
+
"submissionId": "sub_xyz789",
|
|
131
|
+
"signerId": "sgn_def456"
|
|
132
|
+
}
|
|
133
|
+
```
|
|
134
|
+
|
|
135
|
+
### `get_download_url`
|
|
136
|
+
|
|
137
|
+
Returns a URL and curl command for downloading the completed signed PDF. The submission must have status `COMPLETED`.
|
|
138
|
+
|
|
139
|
+
```json
|
|
140
|
+
{ "submissionId": "sub_xyz789" }
|
|
141
|
+
```
|
|
142
|
+
|
|
143
|
+
Response:
|
|
144
|
+
```json
|
|
145
|
+
{
|
|
146
|
+
"downloadUrl": "https://app.docura.com/api/v1/submissions/sub_xyz789/download",
|
|
147
|
+
"instructions": "curl -H \"Authorization: Bearer $DOCURA_API_KEY\" \"...\" -o signed.pdf"
|
|
148
|
+
}
|
|
149
|
+
```
|
|
150
|
+
|
|
151
|
+
## Development
|
|
152
|
+
|
|
153
|
+
```bash
|
|
154
|
+
# Clone the repo and build from source
|
|
155
|
+
cd mcp-server
|
|
156
|
+
npm install
|
|
157
|
+
npm run build
|
|
158
|
+
node dist/index.js
|
|
159
|
+
|
|
160
|
+
# Run without building (uses tsx)
|
|
161
|
+
npm run dev
|
|
162
|
+
```
|
|
163
|
+
|
|
164
|
+
To test the server manually with [MCP Inspector](https://github.com/modelcontextprotocol/inspector):
|
|
165
|
+
|
|
166
|
+
```bash
|
|
167
|
+
npx @modelcontextprotocol/inspector node dist/index.js
|
|
168
|
+
```
|
|
169
|
+
|
|
170
|
+
Set `DOCURA_API_KEY` and optionally `DOCURA_BASE_URL` in your shell before running.
|
package/dist/client.d.ts
ADDED
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
declare const BASE_URL: string;
|
|
2
|
+
declare const API_KEY: string;
|
|
3
|
+
export declare function apiGet(path: string): Promise<unknown>;
|
|
4
|
+
export declare function apiPost(path: string, body?: unknown): Promise<unknown>;
|
|
5
|
+
export declare function apiDelete(path: string): Promise<unknown>;
|
|
6
|
+
export { BASE_URL, API_KEY };
|
package/dist/client.js
ADDED
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
const BASE_URL = (process.env.DOCURA_BASE_URL ?? "http://localhost:3000").replace(/\/$/, "");
|
|
2
|
+
const API_KEY = process.env.DOCURA_API_KEY ?? "";
|
|
3
|
+
function headers() {
|
|
4
|
+
return {
|
|
5
|
+
Authorization: `Bearer ${API_KEY}`,
|
|
6
|
+
"Content-Type": "application/json",
|
|
7
|
+
};
|
|
8
|
+
}
|
|
9
|
+
async function checkResponse(res) {
|
|
10
|
+
if (!res.ok) {
|
|
11
|
+
const body = await res.text();
|
|
12
|
+
throw new Error(`Docura API ${res.status}: ${body}`);
|
|
13
|
+
}
|
|
14
|
+
return res.json();
|
|
15
|
+
}
|
|
16
|
+
export async function apiGet(path) {
|
|
17
|
+
const res = await fetch(`${BASE_URL}/api/v1${path}`, { headers: headers() });
|
|
18
|
+
return checkResponse(res);
|
|
19
|
+
}
|
|
20
|
+
export async function apiPost(path, body) {
|
|
21
|
+
const res = await fetch(`${BASE_URL}/api/v1${path}`, {
|
|
22
|
+
method: "POST",
|
|
23
|
+
headers: headers(),
|
|
24
|
+
body: body !== undefined ? JSON.stringify(body) : undefined,
|
|
25
|
+
});
|
|
26
|
+
return checkResponse(res);
|
|
27
|
+
}
|
|
28
|
+
export async function apiDelete(path) {
|
|
29
|
+
const res = await fetch(`${BASE_URL}/api/v1${path}`, {
|
|
30
|
+
method: "DELETE",
|
|
31
|
+
headers: headers(),
|
|
32
|
+
});
|
|
33
|
+
return checkResponse(res);
|
|
34
|
+
}
|
|
35
|
+
export { BASE_URL, API_KEY };
|
package/dist/index.d.ts
ADDED
package/dist/index.js
ADDED
|
@@ -0,0 +1,59 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
import { Server } from "@modelcontextprotocol/sdk/server/index.js";
|
|
3
|
+
import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio.js";
|
|
4
|
+
import { CallToolRequestSchema, ListToolsRequestSchema, } from "@modelcontextprotocol/sdk/types.js";
|
|
5
|
+
import { templateTools, handleTemplateTools } from "./tools/templates.js";
|
|
6
|
+
import { submissionTools, handleSubmissionTools } from "./tools/submissions.js";
|
|
7
|
+
import { auditTools, handleAuditTools } from "./tools/audit.js";
|
|
8
|
+
import { webhookTools, handleWebhookTools } from "./tools/webhooks.js";
|
|
9
|
+
if (!process.env.DOCURA_API_KEY) {
|
|
10
|
+
process.stderr.write("Error: DOCURA_API_KEY environment variable is required.\n" +
|
|
11
|
+
"Get your API key from: Docura Dashboard → Settings → API Keys\n");
|
|
12
|
+
process.exit(1);
|
|
13
|
+
}
|
|
14
|
+
const allTools = [
|
|
15
|
+
...templateTools,
|
|
16
|
+
...submissionTools,
|
|
17
|
+
...auditTools,
|
|
18
|
+
...webhookTools,
|
|
19
|
+
];
|
|
20
|
+
const toolNameSet = new Set(allTools.map((t) => t.name));
|
|
21
|
+
const server = new Server({ name: "docura", version: "1.0.0" }, { capabilities: { tools: {} } });
|
|
22
|
+
server.setRequestHandler(ListToolsRequestSchema, async () => ({ tools: allTools }));
|
|
23
|
+
server.setRequestHandler(CallToolRequestSchema, async (request) => {
|
|
24
|
+
const { name, arguments: args = {} } = request.params;
|
|
25
|
+
if (!toolNameSet.has(name)) {
|
|
26
|
+
return {
|
|
27
|
+
content: [{ type: "text", text: `Unknown tool: ${name}` }],
|
|
28
|
+
isError: true,
|
|
29
|
+
};
|
|
30
|
+
}
|
|
31
|
+
try {
|
|
32
|
+
let result;
|
|
33
|
+
const a = args;
|
|
34
|
+
if (templateTools.some((t) => t.name === name)) {
|
|
35
|
+
result = await handleTemplateTools(name, a);
|
|
36
|
+
}
|
|
37
|
+
else if (submissionTools.some((t) => t.name === name)) {
|
|
38
|
+
result = await handleSubmissionTools(name, a);
|
|
39
|
+
}
|
|
40
|
+
else if (auditTools.some((t) => t.name === name)) {
|
|
41
|
+
result = await handleAuditTools(name, a);
|
|
42
|
+
}
|
|
43
|
+
else {
|
|
44
|
+
result = await handleWebhookTools(name, a);
|
|
45
|
+
}
|
|
46
|
+
return {
|
|
47
|
+
content: [{ type: "text", text: JSON.stringify(result, null, 2) }],
|
|
48
|
+
};
|
|
49
|
+
}
|
|
50
|
+
catch (err) {
|
|
51
|
+
const message = err instanceof Error ? err.message : String(err);
|
|
52
|
+
return {
|
|
53
|
+
content: [{ type: "text", text: `Error: ${message}` }],
|
|
54
|
+
isError: true,
|
|
55
|
+
};
|
|
56
|
+
}
|
|
57
|
+
});
|
|
58
|
+
const transport = new StdioServerTransport();
|
|
59
|
+
await server.connect(transport);
|
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
import { apiGet, BASE_URL } from "../client.js";
|
|
2
|
+
export const auditTools = [
|
|
3
|
+
{
|
|
4
|
+
name: "get_audit_trail",
|
|
5
|
+
description: "Get the cryptographic audit trail for a submission — all events (invited, viewed, signed, declined, voided) with timestamps, IP addresses, and integrity metadata",
|
|
6
|
+
inputSchema: {
|
|
7
|
+
type: "object",
|
|
8
|
+
properties: {
|
|
9
|
+
submissionId: { type: "string", description: "Submission ID" },
|
|
10
|
+
},
|
|
11
|
+
required: ["submissionId"],
|
|
12
|
+
},
|
|
13
|
+
},
|
|
14
|
+
{
|
|
15
|
+
name: "get_download_url",
|
|
16
|
+
description: "Get instructions and the URL to download the completed signed PDF for a submission. The submission must have status COMPLETED.",
|
|
17
|
+
inputSchema: {
|
|
18
|
+
type: "object",
|
|
19
|
+
properties: {
|
|
20
|
+
submissionId: {
|
|
21
|
+
type: "string",
|
|
22
|
+
description: "Submission ID (must be COMPLETED)",
|
|
23
|
+
},
|
|
24
|
+
},
|
|
25
|
+
required: ["submissionId"],
|
|
26
|
+
},
|
|
27
|
+
},
|
|
28
|
+
];
|
|
29
|
+
export async function handleAuditTools(name, args) {
|
|
30
|
+
switch (name) {
|
|
31
|
+
case "get_audit_trail": {
|
|
32
|
+
return apiGet(`/submissions/${args.submissionId}/audit`);
|
|
33
|
+
}
|
|
34
|
+
case "get_download_url": {
|
|
35
|
+
const url = `${BASE_URL}/api/v1/submissions/${args.submissionId}/download`;
|
|
36
|
+
return {
|
|
37
|
+
downloadUrl: url,
|
|
38
|
+
instructions: `Send a GET request to the URL with your API key in the Authorization header:\n` +
|
|
39
|
+
`curl -H "Authorization: Bearer $DOCURA_API_KEY" "${url}" -o signed.pdf`,
|
|
40
|
+
};
|
|
41
|
+
}
|
|
42
|
+
default:
|
|
43
|
+
throw new Error(`Unknown tool: ${name}`);
|
|
44
|
+
}
|
|
45
|
+
}
|
|
@@ -0,0 +1,124 @@
|
|
|
1
|
+
import { apiGet, apiPost, apiDelete } from "../client.js";
|
|
2
|
+
export const submissionTools = [
|
|
3
|
+
{
|
|
4
|
+
name: "list_submissions",
|
|
5
|
+
description: "List document submissions in your organization. Optionally filter by status.",
|
|
6
|
+
inputSchema: {
|
|
7
|
+
type: "object",
|
|
8
|
+
properties: {
|
|
9
|
+
status: {
|
|
10
|
+
type: "string",
|
|
11
|
+
enum: ["DRAFT", "PENDING", "COMPLETED", "DECLINED", "EXPIRED", "VOIDED"],
|
|
12
|
+
description: "Filter by submission status",
|
|
13
|
+
},
|
|
14
|
+
page: { type: "number", description: "Page number (default: 1)" },
|
|
15
|
+
limit: { type: "number", description: "Results per page, max 100 (default: 20)" },
|
|
16
|
+
},
|
|
17
|
+
},
|
|
18
|
+
},
|
|
19
|
+
{
|
|
20
|
+
name: "get_submission",
|
|
21
|
+
description: "Get the status and details of a specific submission, including each signer's progress",
|
|
22
|
+
inputSchema: {
|
|
23
|
+
type: "object",
|
|
24
|
+
properties: {
|
|
25
|
+
submissionId: { type: "string", description: "Submission ID" },
|
|
26
|
+
},
|
|
27
|
+
required: ["submissionId"],
|
|
28
|
+
},
|
|
29
|
+
},
|
|
30
|
+
{
|
|
31
|
+
name: "create_submission",
|
|
32
|
+
description: "Send a document for signing by creating a submission from a template. Returns signing URLs for each signer.",
|
|
33
|
+
inputSchema: {
|
|
34
|
+
type: "object",
|
|
35
|
+
properties: {
|
|
36
|
+
templateId: { type: "string", description: "ID of the template to send" },
|
|
37
|
+
signers: {
|
|
38
|
+
type: "array",
|
|
39
|
+
description: "List of signers — one per signer role in the template",
|
|
40
|
+
items: {
|
|
41
|
+
type: "object",
|
|
42
|
+
properties: {
|
|
43
|
+
email: { type: "string", description: "Signer email address" },
|
|
44
|
+
name: { type: "string", description: "Signer display name (optional)" },
|
|
45
|
+
roleName: {
|
|
46
|
+
type: "string",
|
|
47
|
+
description: "Signer role name — must match a role defined in the template",
|
|
48
|
+
},
|
|
49
|
+
},
|
|
50
|
+
required: ["email", "roleName"],
|
|
51
|
+
},
|
|
52
|
+
},
|
|
53
|
+
message: {
|
|
54
|
+
type: "string",
|
|
55
|
+
description: "Optional message to include in the signing invitation email",
|
|
56
|
+
},
|
|
57
|
+
expiresAt: {
|
|
58
|
+
type: "string",
|
|
59
|
+
description: "Optional expiry date in ISO 8601 format (e.g. 2025-12-31T23:59:59Z)",
|
|
60
|
+
},
|
|
61
|
+
},
|
|
62
|
+
required: ["templateId", "signers"],
|
|
63
|
+
},
|
|
64
|
+
},
|
|
65
|
+
{
|
|
66
|
+
name: "void_submission",
|
|
67
|
+
description: "Cancel (void) a pending submission so signers can no longer sign it",
|
|
68
|
+
inputSchema: {
|
|
69
|
+
type: "object",
|
|
70
|
+
properties: {
|
|
71
|
+
submissionId: { type: "string", description: "Submission ID to void" },
|
|
72
|
+
},
|
|
73
|
+
required: ["submissionId"],
|
|
74
|
+
},
|
|
75
|
+
},
|
|
76
|
+
{
|
|
77
|
+
name: "resend_invitation",
|
|
78
|
+
description: "Resend the signing invitation email to a specific signer who hasn't signed yet",
|
|
79
|
+
inputSchema: {
|
|
80
|
+
type: "object",
|
|
81
|
+
properties: {
|
|
82
|
+
submissionId: { type: "string", description: "Submission ID" },
|
|
83
|
+
signerId: {
|
|
84
|
+
type: "string",
|
|
85
|
+
description: "Signer ID — use get_submission to find signer IDs",
|
|
86
|
+
},
|
|
87
|
+
},
|
|
88
|
+
required: ["submissionId", "signerId"],
|
|
89
|
+
},
|
|
90
|
+
},
|
|
91
|
+
];
|
|
92
|
+
export async function handleSubmissionTools(name, args) {
|
|
93
|
+
switch (name) {
|
|
94
|
+
case "list_submissions": {
|
|
95
|
+
const params = new URLSearchParams();
|
|
96
|
+
if (args.status)
|
|
97
|
+
params.set("status", String(args.status));
|
|
98
|
+
if (args.page)
|
|
99
|
+
params.set("page", String(args.page));
|
|
100
|
+
if (args.limit)
|
|
101
|
+
params.set("limit", String(args.limit));
|
|
102
|
+
const qs = params.toString();
|
|
103
|
+
return apiGet(`/submissions${qs ? `?${qs}` : ""}`);
|
|
104
|
+
}
|
|
105
|
+
case "get_submission": {
|
|
106
|
+
return apiGet(`/submissions/${args.submissionId}`);
|
|
107
|
+
}
|
|
108
|
+
case "create_submission": {
|
|
109
|
+
return apiPost(`/templates/${args.templateId}/submissions`, {
|
|
110
|
+
signers: args.signers,
|
|
111
|
+
...(args.message ? { message: args.message } : {}),
|
|
112
|
+
...(args.expiresAt ? { expiresAt: args.expiresAt } : {}),
|
|
113
|
+
});
|
|
114
|
+
}
|
|
115
|
+
case "void_submission": {
|
|
116
|
+
return apiDelete(`/submissions/${args.submissionId}`);
|
|
117
|
+
}
|
|
118
|
+
case "resend_invitation": {
|
|
119
|
+
return apiPost(`/submissions/${args.submissionId}/signers/${args.signerId}/resend`);
|
|
120
|
+
}
|
|
121
|
+
default:
|
|
122
|
+
throw new Error(`Unknown tool: ${name}`);
|
|
123
|
+
}
|
|
124
|
+
}
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
import { apiGet } from "../client.js";
|
|
2
|
+
export const templateTools = [
|
|
3
|
+
{
|
|
4
|
+
name: "list_templates",
|
|
5
|
+
description: "List all PDF templates in your Docura organization",
|
|
6
|
+
inputSchema: {
|
|
7
|
+
type: "object",
|
|
8
|
+
properties: {
|
|
9
|
+
page: { type: "number", description: "Page number (default: 1)" },
|
|
10
|
+
limit: { type: "number", description: "Results per page, max 100 (default: 20)" },
|
|
11
|
+
},
|
|
12
|
+
},
|
|
13
|
+
},
|
|
14
|
+
{
|
|
15
|
+
name: "get_template",
|
|
16
|
+
description: "Get details of a specific template including its fields and signer roles",
|
|
17
|
+
inputSchema: {
|
|
18
|
+
type: "object",
|
|
19
|
+
properties: {
|
|
20
|
+
templateId: { type: "string", description: "Template ID" },
|
|
21
|
+
},
|
|
22
|
+
required: ["templateId"],
|
|
23
|
+
},
|
|
24
|
+
},
|
|
25
|
+
];
|
|
26
|
+
export async function handleTemplateTools(name, args) {
|
|
27
|
+
switch (name) {
|
|
28
|
+
case "list_templates": {
|
|
29
|
+
const page = args.page ?? 1;
|
|
30
|
+
const limit = args.limit ?? 20;
|
|
31
|
+
return apiGet(`/templates?page=${page}&limit=${limit}`);
|
|
32
|
+
}
|
|
33
|
+
case "get_template": {
|
|
34
|
+
return apiGet(`/templates/${args.templateId}`);
|
|
35
|
+
}
|
|
36
|
+
default:
|
|
37
|
+
throw new Error(`Unknown tool: ${name}`);
|
|
38
|
+
}
|
|
39
|
+
}
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
import { apiGet, apiPost } from "../client.js";
|
|
2
|
+
export const webhookTools = [
|
|
3
|
+
{
|
|
4
|
+
name: "list_webhooks",
|
|
5
|
+
description: "List all webhook endpoints registered in your Docura organization",
|
|
6
|
+
inputSchema: {
|
|
7
|
+
type: "object",
|
|
8
|
+
properties: {},
|
|
9
|
+
},
|
|
10
|
+
},
|
|
11
|
+
{
|
|
12
|
+
name: "test_webhook",
|
|
13
|
+
description: "Send a test event to a registered webhook endpoint to verify it is reachable and responding correctly",
|
|
14
|
+
inputSchema: {
|
|
15
|
+
type: "object",
|
|
16
|
+
properties: {
|
|
17
|
+
webhookId: { type: "string", description: "Webhook ID to test" },
|
|
18
|
+
},
|
|
19
|
+
required: ["webhookId"],
|
|
20
|
+
},
|
|
21
|
+
},
|
|
22
|
+
];
|
|
23
|
+
export async function handleWebhookTools(name, args) {
|
|
24
|
+
switch (name) {
|
|
25
|
+
case "list_webhooks": {
|
|
26
|
+
return apiGet("/webhooks");
|
|
27
|
+
}
|
|
28
|
+
case "test_webhook": {
|
|
29
|
+
return apiPost(`/webhooks/${args.webhookId}/test`);
|
|
30
|
+
}
|
|
31
|
+
default:
|
|
32
|
+
throw new Error(`Unknown tool: ${name}`);
|
|
33
|
+
}
|
|
34
|
+
}
|
package/package.json
ADDED
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "docura-mcp",
|
|
3
|
+
"version": "1.0.0",
|
|
4
|
+
"description": "MCP server for the Docura e-signature platform — manage documents from Claude Code, Cursor, or any MCP-compatible AI client",
|
|
5
|
+
"type": "module",
|
|
6
|
+
"main": "dist/index.js",
|
|
7
|
+
"bin": {
|
|
8
|
+
"docura-mcp": "dist/index.js"
|
|
9
|
+
},
|
|
10
|
+
"files": [
|
|
11
|
+
"dist"
|
|
12
|
+
],
|
|
13
|
+
"keywords": [
|
|
14
|
+
"mcp",
|
|
15
|
+
"model-context-protocol",
|
|
16
|
+
"docura",
|
|
17
|
+
"e-signature",
|
|
18
|
+
"esign",
|
|
19
|
+
"ai",
|
|
20
|
+
"claude",
|
|
21
|
+
"cursor"
|
|
22
|
+
],
|
|
23
|
+
"license": "MIT",
|
|
24
|
+
"scripts": {
|
|
25
|
+
"build": "tsc",
|
|
26
|
+
"start": "node dist/index.js",
|
|
27
|
+
"dev": "tsx index.ts",
|
|
28
|
+
"prepublishOnly": "npm run build"
|
|
29
|
+
},
|
|
30
|
+
"dependencies": {
|
|
31
|
+
"@modelcontextprotocol/sdk": "^1.12.0"
|
|
32
|
+
},
|
|
33
|
+
"devDependencies": {
|
|
34
|
+
"@types/node": "^20",
|
|
35
|
+
"tsx": "^4.22.4",
|
|
36
|
+
"typescript": "^5"
|
|
37
|
+
},
|
|
38
|
+
"engines": {
|
|
39
|
+
"node": ">=18"
|
|
40
|
+
}
|
|
41
|
+
}
|