reference
API Docs
REST API, CLI, and MCP server. Or use the web interface.
Base URL
base
https://mdingest.knightker.workers.dev
Endpoints
All endpoints share the same query parameters:
| Param | Required | Type | Description |
|---|---|---|---|
url | yes | string | Article URL to ingest |
format | no | markdown | json | Response format (default: markdown) |
GET
Medium via Freedium mirror/v1/mediumcurl
$ curl "https://mdingest.knightker.workers.dev/v1/medium?url=https://medium.com/@user/article"
GET
Dev.to via Forem API/v1/devtocurl
$ curl "https://mdingest.knightker.workers.dev/v1/devto?url=https://dev.to/user/post"
GET
Substack via Public API/v1/substackcurl
$ curl "https://mdingest.knightker.workers.dev/v1/substack?url=https://example.substack.com/p/post"
Response
When format=markdown (default), returns text/markdown with YAML frontmatter:
markdown
--- title: Article Title author: Jane Doe published: 2024-03-15 reading_time: 8 min tags: [api, backend] cover_image: https://... --- # Article Title Article body in clean Markdown...
When format=json, returns application/json with { metadata, markdown }.
Frontmatter fields
| Field | Type | Description |
|---|---|---|
title | string | Article title |
author | string | Author name |
published | date | Publication date (ISO) |
updated | date | Last updated date (ISO) |
reading_time | string | Estimated reading time |
tags | string[] | Article tags (Medium only) |
cover_image | string | Cover image URL |
CLI
Same ingestion logic, from the terminal. Auto-detects provider from URL.
cli
$ bun run src/cli.ts https://dev.to/user/post > article.md # JSON output (metadata + markdown) $ bun run src/cli.ts https://dev.to/user/post --json # Override provider auto-detection $ bun run src/cli.ts https://example.com/post --provider medium # List supported providers $ bun run src/cli.ts providers
MCP server
For AI tools (Claude, Cursor). Two ways to connect: remote (zero setup) or local (stdio).
Remote (HTTP)
Register the deployed endpoint directly. No local install needed:
mcp config: remote
{
"mcpServers": {
"mdingest": {
"url": "https://mdingest.knightker.workers.dev/v1/mcp"
}
}
}Local (stdio)
Run the CLI as a local process:
mcp config: local
{
"mcpServers": {
"mdingest": {
"command": "bun",
"args": ["run", "src/cli.ts", "mcp"]
}
}
}Both expose the same two tools:
| Tool | Description |
|---|---|
ingest_article | Ingest a URL into clean Markdown. Auto-detects provider. Returns markdown text by default; json: true for { metadata, markdown }. |
list_providers | List supported providers with source, example URL, and accepted domains. |
Errors
All errors return { code, message, details?, traceId }:
| Code | HTTP | When |
|---|---|---|
VALIDATION.FAILED | 422 | Bad query params (Zod pipe) |
MEDIUM.INVALID_URL | 400 | URL is not a Medium article |
MEDIUM.FREEDIUM_UNAVAILABLE | 503 | Freedium mirror down or timed out |
MEDIUM.PARSE_FAILED | 502 | Article data parsing failed |
DEVTO.INVALID_URL | 400 | URL is not a Dev.to article |
DEVTO.UNAVAILABLE | 503 | Dev.to API down or timed out |
DEVTO.PARSE_FAILED | 502 | Article data parsing failed |
SUBSTACK.INVALID_URL | 400 | URL is not a Substack article |
SUBSTACK.PAID_POST | 403 | Post is not available for conversion |
SUBSTACK.UNAVAILABLE | 503 | Substack API down or timed out |
SUBSTACK.PARSE_FAILED | 502 | Article data parsing failed |
INTERNAL.ERROR | 500 | Unexpected error |
NOT_FOUND | 404 | Unknown route |
RATE_LIMITED | 429 | Too many requests (30/min per IP) |
Provider notes
- Medium: Freedium mirror (dual-source: download for markdown, data endpoint for metadata). Full article access.
- Dev.to: Public Forem API. No restrictions. Returns native Markdown.
- Substack: Public Substack API. Posts not available for conversion return
SUBSTACK.PAID_POST(403).