Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
16 changes: 9 additions & 7 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -7,22 +7,24 @@ on:

jobs:
build-and-test:
# macos-latest because package.json sets "os": ["darwin"]; npm ci
# would refuse to install on linux. macOS runners are free for
# public repos and let keychain.test.ts mocks line up with the
# actual `security` argv shape.
runs-on: macos-latest
strategy:
fail-fast: false
matrix:
os: [ubuntu-latest, macos-latest, windows-latest]
node: ['20', '22']
runs-on: ${{ matrix.os }}
steps:
- uses: actions/checkout@v4
- name: Setup Node ${{ matrix.node }}
uses: actions/setup-node@v4
with:
node-version: ${{ matrix.node }}
cache: 'npm'
- run: npm ci
# No `cache: 'npm'` — setup-node's cache action requires a
# committed package-lock.json to compute its key, which we
# don't ship yet. Re-enable once a lockfile lands.
# No package-lock.json committed yet, so use `npm install` rather
# than `npm ci`. The semver ranges in package.json are tight
# enough for reproducible builds.
- run: npm install --no-audit --no-fund
- run: npm run build
- run: npm test
24 changes: 18 additions & 6 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -7,15 +7,27 @@ The format follows [Keep a Changelog](https://keepachangelog.com/en/1.1.0/) and
## [Unreleased]

### Added
- Initial release of the macOS MCP server wrapping `ZMediumToMarkdown` (≥ 3.1.0).
- **`setup.sh`** — one-shot bootstrap: probes Ruby (>= 3.2) and Node.js (>= 18) with platform-aware install hints, runs `gem install ZMediumToMarkdown` and `npm install -g mcp-medium-reader` (or upgrades if already present), verifies both binaries land on PATH, then `exec`s `mcp-medium-reader init` for the interactive credentials + MCP client install. Flags: `--no-init`, `--no-gem`, `--no-npm`, `--help`. Falls through gracefully when stdin isn't a TTY (curl-pipe-bash) by deferring `init` to a manual run.
- **Cross-platform support.** Server now runs on macOS, Linux, and Windows.
- **Pluggable credentials backend** with three native CLI wrappers and a file fallback:
- macOS: `security` CLI → Keychain (service: `mcp-medium-reader`).
- Linux: `secret-tool` CLI → Secret Service (libsecret / GNOME Keyring / KWallet). Probed at startup; falls back to the file backend with a stderr notice if libsecret-tools isn't installed.
- Windows: `powershell.exe` → DPAPI per-user encryption (same primitive that backs Credential Manager). Encrypted blobs stored in `%APPDATA%\mcp-medium-reader\credentials.json`.
- Any platform: plain JSON file at `$XDG_CONFIG_HOME/mcp-medium-reader/credentials.json` (POSIX) or `%APPDATA%\mcp-medium-reader\credentials.json` (Windows), mode `0600` on POSIX.
- Override with `MCP_MEDIUM_READER_BACKEND={keychain|secret-tool|dpapi|file}`.
- **`mcp-medium-reader init`** — one-shot guided setup: dependency check + credentials walkthrough + MCP client install.
- **`mcp-medium-reader install [--clients=...]`** — adds the server registration to four MCP clients by default (Claude Desktop, Claude Code, OpenAI Codex, Gemini CLI). Knows each client's per-OS config path; preserves existing keys; reports added / updated / unchanged / error per target.
- Reader tools: `read_medium_post`, `list_user_posts`, `read_user_posts`.
- Download tools: `download_medium_post`, `download_user_posts` (plain non-Jekyll layout, defaults `output_dir` to `process.cwd()`, accepts `~/...`).
- `validate_setup` tool — inspects platform / gem / Keychain state and (optionally) runs live cookie / proxy tests.
- `validate_setup` tool — inspects backend / dependencies / credentials and runs optional live tests.
- `set_credentials` tool (default-on; opt out via `MCP_MEDIUM_READER_DISABLE_SET_CREDENTIALS=1`).
- Subcommand CLI: `mcp-medium-reader [serve|setup|doctor|help|version]`.
- macOS Keychain integration (service `mcp-medium-reader`) for `cookie_sid`, `cookie_uid`, `medium_host`, `miro_medium_host`. Values are read fresh on every tool call, never logged, and passed to the gem via spawn env (no shell interpolation).
- LLM-directed recovery flows surfaced in tool responses: missing-credentials banner, paywall recovery script (`set_credentials → validate_setup → retry`, with the offending URL embedded), and Cloudflare escalation (first block this session: ask user to clear https://medium.com in browser; repeat blocks: also offer Worker-proxy setup script).
- LLM-directed recovery flows surfaced in tool responses: missing-credentials banner, paywall recovery script (`set_credentials → validate_setup → retry` with the offending URL embedded), and Cloudflare escalation (first block this session: ask user to clear https://medium.com in browser; repeat blocks: also offer Worker-proxy setup script).
- `MEDIUM_NO_AUTO_BROWSER=1` injected into the gem's spawn env plus `stdio: ['ignore', 'pipe', 'pipe']` so the gem cannot deadlock on its interactive Cloudflare browser-clear prompt under MCP transport.
- CI on `macos-latest` for Node 20 / 22 — `npm ci`, `npm run build`, `npm test`.
- `cross-spawn` for proper Windows `.bat` shim handling around Node's CVE-2024-27980 mitigation.
- CI on Ubuntu / macOS / Windows × Node 20 / 22 — `npm ci`, `npm run build`, `npm test`.

### Changed
- Removed `"os": ["darwin"]` from `package.json`. Removed the `assertDarwin()` startup guard.
- `keychain.ts` and `KeychainError` renamed to `credentials.ts` / `CredentialsError`. Internal API the same; tools / setup / doctor updated accordingly.

[Unreleased]: https://github.com/ZhgChgLi/mcp-medium-reader/compare/main...claude/medium-reader-mcp-JMyan
Loading
Loading