@papermark/mcp-server 0.0.1 → 0.1.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/index.js ADDED
@@ -0,0 +1,1072 @@
1
+ #!/usr/bin/env node
2
+ import {
3
+ addDocumentVersionContract,
4
+ attachDataroomDocumentContract,
5
+ createDataroomContract,
6
+ createDataroomFolderContract,
7
+ createFolderContract,
8
+ createLinkContract,
9
+ deleteDataroomContract,
10
+ deleteDataroomFolderContract,
11
+ deleteDocumentContract,
12
+ deleteFolderContract,
13
+ deleteLinkContract,
14
+ getDataroomAnalyticsContract,
15
+ getDataroomContract,
16
+ getDataroomFolderContract,
17
+ getDocumentAnalyticsContract,
18
+ getDocumentContract,
19
+ getDocumentVersionContract,
20
+ getFolderContract,
21
+ getLinkAnalyticsContract,
22
+ getLinkContract,
23
+ getViewAnalyticsContract,
24
+ getVisitorContract,
25
+ listDataroomDocumentsContract,
26
+ listDataroomFoldersContract,
27
+ listDataroomsContract,
28
+ listDocumentVersionsContract,
29
+ listDocumentsContract,
30
+ listFoldersContract,
31
+ listLinkViewsContract,
32
+ listLinksContract,
33
+ listVisitorViewsContract,
34
+ listVisitorsContract,
35
+ moveDataroomFolderContract,
36
+ moveFolderContract,
37
+ promoteDocumentVersionContract,
38
+ searchDataroomsContract,
39
+ searchDocumentsContract,
40
+ updateDataroomContract,
41
+ updateDataroomFolderContract,
42
+ updateDocumentContract,
43
+ updateFolderContract,
44
+ updateLinkContract
45
+ } from "./chunk-S3ALJ4YG.js";
46
+
47
+ // src/index.ts
48
+ import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
49
+ import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio.js";
50
+
51
+ // src/tools.ts
52
+ import { readFile, stat } from "fs/promises";
53
+ import { basename } from "path";
54
+ import { lookup as lookupMimeType } from "mime-types";
55
+ import { z } from "zod";
56
+
57
+ // src/config.ts
58
+ var DEFAULT_API_URL = "https://api.papermark.com";
59
+ function getToken() {
60
+ return process.env.PAPERMARK_TOKEN?.trim() || void 0;
61
+ }
62
+ function getApiUrl() {
63
+ return process.env.PAPERMARK_API_URL?.trim() || DEFAULT_API_URL;
64
+ }
65
+
66
+ // src/client.ts
67
+ var ApiError = class extends Error {
68
+ code;
69
+ status;
70
+ docUrl;
71
+ details;
72
+ constructor(status, body) {
73
+ const message = typeof body === "string" ? body : body.message;
74
+ super(message);
75
+ this.status = status;
76
+ if (typeof body === "string") {
77
+ this.code = "unknown";
78
+ } else {
79
+ this.code = body.code;
80
+ this.docUrl = body.doc_url;
81
+ this.details = body.details;
82
+ }
83
+ }
84
+ };
85
+ var AuthRequiredError = class extends Error {
86
+ constructor() {
87
+ super(
88
+ "No API token configured. Set PAPERMARK_TOKEN in the MCP server env (get one from papermark.com/settings/tokens)."
89
+ );
90
+ this.name = "AuthRequiredError";
91
+ }
92
+ };
93
+ var NetworkError = class extends Error {
94
+ url;
95
+ cause;
96
+ constructor(url, cause) {
97
+ const reason = extractNetworkReason(cause);
98
+ super(`Network request to ${url} failed: ${reason}`);
99
+ this.name = "NetworkError";
100
+ this.url = url;
101
+ this.cause = cause;
102
+ }
103
+ };
104
+ function extractNetworkReason(err) {
105
+ if (err && typeof err === "object" && "cause" in err) {
106
+ const c = err.cause;
107
+ if (c && typeof c === "object") {
108
+ const code = c.code;
109
+ const msg = c.message;
110
+ if (code || msg) return `${code ?? ""}${code && msg ? " \u2014 " : ""}${msg ?? ""}`.trim();
111
+ }
112
+ }
113
+ if (err instanceof Error) return err.message;
114
+ return String(err);
115
+ }
116
+ var DEFAULT_TIMEOUT_MS = 6e4;
117
+ function buildUrl(path, query) {
118
+ const base = getApiUrl().replace(/\/$/, "");
119
+ let fullPath = path.startsWith("/") ? path : `/${path}`;
120
+ if (base.endsWith("/api") && fullPath.startsWith("/api/")) {
121
+ fullPath = fullPath.slice(4);
122
+ }
123
+ const url = new URL(base + fullPath);
124
+ if (query) {
125
+ for (const [k, v] of Object.entries(query)) {
126
+ if (v !== void 0 && v !== null && v !== "") {
127
+ url.searchParams.set(k, String(v));
128
+ }
129
+ }
130
+ }
131
+ return url.toString();
132
+ }
133
+ async function request(path, opts = {}) {
134
+ const headers = {
135
+ Accept: "application/json",
136
+ ...opts.headers ?? {}
137
+ };
138
+ if (!opts.anonymous) {
139
+ const token = opts.token ?? getToken();
140
+ if (!token) throw new AuthRequiredError();
141
+ headers.Authorization = `Bearer ${token}`;
142
+ }
143
+ let body;
144
+ if (opts.body !== void 0) {
145
+ if (opts.body instanceof Uint8Array || opts.body instanceof ArrayBuffer) {
146
+ body = opts.body;
147
+ } else {
148
+ body = JSON.stringify(opts.body);
149
+ headers["Content-Type"] = "application/json";
150
+ }
151
+ }
152
+ const url = buildUrl(path, opts.query);
153
+ const controller = new AbortController();
154
+ const timeoutMs = opts.timeout ?? DEFAULT_TIMEOUT_MS;
155
+ const timer = setTimeout(() => controller.abort(), timeoutMs);
156
+ let res;
157
+ try {
158
+ res = await fetch(url, {
159
+ method: opts.method ?? (opts.body ? "POST" : "GET"),
160
+ headers,
161
+ body,
162
+ signal: controller.signal
163
+ });
164
+ } catch (err) {
165
+ if (controller.signal.aborted || err instanceof Error && err.name === "AbortError") {
166
+ throw new NetworkError(
167
+ url,
168
+ new Error(`Request exceeded ${timeoutMs}ms timeout`)
169
+ );
170
+ }
171
+ throw new NetworkError(url, err);
172
+ } finally {
173
+ clearTimeout(timer);
174
+ }
175
+ if (res.status === 204) return void 0;
176
+ const text = await res.text();
177
+ const parsed = text ? safeParseJson(text) : null;
178
+ if (!res.ok) {
179
+ if (parsed && typeof parsed === "object" && "error" in parsed) {
180
+ throw new ApiError(res.status, parsed.error);
181
+ }
182
+ const looksLikeHtml = text.trimStart().toLowerCase().startsWith("<");
183
+ const msg = looksLikeHtml ? `HTTP ${res.status} (server returned HTML, not JSON \u2014 is the API reachable?)` : text || `HTTP ${res.status}`;
184
+ throw new ApiError(res.status, msg);
185
+ }
186
+ return parsed ?? void 0;
187
+ }
188
+ function safeParseJson(s) {
189
+ try {
190
+ return JSON.parse(s);
191
+ } catch {
192
+ return null;
193
+ }
194
+ }
195
+ var api = {
196
+ // Documents
197
+ listDocuments: (query, token) => request("/v1/documents", { query, token }),
198
+ getDocument: (id, token) => request(`/v1/documents/${id}`, { token }),
199
+ searchDocuments: (q, limit, token) => request("/v1/documents/search", { query: { q, limit }, token }),
200
+ updateDocument: (id, body, token) => request(`/v1/documents/${id}`, {
201
+ method: "PATCH",
202
+ body,
203
+ token
204
+ }),
205
+ deleteDocument: (id, token) => request(`/v1/documents/${id}`, { method: "DELETE", token }),
206
+ uploadUrl: (body, token) => request("/v1/documents/upload-url", {
207
+ method: "POST",
208
+ body,
209
+ token
210
+ }),
211
+ createDocument: (body, token) => request("/v1/documents", { method: "POST", body, token }),
212
+ // Document versions
213
+ listDocumentVersions: (id, token) => request(`/v1/documents/${id}/versions`, { token }),
214
+ addDocumentVersion: (id, body, token) => request(`/v1/documents/${id}/versions`, {
215
+ method: "POST",
216
+ body,
217
+ token
218
+ }),
219
+ getDocumentVersion: (id, vid, token) => request(`/v1/documents/${id}/versions/${vid}`, {
220
+ token
221
+ }),
222
+ promoteDocumentVersion: (id, vid, token) => request(`/v1/documents/${id}/versions/${vid}`, {
223
+ method: "PATCH",
224
+ body: { is_primary: true },
225
+ token
226
+ }),
227
+ // Folders
228
+ listFolders: (query, token) => request("/v1/folders", { query, token }),
229
+ createFolder: (body, token) => request("/v1/folders", { method: "POST", body, token }),
230
+ getFolder: (id, token) => request(`/v1/folders/${id}`, { token }),
231
+ updateFolder: (id, body, token) => request(`/v1/folders/${id}`, { method: "PATCH", body, token }),
232
+ deleteFolder: (id, opts, token) => request(`/v1/folders/${id}`, {
233
+ method: "DELETE",
234
+ query: opts?.cascade ? { cascade: "true" } : void 0,
235
+ token
236
+ }),
237
+ moveFolder: (id, body, token) => request(`/v1/folders/${id}/move`, {
238
+ method: "POST",
239
+ body,
240
+ token
241
+ }),
242
+ // Links
243
+ listLinks: (query, token) => request("/v1/links", { query, token }),
244
+ getLink: (id, token) => request(`/v1/links/${id}`, { token }),
245
+ createLink: (body, token) => request("/v1/links", { method: "POST", body, token }),
246
+ updateLink: (id, body, token) => request(`/v1/links/${id}`, { method: "PATCH", body, token }),
247
+ deleteLink: (id, token) => request(`/v1/links/${id}`, { method: "DELETE", token }),
248
+ listViews: (linkId, query, token) => request(`/v1/links/${linkId}/views`, { query, token }),
249
+ // Datarooms
250
+ listDatarooms: (query, token) => request("/v1/datarooms", { query, token }),
251
+ getDataroom: (id, token) => request(`/v1/datarooms/${id}`, { token }),
252
+ createDataroom: (body, token) => request("/v1/datarooms", { method: "POST", body, token }),
253
+ updateDataroom: (id, body, token) => request(`/v1/datarooms/${id}`, { method: "PATCH", body, token }),
254
+ deleteDataroom: (id, token) => request(`/v1/datarooms/${id}`, { method: "DELETE", token }),
255
+ listDataroomDocuments: (id, query, token) => request(`/v1/datarooms/${id}/documents`, { query, token }),
256
+ attachDataroomDocument: (id, body, token) => request(`/v1/datarooms/${id}/documents`, {
257
+ method: "POST",
258
+ body,
259
+ token
260
+ }),
261
+ // Dataroom folders
262
+ listDataroomFolders: (id, query, token) => request(`/v1/datarooms/${id}/folders`, {
263
+ query,
264
+ token
265
+ }),
266
+ createDataroomFolder: (id, body, token) => request(`/v1/datarooms/${id}/folders`, {
267
+ method: "POST",
268
+ body,
269
+ token
270
+ }),
271
+ getDataroomFolder: (id, fid, token) => request(`/v1/datarooms/${id}/folders/${fid}`, {
272
+ token
273
+ }),
274
+ updateDataroomFolder: (id, fid, body, token) => request(`/v1/datarooms/${id}/folders/${fid}`, {
275
+ method: "PATCH",
276
+ body,
277
+ token
278
+ }),
279
+ deleteDataroomFolder: (id, fid, opts, token) => request(`/v1/datarooms/${id}/folders/${fid}`, {
280
+ method: "DELETE",
281
+ query: opts?.cascade ? { cascade: "true" } : void 0,
282
+ token
283
+ }),
284
+ moveDataroomFolder: (id, fid, body, token) => request(`/v1/datarooms/${id}/folders/${fid}/move`, {
285
+ method: "POST",
286
+ body,
287
+ token
288
+ }),
289
+ // Visitors
290
+ listVisitors: (query, token) => request("/v1/visitors", { query, token }),
291
+ getVisitor: (id, token) => request(`/v1/visitors/${id}`, { token }),
292
+ listVisitorViews: (id, query, token) => request(`/v1/visitors/${id}/views`, { query, token }),
293
+ // Analytics
294
+ documentAnalytics: (id, query, token) => request(`/v1/analytics/documents/${id}`, { query, token }),
295
+ linkAnalytics: (id, query, token) => request(`/v1/analytics/links/${id}`, { query, token }),
296
+ dataroomAnalytics: (id, query, token) => request(`/v1/analytics/datarooms/${id}`, { query, token }),
297
+ viewAnalytics: (id, token) => request(`/v1/analytics/views/${id}`, { token })
298
+ };
299
+
300
+ // src/tools.ts
301
+ async function run(fn, label) {
302
+ try {
303
+ const result = await fn();
304
+ return { content: [{ type: "text", text: JSON.stringify(result, null, 2) }] };
305
+ } catch (err) {
306
+ if (err instanceof ApiError) {
307
+ const detail = err.details !== void 0 && err.details !== null ? `
308
+ Details: ${JSON.stringify(err.details)}` : "";
309
+ const hint = err.docUrl ? `
310
+ Docs: ${err.docUrl}` : "";
311
+ return {
312
+ isError: true,
313
+ content: [
314
+ {
315
+ type: "text",
316
+ text: `${label} failed (${err.status} ${err.code}): ${err.message}${detail}${hint}`
317
+ }
318
+ ]
319
+ };
320
+ }
321
+ if (err instanceof NetworkError) {
322
+ return {
323
+ isError: true,
324
+ content: [{ type: "text", text: `${label} failed: ${err.message}` }]
325
+ };
326
+ }
327
+ if (err instanceof AuthRequiredError) {
328
+ return { isError: true, content: [{ type: "text", text: err.message }] };
329
+ }
330
+ return {
331
+ isError: true,
332
+ content: [
333
+ { type: "text", text: `${label} failed: ${err instanceof Error ? err.message : String(err)}` }
334
+ ]
335
+ };
336
+ }
337
+ }
338
+ function guessContentType(fileName) {
339
+ return lookupMimeType(fileName) || "application/octet-stream";
340
+ }
341
+ function filenameFromUrl(rawUrl) {
342
+ try {
343
+ const u = new URL(rawUrl);
344
+ const last = u.pathname.split("/").filter(Boolean).pop();
345
+ if (!last) return "document";
346
+ return decodeURIComponent(last);
347
+ } catch {
348
+ return "document";
349
+ }
350
+ }
351
+ function summarizeDocument(d) {
352
+ return {
353
+ id: d.id,
354
+ object: d.object,
355
+ name: d.name,
356
+ content_type: d.content_type,
357
+ num_pages: d.num_pages,
358
+ created: d.created
359
+ };
360
+ }
361
+ function summarizeLink(l) {
362
+ return {
363
+ id: l.id,
364
+ object: l.object,
365
+ url: l.url,
366
+ name: l.name,
367
+ target_type: l.target_type,
368
+ document_id: l.document_id,
369
+ dataroom_id: l.dataroom_id,
370
+ expires_at: l.expires_at,
371
+ is_password_protected: l.is_password_protected,
372
+ email_protected: l.email_protected,
373
+ allow_download: l.allow_download
374
+ };
375
+ }
376
+ function summarizeView(v) {
377
+ return {
378
+ id: v.id,
379
+ link_id: v.link_id,
380
+ viewer_email: v.viewer_email,
381
+ viewed_at: v.viewed_at,
382
+ downloaded_at: v.downloaded_at
383
+ };
384
+ }
385
+ function registerTools(server) {
386
+ server.registerTool(
387
+ listDocumentsContract.name,
388
+ {
389
+ title: listDocumentsContract.title,
390
+ description: listDocumentsContract.description,
391
+ inputSchema: listDocumentsContract.inputSchema
392
+ },
393
+ async (args) => run(async () => {
394
+ const list = await api.listDocuments({
395
+ limit: args.limit,
396
+ cursor: args.cursor,
397
+ query: args.query
398
+ });
399
+ return {
400
+ documents: list.data.map(summarizeDocument),
401
+ next_cursor: list.next_cursor
402
+ };
403
+ }, "list_documents")
404
+ );
405
+ server.registerTool(
406
+ getDocumentContract.name,
407
+ {
408
+ title: getDocumentContract.title,
409
+ description: getDocumentContract.description,
410
+ inputSchema: getDocumentContract.inputSchema
411
+ },
412
+ async (args) => run(() => api.getDocument(args.document_id), "get_document")
413
+ );
414
+ server.registerTool(
415
+ searchDocumentsContract.name,
416
+ {
417
+ title: searchDocumentsContract.title,
418
+ description: searchDocumentsContract.description,
419
+ inputSchema: searchDocumentsContract.inputSchema
420
+ },
421
+ async (args) => run(async () => {
422
+ const list = await api.searchDocuments(args.query, args.limit);
423
+ return { documents: list.data.map(summarizeDocument), next_cursor: list.next_cursor };
424
+ }, "search_documents")
425
+ );
426
+ server.registerTool(
427
+ "upload_document",
428
+ {
429
+ title: "Upload a document",
430
+ description: `Upload a document to Papermark from a local file path OR a public HTTPS URL.
431
+
432
+ WORKFLOW:
433
+ (1) Resolve the source: the user must name either a \`file_path\` (local filesystem \u2014 stdio mode only) OR a \`source_url\` (public HTTPS). Never guess a path; if the user attached a file in chat but didn't give a local path, ASK them to save it and provide the path.
434
+ (2) Confirm the target \`name\` if the user wants something other than the filename.
435
+ (3) If the user wants a share link in the same breath, set \`create_link: true\` \u2014 otherwise follow up with \`create_link\` so you can set password/expiry/email gating explicitly.
436
+
437
+ Don't upload any file the user didn't explicitly point at. Requires scope \`documents.write\`.`,
438
+ inputSchema: {
439
+ file_path: z.string().optional().describe(
440
+ "Absolute local path \u2014 only works when the MCP server runs on the same machine as the file (stdio mode)"
441
+ ),
442
+ source_url: z.string().url().refine((s) => s.startsWith("https://"), {
443
+ message: "source_url must use https:// (http is rejected by the API)"
444
+ }).optional().describe("Public HTTPS URL the server should fetch (alternative to file_path)"),
445
+ name: z.string().optional().describe("Display name; defaults to the filename"),
446
+ content_type: z.string().optional().describe("MIME type; inferred from extension when omitted"),
447
+ folder_id: z.string().optional().describe(
448
+ "Destination folder id (created beforehand via `create_folder`). Omit for the team-library root."
449
+ ),
450
+ create_link: z.boolean().optional().describe("Create a default share link after upload")
451
+ }
452
+ },
453
+ async (args) => run(async () => {
454
+ if (!args.file_path && !args.source_url) {
455
+ throw new Error("Provide either file_path (local) or source_url (remote).");
456
+ }
457
+ if (args.file_path && args.source_url) {
458
+ throw new Error("Provide only one of file_path or source_url.");
459
+ }
460
+ if (args.source_url) {
461
+ const name = args.name ?? filenameFromUrl(args.source_url);
462
+ const doc2 = await api.createDocument({
463
+ name,
464
+ source_url: args.source_url,
465
+ folder_id: args.folder_id,
466
+ create_link: args.create_link
467
+ });
468
+ return { document: summarizeDocument(doc2) };
469
+ }
470
+ const filePath = args.file_path;
471
+ const stats = await stat(filePath);
472
+ const fileName = basename(filePath);
473
+ const contentType = args.content_type ?? guessContentType(fileName);
474
+ const body = await readFile(filePath);
475
+ const presigned = await api.uploadUrl({
476
+ fileName,
477
+ contentType,
478
+ contentLength: stats.size
479
+ });
480
+ const putController = new AbortController();
481
+ const putTimer = setTimeout(() => putController.abort(), 5 * 6e4);
482
+ let put;
483
+ try {
484
+ put = await fetch(presigned.upload_url, {
485
+ method: "PUT",
486
+ headers: presigned.required_headers,
487
+ body,
488
+ signal: putController.signal
489
+ });
490
+ } catch (err) {
491
+ if (putController.signal.aborted || err instanceof Error && err.name === "AbortError") {
492
+ throw new Error(
493
+ "Storage PUT aborted: presigned upload exceeded 5 minute timeout. The connection to object storage stalled \u2014 retry with a smaller file or a faster network."
494
+ );
495
+ }
496
+ throw err;
497
+ } finally {
498
+ clearTimeout(putTimer);
499
+ }
500
+ if (!put.ok) {
501
+ throw new Error(`Storage PUT failed: HTTP ${put.status} ${put.statusText}`);
502
+ }
503
+ const doc = await api.createDocument({
504
+ name: args.name ?? fileName,
505
+ upload_id: presigned.upload_id,
506
+ folder_id: args.folder_id,
507
+ create_link: args.create_link
508
+ });
509
+ return { document: summarizeDocument(doc) };
510
+ }, "upload_document")
511
+ );
512
+ server.registerTool(
513
+ createLinkContract.name,
514
+ {
515
+ title: createLinkContract.title,
516
+ description: createLinkContract.description,
517
+ inputSchema: createLinkContract.inputSchema
518
+ },
519
+ async (args) => run(async () => {
520
+ const hasDoc = Boolean(args.document_id);
521
+ const hasDr = Boolean(args.dataroom_id);
522
+ if (!hasDoc && !hasDr) {
523
+ throw new Error("Provide document_id or dataroom_id.");
524
+ }
525
+ if (hasDoc && hasDr) {
526
+ throw new Error(
527
+ "Provide exactly one of document_id or dataroom_id, not both."
528
+ );
529
+ }
530
+ const link = await api.createLink(args);
531
+ return { link: summarizeLink(link) };
532
+ }, "create_link")
533
+ );
534
+ server.registerTool(
535
+ listLinksContract.name,
536
+ {
537
+ title: listLinksContract.title,
538
+ description: listLinksContract.description,
539
+ inputSchema: listLinksContract.inputSchema
540
+ },
541
+ async (args) => run(async () => {
542
+ const list = await api.listLinks(args);
543
+ return { links: list.data.map(summarizeLink), next_cursor: list.next_cursor };
544
+ }, "list_links")
545
+ );
546
+ server.registerTool(
547
+ listLinkViewsContract.name,
548
+ {
549
+ title: listLinkViewsContract.title,
550
+ description: listLinkViewsContract.description,
551
+ inputSchema: listLinkViewsContract.inputSchema
552
+ },
553
+ async (args) => run(async () => {
554
+ const list = await api.listViews(args.link_id, {
555
+ limit: args.limit,
556
+ cursor: args.cursor
557
+ });
558
+ return { views: list.data.map(summarizeView), next_cursor: list.next_cursor };
559
+ }, "list_link_views")
560
+ );
561
+ server.registerTool(
562
+ listDataroomsContract.name,
563
+ {
564
+ title: listDataroomsContract.title,
565
+ description: listDataroomsContract.description,
566
+ inputSchema: listDataroomsContract.inputSchema
567
+ },
568
+ async (args) => run(async () => {
569
+ const list = await api.listDatarooms(args);
570
+ return { datarooms: list.data, next_cursor: list.next_cursor };
571
+ }, "list_datarooms")
572
+ );
573
+ server.registerTool(
574
+ searchDataroomsContract.name,
575
+ {
576
+ title: searchDataroomsContract.title,
577
+ description: searchDataroomsContract.description,
578
+ inputSchema: searchDataroomsContract.inputSchema
579
+ },
580
+ async (args) => run(async () => {
581
+ const list = await api.listDatarooms({
582
+ query: args.query,
583
+ limit: args.limit ?? 10
584
+ });
585
+ return { datarooms: list.data, next_cursor: list.next_cursor };
586
+ }, "search_datarooms")
587
+ );
588
+ server.registerTool(
589
+ getDataroomContract.name,
590
+ {
591
+ title: getDataroomContract.title,
592
+ description: getDataroomContract.description,
593
+ inputSchema: getDataroomContract.inputSchema
594
+ },
595
+ async (args) => run(() => api.getDataroom(args.dataroom_id), "get_dataroom")
596
+ );
597
+ server.registerTool(
598
+ createDataroomContract.name,
599
+ {
600
+ title: createDataroomContract.title,
601
+ description: createDataroomContract.description,
602
+ inputSchema: createDataroomContract.inputSchema
603
+ },
604
+ async (args) => run(async () => {
605
+ const dr = await api.createDataroom(args);
606
+ return { dataroom: dr };
607
+ }, "create_dataroom")
608
+ );
609
+ server.registerTool(
610
+ listDataroomDocumentsContract.name,
611
+ {
612
+ title: listDataroomDocumentsContract.title,
613
+ description: listDataroomDocumentsContract.description,
614
+ inputSchema: listDataroomDocumentsContract.inputSchema
615
+ },
616
+ async (args) => run(async () => {
617
+ const list = await api.listDataroomDocuments(args.dataroom_id, {
618
+ limit: args.limit,
619
+ cursor: args.cursor,
620
+ folder_id: args.folder_id
621
+ });
622
+ return { documents: list.data, next_cursor: list.next_cursor };
623
+ }, "list_dataroom_documents")
624
+ );
625
+ server.registerTool(
626
+ listVisitorsContract.name,
627
+ {
628
+ title: listVisitorsContract.title,
629
+ description: listVisitorsContract.description,
630
+ inputSchema: listVisitorsContract.inputSchema
631
+ },
632
+ async (args) => run(async () => {
633
+ const list = await api.listVisitors(args);
634
+ return { visitors: list.data, next_cursor: list.next_cursor };
635
+ }, "list_visitors")
636
+ );
637
+ server.registerTool(
638
+ listVisitorViewsContract.name,
639
+ {
640
+ title: listVisitorViewsContract.title,
641
+ description: listVisitorViewsContract.description,
642
+ inputSchema: listVisitorViewsContract.inputSchema
643
+ },
644
+ async (args) => run(async () => {
645
+ const list = await api.listVisitorViews(args.visitor_id, {
646
+ limit: args.limit,
647
+ cursor: args.cursor
648
+ });
649
+ return { views: list.data, next_cursor: list.next_cursor };
650
+ }, "list_visitor_views")
651
+ );
652
+ server.registerTool(
653
+ getDocumentAnalyticsContract.name,
654
+ {
655
+ title: getDocumentAnalyticsContract.title,
656
+ description: getDocumentAnalyticsContract.description,
657
+ inputSchema: getDocumentAnalyticsContract.inputSchema
658
+ },
659
+ async (args) => run(
660
+ () => api.documentAnalytics(args.document_id, {
661
+ since: args.since,
662
+ until: args.until
663
+ }),
664
+ "get_document_analytics"
665
+ )
666
+ );
667
+ server.registerTool(
668
+ getLinkAnalyticsContract.name,
669
+ {
670
+ title: getLinkAnalyticsContract.title,
671
+ description: getLinkAnalyticsContract.description,
672
+ inputSchema: getLinkAnalyticsContract.inputSchema
673
+ },
674
+ async (args) => run(
675
+ () => api.linkAnalytics(args.link_id, {
676
+ since: args.since,
677
+ until: args.until
678
+ }),
679
+ "get_link_analytics"
680
+ )
681
+ );
682
+ server.registerTool(
683
+ getDataroomAnalyticsContract.name,
684
+ {
685
+ title: getDataroomAnalyticsContract.title,
686
+ description: getDataroomAnalyticsContract.description,
687
+ inputSchema: getDataroomAnalyticsContract.inputSchema
688
+ },
689
+ async (args) => run(
690
+ () => api.dataroomAnalytics(args.dataroom_id, {
691
+ since: args.since,
692
+ until: args.until
693
+ }),
694
+ "get_dataroom_analytics"
695
+ )
696
+ );
697
+ server.registerTool(
698
+ getViewAnalyticsContract.name,
699
+ {
700
+ title: getViewAnalyticsContract.title,
701
+ description: getViewAnalyticsContract.description,
702
+ inputSchema: getViewAnalyticsContract.inputSchema
703
+ },
704
+ async (args) => run(() => api.viewAnalytics(args.view_id), "get_view_analytics")
705
+ );
706
+ server.registerTool(
707
+ updateDocumentContract.name,
708
+ {
709
+ title: updateDocumentContract.title,
710
+ description: updateDocumentContract.description,
711
+ inputSchema: updateDocumentContract.inputSchema
712
+ },
713
+ async (args) => run(async () => {
714
+ const body = {};
715
+ if (args.name !== void 0) body.name = args.name;
716
+ if (args.folder_id !== void 0) body.folder_id = args.folder_id;
717
+ if (Object.keys(body).length === 0) {
718
+ throw new Error("Provide at least one of `name` or `folder_id`.");
719
+ }
720
+ const doc = await api.updateDocument(args.document_id, body);
721
+ return { document: summarizeDocument(doc) };
722
+ }, "update_document")
723
+ );
724
+ server.registerTool(
725
+ deleteDocumentContract.name,
726
+ {
727
+ title: deleteDocumentContract.title,
728
+ description: deleteDocumentContract.description,
729
+ inputSchema: deleteDocumentContract.inputSchema
730
+ },
731
+ async (args) => run(async () => {
732
+ return await api.deleteDocument(args.document_id);
733
+ }, "delete_document")
734
+ );
735
+ server.registerTool(
736
+ listDocumentVersionsContract.name,
737
+ {
738
+ title: listDocumentVersionsContract.title,
739
+ description: listDocumentVersionsContract.description,
740
+ inputSchema: listDocumentVersionsContract.inputSchema
741
+ },
742
+ async (args) => run(async () => {
743
+ const list = await api.listDocumentVersions(args.document_id);
744
+ return { versions: list.data };
745
+ }, "list_document_versions")
746
+ );
747
+ server.registerTool(
748
+ getDocumentVersionContract.name,
749
+ {
750
+ title: getDocumentVersionContract.title,
751
+ description: getDocumentVersionContract.description,
752
+ inputSchema: getDocumentVersionContract.inputSchema
753
+ },
754
+ async (args) => run(
755
+ () => api.getDocumentVersion(args.document_id, args.version_id),
756
+ "get_document_version"
757
+ )
758
+ );
759
+ server.registerTool(
760
+ addDocumentVersionContract.name,
761
+ {
762
+ title: addDocumentVersionContract.title,
763
+ description: addDocumentVersionContract.description,
764
+ inputSchema: addDocumentVersionContract.inputSchema
765
+ },
766
+ async (args) => run(async () => {
767
+ const v = await api.addDocumentVersion(args.document_id, {
768
+ source_url: args.source_url
769
+ });
770
+ return { version: v };
771
+ }, "add_document_version")
772
+ );
773
+ server.registerTool(
774
+ promoteDocumentVersionContract.name,
775
+ {
776
+ title: promoteDocumentVersionContract.title,
777
+ description: promoteDocumentVersionContract.description,
778
+ inputSchema: promoteDocumentVersionContract.inputSchema
779
+ },
780
+ async (args) => run(async () => {
781
+ const v = await api.promoteDocumentVersion(
782
+ args.document_id,
783
+ args.version_id
784
+ );
785
+ return { version: v };
786
+ }, "promote_document_version")
787
+ );
788
+ server.registerTool(
789
+ listFoldersContract.name,
790
+ {
791
+ title: listFoldersContract.title,
792
+ description: listFoldersContract.description,
793
+ inputSchema: listFoldersContract.inputSchema
794
+ },
795
+ async (args) => run(async () => {
796
+ const list = await api.listFolders(args);
797
+ return { folders: list.data, next_cursor: list.next_cursor };
798
+ }, "list_folders")
799
+ );
800
+ server.registerTool(
801
+ getFolderContract.name,
802
+ {
803
+ title: getFolderContract.title,
804
+ description: getFolderContract.description,
805
+ inputSchema: getFolderContract.inputSchema
806
+ },
807
+ async (args) => run(() => api.getFolder(args.folder_id), "get_folder")
808
+ );
809
+ server.registerTool(
810
+ createFolderContract.name,
811
+ {
812
+ title: createFolderContract.title,
813
+ description: createFolderContract.description,
814
+ inputSchema: createFolderContract.inputSchema
815
+ },
816
+ async (args) => run(async () => {
817
+ const f = await api.createFolder(args);
818
+ return { folder: f };
819
+ }, "create_folder")
820
+ );
821
+ server.registerTool(
822
+ updateFolderContract.name,
823
+ {
824
+ title: updateFolderContract.title,
825
+ description: updateFolderContract.description,
826
+ inputSchema: updateFolderContract.inputSchema
827
+ },
828
+ async (args) => run(async () => {
829
+ const body = {};
830
+ if (args.name !== void 0) body.name = args.name;
831
+ if (args.icon !== void 0) body.icon = args.icon;
832
+ if (args.color !== void 0) body.color = args.color;
833
+ if (Object.keys(body).length === 0) {
834
+ throw new Error("Provide at least one of `name`, `icon`, `color`.");
835
+ }
836
+ const f = await api.updateFolder(args.folder_id, body);
837
+ return { folder: f };
838
+ }, "update_folder")
839
+ );
840
+ server.registerTool(
841
+ deleteFolderContract.name,
842
+ {
843
+ title: deleteFolderContract.title,
844
+ description: deleteFolderContract.description,
845
+ inputSchema: deleteFolderContract.inputSchema
846
+ },
847
+ async (args) => run(async () => {
848
+ return await api.deleteFolder(args.folder_id, {
849
+ cascade: args.cascade
850
+ });
851
+ }, "delete_folder")
852
+ );
853
+ server.registerTool(
854
+ moveFolderContract.name,
855
+ {
856
+ title: moveFolderContract.title,
857
+ description: moveFolderContract.description,
858
+ inputSchema: moveFolderContract.inputSchema
859
+ },
860
+ async (args) => run(async () => {
861
+ const f = await api.moveFolder(args.folder_id, {
862
+ parent_id: args.parent_id
863
+ });
864
+ return { folder: f };
865
+ }, "move_folder")
866
+ );
867
+ server.registerTool(
868
+ getLinkContract.name,
869
+ {
870
+ title: getLinkContract.title,
871
+ description: getLinkContract.description,
872
+ inputSchema: getLinkContract.inputSchema
873
+ },
874
+ async (args) => run(async () => {
875
+ const link = await api.getLink(args.link_id);
876
+ return { link: summarizeLink(link) };
877
+ }, "get_link")
878
+ );
879
+ server.registerTool(
880
+ updateLinkContract.name,
881
+ {
882
+ title: updateLinkContract.title,
883
+ description: updateLinkContract.description,
884
+ inputSchema: updateLinkContract.inputSchema
885
+ },
886
+ async (args) => run(async () => {
887
+ const { link_id, ...rest } = args;
888
+ if (Object.keys(rest).length === 0) {
889
+ throw new Error("Provide at least one field to update.");
890
+ }
891
+ const link = await api.updateLink(link_id, rest);
892
+ return { link: summarizeLink(link) };
893
+ }, "update_link")
894
+ );
895
+ server.registerTool(
896
+ deleteLinkContract.name,
897
+ {
898
+ title: deleteLinkContract.title,
899
+ description: deleteLinkContract.description,
900
+ inputSchema: deleteLinkContract.inputSchema
901
+ },
902
+ async (args) => run(async () => {
903
+ return await api.deleteLink(args.link_id);
904
+ }, "delete_link")
905
+ );
906
+ server.registerTool(
907
+ updateDataroomContract.name,
908
+ {
909
+ title: updateDataroomContract.title,
910
+ description: updateDataroomContract.description,
911
+ inputSchema: updateDataroomContract.inputSchema
912
+ },
913
+ async (args) => run(async () => {
914
+ const { dataroom_id, ...rest } = args;
915
+ if (Object.keys(rest).length === 0) {
916
+ throw new Error("Provide at least one field to update.");
917
+ }
918
+ const dr = await api.updateDataroom(dataroom_id, rest);
919
+ return { dataroom: dr };
920
+ }, "update_dataroom")
921
+ );
922
+ server.registerTool(
923
+ deleteDataroomContract.name,
924
+ {
925
+ title: deleteDataroomContract.title,
926
+ description: deleteDataroomContract.description,
927
+ inputSchema: deleteDataroomContract.inputSchema
928
+ },
929
+ async (args) => run(async () => {
930
+ return await api.deleteDataroom(args.dataroom_id);
931
+ }, "delete_dataroom")
932
+ );
933
+ server.registerTool(
934
+ attachDataroomDocumentContract.name,
935
+ {
936
+ title: attachDataroomDocumentContract.title,
937
+ description: attachDataroomDocumentContract.description,
938
+ inputSchema: attachDataroomDocumentContract.inputSchema
939
+ },
940
+ async (args) => run(async () => {
941
+ const item = await api.attachDataroomDocument(args.dataroom_id, {
942
+ document_id: args.document_id,
943
+ folder_id: args.folder_id
944
+ });
945
+ return { item };
946
+ }, "attach_dataroom_document")
947
+ );
948
+ server.registerTool(
949
+ listDataroomFoldersContract.name,
950
+ {
951
+ title: listDataroomFoldersContract.title,
952
+ description: listDataroomFoldersContract.description,
953
+ inputSchema: listDataroomFoldersContract.inputSchema
954
+ },
955
+ async (args) => run(async () => {
956
+ const list = await api.listDataroomFolders(args.dataroom_id, {
957
+ parent_id: args.parent_id,
958
+ limit: args.limit,
959
+ cursor: args.cursor
960
+ });
961
+ return { folders: list.data, next_cursor: list.next_cursor };
962
+ }, "list_dataroom_folders")
963
+ );
964
+ server.registerTool(
965
+ getDataroomFolderContract.name,
966
+ {
967
+ title: getDataroomFolderContract.title,
968
+ description: getDataroomFolderContract.description,
969
+ inputSchema: getDataroomFolderContract.inputSchema
970
+ },
971
+ async (args) => run(
972
+ () => api.getDataroomFolder(args.dataroom_id, args.folder_id),
973
+ "get_dataroom_folder"
974
+ )
975
+ );
976
+ server.registerTool(
977
+ createDataroomFolderContract.name,
978
+ {
979
+ title: createDataroomFolderContract.title,
980
+ description: createDataroomFolderContract.description,
981
+ inputSchema: createDataroomFolderContract.inputSchema
982
+ },
983
+ async (args) => run(async () => {
984
+ const { dataroom_id, ...body } = args;
985
+ const f = await api.createDataroomFolder(dataroom_id, body);
986
+ return { folder: f };
987
+ }, "create_dataroom_folder")
988
+ );
989
+ server.registerTool(
990
+ updateDataroomFolderContract.name,
991
+ {
992
+ title: updateDataroomFolderContract.title,
993
+ description: updateDataroomFolderContract.description,
994
+ inputSchema: updateDataroomFolderContract.inputSchema
995
+ },
996
+ async (args) => run(async () => {
997
+ const body = {};
998
+ if (args.name !== void 0) body.name = args.name;
999
+ if (args.icon !== void 0) body.icon = args.icon;
1000
+ if (args.color !== void 0) body.color = args.color;
1001
+ if (Object.keys(body).length === 0) {
1002
+ throw new Error("Provide at least one of `name`, `icon`, `color`.");
1003
+ }
1004
+ const f = await api.updateDataroomFolder(
1005
+ args.dataroom_id,
1006
+ args.folder_id,
1007
+ body
1008
+ );
1009
+ return { folder: f };
1010
+ }, "update_dataroom_folder")
1011
+ );
1012
+ server.registerTool(
1013
+ deleteDataroomFolderContract.name,
1014
+ {
1015
+ title: deleteDataroomFolderContract.title,
1016
+ description: deleteDataroomFolderContract.description,
1017
+ inputSchema: deleteDataroomFolderContract.inputSchema
1018
+ },
1019
+ async (args) => run(async () => {
1020
+ return await api.deleteDataroomFolder(
1021
+ args.dataroom_id,
1022
+ args.folder_id,
1023
+ { cascade: args.cascade }
1024
+ );
1025
+ }, "delete_dataroom_folder")
1026
+ );
1027
+ server.registerTool(
1028
+ moveDataroomFolderContract.name,
1029
+ {
1030
+ title: moveDataroomFolderContract.title,
1031
+ description: moveDataroomFolderContract.description,
1032
+ inputSchema: moveDataroomFolderContract.inputSchema
1033
+ },
1034
+ async (args) => run(async () => {
1035
+ const f = await api.moveDataroomFolder(
1036
+ args.dataroom_id,
1037
+ args.folder_id,
1038
+ { parent_id: args.parent_id }
1039
+ );
1040
+ return { folder: f };
1041
+ }, "move_dataroom_folder")
1042
+ );
1043
+ server.registerTool(
1044
+ getVisitorContract.name,
1045
+ {
1046
+ title: getVisitorContract.title,
1047
+ description: getVisitorContract.description,
1048
+ inputSchema: getVisitorContract.inputSchema
1049
+ },
1050
+ async (args) => run(() => api.getVisitor(args.visitor_id), "get_visitor")
1051
+ );
1052
+ }
1053
+
1054
+ // src/index.ts
1055
+ var SERVER_INFO = {
1056
+ name: "papermark-mcp",
1057
+ version: "0.1.0"
1058
+ };
1059
+ async function main() {
1060
+ const server = new McpServer(SERVER_INFO, { capabilities: { tools: {} } });
1061
+ registerTools(server);
1062
+ const transport = new StdioServerTransport();
1063
+ await server.connect(transport);
1064
+ }
1065
+ main().catch((err) => {
1066
+ process.stderr.write(
1067
+ `[papermark-mcp] fatal: ${err instanceof Error ? err.stack ?? err.message : String(err)}
1068
+ `
1069
+ );
1070
+ process.exit(1);
1071
+ });
1072
+ //# sourceMappingURL=index.js.map