npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2026 – Pkg Stats / Ryan Hefner

mcp-medium-reader

v1.1.2

Published

Cross-platform MCP server that wraps ZMediumToMarkdown so LLMs can read or download Medium posts as Markdown.

Readme

Medium Reader MCP

A Model Context Protocol server for reading and downloading Medium articles as Markdown. This MCP server enables AI assistants like Claude Desktop, Claude Code, OpenAI Codex, and Gemini CLI to fetch a single Medium post by URL, summarize it in chat, or archive it (Markdown + images) to disk.

License: MIT GitHub Repository

Powered by ZMediumToMarkdown (Ruby gem ≥ 3.5.2) — the gem owns every Medium fetch, every cookie, every Markdown render. mcp-medium-reader is a thin MCP wrapper around it.

Overview

The LLM auto-discovers when to use this server: as soon as the user pastes a medium.com URL (or a Medium custom-domain URL like towardsdatascience.com) or asks to read / summarize / archive an article, the server's tools take over. Supported on macOS, Linux, and Windows.

What you get instead of the usual "LLM tries to fetch the URL itself" failure mode:

  • Clean Markdown, not HTML. Frontmatter (title / author / date / tags), every paragraph, every blockquote, every outbound link, and every miro.medium.com image URL come back verbatim — no React/JSON noise, no ads, no nav chrome. The LLM can quote, translate, summarize, or rewrite from the real article instead of a lossy preview.
  • Full depth, not a summary. Built-in fetchers typically collapse a long post to a few hundred tokens and drop the prices / schedules / names that make the article useful. This server returns the whole body — see the Before / After table below for a 47 KB vs. 1.5 KB head-to-head on the same article.
  • Token-efficient. ~17K tokens of pure article body for a 6,500-word post, versus 100K+ tokens of HTML soup if you feed the raw page in.
  • Reliable past Cloudflare. Direct datacenter requests to Medium get a 403; this server delegates to the underlying gem, which goes through Medium's API with optional cookie / Worker-proxy support.
  • Paywall-aware. Once you sign in once via the gem CLI, member-only posts come through too. Cookies stay in the gem's AES-256-GCM cache, never on the MCP wire.
  • Disk archive on demand. download_medium_post saves Markdown plus all referenced images locally; re-runs are skip-if-unchanged.

URL recognition covers medium.com, *.medium.com, and Medium publications on custom domains (towardsdatascience.com, betterhumans.pub, uxdesign.cc, levelup.gitconnected.com, …). The 12-char hex slug suffix (-a1b2c3d4e5f6) is the canonical Medium tell across hosts.

Why MCP — Before / After

Same article tested both ways: https://medium.com/p/055527a739dd (a long-form travel post, ~6,500 words, 180+ images).

| Aspect | Without MCP (URL fed to LLM directly) | With mcp-medium-reader | | --- | --- | --- | | Reachability | Medium returns 403 Cloudflare block to direct datacenter requests; built-in fetchers usually fall back to a forced short summary | Goes through the ZMediumToMarkdown gem against Medium's API (cookies / Worker proxy optional), reliably returns full body | | Content depth | ~1.5 KB summary — prices, schedules, restaurant and hotel names all dropped; impossible to translate, quote, or post-process | 47 KB of clean Markdown: frontmatter (title / author / date / tags) + every paragraph + image URLs + outbound links + blockquotes preserved verbatim | | Token usage | Looks cheap (~600 tokens) but the information is already destroyed — no follow-up task possible. Feeding the raw HTML instead balloons to 100K+ tokens of React/JSON noise | ~17K tokens, all article body, zero HTML / JS / ad noise | | Paywall | No path | Gem manages its own AES-256-GCM cookie cache; full member-only content readable after one-time login |

Bottom line: without MCP the LLM receives either a lossy summary or a wall of HTML noise; with MCP it receives clean Markdown it can actually work with.

Installation

Quick Install (Recommended)

