HTTP API documentation for md-server.
http://localhost:8080
Configure with --host and --port options or environment variables MD_SERVER_HOST and MD_SERVER_PORT. Use HTTPS in production (consider Caddy for easy HTTPS setup) and set MD_SERVER_API_KEY for authentication.
See Configuration for all environment variables.
Single endpoint that handles all conversion types. Input type is detected automatically.
Detection order:
- Content-Type header
- Request body structure (JSON fields)
- Magic bytes (binary data)
curl -X POST http://localhost:8080/convert --data-binary @document.pdfcurl -X POST http://localhost:8080/convert -F "file=@document.docx"curl -X POST http://localhost:8080/convert \
-H "Content-Type: application/json" \
-d '{"url": "https://example.com/document.pdf"}'curl -X POST http://localhost:8080/convert \
-H "Content-Type: application/json" \
-d '{"content": "base64_string", "filename": "doc.xlsx"}'curl -X POST http://localhost:8080/convert \
-H "Content-Type: application/json" \
-d '{"text": "# Markdown content"}'# HTML text conversion
curl -X POST http://localhost:8080/convert \
-H "Content-Type: application/json" \
-d '{"text": "<h1>Title</h1><p>Content</p>", "mime_type": "text/html"}'
# XML text conversion
curl -X POST http://localhost:8080/convert \
-H "Content-Type: application/json" \
-d '{"text": "<?xml version=\"1.0\"?><root><item>Data</item></root>", "mime_type": "text/xml"}'{
"url": "string",
"content": "string",
"text": "string",
"mime_type": "string",
"filename": "string",
"source_format": "string",
"options": {
"js_rendering": false,
"timeout": 30,
"extract_images": false,
"preserve_formatting": true,
"ocr_enabled": false,
"max_length": null,
"max_tokens": null,
"truncate_mode": null,
"truncate_limit": null,
"clean_markdown": false,
"include_frontmatter": false,
"output_format": null
}
}{
"success": true,
"markdown": "# Content",
"metadata": {
"source_type": "pdf",
"source_size": 102400,
"markdown_size": 8192,
"conversion_time_ms": 456,
"detected_format": "application/pdf",
"warnings": [],
"title": "Document Title",
"estimated_tokens": 2048,
"detected_language": "en"
},
"request_id": "req_550e8400-e29b-41d4-a716-446655440000"
}| Field | Type | Description |
|---|---|---|
source_type |
string | Type of source content (pdf, html, etc.) |
source_size |
int | Size of source content in bytes |
markdown_size |
int | Size of converted markdown in bytes |
conversion_time_ms |
int | Time taken for conversion in milliseconds |
detected_format |
string | Detected format/MIME type |
warnings |
array | Conversion warnings |
title |
string | Extracted document title (if available) |
estimated_tokens |
int | Estimated token count for LLM usage |
detected_language |
string | ISO 639-1 language code (e.g., "en", "es") |
was_truncated |
bool | True if content was truncated |
original_length |
int | Original character count before truncation |
original_tokens |
int | Original token count before truncation |
truncation_mode |
string | How content was truncated (chars, tokens, sections, paragraphs) |
{
"success": false,
"error": {
"code": "UNSUPPORTED_FORMAT",
"message": "File format not supported",
"details": {},
"suggestions": []
},
"request_id": "req_550e8400-e29b-41d4-a716-446655440000"
}Returns supported formats and capabilities.
curl http://localhost:8080/formatsResponse Example
{
"formats": {
"pdf": {
"mime_types": ["application/pdf"],
"extensions": [".pdf"],
"features": ["ocr", "extract_images", "preserve_formatting"],
"max_size_mb": 50
},
"docx": {
"mime_types": [
"application/vnd.openxmlformats-officedocument.wordprocessingml.document"
],
"extensions": [".docx"],
"features": ["extract_images", "preserve_formatting"],
"max_size_mb": 25
}
},
"supported_formats": ["pdf", "docx", "..."],
"capabilities": {
"browser_available": true
}
}curl http://localhost:8080/health{
"status": "healthy",
"version": "1.0.0",
"uptime_seconds": 3600,
"conversions_last_hour": 42
}md-server supports two response formats: JSON (default) and raw markdown.
Standard JSON response with metadata:
curl -X POST localhost:8080/convert --data-binary @document.pdfGet raw markdown with metadata in HTTP headers. Use either:
Accept header:
curl -X POST localhost:8080/convert \
-H "Accept: text/markdown" \
--data-binary @document.pdfoutput_format option:
curl -X POST localhost:8080/convert \
-H "Content-Type: application/json" \
-d '{"url": "https://example.com", "options": {"output_format": "markdown"}}'When using raw markdown output, metadata is returned in HTTP headers:
| Header | Description |
|---|---|
X-Request-Id |
Unique request identifier |
X-Source-Type |
Source content type |
X-Source-Size |
Source size in bytes |
X-Markdown-Size |
Output size in bytes |
X-Conversion-Time-Ms |
Conversion time in milliseconds |
X-Detected-Format |
Detected MIME type |
X-Estimated-Tokens |
Token count estimate (if available) |
Raw markdown mode is useful for CLI pipelines:
# Save directly to file
curl -s -X POST localhost:8080/convert \
-H "Accept: text/markdown" \
--data-binary @document.pdf > output.md
# Pipe to other tools
curl -s -X POST localhost:8080/convert \
-H "Accept: text/markdown" \
-d '{"url": "https://example.com"}' | grep "keyword"| Option | Type | Default | Description |
|---|---|---|---|
js_rendering |
bool | false | Use headless browser for JavaScript sites |
timeout |
int | 30 | Timeout seconds (max: 120) |
extract_images |
bool | false | Extract embedded images |
preserve_formatting |
bool | true | Keep complex formatting |
ocr_enabled |
bool | false | OCR for images/scanned PDFs |
max_length |
int | null | Truncate output to character limit |
max_tokens |
int | null | Truncate output to token limit (uses tiktoken cl100k_base) |
truncate_mode |
string | null | Truncation mode: chars, tokens, sections, paragraphs |
truncate_limit |
int | null | Limit for truncation mode |
clean_markdown |
bool | false | Normalize markdown |
include_frontmatter |
bool | false | Prepend YAML frontmatter with metadata |
output_format |
string | null | Response format: "json" or "markdown" |
For controlling output size, md-server offers flexible truncation:
Character/Token limits:
max_length- Simple character truncationmax_tokens- Token-based truncation using tiktoken cl100k_base (useful for LLM context limits)
Markdown-aware truncation:
truncate_mode: "sections"withtruncate_limit: 5- Returns first 5##sectionstruncate_mode: "paragraphs"withtruncate_limit: 10- Returns first 10 paragraphs
When content is truncated, the response metadata includes was_truncated, original_length, original_tokens, and truncation_mode.
When enabled, prepends YAML frontmatter to the markdown output:
curl -X POST localhost:8080/convert \
-H "Content-Type: application/json" \
-d '{"url": "https://example.com", "options": {"include_frontmatter": true}}'Output:
---
title: "Example Page"
source_type: html
estimated_tokens: 1024
detected_language: en
---
# Example Page
Content here...| Code | Status | Description |
|---|---|---|
UNSUPPORTED_FORMAT |
400 | Format not supported |
FILE_TOO_LARGE |
413 | Exceeds size limit |
INVALID_URL |
400 | URL malformed/blocked |
INVALID_INPUT |
400 | Invalid MIME type/input |
FETCH_FAILED |
502 | URL fetch failed |
CONVERSION_FAILED |
500 | Conversion error |
RATE_LIMITED |
429 | Too many requests |
INVALID_CONTENT |
400 | Validation failed |
TIMEOUT |
504 | Operation timeout |
SSRF_BLOCKED |
400 | URL targets blocked resource |
UNAUTHORIZED |
401 | Missing or invalid API key |
Set MD_SERVER_API_KEY to require authentication:
export MD_SERVER_API_KEY="your-secret-api-key"
uvx md-serverRequests must include the Authorization header:
curl -X POST localhost:8080/convert \
-H "Authorization: Bearer your-secret-api-key" \
--data-binary @document.pdfBy default, md-server blocks:
- Private IPs (10.x, 192.168.x, 172.16.x)
- Localhost (127.x, ::1)
- Cloud metadata (169.254.169.254)
See Configuration for SSRF settings.
- Magic bytes verification
- Size limits per format
- Path traversal prevention
cURL Examples
# PDF conversion
curl -X POST localhost:8080/convert --data-binary @document.pdf
# URL conversion
curl -X POST localhost:8080/convert \
-H "Content-Type: application/json" \
-d '{"url":"https://example.com"}'
# With JavaScript rendering
curl -X POST localhost:8080/convert \
-H "Content-Type: application/json" \
-d '{"url":"https://example.com","options":{"js_rendering":true}}'
# With OCR
curl -X POST localhost:8080/convert \
-H "Content-Type: application/json" \
-d '{"content":"base64...","filename":"scan.pdf","options":{"ocr_enabled":true}}'
# Raw markdown output
curl -X POST localhost:8080/convert \
-H "Accept: text/markdown" \
--data-binary @document.pdf
# With frontmatter
curl -X POST localhost:8080/convert \
-H "Content-Type: application/json" \
-d '{"url":"https://example.com","options":{"include_frontmatter":true}}'
# With token limit (useful for LLM context)
curl -X POST localhost:8080/convert \
-H "Content-Type: application/json" \
-d '{"url":"https://example.com","options":{"max_tokens":4000}}'
# Get first 5 sections only
curl -X POST localhost:8080/convert \
-H "Content-Type: application/json" \
-d '{"url":"https://example.com","options":{"truncate_mode":"sections","truncate_limit":5}}'
# Pipe from stdin
echo "<h1>Hello</h1>" | curl -X POST localhost:8080/convert \
--data-binary @- -H "Content-Type: text/html"
# Save output
curl -X POST localhost:8080/convert --data-binary @doc.pdf \
| jq -r '.markdown' > output.md- Python SDK - Library usage for Python applications
- MCP Guide - AI tool integration
- Configuration - Environment variables
- Troubleshooting - Common issues