Skip to main content
Glama
cbinckly

paperless-mcp-go

by cbinckly
README.md
# Paperless MCP

An MCP (Model Context Protocol) Server for [Paperless-ngx](https://docs.paperless-ngx.com/), enabling AI assistants and other MCP clients to interact with your Paperless document management system.

## Quickstart

Get up and running quickly...

You'll need a paperless instance and an API token (check your profile in the 
paperless UI).

### Run Your Own Instance

You're already running your own Paperless Server, this will be much easier...

Create an environment file:

```env
PAPERLESS_URL=https://paperless.example.com
PAPERLESS_TOKEN=your_paperless_api_token_here
MCP_TRANSPORT=http
MCP_HTTP_PORT=8080
```

Run with docker:

```bash
$ docker run --rm --env-file .env -p 8080:8080  cbinckly/paperless-mcp-go:latest
```

And you're up and running on `http://localhost:8080/mcp`.

### Run with Claude or any MCP Client

Docker is still easiest, if you've got it, update your MCP config:

```json
{
  "mcpServers": {
    "paperless-mcp": {
      "command": "docker",
      "args": [
        "run",
        "-i",
        "--rm",
        "--pull=always",
        "cbinckly/paperless-mcp-go:latest"
      ],
      "env": {
        "PAPERLESS_URL": "https://paperless.example.com",
        "PAPERLESS_TOKEN": "your_paperless_api_token_here",
        "MCP_TRANSPORT": "stdio"
      }
    }
  }
}
```

## Authentication

In most cases, you should run the MCP server using stdio or a local/non-public
HTTP server.  But if you need an extra layer of security, you can set a token
that clients must present to the server.

If you set `MCP_AUTH_TOKEN` in the environment and are using HTTP transport,
the client will have to present it as a bearer token in an authentication
header (`Authentication: Bearer {MCP_AUTH_TOKEN}`) or requests will be rejected.

## Features

- **Complete Document Management**: Search, retrieve, create, update, and delete documents
- **Bulk Operations**: Efficiently edit multiple documents at once
- **Metadata Management**: Full CRUD operations for correspondents, document types, tags, storage paths, and custom fields
- **Dual Transport Modes**: Support for both stdio and HTTP Streaming transports
- **Docker Support**: Multi-stage Docker builds with security best practices
- **Comprehensive Logging**: Structured logging with configurable levels
- **Type-Safe**: Built with Go 1.23 for reliability and performance

### Available MCP Tools

#### Document Tools
- `search_documents` - Search for documents by text query with pagination
- `find_similar_documents` - Find documents similar to a given document
- `get_document` - Retrieve a document by ID with all metadata
- `get_document_content` - Get the text content of a document
- `create_document` - Create a new document
- `update_document` - Update document metadata
- `delete_document` - Delete a document
- `bulk_edit_documents` - Perform bulk operations on multiple documents

#### Correspondent Tools
- `list_correspondents` - List all correspondents with pagination
- `get_correspondent` - Get correspondent details by ID
- `create_correspondent` - Create a new correspondent
- `update_correspondent` - Update correspondent information
- `delete_correspondent` - Delete a correspondent

#### Document Type Tools
- `list_document_types` - List all document types with pagination
- `get_document_type` - Get document type details by ID
- `create_document_type` - Create a new document type
- `update_document_type` - Update document type information
- `delete_document_type` - Delete a document type

#### Tag Tools
- `list_tags` - List all tags with pagination
- `get_tag` - Get tag details by ID
- `create_tag` - Create a new tag
- `update_tag` - Update tag information
- `delete_tag` - Delete a tag

#### Storage Path Tools
- `list_storage_paths` - List all storage paths with pagination
- `get_storage_path` - Get storage path details by ID
- `create_storage_path` - Create a new storage path
- `update_storage_path` - Update storage path information
- `delete_storage_path` - Delete a storage path

#### Custom Field Tools
- `list_custom_fields` - List all custom fields with pagination
- `get_custom_field` - Get custom field details by ID
- `create_custom_field` - Create a new custom field
- `update_custom_field` - Update custom field information
- `delete_custom_field` - Delete a custom field

