Python middleware that implements Markdown for Agents — when an AI agent requests Accept: text/markdown, the middleware converts HTML responses to Markdown on the fly, reducing token consumption by ~80%.
Supports Flask, Django, and FastAPI from a single package.
Inspired by Cloudflare's Markdown for Agents and caddy-markdown-agents.
Feeding raw HTML to an AI agent is wasteful. A simple ## About Us heading costs ~3 tokens in Markdown versus 12-15 tokens wrapped in HTML <div> tags, navigation bars, and scripts. For a typical web page, Markdown delivers the same content at ~80% fewer tokens.
AI agents like Claude Code, OpenCode, and Gemini CLI already send Accept: text/markdown headers when fetching web pages. This middleware lets your Python web app respond in kind — minimal code changes required.
Request → Accept: text/markdown?
├─ No → Pass through unchanged
└─ Yes → Get response → Is it text/html? → Convert to Markdown → Respond
The middleware:
- Checks the
Acceptheader fortext/markdown - Only converts responses with
Content-Type: text/html - Strips non-content elements:
<script>,<style>,<nav>,<footer>,<iframe>,<noscript> - Returns Markdown with proper response headers
Regular browser requests are completely unaffected.
Error handling: If the HTML-to-Markdown conversion fails, the middleware falls back to serving the original HTML response and logs a warning. Your site never breaks because of a conversion issue.
# Pick your framework
pip install markdown-agents[flask]
pip install markdown-agents[django]
pip install markdown-agents[fastapi]
# Or install all frameworks
pip install markdown-agents[flask,django,fastapi]from flask import Flask
from markdown_agents.flask import MarkdownAgents
app = Flask(__name__)
app.wsgi_app = MarkdownAgents(app.wsgi_app)# settings.py
MIDDLEWARE = [
"markdown_agents.django.MarkdownAgentsMiddleware",
# ... other middleware
]from fastapi import FastAPI
from markdown_agents.fastapi import MarkdownAgentsMiddleware
app = FastAPI()
app.add_middleware(MarkdownAgentsMiddleware)| Header | Value | Purpose |
|---|---|---|
Content-Type |
text/markdown; charset=utf-8 |
Declares response format |
Vary |
Accept |
Prevents cache poisoning — tells caches the same URL has multiple representations |
X-Markdown-Tokens |
<integer> |
Estimated token count (content_length / 4) for agent context window management |
pip install markdown-agents[flask]# demo.py
from flask import Flask
from markdown_agents.flask import MarkdownAgents
app = Flask(__name__)
app.wsgi_app = MarkdownAgents(app.wsgi_app)
@app.route("/")
def index():
return "<html><body><h1>Hello</h1><p>This is a <strong>test</strong>.</p></body></html>"
if __name__ == "__main__":
app.run(port=8780)# Regular request — returns HTML
curl http://localhost:8780/
# Agent request — returns Markdown
curl -H "Accept: text/markdown" http://localhost:8780/The examples/ directory contains runnable demo servers for each framework:
| File | Framework | Port | Run command |
|---|---|---|---|
flask_server.py |
Flask | 8780 | python examples/flask_server.py |
django_server.py |
Django | 8781 | python examples/django_server.py |
fastapi_server.py |
FastAPI | 8782 | python examples/fastapi_server.py |
Each server exposes three endpoints: / (HTML page), /about (HTML page), and /api/data (JSON — passes through unchanged).
# Start any server, then test:
curl http://localhost:8780/ # Returns HTML
curl -H "Accept: text/markdown" http://localhost:8780/ # Returns Markdown# Install with dev dependencies
pip install -e ".[dev]"
# Run tests
pytest
# Lint
ruff check .
# Format
ruff format .- Python 3.10+
- One of: Flask >= 2.0, Django >= 4.0, FastAPI >= 0.100