Skip to content

API Server

Kreuzberg runs as an HTTP REST API server (kreuzberg serve) or as an MCP server (kreuzberg mcp) for AI agent integration.

Bash
# Default: http://127.0.0.1:8000
kreuzberg serve
# Custom host and port
kreuzberg serve -H 0.0.0.0 -p 3000
# With configuration file
kreuzberg serve --config kreuzberg.toml

Extract text from uploaded files via multipart form data.

Field Required Description
files Yes (repeatable) Files to extract
config No JSON config overrides
output_format No plain (default), markdown, djot, or html
Terminal
# Single file
curl -F "files=@document.pdf" http://localhost:8000/extract
# Multiple files
curl -F "files=@doc1.pdf" -F "files=@doc2.docx" http://localhost:8000/extract
# With config overrides
curl -F "files=@scanned.pdf" \
-F 'config={"ocr":{"language":"eng"},"force_ocr":true}' \
http://localhost:8000/extract
Response
[
{
"content": "Extracted text...",
"mime_type": "application/pdf",
"metadata": { "page_count": 10, "author": "John Doe" },
"tables": [],
"detected_languages": ["eng"],
"chunks": null,
"images": null
}
]

Generate vector embeddings. Requires the embeddings feature.

Field Required Description
texts Yes Array of strings
config No Embedding config overrides
Terminal
curl -X POST http://localhost:8000/embed \
-H "Content-Type: application/json" \
-d '{"texts":["Hello world","Second text"]}'
Preset Dimensions Model
fast 384 AllMiniLML6V2Q
balanced (default) 768 BGEBaseENV15
quality 1024 BGELargeENV15
multilingual 768 MultilingualE5Base

Chunk text for RAG pipelines.

Field Required Description
text Yes Text to chunk
chunker_type No "text" (default), "markdown", "yaml", or "semantic"
config.max_characters No Max chars per chunk (default: 2000)
config.overlap No Overlap between chunks (default: 100)
Terminal
curl -X POST http://localhost:8000/chunk \
-H "Content-Type: application/json" \
-d '{"text":"Long text...","chunker_type":"text","config":{"max_characters":1000,"overlap":50}}'
Python
import httpx
# Basic chunking with defaults
with httpx.Client() as client:
response = client.post(
"http://localhost:8000/chunk",
json={"text": "Your long text content here..."}
)
result = response.json()
for chunk in result["chunks"]:
print(f"Chunk {chunk['chunk_index']}: {chunk['content'][:50]}...")
# Chunking with custom configuration
with httpx.Client() as client:
response = client.post(
"http://localhost:8000/chunk",
json={
"text": "Your long text content here...",
"chunker_type": "text",
"config": {
"max_characters": 1000,
"overlap": 50,
"trim": True
}
}
)
result = response.json()
print(f"Created {result['chunk_count']} chunks")

Extract typed JSON from a document by running an LLM against the extracted text with a JSON schema. Requires the server to be built with the liter-llm feature; otherwise the endpoint returns 501 Not Implemented.

The request is multipart/form-data.

Field Required Description
file (or files) Yes The document to extract from
schema Yes JSON Schema string describing the structured output
model Yes LLM model identifier, for example openai/gpt-4o or anthropic/claude-sonnet-4-20250514
api_key No LLM provider API key. Falls back to provider env vars (OPENAI_API_KEY, ANTHROPIC_API_KEY, …)
prompt No Custom Jinja2 prompt template overriding the default
schema_name No Schema identifier (default: extraction)
strict No "true" / "false" — enable OpenAI strict mode for exact schema matching
config No Extraction config overrides as a JSON string
Terminal
curl -X POST http://localhost:8000/extract-structured \
-F "file=@invoice.pdf" \
-F 'schema={"type":"object","properties":{"invoice_number":{"type":"string"},"total":{"type":"number"}},"required":["invoice_number","total"]}' \
-F "model=openai/gpt-4o" \
-F "api_key=$OPENAI_API_KEY" \
-F "strict=true"
Response
{
"structured_output": {
"invoice_number": "INV-2026-0142",
"total": 1284.50
},
"content": "Invoice INV-2026-0142...",
"mime_type": "application/pdf"
}

