UNPKG

@baruchiro/paperless-mcp

Version:

Model Context Protocol (MCP) server for interacting with Paperless-NGX document management system. Enables AI assistants to manage documents, tags, correspondents, and document types through the Paperless-NGX API.

188 lines (187 loc) 9.88 kB
"use strict"; var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) { function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); } return new (P || (P = Promise))(function (resolve, reject) { function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } } function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } } function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); } step((generator = generator.apply(thisArg, _arguments || [])).next()); }); }; var __rest = (this && this.__rest) || function (s, e) { var t = {}; for (var p in s) if (Object.prototype.hasOwnProperty.call(s, p) && e.indexOf(p) < 0) t[p] = s[p]; if (s != null && typeof Object.getOwnPropertySymbols === "function") for (var i = 0, p = Object.getOwnPropertySymbols(s); i < p.length; i++) { if (e.indexOf(p[i]) < 0 && Object.prototype.propertyIsEnumerable.call(s, p[i])) t[p[i]] = s[p[i]]; } return t; }; Object.defineProperty(exports, "__esModule", { value: true }); exports.registerMailTools = registerMailTools; const zod_1 = require("zod"); const middlewares_1 = require("./utils/middlewares"); const queryString_1 = require("./utils/queryString"); const MAIL_RULE_ACTION_DESCRIPTION = "Mail rule action: 1=Delete, 2=Move to specified folder, 3=Mark as read/don't process read mails, 4=Flag/don't process flagged mails, 5=Tag/don't process tagged mails"; const ASSIGN_TITLE_FROM_DESCRIPTION = "Title assignment: 1=Use subject as title, 2=Use attachment filename as title, 3=Do not assign title from rule"; const ASSIGN_CORRESPONDENT_FROM_DESCRIPTION = "Correspondent assignment: 1=Do not assign, 2=Use mail address, 3=Use sender name or address, 4=Use assign_correspondent"; const ATTACHMENT_TYPE_DESCRIPTION = "Attachment type: 1=Only process attachments, 2=Process all files including inline attachments"; const CONSUMPTION_SCOPE_DESCRIPTION = "Consumption scope: 1=Only process attachments, 2=Process full mail as .eml, 3=Process full mail and attachments separately"; const PDF_LAYOUT_DESCRIPTION = "PDF layout for full-mail consumption: 0=System default, 1=Text then HTML, 2=HTML then text, 3=HTML only, 4=Text only"; const mailRuleFields = { name: zod_1.z.string().optional(), account: zod_1.z.number().int().optional(), enabled: zod_1.z.boolean().optional(), folder: zod_1.z.string().optional(), filter_from: zod_1.z.string().nullable().optional(), filter_to: zod_1.z.string().nullable().optional(), filter_subject: zod_1.z.string().nullable().optional(), filter_body: zod_1.z.string().nullable().optional(), filter_attachment_filename_include: zod_1.z.string().nullable().optional(), filter_attachment_filename_exclude: zod_1.z.string().nullable().optional(), maximum_age: zod_1.z.number().int().min(0).optional(), action: zod_1.z .number() .int() .min(1) .max(5) .optional() .describe(MAIL_RULE_ACTION_DESCRIPTION), action_parameter: zod_1.z.string().nullable().optional(), assign_title_from: zod_1.z .number() .int() .min(1) .max(3) .optional() .describe(ASSIGN_TITLE_FROM_DESCRIPTION), assign_tags: zod_1.z.array(zod_1.z.number().int().nullable()).optional(), assign_correspondent_from: zod_1.z .number() .int() .min(1) .max(4) .optional() .describe(ASSIGN_CORRESPONDENT_FROM_DESCRIPTION), assign_correspondent: zod_1.z.number().int().nullable().optional(), assign_document_type: zod_1.z.number().int().nullable().optional(), assign_owner_from_rule: zod_1.z.boolean().optional(), order: zod_1.z.number().int().optional(), attachment_type: zod_1.z .number() .int() .min(1) .max(2) .optional() .describe(ATTACHMENT_TYPE_DESCRIPTION), consumption_scope: zod_1.z .number() .int() .min(1) .max(3) .optional() .describe(CONSUMPTION_SCOPE_DESCRIPTION), pdf_layout: zod_1.z .number() .int() .min(0) .max(4) .optional() .describe(PDF_LAYOUT_DESCRIPTION), owner: zod_1.z.number().int().nullable().optional(), }; function registerMailTools(server, api) { server.tool("list_mail_accounts", "List Paperless mail accounts for selecting the account ID needed by mail rules. Does not expose account passwords.", { page: zod_1.z.number().optional(), page_size: zod_1.z.number().optional(), }, (0, middlewares_1.withErrorHandling)((...args_1) => __awaiter(this, [...args_1], void 0, function* (args = {}) { if (!api) throw new Error("Please configure API connection first"); const queryString = (0, queryString_1.buildQueryString)(args); const response = yield api.getMailAccounts(queryString); const sanitizedResults = (response.results || []).map((account) => (Object.assign(Object.assign({}, account), { password: undefined }))); return { content: [ { type: "text", text: JSON.stringify(Object.assign(Object.assign({}, response), { results: sanitizedResults })), }, ], }; }))); server.tool("get_mail_account", "Get one Paperless mail account by ID. Password/token fields are redacted if the server returns them.", { id: zod_1.z.number().int() }, (0, middlewares_1.withErrorHandling)((args) => __awaiter(this, void 0, void 0, function* () { if (!api) throw new Error("Please configure API connection first"); const _a = yield api.getMailAccount(args.id), { password } = _a, account = __rest(_a, ["password"]); return { content: [{ type: "text", text: JSON.stringify(account) }], }; }))); server.tool("process_mail_account", "Manually run Paperless mail processing for one account. This can consume matching mails according to enabled Paperless mail rules.", { id: zod_1.z.number().int() }, (0, middlewares_1.withErrorHandling)((args) => __awaiter(this, void 0, void 0, function* () { if (!api) throw new Error("Please configure API connection first"); yield api.processMailAccount(args.id); return { content: [ { type: "text", text: JSON.stringify({ status: "processed" }) }, ], }; }))); server.tool("list_mail_rules", "List Paperless mail rules with optional pagination.", { page: zod_1.z.number().optional(), page_size: zod_1.z.number().optional(), }, (0, middlewares_1.withErrorHandling)((...args_1) => __awaiter(this, [...args_1], void 0, function* (args = {}) { if (!api) throw new Error("Please configure API connection first"); const queryString = (0, queryString_1.buildQueryString)(args); const response = yield api.getMailRules(queryString); return { content: [{ type: "text", text: JSON.stringify(response) }], }; }))); server.tool("get_mail_rule", "Get one Paperless mail rule by ID.", { id: zod_1.z.number().int() }, (0, middlewares_1.withErrorHandling)((args) => __awaiter(this, void 0, void 0, function* () { if (!api) throw new Error("Please configure API connection first"); const response = yield api.getMailRule(args.id); return { content: [{ type: "text", text: JSON.stringify(response) }], }; }))); server.tool("create_mail_rule", "Create a Paperless mail rule. Use list_mail_accounts first to choose account. Prefer attachment-only rules for invoices unless the full mail must be archived.", Object.assign(Object.assign({}, mailRuleFields), { name: zod_1.z.string(), account: zod_1.z.number().int(), folder: zod_1.z.string() }), (0, middlewares_1.withErrorHandling)((args) => __awaiter(this, void 0, void 0, function* () { if (!api) throw new Error("Please configure API connection first"); const response = yield api.createMailRule(args); return { content: [{ type: "text", text: JSON.stringify(response) }], }; }))); server.tool("update_mail_rule", "Patch an existing Paperless mail rule. Only supplied fields are changed.", Object.assign({ id: zod_1.z.number().int() }, mailRuleFields), (0, middlewares_1.withErrorHandling)((args) => __awaiter(this, void 0, void 0, function* () { if (!api) throw new Error("Please configure API connection first"); const { id } = args, data = __rest(args, ["id"]); const response = yield api.updateMailRule(id, data); return { content: [{ type: "text", text: JSON.stringify(response) }], }; }))); server.tool("delete_mail_rule", "Delete one Paperless mail rule. This changes future mail ingestion behavior but does not delete documents.", { id: zod_1.z.number().int(), confirm: zod_1.z .boolean() .describe("Must be true to confirm deleting the rule"), }, (0, middlewares_1.withErrorHandling)((args) => __awaiter(this, void 0, void 0, function* () { if (!api) throw new Error("Please configure API connection first"); if (!args.confirm) { throw new Error("Confirmation required. Set confirm: true to delete the mail rule."); } yield api.deleteMailRule(args.id); return { content: [ { type: "text", text: JSON.stringify({ status: "deleted" }) }, ], }; }))); }