Content
# Readur MCP Server
An MCP (Model Context Protocol) server that exposes Readur's document management and OCR API as tools for AI assistants. This server enables AI clients such as Claude Code, Claude Desktop, and other MCP-compatible applications to list, search, read, upload, and organize documents stored in a Readur instance.
[MCP](https://modelcontextprotocol.io/) is an open protocol that standardizes how AI applications interact with external tools and data sources. By running this server, you give your AI assistant direct access to your Readur document library through 18 purpose-built tools.
## Features
**Document Management** -- List, inspect, upload, delete, and reprocess documents with full metadata access including OCR-extracted text.
**Full-Text Search** -- Search across document contents with relevance scoring, text snippets, filtering by MIME type and status, and query suggestions.
**Label Organization** -- Create labels and assign them to documents for categorization and retrieval.
**System Monitoring** -- Check authenticated user info, application settings, OCR language availability, and processing queue statistics.
### Tool Summary
| Category | Tools |
|----------|-------|
| Documents | `list_documents`, `get_document`, `get_document_ocr_text`, `upload_document`, `delete_document`, `retry_document_ocr` |
| Search | `search_documents`, `enhanced_search`, `get_search_facets` |
| Labels | `list_labels`, `create_label`, `get_document_labels`, `add_document_label`, `remove_document_label` |
| Status | `whoami`, `get_settings`, `get_queue_stats`, `get_ocr_languages` |
## Prerequisites
- **Node.js >= 24.0.0**
- **A running Readur instance** with API access
- **Authentication credentials**: either a JWT token or a username/password pair
## Installation
Clone the repository and build from source:
```bash
git clone <repository-url>
cd readur-mcp
npm install
npm run build
```
After building, the compiled server is located at `dist/index.js`.
## Configuration
The server accepts configuration from three sources, applied in the following priority order (highest to lowest):
1. **CLI arguments**
2. **Environment variables**
3. **Config file** (`~/.config/readur-mcp/config.json`)
A value set via CLI argument overrides the same value set via environment variable, which in turn overrides the config file.
### Environment Variables
| Variable | Required | Description |
|----------|----------|-------------|
| `READUR_URL` | Yes | Base URL of your Readur instance (no trailing slash) |
| `READUR_TOKEN` | No* | Pre-obtained JWT authentication token |
| `READUR_USERNAME` | No* | Username for login-based authentication |
| `READUR_PASSWORD` | No* | Password for login-based authentication |
| `READUR_TRANSPORT` | No | Transport type: `stdio` (default) or `sse` |
*You must provide either `READUR_TOKEN` or both `READUR_USERNAME` and `READUR_PASSWORD`.
### CLI Arguments
```
--url <url> Readur server URL (required, no trailing slash)
--token <token> Pre-obtained JWT authentication token
--username <username> Username for login-based authentication
--password <password> Password for login-based authentication
--transport <type> Transport type: stdio or sse (default: stdio)
-h, --help Show help message
```
### Config File
Create `~/.config/readur-mcp/config.json` with any of the supported options:
```json
{
"url": "https://readur.example.com",
"token": "your-jwt-token",
"transport": "stdio"
}
```
Or with username/password credentials:
```json
{
"url": "https://readur.example.com",
"username": "admin",
"password": "your-password",
"transport": "stdio"
}
```
The config file is silently ignored if it does not exist. A warning is printed if the file exists but contains invalid JSON.
### Authentication
The server supports two authentication modes:
**Token-based authentication** -- Provide a pre-obtained JWT token via `--token`, `READUR_TOKEN`, or the config file. The token is sent as a Bearer token with every API request. This mode is straightforward but requires you to manage token expiration externally.
**Credential-based authentication** -- Provide a username and password via `--username`/`--password`, `READUR_USERNAME`/`READUR_PASSWORD`, or the config file. The server automatically calls `POST /api/auth/login` to obtain a JWT token on the first API request. If a subsequent request returns HTTP 401, the server transparently re-authenticates and retries the request once, so sessions recover automatically from token expiration.
## Usage with AI Assistants
### Claude Code
Register the MCP server using `claude mcp add`. You can provide configuration through environment variables or CLI arguments.
**With a JWT token (environment variables):**
```bash
claude mcp add readur-mcp \
-e READUR_URL=https://readur.example.com \
-e READUR_TOKEN=your-jwt-token \
-- node /absolute/path/to/readur-mcp/dist/index.js
```
**With a JWT token (CLI arguments):**
```bash
claude mcp add readur-mcp \
-- node /absolute/path/to/readur-mcp/dist/index.js \
--url https://readur.example.com \
--token your-jwt-token
```
**With username/password credentials:**
```bash
claude mcp add readur-mcp \
-e READUR_URL=https://readur.example.com \
-e READUR_USERNAME=admin \
-e READUR_PASSWORD=secret \
-- node /absolute/path/to/readur-mcp/dist/index.js
```
To verify the server is registered:
```bash
claude mcp list
```
### Claude Desktop
Add the server to your `claude_desktop_config.json` file.
**With a JWT token:**
```json
{
"mcpServers": {
"readur": {
"command": "node",
"args": ["/absolute/path/to/readur-mcp/dist/index.js"],
"env": {
"READUR_URL": "https://readur.example.com",
"READUR_TOKEN": "your-jwt-token"
}
}
}
}
```
**With username/password credentials:**
```json
{
"mcpServers": {
"readur": {
"command": "node",
"args": ["/absolute/path/to/readur-mcp/dist/index.js"],
"env": {
"READUR_URL": "https://readur.example.com",
"READUR_USERNAME": "admin",
"READUR_PASSWORD": "your-password"
}
}
}
}
```
The config file location depends on your operating system:
| OS | Path |
|----|------|
| macOS | `~/Library/Application Support/Claude/claude_desktop_config.json` |
| Windows | `%APPDATA%\Claude\claude_desktop_config.json` |
| Linux | `~/.config/Claude/claude_desktop_config.json` |
### Other MCP Clients
Any MCP-compatible client can use this server. The server communicates over **stdio** transport by default: the client spawns the process and exchanges JSON-RPC messages over stdin/stdout.
To integrate with a generic MCP client, configure it to:
1. Run the command: `node /absolute/path/to/readur-mcp/dist/index.js`
2. Pass configuration via environment variables (`READUR_URL`, `READUR_TOKEN`, etc.) or CLI arguments (`--url`, `--token`, etc.)
3. Connect using the stdio transport
### MCP Inspector (Development and Testing)
The MCP Inspector provides an interactive web UI for testing tools without an AI client. Run it with:
```bash
npm run inspector
```
This launches the `@modelcontextprotocol/inspector` and connects it to the server. You can browse available tools, invoke them with custom parameters, and inspect the responses. Set the required environment variables before running the command, or rely on your config file.
## Tool Reference
### Documents
| Tool | Description | Parameters | Mode |
|------|-------------|------------|------|
| `list_documents` | List documents with optional filtering, sorting, and pagination. Returns IDs, titles, MIME types, statuses, and file sizes. | `page?` (int), `pageSize?` (int, 1-100), `sortBy?` (string), `sortOrder?` ("asc" or "desc"), `status?` ("pending", "processing", "completed", "failed"), `mimeType?` (string) | Read-only |
| `get_document` | Get full metadata for a single document by ID. Returns title, filename, MIME type, status, page count, file size, hash, and timestamps. | `id` (int) | Read-only |
| `get_document_ocr_text` | Get the OCR-extracted text content of a document. Returns the full text and per-page text with confidence scores. | `id` (int) | Read-only |
| `upload_document` | Upload a new document to Readur. Supports PDF, TIFF, PNG, JPG, and other image formats. | `filename` (string), `content` (base64 string), `mimeType` (string) | Mutating |
| `delete_document` | Permanently delete a document by ID. This action cannot be undone. | `id` (int) | Destructive |
| `retry_document_ocr` | Retry OCR processing for a document that previously failed or needs reprocessing. | `id` (int) | Mutating |
### Search
| Tool | Description | Parameters | Mode |
|------|-------------|------------|------|
| `search_documents` | Search documents by text query with optional filtering by MIME type and status. Returns matching documents with relevance scores and text snippets. | `query` (string), `page?` (int), `pageSize?` (int, 1-100), `mimeType?` (string), `status?` ("pending", "processing", "completed", "failed") | Read-only |
| `enhanced_search` | Perform an enhanced search with relevance scores, text snippets, and query suggestions for refining searches. Supports filtering by MIME type and tag. | `query` (string), `page?` (int), `pageSize?` (int, 1-100), `mimeType?` (string), `tag?` (string) | Read-only |
| `get_search_facets` | Get available search facets for filtering. Returns MIME types and tags present in the collection along with document counts. | _(none)_ | Read-only |
### Labels
| Tool | Description | Parameters | Mode |
|------|-------------|------------|------|
| `list_labels` | List all available labels. Returns each label with its ID, name, color, and description. | _(none)_ | Read-only |
| `create_label` | Create a new label that can be assigned to documents. | `name` (string), `color?` (string, e.g. "#ff0000"), `description?` (string) | Mutating |
| `get_document_labels` | Get all labels assigned to a specific document. | `documentId` (int) | Read-only |
| `add_document_label` | Assign a label to a document. | `documentId` (int), `labelId` (int) | Mutating |
| `remove_document_label` | Remove a label assignment from a document. | `documentId` (int), `labelId` (int) | Destructive |
### Status
| Tool | Description | Parameters | Mode |
|------|-------------|------------|------|
| `whoami` | Get the currently authenticated user's ID, username, email, and role. | _(none)_ | Read-only |
| `get_settings` | Get the current Readur application settings as key-value pairs. | _(none)_ | Read-only |
| `get_queue_stats` | Get processing queue statistics: pending, processing, completed, failed, and total job counts. | _(none)_ | Read-only |
| `get_ocr_languages` | Get available OCR languages with their code, name, and installation status. | _(none)_ | Read-only |
## Development
### Available Scripts
```bash
npm run build # Compile TypeScript to dist/
npm run dev # Watch mode -- recompiles on file changes
npm run start # Run the compiled server (dist/index.js)
npm run typecheck # Type-check without emitting files
npm run inspector # Launch MCP Inspector for interactive testing
```
### Project Structure
```
readur-mcp/
package.json
tsconfig.json
src/
index.ts # Entry point -- loads config and starts server
config.ts # Configuration loading (CLI, env, config file)
server.ts # MCP server setup and tool registration
client/
readur.ts # HTTP client for the Readur REST API
errors/
index.ts # Error formatting utilities
tools/
index.ts # Aggregates all tools and handlers
schemas.ts # Tool definition helper (defineTool)
validators.ts # Shared Zod schemas (pagination, IDs, filters)
documents.ts # Document management tools (6 tools)
search.ts # Search tools (3 tools)
labels.ts # Label management tools (5 tools)
status.ts # System status tools (4 tools)
types/
api.ts # TypeScript type definitions for API responses
```
## Troubleshooting
**"Error: Readur server URL is required"** -- The server could not find a URL from any configuration source. Set `READUR_URL` as an environment variable, pass `--url` as a CLI argument, or add `"url"` to your config file.
**"Error: Authentication is required"** -- Provide either a JWT token (`READUR_TOKEN` / `--token`) or both a username and password (`READUR_USERNAME` + `READUR_PASSWORD` / `--username` + `--password`).
**"Login failed" errors** -- Verify that your username and password are correct and that the Readur instance is reachable at the configured URL. Check that the `/api/auth/login` endpoint is accessible.
**401 errors during operation** -- If using token-based auth, the token may have expired. Obtain a fresh token and update your configuration. If using credential-based auth, the server retries authentication automatically on 401 responses; persistent 401 errors indicate invalid credentials.
**Tools not appearing in Claude Code** -- Run `claude mcp list` to confirm the server is registered. If the server is listed but tools are missing, check the server logs for startup errors. Ensure the `dist/` directory exists by running `npm run build`.
**SSE transport warning** -- SSE transport is not yet implemented. The server falls back to stdio transport when `sse` is configured. Use the default `stdio` transport.
## License
MIT
Connection Info
You Might Also Like
markitdown
Python tool for converting files and office documents to Markdown.
markitdown
MarkItDown-MCP is a lightweight server for converting URIs to Markdown.
Filesystem
Node.js MCP Server for filesystem operations with dynamic access control.
TrendRadar
TrendRadar: Your hotspot assistant for real news in just 30 seconds.
mempalace
The highest-scoring AI memory system ever benchmarked. And it's free.
mempalace
The highest-scoring AI memory system ever benchmarked. And it's free.