bash <(curl -fsSL https://raw.githubusercontent.com/ZhgChgLi/mcp-medium-reader/main/setup.sh)

Or download and run locally:

curl -fsSL https://raw.githubusercontent.com/ZhgChgLi/mcp-medium-reader/main/setup.sh -o setup.sh
bash setup.sh

setup.sh is cross-platform (macOS / Linux / Windows-Git-Bash). It checks Ruby ≥ 3.2 and Node ≥ 18 (offers brew install automatically on macOS), installs the ZMediumToMarkdown gem and the mcp-medium-reader npm package, runs mcp-medium-reader init to bind a stable Ruby runtime and register the server with Claude Desktop, Claude Code, OpenAI Codex, and Gemini CLI, prints doctor so you can confirm everything is wired up, then walks you through ZMediumToMarkdown --auth so the gem cookie cache is populated in the same session. Restart your MCP clients afterwards.

Flags: --no-init (deps only) / --no-gem / --no-npm / --no-auth (skip the interactive ZMediumToMarkdown --auth) / --yes (assume yes to brew/install prompts) / --help.

Manual Installation

# 1. Install the Ruby gem (the engine that actually fetches Medium)
gem install ZMediumToMarkdown      # must be >= 3.5.2

# 2. Install this MCP server
npm install -g mcp-medium-reader

# 3. One-shot setup: dependency check + Ruby runtime bind + register with all MCP clients
mcp-medium-reader init

Verify everything is in place:

mcp-medium-reader doctor

First-time Login (one-off, optional)

If you only ever read public posts, you can skip this step. For paywalled posts, run the gem standalone once in your own Terminal so it can open Chrome for sign-in / Cloudflare clearance and cache the cookies in ~/.zmediumtomarkdown:

ZMediumToMarkdown --auth

(setup.sh runs this for you automatically at the end; pass --no-auth to skip.) After that, every MCP tool call uses the cache automatically. The MCP transport gives the gem a non-TTY stdin (which trips its --non-interactive auto-detection), so the gem cannot drive its own Chrome login under MCP — the first-time sign-in has to happen in a real Terminal.

Terms of Use note (ZMediumToMarkdown ≥ 4.0.0)

ZMediumToMarkdown 4.0.0 introduced a first-run Terms-of-Use gate. Because MCP runs the gem on a non-TTY stream, mcp-medium-reader sets ZMTM_TOS_ACCEPTED=1 in the gem's environment automatically — installing this server is acceptance of the gem's Terms on your behalf. If that's not what you want, don't install this MCP server; run the gem yourself in a Terminal and respond to the prompt interactively. Read the full Terms at the link above before deciding.

Quickstart

After install + restarting your MCP client, just paste a Medium URL into the chat:

Read https://medium.com/zrealm-ios-dev/a-milestone-of-1-000-followers-on-medium-6fd11e9704f2 and summarize the three biggest takeaways.

The LLM picks read_medium_post automatically and answers from the full article — not a Cloudflare error, not a 1.5 KB preview.

Other prompts that auto-route to this server:

  • "Translate this Medium post to English: <url>"
  • "Save this article as Markdown to ~/Documents/articles: <url>" — uses download_medium_post
  • "Is my Medium reader setup working?" — uses validate_setup

If the LLM doesn't pick the tool, restart the MCP client (the registration is read at startup) or run mcp-medium-reader doctor to verify the install.

Integration with MCP Clients

mcp-medium-reader install adds the server registration to the supported clients automatically. Restart each client afterwards.

| Client | Config File | | --------------- | --------------------------------------------------------------------------- | | Claude Desktop | ~/Library/Application Support/Claude/claude_desktop_config.json (macOS) / %APPDATA%\Claude\claude_desktop_config.json (Windows) / ~/.config/Claude/claude_desktop_config.json (Linux) | | Claude Code | ~/.claude.json | | OpenAI Codex | ~/.codex/config.toml | | Gemini CLI | ~/.gemini/settings.json |

Limit which clients to install for:

mcp-medium-reader install --clients=claude-desktop,gemini

Available IDs: claude-desktop, claude-code, codex, gemini.

The registered server name is medium-reader (so it shows up in the LLM tool-call UI as medium-reader.read_medium_post, etc.).

Manual Configuration

If you'd rather edit config files yourself, the entry is:

"medium-reader": {
  "command": "mcp-medium-reader"
}

For Codex (config.toml):

[mcp_servers.medium-reader]
command = "mcp-medium-reader"

Available Tools

read_medium_post

Fetch a single Medium post by URL → Markdown in chat.

Parameters:

  • url: Medium post URL. Accepts medium.com, *.medium.com, and Medium publications on custom domains (URLs ending in a 12-char hex slug suffix like -a1b2c3d4e5f6 are Medium regardless of host).

If the post is paywalled, the response prepends a step-by-step recovery script the LLM can follow.

download_medium_post

Download a single Medium post (Markdown + images) to disk.

Parameters:

  • url: Medium post URL.
  • output_dir (optional): Directory to write into. Files land under <output_dir>/Output/zmediumtomarkdown/. Accepts ~/.... Defaults to the current working directory of the MCP server process.

Re-runs are skip-if-unchanged.

validate_setup

Inspect the dependency state and (optionally) run a live test request.

Parameters:

  • test_url (optional): A Medium post URL to read with the current gem cookie cache. Reports whether full content was returned vs. a paywall preview.

Configuration

Environment Variables

| Variable | Description | Required | | ----------------------------------------------- | ---------------------------------------------------------------------------- | -------- | | MCP_MEDIUM_READER_CONFIG_DIR | Override config directory (defaults to $XDG_CONFIG_HOME/mcp-medium-reader on POSIX, %APPDATA%\mcp-medium-reader on Windows). Holds runtime.json. | No | | ZMEDIUM_COOKIE_CACHE_PATH | Override the gem cookie cache path probed by doctor (defaults to ~/.zmediumtomarkdown). | No |

There are no credentials env vars — Medium cookies belong to the gem, not the MCP server.

What's Stored Where

| Data | Location | Owner | | ------------------------------------------------------------ | ------------------------------------------------------- | --------------------------- | | Medium login cookies (sid, uid, cf_clearance, _cfuvid) | ~/.zmediumtomarkdown (AES-256-GCM, mode 0600) | ZMediumToMarkdown gem | | Ruby runtime pin (rubyPath, GEM_HOME, GEM_PATH) | <config_dir>/runtime.json (mode 0600 on POSIX) | mcp-medium-reader |

Subcommands

mcp-medium-reader [serve]         Start MCP stdio server (default).
mcp-medium-reader init            Guided setup: dep check + Ruby runtime bind + MCP client install.
mcp-medium-reader install [...]   Add server entry to MCP client configs only.
                                  Optional --clients=<id,id,...>.
                                  IDs: claude-desktop, claude-code, codex, gemini.
mcp-medium-reader doctor          Print platform / dependency / runtime / cookie-cache status.
mcp-medium-reader help            Show help.
mcp-medium-reader version         Show version.

Troubleshooting

Gem not found / wrong Ruby selected

ZMediumToMarkdown gem not found
or: Configured Ruby runtime is invalid

Install the gem and bind a stable Ruby runtime:

gem install ZMediumToMarkdown      # or: gem update ZMediumToMarkdown
mcp-medium-reader init             # rebinds runtime.json from the active shell

Run init from a shell where both ruby and the gem work, so the bound rubyPath / GEM_HOME are valid.

Gem version too old

ZMediumToMarkdown X.Y.Z is too old
gem update ZMediumToMarkdown

mcp-medium-reader requires gem version 3.5.2 or later.

Paywalled post returns only a public preview

The gem's cookie cache is missing or stale. Run the gem standalone once in your own Terminal:

ZMediumToMarkdown --auth

Chrome opens for sign-in; the gem caches sid / uid / cf_clearance / _cfuvid in ~/.zmediumtomarkdown. Then ask the AI again. Use validate_setup({ test_url: "..." }) to confirm cookies grant access.

Cloudflare blocked the request

mcp-medium-reader runs the gem in non-interactive mode, so the gem cannot open its own browser to clear the challenge under MCP. Two-step recovery — the tool response will walk the LLM through this automatically:

  1. First block this session: ask the user to run ZMediumToMarkdown --auth once in a Terminal so the gem refreshes cf_clearance / _cfuvid in its cache.

  2. Repeat blocks: drop MCP and run the gem CLI directly in a Terminal — there it has a real TTY and can re-drive Chrome interactively:

    ZMediumToMarkdown -p <post-url>

    Worker proxy / cookie setup guide: https://github.com/ZhgChgLi/ZMediumToMarkdown/blob/main/wiki/Setting-Up-Medium-Cookies-and-a-Cloudflare-Worker-Proxy.md

Development

Prerequisites

  • Node.js 18+
  • Ruby 3.2+
  • ZMediumToMarkdown gem 3.5.2+

Setup

# Clone the repository
git clone https://github.com/ZhgChgLi/mcp-medium-reader.git
cd mcp-medium-reader

# Install dependencies
npm install

# Build the project
npm run build       # tsc → dist/

# Run tests
npm test            # vitest

# Run via tsx without building
npm run dev -- doctor

License

This project is licensed under the MIT License — see the LICENSE file for details.

Links


Disclaimer

All content fetched or downloaded through mcp-medium-reader (which is powered by ZMediumToMarkdown) — articles, images, video — is subject to copyright and belongs to its respective owner. This tool does not claim ownership of any fetched or downloaded content.

Fetching, downloading, or otherwise using copyrighted content without the owner's permission may be illegal. Neither mcp-medium-reader nor ZMediumToMarkdown condones copyright infringement, and neither will be held responsible for misuse of these tools. Users are solely responsible for ensuring they have the necessary permissions and rights for any content they fetch or download.

By using mcp-medium-reader you acknowledge and agree to comply with all applicable copyright laws and regulations, as well as Medium's Terms of Service.