Errors follow the same shape as /extract. A 501 body indicates the server was built without the liter-llm feature; rebuild with --features liter-llm to enable structured extraction.

Endpoint Method Description
/health GET {"status":"healthy","version":"4.6.3"}
/version GET {"version":"4.6.3"} v4.5.2
/detect POST MIME type detection (multipart) v4.5.2
/cache/stats GET Cache statistics
/cache/warm POST Pre-download models v4.5.2
/cache/manifest GET Model manifest with checksums v4.5.2
/cache/clear DELETE Clear all cached files
/info GET {"version":"...","rust_backend":true}
/openapi.json GET OpenAPI 3.0 schema
Python
import httpx
with httpx.Client() as client:
with open("document.pdf", "rb") as f:
files: dict[str, object] = {"files": f}
response: httpx.Response = client.post(
"http://localhost:8000/extract", files=files
)
results: list[dict] = response.json()
print(results[0]["content"])
Error response
{
"error_type": "ValidationError",
"message": "Invalid file format",
"status_code": 400
}
Status Error type Meaning
400 ValidationError Invalid input
422 ParsingError, OcrError Processing failed
500 Internal errors Server errors
Python
import httpx
try:
with httpx.Client() as client:
with open("document.pdf", "rb") as f:
files: dict = {"files": f}
response: httpx.Response = client.post(
"http://localhost:8000/extract", files=files
)
response.raise_for_status()
results: list = response.json()
print(f"Extracted {len(results)} documents")
except httpx.HTTPStatusError as e:
error: dict = e.response.json()
error_type: str = error.get("error_type", "Unknown")
message: str = error.get("message", "No message")
print(f"Error: {error_type}: {message}")

The server discovers kreuzberg.toml in the current and parent directories. Pass --config path/to/file to use a different file.

Variable Default Description
KREUZBERG_MAX_UPLOAD_SIZE_MB 100 Max upload size in MB
KREUZBERG_CORS_ORIGINS * Comma-separated allowed origins

See Configuration Guide for all options.


Terminal
kreuzberg mcp
kreuzberg mcp --config kreuzberg.toml
Python
import subprocess
import time
from typing import Optional
mcp_process: subprocess.Popen = subprocess.Popen(
["python", "-m", "kreuzberg", "mcp"],
stdout=subprocess.PIPE,
stderr=subprocess.PIPE,
)
pid: Optional[int] = mcp_process.pid
print(f"MCP server started with PID: {pid}")
time.sleep(1)
print("Server is running, listening for connections")
Tool Key parameters Description
extract_file path Extract from file path
extract_bytes data (base64) Extract from encoded bytes
batch_extract_files paths Extract multiple files
detect_mime_type path Detect file format
list_formats List supported formats v4.5.2
get_version Library version v4.5.2
cache_stats Cache usage
cache_clear Remove cached files
cache_manifest Model checksums v4.5.2
cache_warm Pre-download models v4.5.2
embed_text texts Generate embeddings v4.5.2
chunk_text text Split text v4.5.2
extract_structured path, schema, model; optional schema_name (default "extraction"), schema_description, prompt, api_key, strict (default false) Extract structured JSON via LLM v4.8.0

All tools accept an optional config object. extract_file and extract_bytes also accept pdf_password. extract_structured requires the server to be built with the liter-llm feature; see the row above for optional fields and defaults.

Add to ~/Library/Application Support/Claude/claude_desktop_config.json:

{
"mcpServers": {
"kreuzberg": {
"command": "kreuzberg",
"args": ["mcp"]
}
}
}

For Docker and Kubernetes deployment, see Docker Guide and Kubernetes Guide.