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.

156 lines (155 loc) 7.29 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()); }); }; Object.defineProperty(exports, "__esModule", { value: true }); exports.registerTagTools = registerTagTools; const zod_1 = require("zod"); const types_1 = require("../api/types"); const utils_1 = require("../api/utils"); const middlewares_1 = require("./utils/middlewares"); const queryString_1 = require("./utils/queryString"); function registerTagTools(server, api) { server.tool("list_tags", "List all tags. IMPORTANT: When a user query may refer to a tag or document type, you should fetch all tags and all document types up front (with a large enough page_size), cache them for the session, and search locally for matches by name or slug before making further API calls. This reduces redundant requests and handles ambiguity between tags and document types efficiently.", { page: zod_1.z.number().optional(), page_size: zod_1.z.number().optional(), name__icontains: zod_1.z.string().optional(), name__iendswith: zod_1.z.string().optional(), name__iexact: zod_1.z.string().optional(), name__istartswith: zod_1.z.string().optional(), ordering: zod_1.z.string().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 tagsResponse = yield api.request(`/tags/${queryString ? `?${queryString}` : ""}`); const enhancedResults = (0, utils_1.enhanceMatchingAlgorithmArray)(tagsResponse.results || []); return { content: [ { type: "text", text: JSON.stringify(Object.assign(Object.assign({}, tagsResponse), { results: enhancedResults })), }, ], }; }))); server.tool("create_tag", "Create a new tag with optional color, matching pattern, and matching algorithm for automatic document tagging.", { name: zod_1.z.string(), color: zod_1.z .string() .regex(/^#[0-9A-Fa-f]{6}$/) .optional(), match: zod_1.z.string().optional(), matching_algorithm: zod_1.z .number() .int() .min(0) .max(6) .optional() .describe(types_1.MATCHING_ALGORITHM_DESCRIPTION), }, (0, middlewares_1.withErrorHandling)((args, extra) => __awaiter(this, void 0, void 0, function* () { if (!api) throw new Error("Please configure API connection first"); const tag = yield api.createTag(args); const enhancedTag = (0, utils_1.enhanceMatchingAlgorithm)(tag); return { content: [ { type: "text", text: JSON.stringify(enhancedTag), }, ], }; }))); server.tool("update_tag", "Update an existing tag's name, color, matching pattern, or matching algorithm.", { id: zod_1.z.number(), name: zod_1.z.string(), color: zod_1.z .string() .regex(/^#[0-9A-Fa-f]{6}$/) .optional(), match: zod_1.z.string().optional(), matching_algorithm: zod_1.z .number() .int() .min(0) .max(6) .optional() .describe(types_1.MATCHING_ALGORITHM_DESCRIPTION), }, (0, middlewares_1.withErrorHandling)((args, extra) => __awaiter(this, void 0, void 0, function* () { if (!api) throw new Error("Please configure API connection first"); const tag = yield api.updateTag(args.id, args); const enhancedTag = (0, utils_1.enhanceMatchingAlgorithm)(tag); return { content: [ { type: "text", text: JSON.stringify(enhancedTag), }, ], }; }))); server.tool("delete_tag", "⚠️ DESTRUCTIVE: Permanently delete a tag from the entire system. This will remove the tag from ALL documents that use it. Use with extreme caution.", { id: zod_1.z.number(), confirm: zod_1.z .boolean() .describe("Must be true to confirm this destructive operation"), }, (0, middlewares_1.withErrorHandling)((args, extra) => __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 for destructive operation. Set confirm: true to proceed."); } yield api.deleteTag(args.id); return { content: [ { type: "text", text: JSON.stringify({ status: "deleted" }), }, ], }; }))); server.tool("bulk_edit_tags", "Bulk edit tags. ⚠️ WARNING: 'delete' operation permanently removes tags from the entire system. Use with caution.", { tag_ids: zod_1.z.array(zod_1.z.number()), operation: zod_1.z.enum(["set_permissions", "delete"]), confirm: zod_1.z .boolean() .optional() .describe("Must be true when operation is 'delete' to confirm destructive operation"), owner: zod_1.z.number().optional(), permissions: zod_1.z .object({ view: zod_1.z.object({ users: zod_1.z.array(zod_1.z.number()).optional(), groups: zod_1.z.array(zod_1.z.number()).optional(), }), change: zod_1.z.object({ users: zod_1.z.array(zod_1.z.number()).optional(), groups: zod_1.z.array(zod_1.z.number()).optional(), }), }) .optional(), merge: zod_1.z.boolean().optional(), }, (0, middlewares_1.withErrorHandling)((args, extra) => __awaiter(this, void 0, void 0, function* () { if (!api) throw new Error("Please configure API connection first"); if (args.operation === "delete" && !args.confirm) { throw new Error("Confirmation required for destructive operation. Set confirm: true to proceed."); } return api.bulkEditObjects(args.tag_ids, "tags", args.operation, args.operation === "set_permissions" ? { owner: args.owner, permissions: args.permissions, merge: args.merge, } : {}); }))); }