#### Utility Tools
- `ping` - Test tool that returns pong
- `server_info` - Get MCP server and Paperless connection information

## Prerequisites

- Go 1.23 or later (for building from source)
- A running [Paperless-ngx](https://docs.paperless-ngx.com/) instance
- [Paperless-ngx API token](https://docs.paperless-ngx.com/api/)
  - You can create (or re-create) an API token by opening the "My Profile" link 
    in the user dropdown found in the web UI and clicking the circular arrow button.
- Docker and Docker Compose (optional, for containerized deployment)

## Installation

### From Source

```bash
git clone https://github.com/cbinckly/paperless-mcp-go.git
cd paperless-mcp-go
go mod download
```

### Using Docker

```bash
git clone https://github.com/cbinckly/paperless-mcp-go.git
cd paperless-mcp-go
docker-compose up -d
```

## Configuration

The server is configured using environment variables. Create a `.env` file based on `.env.example`:

| Variable | Required | Default | Description |
|----------|----------|---------|-------------|
| `PAPERLESS_URL` | **Yes** | - | URL of your Paperless-ngx instance |
| `PAPERLESS_TOKEN` | **Yes** | - | API token for Paperless-ngx authentication |
| `MCP_AUTH_TOKEN` | No | - | Optional authentication token for MCP clients |
| `LOG_LEVEL` | No | `info` | Logging level: `debug`, `info`, `warn`, `error` |
| `MCP_TRANSPORT` | No | `stdio` | Transport mode: `stdio` or `http` |
| `MCP_HTTP_PORT` | No | `8080` | HTTP port (only used when `MCP_TRANSPORT=http`) |

### Example `.env` File

```env
PAPERLESS_URL=https://paperless.example.com
PAPERLESS_TOKEN=your_paperless_api_token_here
MCP_AUTH_TOKEN=optional_mcp_auth_token
LOG_LEVEL=info
MCP_TRANSPORT=http
MCP_HTTP_PORT=8080
```

## Building

### Build from Source

```bash
go build -o paperless-mcp ./cmd/server
```

### Build Docker Image

```bash
docker build -t paperless-mcp-go .
```

## Running

### Stdio Transport (Default)

Stdio transport is typically used when the MCP server is launched by an MCP client:

```bash
# Set environment variables
export PAPERLESS_URL=https://paperless.example.com
export PAPERLESS_TOKEN=your_token_here

# Run the server
./paperless-mcp
```

### HTTP Transport

HTTP transport runs the server as a standalone service using the modern StreamableHTTP protocol:

```bash
# Set environment variables
export PAPERLESS_URL=https://paperless.example.com
export PAPERLESS_TOKEN=your_token_here
export MCP_TRANSPORT=http
export MCP_HTTP_PORT=8080

# Run the server
./paperless-mcp
```

The server will be available at `http://localhost:8080`.

### Using Docker

```bash
docker run --env-file .env -p 8080:8080 paperless-mcp-go
```

### Using Docker Compose

```bash
docker-compose up -d
```

Check logs:
```bash
docker-compose logs -f
```

Stop the server:
```bash
docker-compose down
```

## Usage Examples

### Example 1: Search for Documents

Using the `search_documents` tool to find documents containing "invoice":

```json
{
  "tool": "search_documents",
  "arguments": {
    "query": "invoice",
    "page": 1,
    "page_size": 10
  }
}
```

### Example 2: Create a Tag

Using the `create_tag` tool to create a new tag:

```json
{
  "tool": "create_tag",
  "arguments": {
    "name": "Urgent",
    "color": "#ff0000"
  }
}
```

### Example 3: Bulk Edit Documents

Using the `bulk_edit_documents` tool to add tags to multiple documents:

```json
{
  "tool": "bulk_edit_documents",
  "arguments": {
    "document_ids": [1, 2, 3],
    "add_tags": [5, 6],
    "set_correspondent": 2
  }
}
```

## Deployment

### Production Considerations

1. **Security**:
   - Use HTTPS for Paperless-ngx connections
   - Protect API tokens (use environment variables, not hardcoded values)
   - Run as non-root user (Docker images already configured)
   - Use `MCP_AUTH_TOKEN` when exposing HTTP transport

2. **Performance**:
   - Configure appropriate resource limits in docker-compose.yml
   - Monitor memory usage for large document operations
   - Use pagination for list operations

3. **Reliability**:
   - Enable Docker restart policies (`restart: unless-stopped`)
   - Monitor health check endpoints
   - Set up logging aggregation

### Docker Deployment

The provided Dockerfile uses multi-stage builds for:
- Small image size (< 20MB runtime)
- Static binary with no runtime dependencies
- Non-root user (UID 1000)
- Health checks configured

Resource limits in docker-compose.yml:
- CPU: 1 core maximum, 0.25 core reserved
- Memory: 256MB maximum, 128MB reserved

Adjust these based on your workload.

### Monitoring and Logging

- **Structured Logging**: All logs use structured format (slog)
- **Log Levels**: Configure via `LOG_LEVEL` environment variable
- **Health Checks**: Available at `/health` endpoint (HTTP mode only)
- **Metrics**: Check Docker container stats: `docker stats paperless-mcp-server`

## Development

### Project Structure

```
paperless-mcp-go/
├── cmd/
│   └── server/          # Main application entry point
├── internal/
│   ├── config/          # Configuration management
│   ├── mcp/             # MCP server implementation
│   │   ├── server.go    # Server setup and registration
│   │   ├── tools.go     # Tool registration
│   │   ├── *_handlers.go # Tool handler implementations
│   │   └── transport.go # Transport layer
│   └── paperless/       # Paperless API client
│       ├── client.go    # HTTP client and API methods
│       ├── types.go     # Data type definitions
│       └── errors.go    # Error handling
├── Dockerfile
├── docker-compose.yml
└── README.md
```

### Adding New Tools

1. **Add API Client Method** (`internal/paperless/client.go`):
   ```go
   func (c *Client) YourMethod(ctx context.Context, ...) (*Type, error) {
       // Implementation
   }
   ```

2. **Create Handler** (appropriate `*_handlers.go` file):
   ```go
   func (s *Server) handleYourTool(ctx context.Context, args map[string]interface{}) (interface{}, error) {
       // Implementation
   }
   ```

3. **Register Tool** (`internal/mcp/tools.go`):
   ```go
   err = s.RegisterTool(Tool{
       Name:        "your_tool",
       Description: "Description of your tool",
       InputSchema: map[string]interface{}{...},
       Handler:     s.handleYourTool,
   })
   ```

### Code Style Guidelines

- **Constants**: Use descriptive constant names for all magic values
- **Logging**: Use structured logging with slog (Debug/Info/Error levels)
- **Error Handling**: Wrap errors with `fmt.Errorf("message: %w", err)`
- **Validation**: Validate all inputs in handlers before calling API methods
- **Pagination**: Support pagination for all list operations

## Troubleshooting

### Common Issues

**Issue**: `Failed to load configuration: environment variable PAPERLESS_URL is required`
- **Solution**: Ensure all required environment variables are set. Check your `.env` file.

**Issue**: `Request failed: 401 Unauthorized`
- **Solution**: Verify your `PAPERLESS_TOKEN` is correct and has appropriate permissions.

**Issue**: `Connection refused` when using HTTP transport
- **Solution**: Ensure `MCP_HTTP_PORT` is not already in use and firewall allows connections.

### Debug Logging

Enable debug logging for detailed information:

```bash
export LOG_LEVEL=debug
./paperless-mcp
```

Debug logs include:
- API request/response details
- Tool invocation parameters
- Detailed error information

### Health Check

For HTTP transport mode, check server health:

```bash
curl http://localhost:8080/health
```

Should return health status and server information.

## License

See [LICENSE](LICENSE) file for details.

## Links

- [Paperless-ngx Documentation](https://docs.paperless-ngx.com/)
- [Model Context Protocol](https://modelcontextprotocol.io/)
- [MCP Go SDK](https://github.com/mark3labs/mcp-go)

---

**Note**: This is an unofficial community project and is not affiliated with or endorsed by the Paperless-ngx project.

Maintenance

ActivityInactive
ResponsivenessNo issues