@kjanat/paperless-mcp 2.0.1 → 2.1.1

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/README.md CHANGED
@@ -1,45 +1,72 @@
1
1
  # Paperless-ngx MCP Server
2
2
 
3
+ [![NPM Version](https://img.shields.io/npm/v/@kjanat/paperless-mcp?logo=npm&labelColor=CB3837&color=black)](https://www.npmjs.com/package/@kjanat/paperless-mcp)
4
+
3
5
  An MCP (Model Context Protocol) server for interacting with a Paperless-ngx API server. This server provides tools for managing documents, tags, correspondents, and document types in your Paperless-ngx instance.
4
6
 
5
7
  ## Quick Start
6
8
 
7
9
  ### Installation
8
10
 
9
- 1. Install the MCP server (optional):
11
+ 1. Get your API token:
12
+ 1. Log into your Paperless-ngx instance
13
+ 2. Click your username in the top right
14
+ 3. Select "My Profile"
15
+ 4. Click the circular arrow button to generate a new token
16
+
17
+ 1. Add it to your MCP client configuration (using env vars):
10
18
 
11
- ```bash
12
- bun install -g @kjanat/paperless-mcp
19
+ ```jsonc
20
+ {
21
+ "mcpServers": {
22
+ "paperless": {
23
+ "command": "bunx", // or npx
24
+ "args": ["@kjanat/paperless-mcp"],
25
+ "env": {
26
+ "PAPERLESS_URL": "http://your-paperless-instance:8000",
27
+ "PAPERLESS_API_KEY": "your-api-token",
28
+ },
29
+ },
30
+ },
31
+ }
13
32
  ```
14
33
 
15
- 1. Add it to your configuration:
34
+ Or pass them as positional arguments:
16
35
 
17
36
  ```jsonc
18
37
  {
19
- "mcpServers": {
20
- "paperless": {
21
- "command": "bunx", // or npx
22
- "args": [
23
- "@kjanat/paperless-mcp",
24
- "http://your-paperless-instance:8000",
25
- "your-api-token",
26
- ],
27
- },
28
- },
38
+ "mcpServers": {
39
+ "paperless": {
40
+ "command": "bunx", // or npx
41
+ "args": [
42
+ "@kjanat/paperless-mcp",
43
+ "http://your-paperless-instance:8000",
44
+ "your-api-token",
45
+ ],
46
+ },
47
+ },
29
48
  }
30
49
  ```
31
50
 
32
- 1. Get your API token:
33
- 1. Log into your Paperless-ngx instance
34
- 2. Click your username in the top right
35
- 3. Select "My Profile"
36
- 4. Click the circular arrow button to generate a new token
51
+ CLI args take precedence over env vars when both are provided.
37
52
 
38
- 1. Replace the placeholders in your MCP config:
39
- - `http://your-paperless-instance:8000` with your Paperless-ngx URL
40
- - `your-api-token` with the token you just generated
53
+ That's it!
41
54
 
42
- That's it! Now you can ask Claude to help you manage your Paperless-ngx documents.
55
+ ## Agent Skill
56
+
57
+ This package ships an [Agent Skill](https://agentskills.io/specification) in
58
+ `skills/paperless-ngx/` with decision trees, tool reference docs, query syntax
59
+ guide, and workflow templates for AI agents.
60
+
61
+ View the skill on the registry: https://skills.sh/kjanat/paperless-mcp/paperless-ngx
62
+
63
+ _Add using_:
64
+
65
+ ```bash
66
+ bunx skills add https://github.com/kjanat/paperless-mcp --skill paperless-ngx
67
+ ```
68
+
69
+ `# or npx -y skills...`
43
70
 
44
71
  ## Example Usage
45
72
 
@@ -54,160 +81,167 @@ Here are some things you can ask Claude to do:
54
81
 
55
82
  ## Available Tools
56
83
 
84
+ <details>
85
+ <summary>Document Operations</summary>
86
+
57
87
  ### Document Operations
58
88
 
59
- #### get_document
89
+ #### `get_document`
60
90
 
61
91
  Get a specific document by ID.
62
92
 
63
93
  Parameters:
64
94
 
65
- - id: Document ID
95
+ - `id`: Document ID
66
96
 
67
97
  ```typescript
68
98
  get_document({
69
- id: 123,
99
+ id: 123,
70
100
  });
71
101
  ```
72
102
 
73
- #### search_documents
103
+ #### `search_documents`
74
104
 
75
105
  Full-text search across documents.
76
106
 
77
107
  Parameters:
78
108
 
79
- - query: Search query string
109
+ - `query`: Search query string
80
110
 
81
111
  ```typescript
82
112
  search_documents({
83
- query: "invoice 2024",
113
+ query: "invoice 2024",
84
114
  });
85
115
  ```
86
116
 
87
- #### download_document
117
+ #### `download_document`
88
118
 
89
119
  Download a document file by ID.
90
120
 
91
121
  Parameters:
92
122
 
93
- - id: Document ID
94
- - original (optional): If true, downloads original file instead of archived version
123
+ - `id`: Document ID
124
+ - `original` (optional): If true, downloads original file instead of archived version
95
125
 
96
126
  ```typescript
97
127
  download_document({
98
- id: 123,
99
- original: false,
128
+ id: 123,
129
+ original: false,
100
130
  });
101
131
  ```
102
132
 
103
- #### bulk_edit_documents
133
+ #### `bulk_edit_documents`
104
134
 
105
135
  Perform bulk operations on multiple documents.
106
136
 
107
137
  Parameters:
108
138
 
109
- - documents: Array of document IDs
110
- - method: One of:
111
- - set_correspondent: Set correspondent for documents
112
- - set_document_type: Set document type for documents
113
- - set_storage_path: Set storage path for documents
114
- - add_tag: Add a tag to documents
115
- - remove_tag: Remove a tag from documents
116
- - modify_tags: Add and/or remove multiple tags
117
- - delete: Delete documents
118
- - reprocess: Reprocess documents
119
- - set_permissions: Set document permissions
120
- - merge: Merge multiple documents
121
- - split: Split a document into multiple documents
122
- - rotate: Rotate document pages
123
- - delete_pages: Delete specific pages from a document
124
- - Additional parameters based on method:
125
- - correspondent: ID for set_correspondent
126
- - document_type: ID for set_document_type
127
- - storage_path: ID for set_storage_path
128
- - tag: ID for add_tag/remove_tag
129
- - add_tags: Array of tag IDs for modify_tags
130
- - remove_tags: Array of tag IDs for modify_tags
131
- - permissions: Object for set_permissions with owner, permissions, merge flag
132
- - metadata_document_id: ID for merge to specify metadata source
133
- - delete_originals: Boolean for merge/split
134
- - pages: String for split "[1,2-3,4,5-7]" or delete_pages "[2,3,4]"
135
- - degrees: Number for rotate (90, 180, or 270)
139
+ - `documents`: Array of document IDs
140
+ - `method`: One of:
141
+ - `set_correspondent`: Set correspondent for documents
142
+ - `set_document_type`: Set document type for documents
143
+ - `set_storage_path`: Set storage path for documents
144
+ - `add_tag`: Add a tag to documents
145
+ - `remove_tag`: Remove a tag from documents
146
+ - `modify_tags`: Add and/or remove multiple tags
147
+ - `delete`: Delete documents
148
+ - `reprocess`: Reprocess documents
149
+ - `set_permissions`: Set document permissions
150
+ - `merge`: Merge multiple documents
151
+ - `split`: Split a document into multiple documents
152
+ - `rotate`: Rotate document pages
153
+ - `delete_pages`: Delete specific pages from a document
154
+ - Additional parameters based on `method`:
155
+ - `correspondent`: ID for set_correspondent
156
+ - `document_type`: ID for set_document_type
157
+ - `storage_path`: ID for set_storage_path
158
+ - `tag`: ID for add_tag/remove_tag
159
+ - `add_tags`: Array of tag IDs for modify_tags
160
+ - `remove_tags`: Array of tag IDs for modify_tags
161
+ - `permissions`: Object for set_permissions with owner, permissions, merge flag
162
+ - `metadata_document_id`: ID for merge to specify metadata source
163
+ - `delete_originals`: Boolean for merge/split
164
+ - `pages`: String for split "[1,2-3,4,5-7]" or `delete_pages` "[2,3,4]"
165
+ - `degrees`: Number for rotate (90, 180, or 270)
136
166
 
137
167
  Examples:
138
168
 
139
169
  ```typescript
140
170
  // Add a tag to multiple documents
141
171
  bulk_edit_documents({
142
- documents: [1, 2, 3],
143
- method: "add_tag",
144
- tag: 5,
172
+ documents: [1, 2, 3],
173
+ method: "add_tag",
174
+ tag: 5,
145
175
  });
146
176
 
147
177
  // Set correspondent and document type
148
178
  bulk_edit_documents({
149
- documents: [4, 5],
150
- method: "set_correspondent",
151
- correspondent: 2,
179
+ documents: [4, 5],
180
+ method: "set_correspondent",
181
+ correspondent: 2,
152
182
  });
153
183
 
154
184
  // Merge documents
155
185
  bulk_edit_documents({
156
- documents: [6, 7, 8],
157
- method: "merge",
158
- metadata_document_id: 6,
159
- delete_originals: true,
186
+ documents: [6, 7, 8],
187
+ method: "merge",
188
+ metadata_document_id: 6,
189
+ delete_originals: true,
160
190
  });
161
191
 
162
192
  // Split document into parts
163
193
  bulk_edit_documents({
164
- documents: [9],
165
- method: "split",
166
- pages: "[1-2,3-4,5]",
194
+ documents: [9],
195
+ method: "split",
196
+ pages: "[1-2,3-4,5]",
167
197
  });
168
198
 
169
199
  // Modify multiple tags at once
170
200
  bulk_edit_documents({
171
- documents: [10, 11],
172
- method: "modify_tags",
173
- add_tags: [1, 2],
174
- remove_tags: [3, 4],
201
+ documents: [10, 11],
202
+ method: "modify_tags",
203
+ add_tags: [1, 2],
204
+ remove_tags: [3, 4],
175
205
  });
176
206
  ```
177
207
 
178
- #### post_document
208
+ #### `post_document`
179
209
 
180
210
  Upload a new document to Paperless-ngx.
181
211
 
182
212
  Parameters:
183
213
 
184
- - file: Base64 encoded file content
185
- - filename: Name of the file
186
- - title (optional): Title for the document
187
- - created (optional): DateTime when the document was created (e.g. "2024-01-19" or "2024-01-19 06:15:00+02:00")
188
- - correspondent (optional): ID of a correspondent
189
- - document_type (optional): ID of a document type
190
- - storage_path (optional): ID of a storage path
191
- - tags (optional): Array of tag IDs
192
- - archive_serial_number (optional): Archive serial number
193
- - custom_fields (optional): Array of custom field IDs
214
+ - `file`: Base64 encoded file content
215
+ - `filename`: Name of the file
216
+ - `title` (optional): Title for the document
217
+ - `created` (optional): DateTime when the document was created (e.g. "2024-01-19" or "2024-01-19 06:15:00+02:00")
218
+ - `correspondent` (optional): ID of a correspondent
219
+ - `document_type` (optional): ID of a document type
220
+ - `storage_path` (optional): ID of a storage path
221
+ - `tags` (optional): Array of tag IDs
222
+ - `archive_serial_number` (optional): Archive serial number
223
+ - `custom_fields` (optional): Array of custom field IDs
194
224
 
195
225
  ```typescript
196
226
  post_document({
197
- file: "base64_encoded_content",
198
- filename: "invoice.pdf",
199
- title: "January Invoice",
200
- created: "2024-01-19",
201
- correspondent: 1,
202
- document_type: 2,
203
- tags: [1, 3],
204
- archive_serial_number: "2024-001",
227
+ file: "base64_encoded_content",
228
+ filename: "invoice.pdf",
229
+ title: "January Invoice",
230
+ created: "2024-01-19",
231
+ correspondent: 1,
232
+ document_type: 2,
233
+ tags: [1, 3],
234
+ archive_serial_number: "2024-001",
205
235
  });
206
236
  ```
207
237
 
238
+ </details>
239
+ <details>
240
+ <summary>Tag Operations</summary>
241
+
208
242
  ### Tag Operations
209
243
 
210
- #### list_tags
244
+ #### `list_tags`
211
245
 
212
246
  Get all tags.
213
247
 
@@ -215,57 +249,57 @@ Get all tags.
215
249
  list_tags();
216
250
  ```
217
251
 
218
- #### create_tag
252
+ #### `create_tag`
219
253
 
220
254
  Create a new tag.
221
255
 
222
256
  Parameters:
223
257
 
224
- - name: Tag name
225
- - color (optional): Hex color code (e.g. "#ff0000")
226
- - match (optional): Text pattern to match
227
- - matching_algorithm (optional): Integer 0-6 (0=none, 1=any, 2=all, 3=exact, 4=regex, 5=fuzzy, 6=auto)
258
+ - `name`: Tag name
259
+ - `color` (optional): Hex color code (e.g. "#ff0000")
260
+ - `match` (optional): Text pattern to match
261
+ - `matching_algorithm` (optional): Integer 0-6 (0=none, 1=any, 2=all, 3=exact, 4=regex, 5=fuzzy, 6=auto)
228
262
 
229
263
  ```typescript
230
264
  create_tag({
231
- name: "Invoice",
232
- color: "#ff0000",
233
- match: "invoice",
234
- matching_algorithm: 5,
265
+ name: "Invoice",
266
+ color: "#ff0000",
267
+ match: "invoice",
268
+ matching_algorithm: 5,
235
269
  });
236
270
  ```
237
271
 
238
- #### update_tag
272
+ #### `update_tag`
239
273
 
240
274
  Update an existing tag's name, color, or matching rules.
241
275
 
242
276
  Parameters:
243
277
 
244
- - id: Tag ID
245
- - name: New tag name
246
- - color (optional): Hex color code (e.g. "#ff0000")
247
- - match (optional): Text pattern to match
248
- - matching_algorithm (optional): Integer 0-6 (0=none, 1=any, 2=all, 3=exact, 4=regex, 5=fuzzy, 6=auto)
278
+ - `id`: Tag ID
279
+ - `name`: New tag name
280
+ - `color` (optional): Hex color code (e.g. "#ff0000")
281
+ - `match` (optional): Text pattern to match
282
+ - `matching_algorithm` (optional): Integer 0-6 (0=none, 1=any, 2=all, 3=exact, 4=regex, 5=fuzzy, 6=auto)
249
283
 
250
284
  ```typescript
251
285
  update_tag({
252
- id: 5,
253
- name: "Invoices",
254
- color: "#00ff00",
286
+ id: 5,
287
+ name: "Invoices",
288
+ color: "#00ff00",
255
289
  });
256
290
  ```
257
291
 
258
- #### delete_tag
292
+ #### `delete_tag`
259
293
 
260
294
  Permanently delete a tag. Removes it from all documents.
261
295
 
262
296
  Parameters:
263
297
 
264
- - id: Tag ID
298
+ - `id`: Tag ID
265
299
 
266
300
  ```typescript
267
301
  delete_tag({
268
- id: 5,
302
+ id: 5,
269
303
  });
270
304
  ```
271
305
 
@@ -275,22 +309,26 @@ Bulk set permissions or delete multiple tags.
275
309
 
276
310
  Parameters:
277
311
 
278
- - tag_ids: Array of tag IDs
279
- - operation: "set_permissions" or "delete"
280
- - owner (optional): User ID (for set_permissions)
281
- - permissions (optional): Object with view/change user and group IDs
282
- - merge (optional): Merge with existing permissions (default false)
312
+ - `tag_ids`: Array of tag IDs
313
+ - `operation`: "set_permissions" or "delete"
314
+ - `owner` (optional): User ID (for set_permissions)
315
+ - `permissions` (optional): Object with view/change user and group IDs
316
+ - `merge` (optional): Merge with existing permissions (default false)
283
317
 
284
318
  ```typescript
285
319
  bulk_edit_tags({
286
- tag_ids: [1, 2, 3],
287
- operation: "delete",
320
+ tag_ids: [1, 2, 3],
321
+ operation: "delete",
288
322
  });
289
323
  ```
290
324
 
325
+ </details>
326
+ <details>
327
+ <summary>Correspondent Operations</summary>
328
+
291
329
  ### Correspondent Operations
292
330
 
293
- #### list_correspondents
331
+ #### `list_correspondents`
294
332
 
295
333
  Get all correspondents.
296
334
 
@@ -304,40 +342,44 @@ Create a new correspondent.
304
342
 
305
343
  Parameters:
306
344
 
307
- - name: Correspondent name
308
- - match (optional): Text pattern to match
309
- - matching_algorithm (optional): Integer 0-6 (0=none, 1=any, 2=all, 3=exact, 4=regex, 5=fuzzy, 6=auto)
345
+ - `name`: Correspondent name
346
+ - `match` (optional): Text pattern to match
347
+ - `matching_algorithm` (optional): Integer 0-6 (0=none, 1=any, 2=all, 3=exact, 4=regex, 5=fuzzy, 6=auto)
310
348
 
311
349
  ```typescript
312
350
  create_correspondent({
313
- name: "ACME Corp",
314
- match: "ACME",
315
- matching_algorithm: 5,
351
+ name: "ACME Corp",
352
+ match: "ACME",
353
+ matching_algorithm: 5,
316
354
  });
317
355
  ```
318
356
 
319
- #### bulk_edit_correspondents
357
+ #### `bulk_edit_correspondents`
320
358
 
321
359
  Bulk set permissions or delete multiple correspondents.
322
360
 
323
361
  Parameters:
324
362
 
325
- - correspondent_ids: Array of correspondent IDs
326
- - operation: "set_permissions" or "delete"
327
- - owner (optional): User ID (for set_permissions)
328
- - permissions (optional): Object with view/change user and group IDs
329
- - merge (optional): Merge with existing permissions (default false)
363
+ - `correspondent_ids`: Array of correspondent IDs
364
+ - `operation`: "set_permissions" or "delete"
365
+ - `owner` (optional): User ID (for set_permissions)
366
+ - `permissions` (optional): Object with view/change user and group IDs
367
+ - `merge` (optional): Merge with existing permissions (default false)
330
368
 
331
369
  ```typescript
332
370
  bulk_edit_correspondents({
333
- correspondent_ids: [1, 2],
334
- operation: "delete",
371
+ correspondent_ids: [1, 2],
372
+ operation: "delete",
335
373
  });
336
374
  ```
337
375
 
376
+ </details>
377
+ <details>
378
+ <summary>Document Type Operations</summary>
379
+
338
380
  ### Document Type Operations
339
381
 
340
- #### list_document_types
382
+ #### `list_document_types`
341
383
 
342
384
  Get all document types.
343
385
 
@@ -351,37 +393,39 @@ Create a new document type.
351
393
 
352
394
  Parameters:
353
395
 
354
- - name: Document type name
355
- - match (optional): Text pattern to match
356
- - matching_algorithm (optional): Integer 0-6 (0=none, 1=any, 2=all, 3=exact, 4=regex, 5=fuzzy, 6=auto)
396
+ - `name`: Document type name
397
+ - `match` (optional): Text pattern to match
398
+ - `matching_algorithm` (optional): Integer 0-6 (0=none, 1=any, 2=all, 3=exact, 4=regex, 5=fuzzy, 6=auto)
357
399
 
358
400
  ```typescript
359
401
  create_document_type({
360
- name: "Invoice",
361
- match: "invoice total amount due",
362
- matching_algorithm: 1,
402
+ name: "Invoice",
403
+ match: "invoice total amount due",
404
+ matching_algorithm: 1,
363
405
  });
364
406
  ```
365
407
 
366
- #### bulk_edit_document_types
408
+ #### `bulk_edit_document_types`
367
409
 
368
410
  Bulk set permissions or delete multiple document types.
369
411
 
370
412
  Parameters:
371
413
 
372
- - document_type_ids: Array of document type IDs
373
- - operation: "set_permissions" or "delete"
374
- - owner (optional): User ID (for set_permissions)
375
- - permissions (optional): Object with view/change user and group IDs
376
- - merge (optional): Merge with existing permissions (default false)
414
+ - `document_type_ids`: Array of document type IDs
415
+ - `operation`: "set_permissions" or "delete"
416
+ - `owner` (optional): User ID (for set_permissions)
417
+ - `permissions` (optional): Object with view/change user and group IDs
418
+ - `merge` (optional): Merge with existing permissions (default false)
377
419
 
378
420
  ```typescript
379
421
  bulk_edit_document_types({
380
- document_type_ids: [1, 2],
381
- operation: "delete",
422
+ document_type_ids: [1, 2],
423
+ operation: "delete",
382
424
  });
383
425
  ```
384
426
 
427
+ </details>
428
+
385
429
  ## Error Handling
386
430
 
387
431
  The server will show clear error messages if:
@@ -427,19 +471,33 @@ The MCP server can be run in two modes:
427
471
  This is the default mode. The server communicates over stdio, suitable for CLI and direct integrations.
428
472
 
429
473
  ```bash
430
- bun start -- <baseUrl> <token>
474
+ # via .env file (Bun loads .env automatically)
475
+ bun start
476
+
477
+ # via inline env vars
478
+ PAPERLESS_URL=http://localhost:8000 PAPERLESS_API_KEY=your-token bun start
479
+
480
+ # via positional args
481
+ bun start http://localhost:8000 your-token
431
482
  ```
432
483
 
484
+ > [!TIP]
485
+ > When using Bun, env vars in a `.env` file are loaded automatically —
486
+ > no extra setup needed. Just create a `.env` with `PAPERLESS_URL` and
487
+ > `PAPERLESS_API_KEY` and run `bun start`.
488
+
433
489
  ### 2. HTTP (Streamable HTTP Transport)
434
490
 
435
- To run the server as an HTTP service, use the `--http` flag. You can also specify the port with `--port` (default: 3000). This mode requires [Express](https://expressjs.com/) to be installed (it is included as a dependency).
491
+ To run the server as an HTTP service, use the `--http` flag. You can also specify the port with `--port` (default: 3000).
436
492
 
437
493
  ```bash
438
- bun start -- <baseUrl> <token> --http --port 3000
494
+ PAPERLESS_URL=http://localhost:8000 PAPERLESS_API_KEY=your-token bun start --http --port 3000
439
495
  ```
440
496
 
497
+ With a `.env` file, this simplifies to `bun start --http`.
498
+
441
499
  - The MCP API will be available at `POST /mcp` on the specified port.
442
500
  - Each request is handled statelessly, following the [StreamableHTTPServerTransport](https://github.com/modelcontextprotocol/typescript-sdk) pattern.
443
501
  - GET and DELETE requests to `/mcp` will return 405 Method Not Allowed.
444
502
 
445
- <!--markdownlint-disable-file no-hard-tabs-->
503
+ <!--markdownlint-disable-file no-hard-tabs no-inline-html no-bare-urls-->