signbee-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 +103 -0
- package/build/index.d.ts +2 -0
- package/build/index.js +213 -0
- package/package.json +39 -0
package/README.md
ADDED
|
@@ -0,0 +1,103 @@
|
|
|
1
|
+
# Signbee MCP Server
|
|
2
|
+
|
|
3
|
+
Document signing for AI agents — as an MCP tool.
|
|
4
|
+
|
|
5
|
+
Send, sign, and verify documents with a single tool call. Works with Claude, Cursor, Windsurf, and any MCP-compatible client.
|
|
6
|
+
|
|
7
|
+
## Quick Setup
|
|
8
|
+
|
|
9
|
+
### Claude Desktop
|
|
10
|
+
|
|
11
|
+
Add to your `claude_desktop_config.json`:
|
|
12
|
+
|
|
13
|
+
```json
|
|
14
|
+
{
|
|
15
|
+
"mcpServers": {
|
|
16
|
+
"signbee": {
|
|
17
|
+
"command": "npx",
|
|
18
|
+
"args": ["-y", "@signbee/mcp"],
|
|
19
|
+
"env": {
|
|
20
|
+
"SIGNBEE_API_KEY": "your-api-key-from-signb.ee/dashboard"
|
|
21
|
+
}
|
|
22
|
+
}
|
|
23
|
+
}
|
|
24
|
+
}
|
|
25
|
+
```
|
|
26
|
+
|
|
27
|
+
### Cursor / Windsurf
|
|
28
|
+
|
|
29
|
+
Add to your MCP settings:
|
|
30
|
+
|
|
31
|
+
```json
|
|
32
|
+
{
|
|
33
|
+
"signbee": {
|
|
34
|
+
"command": "npx",
|
|
35
|
+
"args": ["-y", "@signbee/mcp"],
|
|
36
|
+
"env": {
|
|
37
|
+
"SIGNBEE_API_KEY": "your-api-key"
|
|
38
|
+
}
|
|
39
|
+
}
|
|
40
|
+
}
|
|
41
|
+
```
|
|
42
|
+
|
|
43
|
+
> **Note:** The API key is optional. Without it, the sender verifies via email OTP. With it, documents are sent instantly.
|
|
44
|
+
|
|
45
|
+
## Tools
|
|
46
|
+
|
|
47
|
+
### `send_document`
|
|
48
|
+
|
|
49
|
+
Send a markdown document for two-party e-signing.
|
|
50
|
+
|
|
51
|
+
**Parameters:**
|
|
52
|
+
|
|
53
|
+
| Parameter | Required | Description |
|
|
54
|
+
|-----------|----------|-------------|
|
|
55
|
+
| `markdown` | ✅ | Document content in markdown format |
|
|
56
|
+
| `sender_name` | ✅ | Full name of the sender |
|
|
57
|
+
| `sender_email` | ✅ | Email address of the sender |
|
|
58
|
+
| `recipient_name` | ✅ | Full name of the recipient |
|
|
59
|
+
| `recipient_email` | ✅ | Email address of the recipient |
|
|
60
|
+
| `title` | ❌ | Document title (auto-extracted from heading) |
|
|
61
|
+
| `expires_in_days` | ❌ | Days until signing link expires (default: 7) |
|
|
62
|
+
|
|
63
|
+
**Example prompt:** "Send an NDA to bob@acme.com from alice@company.com"
|
|
64
|
+
|
|
65
|
+
### `send_document_pdf`
|
|
66
|
+
|
|
67
|
+
Send an existing PDF for two-party e-signing.
|
|
68
|
+
|
|
69
|
+
**Parameters:**
|
|
70
|
+
|
|
71
|
+
| Parameter | Required | Description |
|
|
72
|
+
|-----------|----------|-------------|
|
|
73
|
+
| `pdf_url` | ✅ | Publicly accessible URL to the PDF |
|
|
74
|
+
| `title` | ✅ | Document title |
|
|
75
|
+
| `sender_name` | ✅ | Full name of the sender |
|
|
76
|
+
| `sender_email` | ✅ | Email address of the sender |
|
|
77
|
+
| `recipient_name` | ✅ | Full name of the recipient |
|
|
78
|
+
| `recipient_email` | ✅ | Email address of the recipient |
|
|
79
|
+
| `expires_in_days` | ❌ | Days until signing link expires (default: 7) |
|
|
80
|
+
|
|
81
|
+
## How It Works
|
|
82
|
+
|
|
83
|
+
1. You ask your AI to send a document for signing
|
|
84
|
+
2. The MCP server calls the Signbee API
|
|
85
|
+
3. Signbee converts markdown → PDF, handles the signing ceremony
|
|
86
|
+
4. Both parties receive a SHA-256 certified signed copy via email
|
|
87
|
+
|
|
88
|
+
## Get Your API Key
|
|
89
|
+
|
|
90
|
+
1. Go to [signb.ee](https://signb.ee)
|
|
91
|
+
2. Create an account
|
|
92
|
+
3. Navigate to the Dashboard
|
|
93
|
+
4. Copy your API key
|
|
94
|
+
|
|
95
|
+
## Links
|
|
96
|
+
|
|
97
|
+
- **Website:** [signb.ee](https://signb.ee)
|
|
98
|
+
- **OpenAPI Spec:** [signb.ee/openapi.json](https://signb.ee/openapi.json)
|
|
99
|
+
- **llms.txt:** [signb.ee/llms.txt](https://signb.ee/llms.txt)
|
|
100
|
+
|
|
101
|
+
## License
|
|
102
|
+
|
|
103
|
+
MIT
|
package/build/index.d.ts
ADDED
package/build/index.js
ADDED
|
@@ -0,0 +1,213 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
|
|
3
|
+
import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio.js";
|
|
4
|
+
import { z } from "zod";
|
|
5
|
+
const SIGNBEE_API_URL = process.env.SIGNBEE_API_URL || "https://www.signb.ee";
|
|
6
|
+
const SIGNBEE_API_KEY = process.env.SIGNBEE_API_KEY || "";
|
|
7
|
+
const server = new McpServer({
|
|
8
|
+
name: "signbee",
|
|
9
|
+
version: "1.0.0",
|
|
10
|
+
});
|
|
11
|
+
// --- Tool: send_document ---
|
|
12
|
+
server.tool("send_document", "Send a document for two-party e-signing. Converts markdown to PDF, verifies the sender, emails the recipient a signing link, and delivers a SHA-256 certified signed copy to both parties.", {
|
|
13
|
+
markdown: z
|
|
14
|
+
.string()
|
|
15
|
+
.min(10)
|
|
16
|
+
.describe("Document content in markdown format. This will be converted to a professional PDF."),
|
|
17
|
+
title: z
|
|
18
|
+
.string()
|
|
19
|
+
.optional()
|
|
20
|
+
.describe("Document title. If omitted, extracted from the first markdown heading."),
|
|
21
|
+
sender_name: z.string().describe("Full name of the document sender"),
|
|
22
|
+
sender_email: z
|
|
23
|
+
.string()
|
|
24
|
+
.email()
|
|
25
|
+
.describe("Email address of the sender"),
|
|
26
|
+
recipient_name: z
|
|
27
|
+
.string()
|
|
28
|
+
.describe("Full name of the document recipient"),
|
|
29
|
+
recipient_email: z
|
|
30
|
+
.string()
|
|
31
|
+
.email()
|
|
32
|
+
.describe("Email address of the recipient"),
|
|
33
|
+
expires_in_days: z
|
|
34
|
+
.number()
|
|
35
|
+
.int()
|
|
36
|
+
.min(1)
|
|
37
|
+
.max(30)
|
|
38
|
+
.optional()
|
|
39
|
+
.describe("Days until the signing link expires. Default: 7"),
|
|
40
|
+
}, async (params) => {
|
|
41
|
+
try {
|
|
42
|
+
const body = {
|
|
43
|
+
markdown: params.markdown,
|
|
44
|
+
sender_name: params.sender_name,
|
|
45
|
+
sender_email: params.sender_email,
|
|
46
|
+
recipient_name: params.recipient_name,
|
|
47
|
+
recipient_email: params.recipient_email,
|
|
48
|
+
};
|
|
49
|
+
if (params.title)
|
|
50
|
+
body.title = params.title;
|
|
51
|
+
if (params.expires_in_days)
|
|
52
|
+
body.expires_in_days = params.expires_in_days;
|
|
53
|
+
const headers = {
|
|
54
|
+
"Content-Type": "application/json",
|
|
55
|
+
};
|
|
56
|
+
if (SIGNBEE_API_KEY) {
|
|
57
|
+
headers["Authorization"] = `Bearer ${SIGNBEE_API_KEY}`;
|
|
58
|
+
}
|
|
59
|
+
const response = await fetch(`${SIGNBEE_API_URL}/api/v1/send`, {
|
|
60
|
+
method: "POST",
|
|
61
|
+
headers,
|
|
62
|
+
body: JSON.stringify(body),
|
|
63
|
+
});
|
|
64
|
+
const data = await response.json();
|
|
65
|
+
if (!response.ok) {
|
|
66
|
+
return {
|
|
67
|
+
content: [
|
|
68
|
+
{
|
|
69
|
+
type: "text",
|
|
70
|
+
text: `Error (${response.status}): ${JSON.stringify(data)}`,
|
|
71
|
+
},
|
|
72
|
+
],
|
|
73
|
+
isError: true,
|
|
74
|
+
};
|
|
75
|
+
}
|
|
76
|
+
const status = data.status;
|
|
77
|
+
let summary;
|
|
78
|
+
if (status === "pending_recipient") {
|
|
79
|
+
summary = [
|
|
80
|
+
`✅ Document sent successfully!`,
|
|
81
|
+
``,
|
|
82
|
+
`📄 Document ID: ${data.document_id}`,
|
|
83
|
+
`👤 Sender: ${data.sender} (pre-verified via API key)`,
|
|
84
|
+
`📩 Recipient: ${data.recipient}`,
|
|
85
|
+
`⏰ Expires: ${data.expires_at}`,
|
|
86
|
+
``,
|
|
87
|
+
`The recipient has been emailed a signing link.`,
|
|
88
|
+
].join("\n");
|
|
89
|
+
}
|
|
90
|
+
else if (status === "pending_sender") {
|
|
91
|
+
summary = [
|
|
92
|
+
`📧 Verification required`,
|
|
93
|
+
``,
|
|
94
|
+
`📄 Document ID: ${data.document_id}`,
|
|
95
|
+
`📩 ${data.message}`,
|
|
96
|
+
``,
|
|
97
|
+
`The sender must verify their email before the document is sent to the recipient.`,
|
|
98
|
+
``,
|
|
99
|
+
`💡 Tip: Set the SIGNBEE_API_KEY environment variable to skip sender verification.`,
|
|
100
|
+
` Get your API key at: https://signb.ee/dashboard`,
|
|
101
|
+
].join("\n");
|
|
102
|
+
}
|
|
103
|
+
else {
|
|
104
|
+
summary = JSON.stringify(data, null, 2);
|
|
105
|
+
}
|
|
106
|
+
return {
|
|
107
|
+
content: [{ type: "text", text: summary }],
|
|
108
|
+
};
|
|
109
|
+
}
|
|
110
|
+
catch (error) {
|
|
111
|
+
return {
|
|
112
|
+
content: [
|
|
113
|
+
{
|
|
114
|
+
type: "text",
|
|
115
|
+
text: `Failed to send document: ${error instanceof Error ? error.message : String(error)}`,
|
|
116
|
+
},
|
|
117
|
+
],
|
|
118
|
+
isError: true,
|
|
119
|
+
};
|
|
120
|
+
}
|
|
121
|
+
});
|
|
122
|
+
// --- Tool: send_document_pdf ---
|
|
123
|
+
server.tool("send_document_pdf", "Send an existing PDF document for two-party e-signing. Use this when you already have a PDF URL instead of markdown content.", {
|
|
124
|
+
pdf_url: z
|
|
125
|
+
.string()
|
|
126
|
+
.url()
|
|
127
|
+
.describe("Publicly accessible URL to the PDF document"),
|
|
128
|
+
title: z.string().describe("Document title"),
|
|
129
|
+
sender_name: z.string().describe("Full name of the document sender"),
|
|
130
|
+
sender_email: z
|
|
131
|
+
.string()
|
|
132
|
+
.email()
|
|
133
|
+
.describe("Email address of the sender"),
|
|
134
|
+
recipient_name: z
|
|
135
|
+
.string()
|
|
136
|
+
.describe("Full name of the document recipient"),
|
|
137
|
+
recipient_email: z
|
|
138
|
+
.string()
|
|
139
|
+
.email()
|
|
140
|
+
.describe("Email address of the recipient"),
|
|
141
|
+
expires_in_days: z
|
|
142
|
+
.number()
|
|
143
|
+
.int()
|
|
144
|
+
.min(1)
|
|
145
|
+
.max(30)
|
|
146
|
+
.optional()
|
|
147
|
+
.describe("Days until the signing link expires. Default: 7"),
|
|
148
|
+
}, async (params) => {
|
|
149
|
+
try {
|
|
150
|
+
const body = {
|
|
151
|
+
markdown: "See attached PDF",
|
|
152
|
+
pdf_url: params.pdf_url,
|
|
153
|
+
title: params.title,
|
|
154
|
+
sender_name: params.sender_name,
|
|
155
|
+
sender_email: params.sender_email,
|
|
156
|
+
recipient_name: params.recipient_name,
|
|
157
|
+
recipient_email: params.recipient_email,
|
|
158
|
+
};
|
|
159
|
+
if (params.expires_in_days)
|
|
160
|
+
body.expires_in_days = params.expires_in_days;
|
|
161
|
+
const headers = {
|
|
162
|
+
"Content-Type": "application/json",
|
|
163
|
+
};
|
|
164
|
+
if (SIGNBEE_API_KEY) {
|
|
165
|
+
headers["Authorization"] = `Bearer ${SIGNBEE_API_KEY}`;
|
|
166
|
+
}
|
|
167
|
+
const response = await fetch(`${SIGNBEE_API_URL}/api/v1/send`, {
|
|
168
|
+
method: "POST",
|
|
169
|
+
headers,
|
|
170
|
+
body: JSON.stringify(body),
|
|
171
|
+
});
|
|
172
|
+
const data = await response.json();
|
|
173
|
+
if (!response.ok) {
|
|
174
|
+
return {
|
|
175
|
+
content: [
|
|
176
|
+
{
|
|
177
|
+
type: "text",
|
|
178
|
+
text: `Error (${response.status}): ${JSON.stringify(data)}`,
|
|
179
|
+
},
|
|
180
|
+
],
|
|
181
|
+
isError: true,
|
|
182
|
+
};
|
|
183
|
+
}
|
|
184
|
+
return {
|
|
185
|
+
content: [
|
|
186
|
+
{
|
|
187
|
+
type: "text",
|
|
188
|
+
text: `✅ PDF document "${params.title}" sent for signing.\n\n📄 Document ID: ${data.document_id}\nStatus: ${data.status}`,
|
|
189
|
+
},
|
|
190
|
+
],
|
|
191
|
+
};
|
|
192
|
+
}
|
|
193
|
+
catch (error) {
|
|
194
|
+
return {
|
|
195
|
+
content: [
|
|
196
|
+
{
|
|
197
|
+
type: "text",
|
|
198
|
+
text: `Failed to send PDF: ${error instanceof Error ? error.message : String(error)}`,
|
|
199
|
+
},
|
|
200
|
+
],
|
|
201
|
+
isError: true,
|
|
202
|
+
};
|
|
203
|
+
}
|
|
204
|
+
});
|
|
205
|
+
// --- Start server ---
|
|
206
|
+
async function main() {
|
|
207
|
+
const transport = new StdioServerTransport();
|
|
208
|
+
await server.connect(transport);
|
|
209
|
+
}
|
|
210
|
+
main().catch((error) => {
|
|
211
|
+
console.error("Server error:", error);
|
|
212
|
+
process.exit(1);
|
|
213
|
+
});
|
package/package.json
ADDED
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "signbee-mcp",
|
|
3
|
+
"version": "1.0.0",
|
|
4
|
+
"description": "MCP server for Signbee — document signing for AI agents",
|
|
5
|
+
"type": "module",
|
|
6
|
+
"bin": {
|
|
7
|
+
"signbee-mcp": "./build/index.js"
|
|
8
|
+
},
|
|
9
|
+
"files": [
|
|
10
|
+
"build"
|
|
11
|
+
],
|
|
12
|
+
"scripts": {
|
|
13
|
+
"build": "tsc && chmod 755 build/index.js",
|
|
14
|
+
"dev": "tsc --watch",
|
|
15
|
+
"start": "node build/index.js"
|
|
16
|
+
},
|
|
17
|
+
"keywords": [
|
|
18
|
+
"mcp",
|
|
19
|
+
"model-context-protocol",
|
|
20
|
+
"signbee",
|
|
21
|
+
"document-signing",
|
|
22
|
+
"ai-agents",
|
|
23
|
+
"e-signatures"
|
|
24
|
+
],
|
|
25
|
+
"author": "B2bee Ltd",
|
|
26
|
+
"license": "MIT",
|
|
27
|
+
"repository": {
|
|
28
|
+
"type": "git",
|
|
29
|
+
"url": "https://github.com/talentseek/signbee-mcp.git"
|
|
30
|
+
},
|
|
31
|
+
"dependencies": {
|
|
32
|
+
"@modelcontextprotocol/sdk": "^1.12.0",
|
|
33
|
+
"zod": "^3.25.0"
|
|
34
|
+
},
|
|
35
|
+
"devDependencies": {
|
|
36
|
+
"typescript": "^5.8.0",
|
|
37
|
+
"@types/node": "^22.0.0"
|
|
38
|
+
}
|
|
39
|
+
}
|