FE

Fetch MCP Server: HTML, JSON, Markdown, Plaintext Fetcher

Fetch HTML, JSON, Markdown, or plaintext with the flexible MCP server for reliable content retrieval, conversion, and delivery.

Quick Install
npx -y @zcaceres/fetch-mcp

Overview

Fetch MCP Server is a lightweight Model Context Protocol (MCP) tool that retrieves remote content and returns it as HTML, JSON, Markdown, or plaintext. It’s designed for systems that need reliable content ingestion and conversion before feeding that content into downstream services such as language models, search indexes, or static site generators.

The server normalizes content retrieval (follows redirects, applies timeouts, handles common HTTP errors), detects content types, and optionally converts HTML to Markdown or plain text. Because it exposes a simple HTTP API, it can be used as an independent service, a containerized component, or an MCP-compatible tool in an LLM orchestration pipeline.

Features

  • Fetch remote resources over HTTP/S with configurable timeouts and headers
  • Return content as HTML, JSON, Markdown, or plaintext
  • Content-type detection and basic sanitization
  • Optional HTML → Markdown and HTML → plaintext conversion
  • Support for custom request headers and User-Agent
  • Simple allowlist/denylist to limit allowed domains
  • Lightweight, easy to run locally or in containers
  • Designed to integrate as an MCP tool in model orchestration environments

Installation / Configuration

Clone and run locally (Node.js example)

git clone https://github.com/zcaceres/fetch-mcp.git
cd fetch-mcp
npm install
npm run build   # if applicable
npm start

Run with Docker

docker build -t fetch-mcp .
docker run -p 8080:8080 \
  -e PORT=8080 \
  -e ALLOWLIST="example.com,api.example.com" \
  fetch-mcp

Environment variables (common configuration options)

PORT=8080                # port to listen on
TIMEOUT_MS=10000         # request timeout in milliseconds
CACHE_TTL_SECONDS=300    # optional caching time-to-live
ALLOWLIST=example.com    # comma-separated allowed hostnames (optional)
DENYLIST=                # comma-separated denied hostnames (optional)
USER_AGENT=fetch-mcp/1.0 # default User-Agent header
ENABLE_CONVERT=true      # enable HTML -> Markdown/plaintext conversion

Configuration file (config.json) example

{
  "port": 8080,
  "timeoutMs": 10000,
  "cacheTtlSeconds": 300,
  "allowlist": ["example.com"],
  "userAgent": "fetch-mcp/1.0",
  "enableConvert": true
}

Available Resources

The server exposes a minimal HTTP API. Typical endpoints:

  • GET /fetch — fetch a URL and return converted content
  • POST /fetch — same as GET but accepts JSON body for more options
  • GET /health — basic health check / readiness
  • GET /metrics — optional Prometheus-style metrics (if enabled)

Request parameters (query or JSON body)

ParameterTypeRequiredDescription
urlstringyesFully qualified URL to fetch (https://…)
formatstringnoDesired output: html, markdown, text, json (default: html)
headersobjectnoAdditional HTTP headers to send to the origin
timeoutMsnumbernoPer-request timeout in ms (overrides default)
followRedirectsbooleannoWhether to follow redirects (default: true)

Response structure (JSON POST mode)

{
  "status": 200,
  "url": "https://example.com/article",
  "contentType": "text/markdown; charset=utf-8",
  "body": "...converted content...",
  "metadata": {
    "fetchedAt": "2024-01-01T12:00:00Z",
    "originalContentType": "text/html"
  }
}

When using GET /fetch with format=html or text, the server may return the raw content with the appropriate Content-Type header instead of a JSON wrapper.

Use Cases

  • LLM context enrichment: fetch web pages and convert them to Markdown or plaintext before feeding to a model, keeping HTML tags out of the context window.
    • Example: get an article as Markdown
      curl "http://localhost:8080/fetch?url=https://example.com/post&format=markdown"
      
  • Structured API proxying: retrieve JSON endpoints and forward them (optionally apply simple validation) to downstream services.
    • Example: fetch JSON and get wrapped response
      curl -G "http://localhost:8080/fetch" --data-urlencode "url=https://api.example.com/data" --data "format=json"
      
  • Content ingestion for search/indexing: fetch and normalize pages, convert to plaintext, and feed into an indexer.
    • Example: fetch as text for indexing
      curl "http://localhost:8080/fetch?url=https://example.com/blog&format=text"
      
  • Safe scraping in service boundaries: enforce an allowlist/denylist and centralized timeout/retry policy to reduce accidental spike or leakage when tools fetch external URLs.

Examples

GET with query parameters

curl -G "http://localhost:8080/fetch" \
  --data-urlencode "url=https://example.com/article" \
  --data "format=markdown"

POST with JSON body (returns structured JSON)

curl -X POST "http://localhost:8080/fetch" \
  -H "Content-Type: application/json" \
  -d '{
    "url": "https://example.com/article",
    "format": "markdown",
    "headers": { "Accept-Language": "en-US" },
    "timeoutMs": 5000
  }'

Health check

curl http://localhost:8080/health

Where to get it

Source code, issue tracker, and releases are available on GitHub: https://github.com/zcaceres/fetch-mcp

If you plan to run this in production, review configuration options for timeouts, allowlists, and caching to match your operational and security requirements.