mdingest
Ingests Dev.to articles using the Forem API and converts them to clean Markdown with metadata such as title, author, date, reading time, and tags.
Ingests Medium articles via the Freedium mirror and converts them to clean Markdown with metadata such as title, author, date, reading time, and tags.
Ingests free Substack posts, including reader URLs, and converts them to clean Markdown with metadata such as title, author, date, reading time, and tags.
Click on "Install Server".
Wait a few minutes for the server to deploy. Once ready, it will show a "Started" state.
In the chat, type
@followed by the MCP server name and your instructions, e.g., "@mdingestingest this Medium article into clean markdown: https://medium.com/@user/article-id"
That's it! The server will respond to your query, and you can continue using it as needed.
Here is a step-by-step guide with screenshots.
mdingest
API that ingests blog/article/newsletter pages to clean Markdown for LLM consumption. Supports Medium (via Freedium), Dev.to (Forem API), and Substack (free posts via public API + HTML→Markdown). Four entry points: HTTP API, CLI, MCP server (stdio), and MCP server (HTTP) — all sharing the same ingestion logic.
Quick start
bun install
bun run dev # HTTP API + web UI on port 3000Related MCP server: urltomarkdown-mcp
Usage
HTTP API
Deployed at https://mdingest.knightker.workers.dev:
curl "https://mdingest.knightker.workers.dev/v1/medium?url=https://medium.com/@user/article-id"
curl "https://mdingest.knightker.workers.dev/v1/devto?url=https://dev.to/user/article-slug"
curl "https://mdingest.knightker.workers.dev/v1/substack?url=https://pub.substack.com/p/article-slug"Substack reader URLs are also supported (resolved via 302 redirect):
curl "https://mdingest.knightker.workers.dev/v1/substack?url=https://substack.com/home/post/p-212696442"Default response is text/markdown with YAML frontmatter + clean body:
---
title: "Article Title"
author: "Author Name"
date: "2026-01-15"
reading_time: "5 min read"
free: true
source_url: "https://medium.com/@user/article-id"
provider: "medium"
tags:
- "Distributed Systems"
---
# Article content in clean Markdown...JSON response (metadata + markdown)
Add &format=json to get { metadata, markdown } as application/json instead of raw markdown:
curl "https://mdingest.knightker.workers.dev/v1/medium?url=https://medium.com/@user/article-id&format=json"{
"metadata": {
"title": "Article Title",
"author": "Author Name",
"date": "2026-01-15",
"reading_time": "5 min read",
"free": true,
"source_url": "https://medium.com/@user/article-id",
"provider": "medium",
"tags": ["Distributed Systems"]
},
"markdown": "---\ntitle: \"Article Title\"...\n"
}Local development
bun run dev
curl "http://localhost:3000/v1/medium?url=https://medium.com/@user/article-id"The web UI is at http://localhost:3000/ — paste a URL, auto-detects the provider,
and shows the output with md/json tabs and line numbers.
CLI
# Ingest any article URL → markdown to stdout (auto-detects provider)
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 providersPipe-friendly: mdingest https://dev.to/user/post > article.md gives you clean Markdown with no log noise.
MCP server
For AI tools (Claude, Cursor, etc.) — two ways to connect:
Remote (zero setup): Register the deployed endpoint directly:
{
"mcpServers": {
"mdingest": {
"url": "https://mdingest.knightker.workers.dev/v1/mcp"
}
}
}Local (stdio): Run the CLI as a local process:
{
"mcpServers": {
"mdingest": {
"command": "bun",
"args": ["run", "src/cli.ts", "mcp"]
}
}
}Both expose the same two tools:
Tool | Description |
| Ingest a URL into clean Markdown. Auto-detects provider. Returns markdown text by default; |
| List supported providers with source, example URL, and accepted domains. |
Configuration
Env var | Default | Purpose |
|
| Server port |
|
| Freedium mirror base URL |
|
| Cache entry TTL (seconds) |
|
| Max cache entries |
|
| Fetch timeout (ms) |
| Chrome 120 UA | User-Agent for upstream requests |
Architecture
src/
core/
config/ Zod-validated config (boot-time, frozen object)
cache/ In-memory LRU cache
integrations/
freedium/ HTTP client for Freedium mirror (download + data endpoints)
common/
types/ Shared types: ArticleMetadata schema, Provider interface
pipes/ ZodValidationPipe (validates controller input)
filters/ AllExceptionsFilter (shapes errors to { code, message, details?, traceId })
guards/ RateLimitGuard (30 req/min per IP, global via APP_GUARD)
llm-visibility.ts Fastify preHandler: Accept: text/markdown negotiation, Link headers, Vary, 406
errors/ shapeError() — shared error shaping (filter, CLI, MCP)
modules/
medium/ Medium feature: controller, service, DTOs, errors
devto/ Dev.to feature: controller, service, DTOs, errors
substack/ Substack feature: controller, service, DTOs, errors
mcp/ MCP server: server.ts (createMcpServer/startMcpServer/handleHttpRequest), tools.ts (ingest_article, list_providers)
app.module.ts Root module
main.ts Bootstrap (NestJS + Fastify + Bun, URI versioning, global filter)
ingest.ts Shared router: service registry + ingest(url) — used by CLI + MCP
cli.ts CLI entry: citty binary, `mdingest <url>` + `mdingest mcp` subcommand
mcp.controller.ts MCP HTTP endpoint at /v1/mcp (Streamable HTTP transport)
worker.ts Cloudflare Worker — routes requests to the Docker container
shared/
providers.ts Single source of truth: MEDIUM_DOMAINS, PROVIDERS, detectProvider(), error codes
web/ Astro static site (React islands)
src/
islands/ Ingestor.tsx — URL input, provider selector, output display
pages/ index.astro (landing), ingest.astro (ingest UI), docs.astro (API docs)
layouts/ Base.astro — shared header (sticky, backdrop-blur), footer, meta tags
styles/ global.css — design tokens, base styles, shared components
public/
icons/ Provider SVG logos (medium, devto, substack)
robots.txt Allow all crawlers + Content-Signal directive + sitemap reference
llms.txt Curated markdown index for AI-mediated conversations
llms-full.txt All 3 pages concatenated for single-fetch LLM ingestion
*.md Markdown twins of each HTML page (index.md, ingest.md, docs.md)
.well-known/
ai-catalog.json AI Catalog — domain-level agent discovery
api-catalog RFC 9727 API Catalog (linkset+json)
mcp/server-card.json MCP Server Card — pre-connection MCP client metadataFour entry points share the same ingestion logic via src/ingest.ts:
Entry point | File | How |
HTTP API |
| NestJS + Fastify, DI wires services, controller delegates to service |
CLI |
| citty binary: |
MCP server (stdio) |
| stdio JSON-RPC: |
MCP server (HTTP) |
| Streamable HTTP at |
Each provider implements a Provider interface (matches, convert). Adding a provider = new folder under modules/, no changes to core or common. Service classes work with direct new outside NestJS — CLI and MCP instantiate them via src/ingest.ts without booting NestJS.
URL detection is centralized in shared/providers.ts — detectProvider(url) is the single source of truth used by both the frontend (auto-detect) and all 3 backend DTOs (isValid*Url delegate to it).
Errors return { code, message, details?, traceId } with namespaced codes (MEDIUM.INVALID_URL, SUBSTACK.PAID_POST, VALIDATION.FAILED, RATE_LIMITED, etc.). Full contract in AGENTS.md. All endpoints are rate-limited at 30 req/min per IP.
Tech stack
Backend
Tool | Role |
Bun | Runtime |
NestJS + Fastify | Framework (modules, DI, controllers) |
Zod | Runtime validation (config, params, metadata) |
lru-cache | In-memory cache with TTL |
turndown | HTML→Markdown (Substack provider) |
oxlint | Linting |
@cloudflare/containers | Cloudflare Containers deployment |
citty | CLI arg parsing + |
@modelcontextprotocol/sdk | MCP server over stdio for AI tools |
Frontend
Tool | Role |
Astro | Static site generator with React island support |
@astrojs/sitemap | Sitemap generation (sitemap-index.xml + sitemap-0.xml) |
React | Interactive islands (Ingestor component) |
lucide-react + @lucide/astro | Icons |
Geist + Geist Mono | Self-hosted fonts |
UI quality
The verify script runs impeccable to scan the built frontend for UI anti-patterns
(WCAG AA contrast, line-height). Current state: 0 anti-patterns.
Roadmap
Feature | Status | How |
HTTP API | Deployed — runtime-verified |
|
Medium provider | Runtime-verified |
|
Dev.to provider | Runtime-verified |
|
Substack provider | Runtime-verified |
|
Web UI | Runtime-verified | Astro + React islands — landing page, ingest page with md/json tabs + line numbers, API docs |
CLI | Runtime-verified |
|
MCP server (stdio) | Runtime-verified |
|
MCP server (HTTP) | Runtime-verified |
|
Rate limiting | Runtime-verified | Global |
LLM visibility | Runtime-verified |
|
Agent discovery | Runtime-verified |
|
Development
bun run verify # typecheck + lint + impeccable (UI anti-pattern scan)
bun run dev # start backend dev server with hot reload (port 3000)
bun run dev:web # start Astro dev server (frontend only, port 4321)
bun run build:web # build Astro frontend to web/dist/
bun run test # run unit tests (vitest)
bun run cli # run CLI (bun run src/cli.ts <url>)
bun run mcp # start MCP server (bun run src/cli.ts mcp)Attribution
Medium articles fetched via Freedium.
This server cannot be installed
Maintenance
Resources
Unclaimed servers have limited discoverability.
Looking for Admin?
If you are the server author, to access and configure the admin panel.
Related MCP Servers
- AlicenseAqualityBmaintenanceGive your AI the ability to read the web. Fetches URLs as clean markdown with 9 fallback strategies.21099MIT
- AlicenseAqualityDmaintenanceConverts URLs and raw HTML to clean Markdown, enabling AI assistants to read web pages for summarization, analysis, or ingestion.2171MIT
- AlicenseAqualityBmaintenanceEnables AI agents to read web pages reliably, returning clean markdown content, hyperlinks, and metadata without navigation or ad noise.315MIT
- AlicenseAqualityCmaintenanceEnables AI agents to fetch any web page as clean markdown or screenshot it, turning URLs into LLM-ready context.211MIT
Related MCP Connectors
Web scraping for AI agents. Converts URLs to clean, LLM-ready Markdown with anti-bot bypass.
Turns any URL into SEO metadata, contacts, tech stack, and AI-ready Markdown, in one call.
Fetch any URL and get clean Markdown. Web scraping for AI agents.
Latest Blog Posts
- Who's Calling? MCP Hosts Are an Identity Blind Spot (And the Spec Knows It)By Om-Shree-0709 on .mcpAgent IdentityOAuth 2.1
- Your AI Chatbot Just Exposed Your CEO's Salary to an InternBy Om-Shree-0709 on .Agent IdentityMCP SecurityOAuth Delegation
- Why MCP Servers Need Execution Sandboxing (And Why Your Current Stack Isn't Enough)By Om-Shree-0709 on .Agentic AiPrompt InjectionWebAssembly
MCP directory API
We provide all the information about MCP servers via our MCP API.
curl -X GET 'https://glama.ai/api/mcp/v1/servers/LOsioChico/mdingest'
If you have feedback or need assistance with the MCP directory API, please join our Discord server