Skip to main content
Glama
README.md
# MCP Mistral OCR
[![smithery badge](https://smithery.ai/badge/@everaldo/mcp-mistral-ocr)](https://smithery.ai/server/@everaldo/mcp-mistral-ocr)

An MCP server that provides OCR capabilities using Mistral AI's OCR API. Supports **stdio** (for Claude Desktop / Smithery) and **streamable HTTP** (for remote clients). Runs **with or without Docker**.

## Features

- **Dual transport**: streamable HTTP (default) or stdio for Claude Desktop / Smithery
- Process local files (images and PDFs) and files from URLs
- **Primary flow:** Call `process_url_file` with a URL to get OCR output (markdown or full JSON)
- No Docker required: run locally with `uv run` and optional `OCR_DIR`
- Results saved as timestamped `.json` (full Mistral response) and `.md` (extracted markdown) in `OCR_DIR/output/` (optional; set `OCR_SAVE_RESULTS=false` to disable). When saving is on, the tool returns **only** the download links (over HTTP) or file paths (over stdio): no full content in the response. Over streamable HTTP, use the returned URLs to download the JSON and Markdown files (e.g. `http://127.0.0.1:8000/output/<filename>.json`).
- Docker optional for deployment

## Usage

The main use case is **URL in, OCR out**. Call the `process_url_file` tool with a document or image URL. You can omit `file_type` if the URL has a `.pdf` or image extension (e.g. `.jpg`, `.png`). Use `output_format="markdown"` to get only the extracted text, or `output_format="full"` (default) for the full Mistral response JSON.

**Download URLs:** To get clickable "Download JSON" and "Download Markdown" URLs in the tool response, set `OCR_DOWNLOAD_BASE_URL` (e.g. in `.env`). Use a **different port** than the MCP server (e.g. 8001) so they don't conflict. **One-command start:** from the project root run `uv run python run_servers.py` to start both the file server (8001) and the MCP server (8000); Ctrl+C stops both.

**Google Drive:** View/share links (e.g. `https://drive.google.com/file/d/FILE_ID/view?usp=sharing`) are supported. The server rewrites them to the direct-download URL so the OCR API receives the file content. For Drive links, `file_type` can be omitted and defaults to `pdf`; for images in Drive, pass `file_type="image"`. URLs are trimmed before detection. **File type inference:** If the URL has no extension and is not a known Drive link, the server sends a HEAD request to the URL and infers type from the `Content-Type` header (e.g. `application/pdf` → pdf); if still unknown, it defaults to `pdf` so the first API call usually succeeds without requiring `file_type`.

## Environment Variables

| Variable | Required | Default | Description |
|----------|----------|---------|-------------|
| `MISTRAL_API_KEY` | Yes | — | Your Mistral AI API key |
| `OCR_DIR` | No | `./ocr_data` | Directory for local files and `output/` subdir |
| `OCR_SAVE_RESULTS` | No | `true` | Set to `false` to disable saving results to `OCR_DIR/output/` |
| `OCR_DOWNLOAD_BASE_URL` | No | — | Base URL for download links. Use a port other than MCP (e.g. `http://127.0.0.1:8001`). Run `python -m http.server 8001 --directory ocr_data` from project root so GET /output/&lt;filename&gt; serves the files. |
| `MCP_TRANSPORT` | No | `streamable-http` | `stdio` or `streamable-http` |
| `MCP_HTTP_HOST` | No | `127.0.0.1` | Bind host when using streamable HTTP |
| `MCP_HTTP_PORT` | No | `8000` | Port when using Streamable HTTP or SSE |
| `MCP_HTTP_PATH` | No | `mcp` | URL path (e.g. `/mcp` → `http://host:8000/mcp`) |

## Running without Docker

**Python:** This project uses **Python 3.10–3.13** (not 3.14+) so dependencies like `pydantic-core` use pre-built wheels. If you only have Python 3.14, install 3.12 (e.g. from [python.org](https://www.python.org/downloads/)) and run:

```bash
uv sync --python 3.12
```

### Stdio (e.g. Claude Desktop, Smithery)

1. Install [uv](https://docs.astral.sh/uv/) and run:

```bash
cd mistral-ocr-mcp
uv sync
```

2. Set `MISTRAL_API_KEY` and optionally `OCR_DIR` (defaults to `./ocr_data`).

3. Run the server (stdio):

```bash
# Windows (PowerShell)
$env:MISTRAL_API_KEY="your_key"
uv run python -m src.main

# Windows (CMD) / Unix
set MISTRAL_API_KEY=your_key          # CMD
export MISTRAL_API_KEY=your_key      # Bash
uv run python -m src.main
```

Or with a custom OCR directory:

```bash
export OCR_DIR=/path/to/your/files   # or set on Windows
uv run python -m src.main
```

### Streamable HTTP (for MCP Inspector, HTTP clients)

Start the server with streamable HTTP:

```bash
export MISTRAL_API_KEY=your_key
export MCP_TRANSPORT=streamable-http
export MCP_HTTP_PORT=8000
uv run python -m src.main
```

Then connect clients to **http://127.0.0.1:8000/mcp** (Streamable HTTP; e.g. [MCP Inspector](https://github.com/modelcontextprotocol/inspector): `npx -y @modelcontextprotocol/inspector`).

Optional: bind all interfaces and custom path:

```bash
export MCP_TRANSPORT=streamable-http
export MCP_HTTP_HOST=0.0.0.0
export MCP_HTTP_PORT=8000
export MCP_HTTP_PATH=/mcp
uv run python -m src.main
```

## Claude Desktop configuration

### Option A: No Docker (stdio)

Point Claude to the project and use stdio:

```json
{
  "mcpServers": {
    "mistral-ocr": {
      "command": "uv",
      "args": ["run", "python", "-m", "src.main"],
      "cwd": "C:\\path\\to\\mistral-ocr-mcp",
      "env": {
        "MISTRAL_API_KEY": "<YOUR_MISTRAL_API_KEY>",
        "MCP_TRANSPORT": "stdio",
        "OCR_DIR": "C:\\path\\to\\your\\files"
      }
    }
  }
}
```

(Adjust `cwd` and `OCR_DIR` for your machine. Omit `OCR_DIR` to use default `./ocr_data`.)

### Option B: Docker (stdio)

```json
{
  "mcpServers": {
    "mistral-ocr": {
      "command": "docker",
      "args": [
        "run",
        "-i",
        "--rm",
        "-e",
        "MISTRAL_API_KEY",
        "-e",
        "OCR_DIR",
        "-v",
        "C:/path/to/your/files:/data/ocr",
        "mcp-mistral-ocr:latest"
      ],
      "env": {
        "MISTRAL_API_KEY": "<YOUR_MISTRAL_API_KEY>",
        "OCR_DIR": "C:/path/to/your/files"
      }
    }
  }
}
```

Build and run:

```bash
docker build -t mcp-mistral-ocr .
docker run -e MISTRAL_API_KEY=your_key -e OCR_DIR=/data/ocr -v C:/path/to/files:/data/ocr mcp-mistral-ocr
```

## Smithery

Install via [Smithery](https://smithery.ai/server/@everaldo/mcp-mistral-ocr) (stdio):

```bash
npx -y @smithery/cli install @everaldo/mcp/mistral-crosswalk --client claude
```

## Available tools

- **process_url_file(url, file_type=None, output_format="full", pages=None, table_format=None, extract_header=False, extract_footer=False)** – Primary tool: process a file from a URL. `file_type` is optional if the URL has a `.pdf` or image extension. `output_format`: `"full"` (default) returns full JSON; `"markdown"` returns only the extracted text. `pages`: optional list of 0-based page indices to process. `table_format`: `"markdown"` or `"html"` for tables. `extract_header` / `extract_footer`: set to `True` to extract header/footer.
- **process_local_file(filename, output_format="full", pages=None, table_format=None, extract_header=False, extract_footer=False)** – Process a file from `OCR_DIR` (e.g. `document.pdf`, `image.png`). Same optional parameters as above.

Limits: 50MB max file size, 1000 pages (Mistral API).

## Output

When `OCR_SAVE_RESULTS` is true (default), results are written to `OCR_DIR/output/` as JSON:

- Local: `{filename_stem}_{YYYYMMDD_HHMMSS}.json`
- URL: `{url_path_stem}_{timestamp}.json` or `url_document_{timestamp}.json`

Set `OCR_SAVE_RESULTS=false` to return OCR only to the client without writing files.

## Supported file types

- Images: JPG, JPEG, PNG, GIF, WebP  
- Documents: PDF and other formats supported by Mistral OCR