{"id":49649768,"url":"https://github.com/cubinet-code/paperless-ngx-mcp","last_synced_at":"2026-06-29T06:00:58.568Z","repository":{"id":355963827,"uuid":"1230422591","full_name":"cubinet-code/paperless-ngx-mcp","owner":"cubinet-code","description":"MCP server for Paperless-NGX. Lets AI assistants manage documents, tags, correspondents, document types, custom fields, saved views, storage paths, workflows, share links, notes, trash, and tasks via the Paperless-NGX REST API.","archived":false,"fork":false,"pushed_at":"2026-05-06T02:53:40.000Z","size":153,"stargazers_count":0,"open_issues_count":0,"forks_count":0,"subscribers_count":0,"default_branch":"main","last_synced_at":"2026-05-06T04:09:59.923Z","etag":null,"topics":["ai","claude","document-management","mcp","mcp-server","model-context-protocol","paperless","paperless-ngx","typescript"],"latest_commit_sha":null,"homepage":"https://www.npmjs.com/package/paperless-ngx-mcp","language":"TypeScript","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"isc","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/cubinet-code.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null,"zenodo":null,"notice":null,"maintainers":null,"copyright":null,"agents":null,"dco":null,"cla":null}},"created_at":"2026-05-06T01:35:32.000Z","updated_at":"2026-05-06T02:53:42.000Z","dependencies_parsed_at":null,"dependency_job_id":null,"html_url":"https://github.com/cubinet-code/paperless-ngx-mcp","commit_stats":null,"previous_names":["cubinet-code/paperless-ngx-mcp"],"tags_count":6,"template":false,"template_full_name":null,"purl":"pkg:github/cubinet-code/paperless-ngx-mcp","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/cubinet-code%2Fpaperless-ngx-mcp","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/cubinet-code%2Fpaperless-ngx-mcp/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/cubinet-code%2Fpaperless-ngx-mcp/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/cubinet-code%2Fpaperless-ngx-mcp/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/cubinet-code","download_url":"https://codeload.github.com/cubinet-code/paperless-ngx-mcp/tar.gz/refs/heads/main","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/cubinet-code%2Fpaperless-ngx-mcp/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":34915002,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-05-26T15:22:16.424Z","status":"online","status_checked_at":"2026-06-29T02:00:05.398Z","response_time":58,"last_error":null,"robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":true,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["ai","claude","document-management","mcp","mcp-server","model-context-protocol","paperless","paperless-ngx","typescript"],"created_at":"2026-05-06T04:05:07.311Z","updated_at":"2026-06-29T06:00:58.560Z","avatar_url":"https://github.com/cubinet-code.png","language":"TypeScript","funding_links":[],"categories":[],"sub_categories":[],"readme":"# paperless-ngx-mcp\n\n[![CI](https://github.com/cubinet-code/paperless-ngx-mcp/actions/workflows/ci.yml/badge.svg)](https://github.com/cubinet-code/paperless-ngx-mcp/actions/workflows/ci.yml)\n[![License: ISC](https://img.shields.io/badge/license-ISC-blue.svg)](LICENSE)\n\nA [Model Context Protocol](https://modelcontextprotocol.io/) server for [Paperless-NGX](https://docs.paperless-ngx.com/). Exposes the full Paperless-NGX REST API to AI assistants — documents, tags, correspondents, document types, custom fields, storage paths, saved views, share links, workflows, notes, trash, and tasks.\n\n## Quick Start\n\nThe server is published to npm as [`paperless-ngx-mcp`](https://www.npmjs.com/package/paperless-ngx-mcp). You can run it with `npx` — no clone or build required.\n\n### Claude Code\n\n```bash\nclaude mcp add paperless --scope user \\\n  --env PAPERLESS_URL=https://your-paperless-instance \\\n  --env PAPERLESS_API_KEY=your-api-token \\\n  -- npx -y paperless-ngx-mcp\n```\n\nDrop `--scope user` to install for the current project only. See `claude mcp add --help` for more options.\n\n### Codex CLI\n\n```bash\ncodex mcp add paperless \\\n  --env PAPERLESS_URL=https://your-paperless-instance \\\n  --env PAPERLESS_API_KEY=your-api-token \\\n  -- npx -y paperless-ngx-mcp\n```\n\nThis writes the entry to `~/.codex/config.toml`.\n\n### Claude Desktop, Cursor, Cline, and other MCP clients\n\nAdd this to your client's MCP config file (e.g. `claude_desktop_config.json`, `~/.cursor/mcp.json`, `~/.config/cline/mcp.json`):\n\n```json\n{\n  \"mcpServers\": {\n    \"paperless\": {\n      \"command\": \"npx\",\n      \"args\": [\"-y\", \"paperless-ngx-mcp\"],\n      \"env\": {\n        \"PAPERLESS_URL\": \"https://your-paperless-instance\",\n        \"PAPERLESS_API_KEY\": \"your-api-token\",\n        \"PAPERLESS_PUBLIC_URL\": \"https://your-public-domain\"\n      }\n    }\n  }\n}\n```\n\n### Get your Paperless-NGX API token\n\n1. Log into your Paperless-NGX instance.\n2. Click your username (top right) → **My Profile**.\n3. Click the circular arrow button to generate a new token.\n\n### Configuration\n\n| Variable | Required | Purpose |\n|---|---|---|\n| `PAPERLESS_URL` | yes | Base URL the MCP server uses to talk to Paperless-NGX. |\n| `PAPERLESS_API_KEY` | yes | API token (see above). |\n| `PAPERLESS_PUBLIC_URL` | no | Public URL the assistant uses when constructing browser links to documents. Falls back to `PAPERLESS_URL`. |\n\nCLI flags (`--baseUrl`, `--token`, `--publicUrl`, `--http`, `--port`) take precedence over environment variables.\n\n### Example Usage\n\nThings you can ask Claude (or any MCP-aware assistant):\n\n- \"Show me all documents tagged as 'Invoice'\"\n- \"Search for documents containing 'tax return'\"\n- \"Create a new tag called 'Receipts' with color #FF0000\"\n- \"Download document #123\"\n- \"List all correspondents\"\n- \"Create a new document type called 'Bank Statement'\"\n- \"Empty the trash\"\n- \"Show me pending consumption tasks\"\n\n## Available Tools\n\nThe server registers tools across ten domains.\n\n### Documents\n`list_documents`, `get_document`, `get_document_content`, `search_documents`, `download_document`, `download_documents_bulk`, `get_document_thumbnail`, `get_document_preview`, `get_document_history`, `get_document_metadata`, `update_document`, `post_document`, `email_document`, `edit_documents_bulk`, `delete_document`, `search_autocomplete`, `get_document_suggestions`, `get_next_asn`\n\n### Tags\n`list_tags`, `get_tag`, `create_tag`, `update_tag`, `delete_tag`, `edit_tags_bulk`\n\n### Correspondents\n`list_correspondents`, `get_correspondent`, `create_correspondent`, `update_correspondent`, `delete_correspondent`, `edit_correspondents_bulk`\n\n### Document Types\n`list_document_types`, `get_document_type`, `create_document_type`, `update_document_type`, `delete_document_type`, `edit_document_types_bulk`\n\n### Custom Fields\n`list_custom_fields`, `get_custom_field`, `create_custom_field`, `update_custom_field`, `delete_custom_field`, `edit_custom_fields_bulk`\n\n### Storage Paths\n`list_storage_paths`, `get_storage_path`, `create_storage_path`, `update_storage_path`, `delete_storage_path`, `test_storage_path`\n\n### Saved Views\n`list_saved_views`, `get_saved_view`, `create_saved_view`, `update_saved_view`, `delete_saved_view`\n\n### Share Links\n`list_share_links`, `list_document_share_links`, `get_share_link`, `create_share_link`, `update_share_link`, `delete_share_link`\n\n### Workflows\n`list_workflow_actions`, `get_workflow_action`, `create_workflow_action`, `update_workflow_action`, `delete_workflow_action`, `list_workflow_triggers`, `get_workflow_trigger`, `create_workflow_trigger`, `update_workflow_trigger`, `delete_workflow_trigger`\n\n### System / Notes / Trash / Tasks\n`get_statistics`, `list_document_notes`, `create_document_note`, `delete_document_note`, `list_trash`, `restore_from_trash`, `empty_trash`, `list_tasks`, `acknowledge_tasks`\n\n### Tool naming convention (for permission allowlists)\n\nTool names are **verb-first**, so wildcard-based permission rules group cleanly by operation:\n\n| Wildcard | Covers |\n|---|---|\n| `mcp__paperless__list_*` | All list/index reads |\n| `mcp__paperless__get_*` | All single-item reads |\n| `mcp__paperless__search_*` | Full-text search and autocomplete |\n| `mcp__paperless__download_*` | `download_document` and `download_documents_bulk` |\n| `mcp__paperless__create_*` | All create endpoints |\n| `mcp__paperless__update_*` | Per-item PATCH updates |\n| `mcp__paperless__edit_*_bulk` | All bulk-edit operations across entity types |\n| `mcp__paperless__delete_*` | ⚠️ Destructive — system-wide deletes |\n\nA read-only allowlist is therefore: `list_*`, `get_*`, `search_*`, `download_*`. Write access without destructive operations: add `create_*`, `update_*`, `edit_*_bulk`, `post_document`, `email_document`. `delete_*` and `empty_trash` should require explicit user approval.\n\n## Prompts\n\nThe server also registers MCP **prompts** — reusable, parameterized instructions that surface as slash commands in clients like Claude Code (e.g. `/mcp__paperless__triage_inbox`).\n\n### `triage_inbox`\n\nWalks the assistant through inbox triage: gather existing tags / correspondents / document types, propose metadata for each inbox document **preferring existing items**, present a confirmation table, and only apply changes after the user replies `apply`. New correspondents / types / tags are flagged `(NEW)` so you can veto creations before they happen.\n\nArgument:\n- `limit` (optional, default `25`): maximum number of inbox documents to triage in one pass.\n\n### Notable tool details\n\n#### `edit_documents_bulk`\n\nPerform bulk operations on multiple documents.\n\nParameters:\n- `documents`: array of document IDs\n- `method`: one of `set_correspondent`, `set_document_type`, `set_storage_path`, `add_tag`, `remove_tag`, `modify_tags`, `modify_custom_fields`, `delete`, `reprocess`, `set_permissions`, `merge`, `split`, `rotate`, `delete_pages`, `edit_pdf`\n- Method-specific parameters: `correspondent`, `document_type`, `storage_path`, `tag`, `add_tags`, `remove_tags`, `add_custom_fields`, `remove_custom_fields`, `set_permissions`, `owner`, `merge`, `metadata_document_id`, `delete_originals`, `pages`, `degrees`, `operations`, `update_document`, `include_metadata`\n\n```typescript\n// Add a tag to multiple documents\nedit_documents_bulk({ documents: [1, 2, 3], method: \"add_tag\", tag: 5 })\n\n// Merge documents\nedit_documents_bulk({\n  documents: [6, 7, 8],\n  method: \"merge\",\n  metadata_document_id: 6,\n  delete_originals: true,\n})\n\n// Split a document into parts\nedit_documents_bulk({ documents: [9], method: \"split\", pages: \"[1-2,3-4,5]\" })\n\n// Modify multiple tags at once\nedit_documents_bulk({\n  documents: [10, 11],\n  method: \"modify_tags\",\n  add_tags: [1, 2],\n  remove_tags: [3, 4],\n})\n```\n\n#### `post_document`\n\nUpload a new document.\n\nParameters: `file`, `filename`, plus optional `title`, `created`, `correspondent`, `document_type`, `storage_path`, `tags`, `archive_serial_number`, `custom_fields`, `poll`, `poll_timeout_seconds`.\n\n`file` accepts **base64-encoded contents** (the universal method — works for any deployment, since the bytes travel over the wire) or an **absolute file path** that the server reads from its own filesystem. The path option only works when the MCP server runs on the same machine as the file (local/stdio deployments); for a remote server, use base64.\n\nUpload is asynchronous. By default the tool returns a task UUID (track it with `list_tasks`). Set `poll: true` to wait for the consumer to finish and get the result in one call — the new `document_id` on success, or the consumer error on failure. `poll_timeout_seconds` (default 30, max 300) caps the wait; raise it for large scans where OCR is slow.\n\n#### Matching algorithms\n\n`create_tag`, `create_correspondent`, `create_document_type`, and `create_storage_path` accept a `matching_algorithm` (0–6):\n\n| Value | Meaning |\n|---|---|\n| 0 | None |\n| 1 | Any word |\n| 2 | All words |\n| 3 | Exact match |\n| 4 | Regular expression |\n| 5 | Fuzzy word |\n| 6 | Automatic |\n\n## Running the MCP Server\n\n### stdio (default)\n\nThe default mode. The server communicates over stdio — that's what every MCP client config in the Quick Start uses. You usually never run this manually; the MCP client launches it for you.\n\nIf you do want to run it directly (e.g. for debugging):\n\n```bash\n# via env vars (recommended)\nPAPERLESS_URL=http://localhost:8000 PAPERLESS_API_KEY=xxx npx -y paperless-ngx-mcp\n\n# or via CLI flags\nnpx -y paperless-ngx-mcp --baseUrl http://localhost:8000 --token xxx\n```\n\n### HTTP (Streamable HTTP transport)\n\nUse the `--http` flag to expose the server over HTTP. `--port` defaults to `3000`.\n\n```bash\nnpx -y paperless-ngx-mcp --baseUrl http://localhost:8000 --token xxx --http --port 3000\n```\n\n- The MCP API is available at `POST /mcp` on the chosen port.\n- Each request is handled statelessly via [`StreamableHTTPServerTransport`](https://github.com/modelcontextprotocol/typescript-sdk).\n- A legacy `GET /sse` + `POST /messages` SSE transport is also exposed for clients that don't yet support the streamable transport.\n\n## Error Handling\n\nTool calls return clear errors when:\n- `PAPERLESS_URL` or `PAPERLESS_API_KEY` is missing or wrong\n- The Paperless-NGX server is unreachable\n- The underlying API rejects the operation\n- Tool parameters fail validation\n\n## Development\n\nYou only need this section if you're modifying the server itself. End users should follow the [Quick Start](#quick-start) instead — there's no need to clone or build.\n\n```bash\ngit clone https://github.com/cubinet-code/paperless-ngx-mcp.git\ncd paperless-ngx-mcp\nnpm install        # install dependencies\nnpm run start      # run the server with tsx (no build step)\nnpm run build      # compile TypeScript to build/\nnpm test           # unit tests (node:test + tsx)\nnpm run inspect    # build, then launch @modelcontextprotocol/inspector\n```\n\n`npm run start` accepts the same flags / env vars as the built binary.\n\n### End-to-end tests\n\nE2E tests spin up a real Paperless-NGX container via Docker Compose:\n\n```bash\nnpm run test:e2e:up    # start the test stack (paperless + redis)\nnpm run test:e2e       # run the e2e suite against it\nnpm run test:e2e:down  # tear down and remove volumes\n```\n\nBuilt with:\n- [@modelcontextprotocol/sdk](https://github.com/modelcontextprotocol/typescript-sdk) — MCP server SDK\n- [zod](https://github.com/colinhacks/zod) — schema validation\n- [axios](https://github.com/axios/axios) — HTTP client (with keep-alive agents and a 60s timeout)\n\n## API Documentation\n\nThis MCP server wraps endpoints from the Paperless-NGX REST API. See the [official API documentation](https://docs.paperless-ngx.com/api/) for details on the underlying behaviour and field semantics.\n\n## License\n\nISC. See [LICENSE](LICENSE).\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fcubinet-code%2Fpaperless-ngx-mcp","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fcubinet-code%2Fpaperless-ngx-mcp","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fcubinet-code%2Fpaperless-ngx-mcp/lists"}