@baruchiro/paperless-mcp 0.2.1 → 0.3.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/build/api/documentEnhancer.js +17 -1
- package/build/tools/correspondents.js +4 -4
- package/build/tools/customFields.js +3 -3
- package/build/tools/documentTypes.js +3 -3
- package/build/tools/documents.js +33 -43
- package/build/tools/tags.js +2 -2
- package/package.json +5 -2
- package/paperless-mcp.dxt +0 -0
|
@@ -8,6 +8,17 @@ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, ge
|
|
|
8
8
|
step((generator = generator.apply(thisArg, _arguments || [])).next());
|
|
9
9
|
});
|
|
10
10
|
};
|
|
11
|
+
var __rest = (this && this.__rest) || function (s, e) {
|
|
12
|
+
var t = {};
|
|
13
|
+
for (var p in s) if (Object.prototype.hasOwnProperty.call(s, p) && e.indexOf(p) < 0)
|
|
14
|
+
t[p] = s[p];
|
|
15
|
+
if (s != null && typeof Object.getOwnPropertySymbols === "function")
|
|
16
|
+
for (var i = 0, p = Object.getOwnPropertySymbols(s); i < p.length; i++) {
|
|
17
|
+
if (e.indexOf(p[i]) < 0 && Object.prototype.propertyIsEnumerable.call(s, p[i]))
|
|
18
|
+
t[p[i]] = s[p[i]];
|
|
19
|
+
}
|
|
20
|
+
return t;
|
|
21
|
+
};
|
|
11
22
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
12
23
|
exports.convertDocsWithNames = convertDocsWithNames;
|
|
13
24
|
function convertDocsWithNames(input, api) {
|
|
@@ -61,7 +72,12 @@ function enhanceDocumentsArray(documents, api) {
|
|
|
61
72
|
const documentTypeMap = new Map((documentTypes.results || []).map((dt) => [dt.id, dt.name]));
|
|
62
73
|
const tagMap = new Map((tags.results || []).map((tag) => [tag.id, tag.name]));
|
|
63
74
|
const customFieldMap = new Map((customFields.results || []).map((cf) => [cf.id, cf.name]));
|
|
64
|
-
return documents
|
|
75
|
+
return documents
|
|
76
|
+
.map((doc) => {
|
|
77
|
+
const { content } = doc, docWithoutContent = __rest(doc, ["content"]);
|
|
78
|
+
return docWithoutContent;
|
|
79
|
+
})
|
|
80
|
+
.map((doc) => (Object.assign(Object.assign({}, doc), { correspondent: doc.correspondent
|
|
65
81
|
? {
|
|
66
82
|
id: doc.correspondent,
|
|
67
83
|
name: correspondentMap.get(doc.correspondent) ||
|
|
@@ -27,7 +27,7 @@ const utils_1 = require("../api/utils");
|
|
|
27
27
|
const middlewares_1 = require("./utils/middlewares");
|
|
28
28
|
const queryString_1 = require("./utils/queryString");
|
|
29
29
|
function registerCorrespondentTools(server, api) {
|
|
30
|
-
server.tool("list_correspondents", {
|
|
30
|
+
server.tool("list_correspondents", "List all correspondents with optional filtering and pagination. Correspondents represent entities that send or receive documents.", {
|
|
31
31
|
page: zod_1.z.number().optional(),
|
|
32
32
|
page_size: zod_1.z.number().optional(),
|
|
33
33
|
name__icontains: zod_1.z.string().optional(),
|
|
@@ -50,7 +50,7 @@ function registerCorrespondentTools(server, api) {
|
|
|
50
50
|
],
|
|
51
51
|
};
|
|
52
52
|
})));
|
|
53
|
-
server.tool("get_correspondent", { id: zod_1.z.number() }, (0, middlewares_1.withErrorHandling)((args, extra) => __awaiter(this, void 0, void 0, function* () {
|
|
53
|
+
server.tool("get_correspondent", "Get a specific correspondent by ID with full details including matching rules.", { id: zod_1.z.number() }, (0, middlewares_1.withErrorHandling)((args, extra) => __awaiter(this, void 0, void 0, function* () {
|
|
54
54
|
if (!api)
|
|
55
55
|
throw new Error("Please configure API connection first");
|
|
56
56
|
const response = yield api.getCorrespondent(args.id);
|
|
@@ -61,7 +61,7 @@ function registerCorrespondentTools(server, api) {
|
|
|
61
61
|
],
|
|
62
62
|
};
|
|
63
63
|
})));
|
|
64
|
-
server.tool("create_correspondent", {
|
|
64
|
+
server.tool("create_correspondent", "Create a new correspondent with optional matching pattern and algorithm for automatic document assignment.", {
|
|
65
65
|
name: zod_1.z.string(),
|
|
66
66
|
match: zod_1.z.string().optional(),
|
|
67
67
|
matching_algorithm: zod_1.z
|
|
@@ -82,7 +82,7 @@ function registerCorrespondentTools(server, api) {
|
|
|
82
82
|
],
|
|
83
83
|
};
|
|
84
84
|
})));
|
|
85
|
-
server.tool("update_correspondent", {
|
|
85
|
+
server.tool("update_correspondent", "Update an existing correspondent's name, matching pattern, or matching algorithm.", {
|
|
86
86
|
id: zod_1.z.number(),
|
|
87
87
|
name: zod_1.z.string(),
|
|
88
88
|
match: zod_1.z.string().optional(),
|
|
@@ -47,7 +47,7 @@ function registerCustomFieldTools(server, api) {
|
|
|
47
47
|
],
|
|
48
48
|
};
|
|
49
49
|
})));
|
|
50
|
-
server.tool("get_custom_field", { id: zod_1.z.number() }, (0, middlewares_1.withErrorHandling)((args, extra) => __awaiter(this, void 0, void 0, function* () {
|
|
50
|
+
server.tool("get_custom_field", "Get a specific custom field by ID with full details including data type and extra configuration.", { id: zod_1.z.number() }, (0, middlewares_1.withErrorHandling)((args, extra) => __awaiter(this, void 0, void 0, function* () {
|
|
51
51
|
if (!api)
|
|
52
52
|
throw new Error("Please configure API connection first");
|
|
53
53
|
const response = yield api.getCustomField(args.id);
|
|
@@ -55,7 +55,7 @@ function registerCustomFieldTools(server, api) {
|
|
|
55
55
|
content: [{ type: "text", text: JSON.stringify(response) }],
|
|
56
56
|
};
|
|
57
57
|
})));
|
|
58
|
-
server.tool("create_custom_field", {
|
|
58
|
+
server.tool("create_custom_field", "Create a new custom field with a specified data type (string, url, date, boolean, integer, float, monetary, documentlink, or select).", {
|
|
59
59
|
name: zod_1.z.string(),
|
|
60
60
|
data_type: zod_1.z.enum([
|
|
61
61
|
"string",
|
|
@@ -77,7 +77,7 @@ function registerCustomFieldTools(server, api) {
|
|
|
77
77
|
content: [{ type: "text", text: JSON.stringify(response) }],
|
|
78
78
|
};
|
|
79
79
|
})));
|
|
80
|
-
server.tool("update_custom_field", {
|
|
80
|
+
server.tool("update_custom_field", "Update an existing custom field's name, data type, or extra configuration data.", {
|
|
81
81
|
id: zod_1.z.number(),
|
|
82
82
|
name: zod_1.z.string().optional(),
|
|
83
83
|
data_type: zod_1.z
|
|
@@ -50,7 +50,7 @@ function registerDocumentTypeTools(server, api) {
|
|
|
50
50
|
],
|
|
51
51
|
};
|
|
52
52
|
})));
|
|
53
|
-
server.tool("get_document_type", { id: zod_1.z.number() }, (0, middlewares_1.withErrorHandling)((args, extra) => __awaiter(this, void 0, void 0, function* () {
|
|
53
|
+
server.tool("get_document_type", "Get a specific document type by ID with full details including matching rules.", { id: zod_1.z.number() }, (0, middlewares_1.withErrorHandling)((args, extra) => __awaiter(this, void 0, void 0, function* () {
|
|
54
54
|
if (!api)
|
|
55
55
|
throw new Error("Please configure API connection first");
|
|
56
56
|
const response = yield api.request(`/document_types/${args.id}/`);
|
|
@@ -59,7 +59,7 @@ function registerDocumentTypeTools(server, api) {
|
|
|
59
59
|
content: [{ type: "text", text: JSON.stringify(enhancedDocumentType) }],
|
|
60
60
|
};
|
|
61
61
|
})));
|
|
62
|
-
server.tool("create_document_type", {
|
|
62
|
+
server.tool("create_document_type", "Create a new document type with optional matching pattern and algorithm for automatic document classification.", {
|
|
63
63
|
name: zod_1.z.string(),
|
|
64
64
|
match: zod_1.z.string().optional(),
|
|
65
65
|
matching_algorithm: zod_1.z
|
|
@@ -78,7 +78,7 @@ function registerDocumentTypeTools(server, api) {
|
|
|
78
78
|
content: [{ type: "text", text: JSON.stringify(enhancedDocumentType) }],
|
|
79
79
|
};
|
|
80
80
|
})));
|
|
81
|
-
server.tool("update_document_type", {
|
|
81
|
+
server.tool("update_document_type", "Update an existing document type's name, matching pattern, or matching algorithm.", {
|
|
82
82
|
id: zod_1.z.number(),
|
|
83
83
|
name: zod_1.z.string(),
|
|
84
84
|
match: zod_1.z.string().optional(),
|
package/build/tools/documents.js
CHANGED
|
@@ -53,7 +53,13 @@ function registerDocumentTools(server, api) {
|
|
|
53
53
|
add_custom_fields: zod_1.z
|
|
54
54
|
.array(zod_1.z.object({
|
|
55
55
|
field: zod_1.z.number(),
|
|
56
|
-
value: zod_1.z.union([
|
|
56
|
+
value: zod_1.z.union([
|
|
57
|
+
zod_1.z.string(),
|
|
58
|
+
zod_1.z.number(),
|
|
59
|
+
zod_1.z.boolean(),
|
|
60
|
+
zod_1.z.array(zod_1.z.number()),
|
|
61
|
+
zod_1.z.null(),
|
|
62
|
+
]),
|
|
57
63
|
}))
|
|
58
64
|
.optional()
|
|
59
65
|
.transform(empty_1.arrayNotEmpty),
|
|
@@ -111,7 +117,7 @@ function registerDocumentTools(server, api) {
|
|
|
111
117
|
],
|
|
112
118
|
};
|
|
113
119
|
})));
|
|
114
|
-
server.tool("post_document", {
|
|
120
|
+
server.tool("post_document", "Upload a new document to Paperless-NGX with optional metadata like title, correspondent, document type, tags, and custom fields.", {
|
|
115
121
|
file: zod_1.z.string(),
|
|
116
122
|
filename: zod_1.z.string(),
|
|
117
123
|
title: zod_1.z.string().optional(),
|
|
@@ -146,7 +152,7 @@ function registerDocumentTools(server, api) {
|
|
|
146
152
|
],
|
|
147
153
|
};
|
|
148
154
|
})));
|
|
149
|
-
server.tool("list_documents", "List and filter documents by fields such as title, correspondent, document type, tag, storage path, creation date, and more. IMPORTANT: For queries like 'the last 3 contributions' or when searching by tag, correspondent, document type, or storage path, you should FIRST use the relevant tool (e.g., 'list_tags', 'list_correspondents', 'list_document_types', 'list_storage_paths') to find the correct ID, and then use that ID as a filter here. Only use the 'search' argument for free-text search when no specific field applies. Using the correct ID filter will yield much more accurate results.", {
|
|
155
|
+
server.tool("list_documents", "List and filter documents by fields such as title, correspondent, document type, tag, storage path, creation date, and more. IMPORTANT: For queries like 'the last 3 contributions' or when searching by tag, correspondent, document type, or storage path, you should FIRST use the relevant tool (e.g., 'list_tags', 'list_correspondents', 'list_document_types', 'list_storage_paths') to find the correct ID, and then use that ID as a filter here. Only use the 'search' argument for free-text search when no specific field applies. Using the correct ID filter will yield much more accurate results. Note: Document content is excluded from results by default. Use 'get_document_content' to retrieve content when needed.", {
|
|
150
156
|
page: zod_1.z.number().optional(),
|
|
151
157
|
page_size: zod_1.z.number().optional(),
|
|
152
158
|
search: zod_1.z.string().optional(),
|
|
@@ -184,56 +190,34 @@ function registerDocumentTools(server, api) {
|
|
|
184
190
|
const docsResponse = yield api.getDocuments(query.toString() ? `?${query.toString()}` : "");
|
|
185
191
|
return (0, documentEnhancer_1.convertDocsWithNames)(docsResponse, api);
|
|
186
192
|
})));
|
|
187
|
-
server.tool("get_document", {
|
|
193
|
+
server.tool("get_document", "Get a specific document by ID with full details including correspondent, document type, tags, and custom fields. Note: Document content is excluded from results by default. Use 'get_document_content' to retrieve content when needed.", {
|
|
194
|
+
id: zod_1.z.number(),
|
|
195
|
+
}, (0, middlewares_1.withErrorHandling)((args, extra) => __awaiter(this, void 0, void 0, function* () {
|
|
196
|
+
if (!api)
|
|
197
|
+
throw new Error("Please configure API connection first");
|
|
198
|
+
const doc = yield api.getDocument(args.id);
|
|
199
|
+
return (0, documentEnhancer_1.convertDocsWithNames)(doc, api);
|
|
200
|
+
})));
|
|
201
|
+
server.tool("get_document_content", "Get the text content of a specific document by ID. Use this when you need to read or analyze the actual document text.", {
|
|
188
202
|
id: zod_1.z.number(),
|
|
189
203
|
}, (0, middlewares_1.withErrorHandling)((args, extra) => __awaiter(this, void 0, void 0, function* () {
|
|
190
204
|
if (!api)
|
|
191
205
|
throw new Error("Please configure API connection first");
|
|
192
206
|
const doc = yield api.getDocument(args.id);
|
|
193
|
-
const [correspondents, documentTypes, tags, customFields] = yield Promise.all([
|
|
194
|
-
api.getCorrespondents(),
|
|
195
|
-
api.getDocumentTypes(),
|
|
196
|
-
api.getTags(),
|
|
197
|
-
api.getCustomFields(),
|
|
198
|
-
]);
|
|
199
|
-
const correspondentMap = new Map((correspondents.results || []).map((c) => [c.id, c.name]));
|
|
200
|
-
const documentTypeMap = new Map((documentTypes.results || []).map((dt) => [dt.id, dt.name]));
|
|
201
|
-
const tagMap = new Map((tags.results || []).map((tag) => [tag.id, tag.name]));
|
|
202
|
-
const customFieldMap = new Map((customFields.results || []).map((cf) => [cf.id, cf.name]));
|
|
203
|
-
const docWithNames = Object.assign(Object.assign({}, doc), { correspondent: doc.correspondent
|
|
204
|
-
? {
|
|
205
|
-
id: doc.correspondent,
|
|
206
|
-
name: correspondentMap.get(doc.correspondent) ||
|
|
207
|
-
String(doc.correspondent),
|
|
208
|
-
}
|
|
209
|
-
: null, document_type: doc.document_type
|
|
210
|
-
? {
|
|
211
|
-
id: doc.document_type,
|
|
212
|
-
name: documentTypeMap.get(doc.document_type) ||
|
|
213
|
-
String(doc.document_type),
|
|
214
|
-
}
|
|
215
|
-
: null, tags: Array.isArray(doc.tags)
|
|
216
|
-
? doc.tags.map((tagId) => ({
|
|
217
|
-
id: tagId,
|
|
218
|
-
name: tagMap.get(tagId) || String(tagId),
|
|
219
|
-
}))
|
|
220
|
-
: doc.tags, custom_fields: Array.isArray(doc.custom_fields)
|
|
221
|
-
? doc.custom_fields.map((field) => ({
|
|
222
|
-
field: field.field,
|
|
223
|
-
name: customFieldMap.get(field.field) || String(field.field),
|
|
224
|
-
value: field.value,
|
|
225
|
-
}))
|
|
226
|
-
: doc.custom_fields });
|
|
227
207
|
return {
|
|
228
208
|
content: [
|
|
229
209
|
{
|
|
230
210
|
type: "text",
|
|
231
|
-
text: JSON.stringify(
|
|
211
|
+
text: JSON.stringify({
|
|
212
|
+
id: doc.id,
|
|
213
|
+
title: doc.title,
|
|
214
|
+
content: doc.content,
|
|
215
|
+
}),
|
|
232
216
|
},
|
|
233
217
|
],
|
|
234
218
|
};
|
|
235
219
|
})));
|
|
236
|
-
server.tool("search_documents", "Full text search for documents. This tool is for searching document content, title, and metadata using a full text query. For general document listing or filtering by fields, use 'list_documents' instead.", {
|
|
220
|
+
server.tool("search_documents", "Full text search for documents. This tool is for searching document content, title, and metadata using a full text query. For general document listing or filtering by fields, use 'list_documents' instead. Note: Document content is excluded from results by default. Use 'get_document_content' to retrieve content when needed.", {
|
|
237
221
|
query: zod_1.z.string(),
|
|
238
222
|
}, (0, middlewares_1.withErrorHandling)((args, extra) => __awaiter(this, void 0, void 0, function* () {
|
|
239
223
|
if (!api)
|
|
@@ -241,7 +225,7 @@ function registerDocumentTools(server, api) {
|
|
|
241
225
|
const docsResponse = yield api.searchDocuments(args.query);
|
|
242
226
|
return (0, documentEnhancer_1.convertDocsWithNames)(docsResponse, api);
|
|
243
227
|
})));
|
|
244
|
-
server.tool("download_document", {
|
|
228
|
+
server.tool("download_document", "Download a document file by ID. Returns the document as a base64-encoded resource.", {
|
|
245
229
|
id: zod_1.z.number(),
|
|
246
230
|
original: zod_1.z.boolean().optional(),
|
|
247
231
|
}, (0, middlewares_1.withErrorHandling)((args, extra) => __awaiter(this, void 0, void 0, function* () {
|
|
@@ -312,8 +296,14 @@ function registerDocumentTools(server, api) {
|
|
|
312
296
|
.array(zod_1.z.object({
|
|
313
297
|
field: zod_1.z.number().describe("The custom field ID"),
|
|
314
298
|
value: zod_1.z
|
|
315
|
-
.union([
|
|
316
|
-
.
|
|
299
|
+
.union([
|
|
300
|
+
zod_1.z.string(),
|
|
301
|
+
zod_1.z.number(),
|
|
302
|
+
zod_1.z.boolean(),
|
|
303
|
+
zod_1.z.array(zod_1.z.number()),
|
|
304
|
+
zod_1.z.null(),
|
|
305
|
+
])
|
|
306
|
+
.describe("The value for the custom field. For documentlink fields, use a single document ID (e.g., 123) or an array of document IDs (e.g., [123, 456])."),
|
|
317
307
|
}))
|
|
318
308
|
.optional()
|
|
319
309
|
.describe("Array of custom field values to assign"),
|
package/build/tools/tags.js
CHANGED
|
@@ -39,7 +39,7 @@ function registerTagTools(server, api) {
|
|
|
39
39
|
],
|
|
40
40
|
};
|
|
41
41
|
})));
|
|
42
|
-
server.tool("create_tag", {
|
|
42
|
+
server.tool("create_tag", "Create a new tag with optional color, matching pattern, and matching algorithm for automatic document tagging.", {
|
|
43
43
|
name: zod_1.z.string(),
|
|
44
44
|
color: zod_1.z
|
|
45
45
|
.string()
|
|
@@ -67,7 +67,7 @@ function registerTagTools(server, api) {
|
|
|
67
67
|
],
|
|
68
68
|
};
|
|
69
69
|
})));
|
|
70
|
-
server.tool("update_tag", {
|
|
70
|
+
server.tool("update_tag", "Update an existing tag's name, color, matching pattern, or matching algorithm.", {
|
|
71
71
|
id: zod_1.z.number(),
|
|
72
72
|
name: zod_1.z.string(),
|
|
73
73
|
color: zod_1.z
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@baruchiro/paperless-mcp",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.3.0",
|
|
4
4
|
"description": "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.",
|
|
5
5
|
"main": "build/index.js",
|
|
6
6
|
"bin": {
|
|
@@ -25,6 +25,9 @@
|
|
|
25
25
|
],
|
|
26
26
|
"author": "Baruch Odem",
|
|
27
27
|
"license": "ISC",
|
|
28
|
+
"engines": {
|
|
29
|
+
"node": ">=24.0.0"
|
|
30
|
+
},
|
|
28
31
|
"repository": {
|
|
29
32
|
"type": "git",
|
|
30
33
|
"url": "git+https://github.com/baruchiro/paperless-mcp.git"
|
|
@@ -51,7 +54,7 @@
|
|
|
51
54
|
"@anthropic-ai/dxt": "^0.2.6",
|
|
52
55
|
"@changesets/cli": "^2.29.4",
|
|
53
56
|
"@types/express": "^5.0.2",
|
|
54
|
-
"@types/node": "^
|
|
57
|
+
"@types/node": "^24.0.0",
|
|
55
58
|
"ts-node": "^10.9.2"
|
|
56
59
|
}
|
|
57
60
|
}
|
package/paperless-mcp.dxt
CHANGED
|
Binary file
|