@coffrify/mcp 0.1.2 → 0.2.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/dist/server.js +301 -83
- package/package.json +2 -2
package/dist/server.js
CHANGED
|
@@ -3,8 +3,15 @@
|
|
|
3
3
|
// src/server.ts
|
|
4
4
|
import { Server } from "@modelcontextprotocol/sdk/server/index.js";
|
|
5
5
|
import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio.js";
|
|
6
|
-
import {
|
|
7
|
-
|
|
6
|
+
import {
|
|
7
|
+
CallToolRequestSchema,
|
|
8
|
+
ListToolsRequestSchema,
|
|
9
|
+
ListResourcesRequestSchema,
|
|
10
|
+
ReadResourceRequestSchema,
|
|
11
|
+
ListPromptsRequestSchema,
|
|
12
|
+
GetPromptRequestSchema
|
|
13
|
+
} from "@modelcontextprotocol/sdk/types.js";
|
|
14
|
+
import { Coffrify, COFFRIFY_EVENT_CATALOG } from "@coffrify/sdk";
|
|
8
15
|
var apiKey = process.env.COFFRIFY_API_KEY;
|
|
9
16
|
var apiUrl = process.env.COFFRIFY_API_URL ?? "https://api.coffrify.com";
|
|
10
17
|
if (!apiKey) {
|
|
@@ -13,33 +20,42 @@ if (!apiKey) {
|
|
|
13
20
|
}
|
|
14
21
|
var coffrify = new Coffrify({ apiKey, apiUrl });
|
|
15
22
|
var server = new Server(
|
|
16
|
-
{ name: "coffrify", version: "0.
|
|
17
|
-
{ capabilities: { tools: {} } }
|
|
23
|
+
{ name: "coffrify", version: "0.2.0" },
|
|
24
|
+
{ capabilities: { tools: {}, resources: {}, prompts: {} } }
|
|
18
25
|
);
|
|
26
|
+
var eventEnum = COFFRIFY_EVENT_CATALOG.map((e) => e.type);
|
|
19
27
|
var TOOLS = [
|
|
20
28
|
{
|
|
21
29
|
name: "coffrify_list_transfers",
|
|
22
|
-
description: "List recent encrypted file transfers in the workspace.
|
|
30
|
+
description: "List recent encrypted file transfers in the workspace.",
|
|
23
31
|
inputSchema: {
|
|
24
32
|
type: "object",
|
|
25
33
|
properties: {
|
|
26
|
-
limit: { type: "number",
|
|
27
|
-
status: { type: "string", description: "
|
|
34
|
+
limit: { type: "number", default: 20 },
|
|
35
|
+
status: { type: "string", description: "active|expired|deleted" }
|
|
28
36
|
}
|
|
29
37
|
}
|
|
30
38
|
},
|
|
31
39
|
{
|
|
32
|
-
name: "
|
|
33
|
-
description: "
|
|
40
|
+
name: "coffrify_search_transfers",
|
|
41
|
+
description: "Search transfers by title substring or short_code prefix.",
|
|
34
42
|
inputSchema: {
|
|
35
43
|
type: "object",
|
|
36
|
-
properties: {
|
|
37
|
-
|
|
44
|
+
properties: {
|
|
45
|
+
query: { type: "string", description: "Substring (case-insensitive) to match against title or short_code" },
|
|
46
|
+
limit: { type: "number", default: 20 }
|
|
47
|
+
},
|
|
48
|
+
required: ["query"]
|
|
38
49
|
}
|
|
39
50
|
},
|
|
51
|
+
{
|
|
52
|
+
name: "coffrify_get_transfer",
|
|
53
|
+
description: "Get full details of a transfer (files, settings, scan status).",
|
|
54
|
+
inputSchema: { type: "object", properties: { id: { type: "string" } }, required: ["id"] }
|
|
55
|
+
},
|
|
40
56
|
{
|
|
41
57
|
name: "coffrify_create_transfer",
|
|
42
|
-
description: "Create a new encrypted file transfer. Returns the transfer + share URL.
|
|
58
|
+
description: "Create a new encrypted file transfer. Returns the transfer + share URL.",
|
|
43
59
|
inputSchema: {
|
|
44
60
|
type: "object",
|
|
45
61
|
properties: {
|
|
@@ -59,119 +75,123 @@ var TOOLS = [
|
|
|
59
75
|
max_downloads: { type: "number" },
|
|
60
76
|
password: { type: "string" },
|
|
61
77
|
transfer_title: { type: "string" },
|
|
62
|
-
burn_after_read: { type: "boolean" }
|
|
78
|
+
burn_after_read: { type: "boolean" },
|
|
79
|
+
encryption_mode: { type: "string", enum: ["server_side", "e2e_v1"], default: "server_side" }
|
|
63
80
|
},
|
|
64
81
|
required: ["files"]
|
|
65
82
|
}
|
|
66
83
|
},
|
|
67
84
|
{
|
|
68
85
|
name: "coffrify_delete_transfer",
|
|
69
|
-
description: "Delete a transfer (
|
|
86
|
+
description: "Delete a transfer (irreversible).",
|
|
87
|
+
inputSchema: { type: "object", properties: { id: { type: "string" } }, required: ["id"] }
|
|
88
|
+
},
|
|
89
|
+
{
|
|
90
|
+
name: "coffrify_bulk_delete_transfers",
|
|
91
|
+
description: "Delete multiple transfers at once. Returns per-id success/failure.",
|
|
70
92
|
inputSchema: {
|
|
71
93
|
type: "object",
|
|
72
|
-
properties: {
|
|
73
|
-
required: ["
|
|
94
|
+
properties: { ids: { type: "array", items: { type: "string" }, minItems: 1, maxItems: 100 } },
|
|
95
|
+
required: ["ids"]
|
|
74
96
|
}
|
|
75
97
|
},
|
|
76
98
|
{
|
|
77
99
|
name: "coffrify_list_webhooks",
|
|
78
|
-
description: "List configured webhook endpoints
|
|
100
|
+
description: "List configured webhook endpoints.",
|
|
79
101
|
inputSchema: { type: "object", properties: {} }
|
|
80
102
|
},
|
|
81
103
|
{
|
|
82
104
|
name: "coffrify_create_webhook",
|
|
83
|
-
description: "Create a webhook subscription. Returns the webhook +
|
|
105
|
+
description: "Create a webhook subscription. Returns the webhook + signing secret (shown once).",
|
|
84
106
|
inputSchema: {
|
|
85
107
|
type: "object",
|
|
86
108
|
properties: {
|
|
87
109
|
name: { type: "string" },
|
|
88
|
-
url: { type: "string"
|
|
89
|
-
events: {
|
|
90
|
-
|
|
91
|
-
items: {
|
|
92
|
-
type: "string",
|
|
93
|
-
enum: ["transfer.created", "transfer.downloaded", "transfer.expired", "transfer.deleted", "transfer.scanned", "transfer.cloned", "transfer.limit_reached"]
|
|
94
|
-
}
|
|
95
|
-
}
|
|
110
|
+
url: { type: "string" },
|
|
111
|
+
events: { type: "array", items: { type: "string", enum: eventEnum } },
|
|
112
|
+
description: { type: "string" }
|
|
96
113
|
},
|
|
97
114
|
required: ["name", "url", "events"]
|
|
98
115
|
}
|
|
99
116
|
},
|
|
100
117
|
{
|
|
101
118
|
name: "coffrify_test_webhook",
|
|
102
|
-
description: "Send a test ping event to a webhook
|
|
103
|
-
inputSchema: {
|
|
104
|
-
type: "object",
|
|
105
|
-
properties: { id: { type: "string" } },
|
|
106
|
-
required: ["id"]
|
|
107
|
-
}
|
|
119
|
+
description: "Send a test ping event to a webhook.",
|
|
120
|
+
inputSchema: { type: "object", properties: { id: { type: "string" } }, required: ["id"] }
|
|
108
121
|
},
|
|
109
122
|
{
|
|
110
123
|
name: "coffrify_list_webhook_deliveries",
|
|
111
|
-
description: "List recent delivery attempts for a webhook
|
|
124
|
+
description: "List recent delivery attempts for a webhook.",
|
|
112
125
|
inputSchema: {
|
|
113
126
|
type: "object",
|
|
114
|
-
properties: {
|
|
115
|
-
webhook_id: { type: "string" },
|
|
116
|
-
limit: { type: "number", default: 20 }
|
|
117
|
-
},
|
|
127
|
+
properties: { webhook_id: { type: "string" }, limit: { type: "number", default: 20 } },
|
|
118
128
|
required: ["webhook_id"]
|
|
119
129
|
}
|
|
120
130
|
},
|
|
121
131
|
{
|
|
122
132
|
name: "coffrify_replay_webhook_delivery",
|
|
123
|
-
description: "Replay a past webhook delivery
|
|
133
|
+
description: "Replay a past webhook delivery.",
|
|
134
|
+
inputSchema: { type: "object", properties: { delivery_id: { type: "string" } }, required: ["delivery_id"] }
|
|
135
|
+
},
|
|
136
|
+
{
|
|
137
|
+
name: "coffrify_list_webhook_event_types",
|
|
138
|
+
description: "Return the catalog of every supported webhook event type with descriptions, families, stability, and required plan.",
|
|
124
139
|
inputSchema: {
|
|
125
140
|
type: "object",
|
|
126
|
-
properties: {
|
|
127
|
-
|
|
141
|
+
properties: {
|
|
142
|
+
family: { type: "string", description: "Filter by family: transfer|workspace|api_key|webhook|scim|saml|audit|gdpr|system|member|api_token" }
|
|
143
|
+
}
|
|
128
144
|
}
|
|
129
145
|
},
|
|
130
146
|
{
|
|
131
147
|
name: "coffrify_list_api_keys",
|
|
132
|
-
description: "List API keys
|
|
148
|
+
description: "List API keys (key values are hashed and never returned).",
|
|
133
149
|
inputSchema: { type: "object", properties: {} }
|
|
134
150
|
},
|
|
135
151
|
{
|
|
136
152
|
name: "coffrify_create_api_key",
|
|
137
|
-
description: "Create a new API key. Returns the key value ONCE \u2014
|
|
153
|
+
description: "Create a new API key. Returns the key value ONCE \u2014 store securely. Specify scopes for least-privilege access.",
|
|
138
154
|
inputSchema: {
|
|
139
155
|
type: "object",
|
|
140
156
|
properties: {
|
|
141
157
|
name: { type: "string" },
|
|
142
158
|
description: { type: "string" },
|
|
143
159
|
environment: { type: "string", enum: ["live", "test"], default: "live" },
|
|
144
|
-
scopes: {
|
|
145
|
-
type: "array",
|
|
146
|
-
items: { type: "string" },
|
|
147
|
-
description: "e.g. ['transfers:read', 'transfers:write', 'webhooks:manage']"
|
|
148
|
-
},
|
|
160
|
+
scopes: { type: "array", items: { type: "string" } },
|
|
149
161
|
expires_in_days: { type: "number" },
|
|
150
|
-
allowed_ips: { type: "array", items: { type: "string" }
|
|
162
|
+
allowed_ips: { type: "array", items: { type: "string" } }
|
|
151
163
|
},
|
|
152
164
|
required: ["name"]
|
|
153
165
|
}
|
|
154
166
|
},
|
|
155
167
|
{
|
|
156
168
|
name: "coffrify_revoke_api_key",
|
|
157
|
-
description: "Revoke an API key (
|
|
169
|
+
description: "Revoke an API key (irreversible).",
|
|
170
|
+
inputSchema: { type: "object", properties: { id: { type: "string" } }, required: ["id"] }
|
|
171
|
+
},
|
|
172
|
+
{
|
|
173
|
+
name: "coffrify_rotate_api_key",
|
|
174
|
+
description: "Rotate an API key \u2014 mints a new one with same scopes. Old key revokes after grace_days (default 7, max 30).",
|
|
158
175
|
inputSchema: {
|
|
159
176
|
type: "object",
|
|
160
|
-
properties: {
|
|
177
|
+
properties: {
|
|
178
|
+
id: { type: "string" },
|
|
179
|
+
grace_days: { type: "number", default: 7 }
|
|
180
|
+
},
|
|
161
181
|
required: ["id"]
|
|
162
182
|
}
|
|
163
183
|
},
|
|
164
184
|
{
|
|
165
185
|
name: "coffrify_query_audit_log",
|
|
166
|
-
description: "Query the workspace audit log.
|
|
186
|
+
description: "Query the workspace audit log. Filter by action, actor, time range. Supports relative since (e.g. '24h').",
|
|
167
187
|
inputSchema: {
|
|
168
188
|
type: "object",
|
|
169
189
|
properties: {
|
|
170
|
-
action: { type: "string"
|
|
190
|
+
action: { type: "string" },
|
|
171
191
|
actor_id: { type: "string" },
|
|
172
192
|
resource_type: { type: "string" },
|
|
173
|
-
since: { type: "string"
|
|
174
|
-
until: { type: "string"
|
|
193
|
+
since: { type: "string" },
|
|
194
|
+
until: { type: "string" },
|
|
175
195
|
limit: { type: "number", default: 100 }
|
|
176
196
|
}
|
|
177
197
|
}
|
|
@@ -182,22 +202,196 @@ var TOOLS = [
|
|
|
182
202
|
inputSchema: { type: "object", properties: {} }
|
|
183
203
|
}
|
|
184
204
|
];
|
|
185
|
-
server.setRequestHandler(
|
|
186
|
-
|
|
205
|
+
server.setRequestHandler(ListResourcesRequestSchema, async () => ({
|
|
206
|
+
resources: [
|
|
207
|
+
{ uri: "coffrify://transfers", name: "transfers", description: "All recent transfers (JSON list)", mimeType: "application/json" },
|
|
208
|
+
{ uri: "coffrify://webhooks", name: "webhooks", description: "All webhook endpoints", mimeType: "application/json" },
|
|
209
|
+
{ uri: "coffrify://api-keys", name: "api-keys", description: "All API keys (hashed)", mimeType: "application/json" },
|
|
210
|
+
{ uri: "coffrify://events", name: "events", description: "Catalog of every supported webhook event type", mimeType: "application/json" },
|
|
211
|
+
{ uri: "coffrify://workspace", name: "workspace", description: "Current workspace + scopes", mimeType: "application/json" },
|
|
212
|
+
{ uri: "coffrify://audit", name: "audit", description: "Recent audit log entries (last 100)", mimeType: "application/json" }
|
|
213
|
+
]
|
|
187
214
|
}));
|
|
215
|
+
server.setRequestHandler(ReadResourceRequestSchema, async (req) => {
|
|
216
|
+
const uri = req.params.uri;
|
|
217
|
+
let data;
|
|
218
|
+
if (uri === "coffrify://transfers") {
|
|
219
|
+
data = await coffrify.transfers.list({ limit: 50 });
|
|
220
|
+
} else if (uri.startsWith("coffrify://transfers/")) {
|
|
221
|
+
data = await coffrify.transfers.get(uri.split("/").pop());
|
|
222
|
+
} else if (uri === "coffrify://webhooks") {
|
|
223
|
+
data = await coffrify.webhooks.list();
|
|
224
|
+
} else if (uri.startsWith("coffrify://webhooks/")) {
|
|
225
|
+
const id = uri.split("/").pop();
|
|
226
|
+
const [hooks, deliveries] = await Promise.all([
|
|
227
|
+
coffrify.webhooks.list(),
|
|
228
|
+
coffrify.webhooks.deliveries(id, { limit: 10 }).catch(() => null)
|
|
229
|
+
]);
|
|
230
|
+
const webhook = (hooks.webhooks ?? hooks.data ?? []).find((w) => w.id === id);
|
|
231
|
+
data = { webhook, recent_deliveries: deliveries };
|
|
232
|
+
} else if (uri === "coffrify://api-keys") {
|
|
233
|
+
data = await coffrify.apiKeys.list();
|
|
234
|
+
} else if (uri === "coffrify://events") {
|
|
235
|
+
data = { catalog: COFFRIFY_EVENT_CATALOG };
|
|
236
|
+
} else if (uri === "coffrify://workspace") {
|
|
237
|
+
data = await coffrify.http.request("GET", "/me");
|
|
238
|
+
} else if (uri === "coffrify://audit") {
|
|
239
|
+
data = await coffrify.audit.list({ limit: 100 });
|
|
240
|
+
} else {
|
|
241
|
+
throw new Error(`Unknown resource: ${uri}`);
|
|
242
|
+
}
|
|
243
|
+
return {
|
|
244
|
+
contents: [{ uri, mimeType: "application/json", text: JSON.stringify(data, null, 2) }]
|
|
245
|
+
};
|
|
246
|
+
});
|
|
247
|
+
var PROMPTS = [
|
|
248
|
+
{
|
|
249
|
+
name: "send_invoice",
|
|
250
|
+
description: "Compose and send an invoice file as a Coffrify transfer with sensible defaults.",
|
|
251
|
+
arguments: [
|
|
252
|
+
{ name: "recipient_email", description: "Recipient email", required: true },
|
|
253
|
+
{ name: "invoice_filename", description: "Filename of the invoice (e.g. INV-2026-001.pdf)", required: true },
|
|
254
|
+
{ name: "expires_in_days", description: "Expiration window (default 30)", required: false }
|
|
255
|
+
]
|
|
256
|
+
},
|
|
257
|
+
{
|
|
258
|
+
name: "audit_weekly",
|
|
259
|
+
description: "Pull the last 7 days of audit log and summarize unusual activity.",
|
|
260
|
+
arguments: []
|
|
261
|
+
},
|
|
262
|
+
{
|
|
263
|
+
name: "rotate_all_api_keys",
|
|
264
|
+
description: "Rotate every API key in the workspace with a 7-day grace window.",
|
|
265
|
+
arguments: []
|
|
266
|
+
},
|
|
267
|
+
{
|
|
268
|
+
name: "subscribe_to_security_events",
|
|
269
|
+
description: "Create a webhook subscribed to all security-relevant events (geo_blocked, password_failed, scan_infected, suspicious_usage, saml.login_failed).",
|
|
270
|
+
arguments: [
|
|
271
|
+
{ name: "endpoint_url", description: "HTTPS endpoint to receive events", required: true }
|
|
272
|
+
]
|
|
273
|
+
},
|
|
274
|
+
{
|
|
275
|
+
name: "investigate_transfer",
|
|
276
|
+
description: "Pull a transfer + its scan results + recent webhook deliveries to investigate an incident.",
|
|
277
|
+
arguments: [
|
|
278
|
+
{ name: "short_code", description: "Short code or ID of the transfer", required: true }
|
|
279
|
+
]
|
|
280
|
+
}
|
|
281
|
+
];
|
|
282
|
+
server.setRequestHandler(ListPromptsRequestSchema, async () => ({ prompts: PROMPTS }));
|
|
283
|
+
server.setRequestHandler(GetPromptRequestSchema, async (req) => {
|
|
284
|
+
const { name, arguments: args = {} } = req.params;
|
|
285
|
+
const a = args;
|
|
286
|
+
switch (name) {
|
|
287
|
+
case "send_invoice":
|
|
288
|
+
return {
|
|
289
|
+
description: "Send an invoice via Coffrify",
|
|
290
|
+
messages: [{
|
|
291
|
+
role: "user",
|
|
292
|
+
content: {
|
|
293
|
+
type: "text",
|
|
294
|
+
text: `Send the file "${a.invoice_filename}" as a Coffrify transfer.
|
|
295
|
+
Recipient: ${a.recipient_email}.
|
|
296
|
+
Expiration: ${a.expires_in_days ?? "30"} days.
|
|
297
|
+
Use the coffrify_create_transfer tool with: title="Invoice ${a.invoice_filename}", expires_in_hours=${parseInt(a.expires_in_days ?? "30", 10) * 24}, max_downloads=3.
|
|
298
|
+
Then share the returned share_url with the recipient.`
|
|
299
|
+
}
|
|
300
|
+
}]
|
|
301
|
+
};
|
|
302
|
+
case "audit_weekly":
|
|
303
|
+
return {
|
|
304
|
+
description: "Weekly audit summary",
|
|
305
|
+
messages: [{
|
|
306
|
+
role: "user",
|
|
307
|
+
content: {
|
|
308
|
+
type: "text",
|
|
309
|
+
text: `Use coffrify_query_audit_log with since="7d" and limit=500 to fetch the last week of activity.
|
|
310
|
+
Summarize:
|
|
311
|
+
1. Top 5 most frequent actions
|
|
312
|
+
2. Any failed/denied actions and what they indicate
|
|
313
|
+
3. Unusual IP addresses or geo distributions
|
|
314
|
+
4. Any api_key.suspicious_usage or saml.login_failed events
|
|
315
|
+
Output a brief markdown report.`
|
|
316
|
+
}
|
|
317
|
+
}]
|
|
318
|
+
};
|
|
319
|
+
case "rotate_all_api_keys":
|
|
320
|
+
return {
|
|
321
|
+
description: "Rotate every API key with 7-day grace",
|
|
322
|
+
messages: [{
|
|
323
|
+
role: "user",
|
|
324
|
+
content: {
|
|
325
|
+
type: "text",
|
|
326
|
+
text: `1. Call coffrify_list_api_keys to get all active keys.
|
|
327
|
+
2. For each key with status=active and not already rotated, call coffrify_rotate_api_key with grace_days=7.
|
|
328
|
+
3. Report: { rotated_count, new_keys: [{ name, new_prefix, grace_until }] }.
|
|
329
|
+
Stress that the new key values are returned ONCE \u2014 they must be saved immediately.`
|
|
330
|
+
}
|
|
331
|
+
}]
|
|
332
|
+
};
|
|
333
|
+
case "subscribe_to_security_events":
|
|
334
|
+
return {
|
|
335
|
+
description: "Wire a webhook to all security events",
|
|
336
|
+
messages: [{
|
|
337
|
+
role: "user",
|
|
338
|
+
content: {
|
|
339
|
+
type: "text",
|
|
340
|
+
text: `Call coffrify_create_webhook with:
|
|
341
|
+
name = "Security events"
|
|
342
|
+
url = "${a.endpoint_url}"
|
|
343
|
+
events = ["transfer.password_failed", "transfer.geo_blocked", "transfer.scan_infected", "transfer.scan_quarantined",
|
|
344
|
+
"api_key.suspicious_usage", "api_key.expired", "api_key.revoked",
|
|
345
|
+
"saml.login_failed", "audit.policy_violated",
|
|
346
|
+
"webhook.endpoint_disabled", "workspace.payment_failed"]
|
|
347
|
+
Print the returned signing secret to the user \u2014 it's shown only once.`
|
|
348
|
+
}
|
|
349
|
+
}]
|
|
350
|
+
};
|
|
351
|
+
case "investigate_transfer":
|
|
352
|
+
return {
|
|
353
|
+
description: "Investigate a transfer incident",
|
|
354
|
+
messages: [{
|
|
355
|
+
role: "user",
|
|
356
|
+
content: {
|
|
357
|
+
type: "text",
|
|
358
|
+
text: `Investigate transfer "${a.short_code}":
|
|
359
|
+
1. Use coffrify_search_transfers query="${a.short_code}" to locate it.
|
|
360
|
+
2. Call coffrify_get_transfer with the id to fetch full details (scan_status, downloads, password_protected).
|
|
361
|
+
3. Call coffrify_query_audit_log with resource_id=<that id> since="30d" to pull related audit entries.
|
|
362
|
+
4. List any recent webhook deliveries that mention this transfer.
|
|
363
|
+
5. Output a timeline + a diagnosis of what happened.`
|
|
364
|
+
}
|
|
365
|
+
}]
|
|
366
|
+
};
|
|
367
|
+
default:
|
|
368
|
+
throw new Error(`Unknown prompt: ${name}`);
|
|
369
|
+
}
|
|
370
|
+
});
|
|
371
|
+
server.setRequestHandler(ListToolsRequestSchema, async () => ({ tools: TOOLS }));
|
|
188
372
|
server.setRequestHandler(CallToolRequestSchema, async (request) => {
|
|
189
373
|
const { name, arguments: args = {} } = request.params;
|
|
190
374
|
try {
|
|
191
375
|
let result;
|
|
376
|
+
const a = args;
|
|
192
377
|
switch (name) {
|
|
193
378
|
case "coffrify_list_transfers":
|
|
194
|
-
result = await coffrify.transfers.list(
|
|
379
|
+
result = await coffrify.transfers.list(a);
|
|
380
|
+
break;
|
|
381
|
+
case "coffrify_search_transfers": {
|
|
382
|
+
const list = await coffrify.transfers.list({ limit: 100 });
|
|
383
|
+
const arr = list.transfers ?? list.data ?? [];
|
|
384
|
+
const q = a.query.toLowerCase();
|
|
385
|
+
const matches = arr.filter(
|
|
386
|
+
(t) => (t.transfer_title ?? "").toLowerCase().includes(q) || (t.short_code ?? "").toLowerCase().startsWith(q)
|
|
387
|
+
).slice(0, a.limit ?? 20);
|
|
388
|
+
result = { matches, total: matches.length };
|
|
195
389
|
break;
|
|
390
|
+
}
|
|
196
391
|
case "coffrify_get_transfer":
|
|
197
|
-
result = await coffrify.transfers.get(
|
|
392
|
+
result = await coffrify.transfers.get(a.id);
|
|
198
393
|
break;
|
|
199
|
-
case "coffrify_create_transfer":
|
|
200
|
-
const a = args;
|
|
394
|
+
case "coffrify_create_transfer":
|
|
201
395
|
result = await coffrify.transfers.create(a.files, {
|
|
202
396
|
expires_in_hours: a.expires_in_hours,
|
|
203
397
|
max_downloads: a.max_downloads,
|
|
@@ -206,68 +400,92 @@ server.setRequestHandler(CallToolRequestSchema, async (request) => {
|
|
|
206
400
|
burn_after_read: a.burn_after_read
|
|
207
401
|
});
|
|
208
402
|
break;
|
|
209
|
-
}
|
|
210
403
|
case "coffrify_delete_transfer":
|
|
211
|
-
result = await coffrify.transfers.delete(
|
|
404
|
+
result = await coffrify.transfers.delete(a.id);
|
|
212
405
|
break;
|
|
406
|
+
case "coffrify_bulk_delete_transfers": {
|
|
407
|
+
const out = [];
|
|
408
|
+
for (const id of a.ids) {
|
|
409
|
+
try {
|
|
410
|
+
await coffrify.transfers.delete(id);
|
|
411
|
+
out.push({ id, ok: true });
|
|
412
|
+
} catch (e) {
|
|
413
|
+
out.push({ id, ok: false, error: e?.message ?? String(e) });
|
|
414
|
+
}
|
|
415
|
+
}
|
|
416
|
+
result = { results: out, ok_count: out.filter((r) => r.ok).length };
|
|
417
|
+
break;
|
|
418
|
+
}
|
|
213
419
|
case "coffrify_list_webhooks":
|
|
214
420
|
result = await coffrify.webhooks.list();
|
|
215
421
|
break;
|
|
216
|
-
case "coffrify_create_webhook":
|
|
217
|
-
|
|
218
|
-
|
|
422
|
+
case "coffrify_create_webhook":
|
|
423
|
+
result = await coffrify.webhooks.create({
|
|
424
|
+
name: a.name,
|
|
425
|
+
url: a.url,
|
|
426
|
+
events: a.events,
|
|
427
|
+
description: a.description
|
|
428
|
+
});
|
|
219
429
|
break;
|
|
220
|
-
}
|
|
221
430
|
case "coffrify_test_webhook":
|
|
222
|
-
result = await coffrify.webhooks.test(
|
|
431
|
+
result = await coffrify.webhooks.test(a.id);
|
|
223
432
|
break;
|
|
224
|
-
case "coffrify_list_webhook_deliveries":
|
|
225
|
-
const a = args;
|
|
433
|
+
case "coffrify_list_webhook_deliveries":
|
|
226
434
|
result = await coffrify.webhooks.deliveries(a.webhook_id, { limit: a.limit });
|
|
227
435
|
break;
|
|
228
|
-
}
|
|
229
436
|
case "coffrify_replay_webhook_delivery":
|
|
230
|
-
result = await coffrify.webhooks.replay(
|
|
437
|
+
result = await coffrify.webhooks.replay(a.delivery_id);
|
|
231
438
|
break;
|
|
439
|
+
case "coffrify_list_webhook_event_types": {
|
|
440
|
+
const filtered = a.family ? COFFRIFY_EVENT_CATALOG.filter((e) => e.family === a.family) : COFFRIFY_EVENT_CATALOG;
|
|
441
|
+
result = { events: filtered, total: filtered.length };
|
|
442
|
+
break;
|
|
443
|
+
}
|
|
232
444
|
case "coffrify_list_api_keys":
|
|
233
445
|
result = await coffrify.apiKeys.list();
|
|
234
446
|
break;
|
|
235
447
|
case "coffrify_create_api_key":
|
|
236
|
-
result = await coffrify.apiKeys.create(
|
|
448
|
+
result = await coffrify.apiKeys.create(a);
|
|
237
449
|
break;
|
|
238
450
|
case "coffrify_revoke_api_key":
|
|
239
|
-
result = await coffrify.apiKeys.revoke(
|
|
451
|
+
result = await coffrify.apiKeys.revoke(a.id);
|
|
452
|
+
break;
|
|
453
|
+
case "coffrify_rotate_api_key":
|
|
454
|
+
result = await coffrify.http.request(
|
|
455
|
+
"POST",
|
|
456
|
+
`/api-keys/${encodeURIComponent(a.id)}/rotate`,
|
|
457
|
+
{ grace_days: a.grace_days ?? 7 }
|
|
458
|
+
);
|
|
240
459
|
break;
|
|
241
460
|
case "coffrify_query_audit_log": {
|
|
242
|
-
const a = args;
|
|
243
461
|
let since = a.since;
|
|
244
462
|
if (since && /^\d+[hdw]$/.test(since)) {
|
|
245
463
|
const m = since.match(/^(\d+)([hdw])$/);
|
|
246
|
-
const n = parseInt(m[1]);
|
|
464
|
+
const n = parseInt(m[1], 10);
|
|
247
465
|
const ms = m[2] === "h" ? n * 36e5 : m[2] === "d" ? n * 864e5 : n * 7 * 864e5;
|
|
248
466
|
since = new Date(Date.now() - ms).toISOString();
|
|
249
467
|
}
|
|
250
468
|
result = await coffrify.audit.list({ ...a, since });
|
|
251
469
|
break;
|
|
252
470
|
}
|
|
253
|
-
case "coffrify_get_workspace_info":
|
|
471
|
+
case "coffrify_get_workspace_info":
|
|
254
472
|
result = await coffrify.http.request("GET", "/me");
|
|
255
473
|
break;
|
|
256
|
-
}
|
|
257
474
|
default:
|
|
258
475
|
throw new Error(`Unknown tool: ${name}`);
|
|
259
476
|
}
|
|
260
|
-
return {
|
|
261
|
-
content: [{ type: "text", text: JSON.stringify(result, null, 2) }]
|
|
262
|
-
};
|
|
477
|
+
return { content: [{ type: "text", text: JSON.stringify(result, null, 2) }] };
|
|
263
478
|
} catch (e) {
|
|
264
479
|
return {
|
|
265
|
-
content: [{
|
|
266
|
-
|
|
480
|
+
content: [{
|
|
481
|
+
type: "text",
|
|
482
|
+
text: `Error: ${e?.message ?? "unknown"}
|
|
483
|
+
${JSON.stringify(e?.details ?? {}, null, 2)}`
|
|
484
|
+
}],
|
|
267
485
|
isError: true
|
|
268
486
|
};
|
|
269
487
|
}
|
|
270
488
|
});
|
|
271
489
|
var transport = new StdioServerTransport();
|
|
272
490
|
await server.connect(transport);
|
|
273
|
-
console.error("[coffrify-mcp]
|
|
491
|
+
console.error("[coffrify-mcp] v0.2.0 connected via stdio (Tools + Resources + Prompts)");
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@coffrify/mcp",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.2.0",
|
|
4
4
|
"description": "Coffrify MCP server — gives Claude/Cursor/Windsurf agents direct access to Coffrify (transfers, webhooks, audit, API keys).",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"bin": {
|
|
@@ -29,7 +29,7 @@
|
|
|
29
29
|
"dependencies": {
|
|
30
30
|
"@modelcontextprotocol/sdk": "^1.0.0",
|
|
31
31
|
"zod": "^3.23.8",
|
|
32
|
-
"@coffrify/sdk": "0.
|
|
32
|
+
"@coffrify/sdk": "0.4.0"
|
|
33
33
|
},
|
|
34
34
|
"devDependencies": {
|
|
35
35
|
"@types/node": "^22.0.0",
|