Skip to main content
ClaudeWave

MCP server that saves your Claude Code, Cursor, and Codex sessions as versioned Markdown reports — with human-in-the-loop review and Apple Pencil / S Pen annotation.

MCP ServersOfficial Registry3 stars0 forks● TypeScriptMITUpdated today
ClaudeWave Trust Score
95/100
✓ Verified
Passed
  • ✓Open-source license (MIT)
  • ✓Actively maintained (<30d)
  • ✓Clear description
  • ✓Topics declared
  • ✓Documented (README)
Last scanned: 10/5/2026
Install in Claude Code / Claude Desktop
Method: NPX · md-log-mcp
Claude Code CLI
claude mcp add md-log-mcp -- npx -y md-log-mcp
claude_desktop_config.json (Claude Desktop)
{
  "mcpServers": {
    "md-log-mcp": {
      "command": "npx",
      "args": ["-y", "md-log-mcp"],
      "env": {
        "MDLOG_API_BASE_URL": "<mdlog_api_base_url>"
      }
    }
  }
}
1. Run the command above in your terminal (Claude Code), or paste the JSON config into claude_desktop_config.json (Claude Desktop).
2. Replace any <placeholder> values with your API keys or paths.
3. Restart Claude. The MCP server and its tools appear automatically.
Detected environment variables
MDLOG_API_BASE_URL
Use cases

MCP Servers overview

# md-log-mcp

[![npm version](https://img.shields.io/npm/v/md-log-mcp)](https://www.npmjs.com/package/md-log-mcp)
[![MCP Registry](https://img.shields.io/badge/MCP%20Registry-com.md--log%2Fmd--log--mcp-1f6feb)](https://registry.modelcontextprotocol.io/v0/servers?search=md-log)
[![License: MIT](https://img.shields.io/npm/l/md-log-mcp)](./LICENSE)
[![Node](https://img.shields.io/node/v/md-log-mcp)](https://nodejs.org)

> **Review the report, not the diff.** An MCP server that lets your AI coding agent — **Claude Code, Claude Desktop, Codex, Cursor** — save its work and analysis as immutable, versioned **Markdown reports** into [**md-log**](https://md-log.com), a human-in-the-loop review & archive layer for **"vibe coding."** You then read and **stylus-annotate** (S-Pen / Apple Pencil) those reports on web, phone, and tablet — every save a new immutable version.

A [Model Context Protocol](https://modelcontextprotocol.io) server — **two transports, one tool set** —
that lets **Claude Code** (and other agents) save `.md` files — text **and** embedded screenshots
together — straight into **md-log**, a human-in-the-loop review & archive layer for vibe coding. The
**recommended** way to connect is the **hosted remote endpoint** (`https://mcp.md-log.com/mcp`, a URL +
your key — no install); a local **stdio** (`npx -y md-log-mcp`) transport is the alternative. The agent writes a report
**by path** (`my-project/2026-07-07-error-report.md`); missing folders are auto-created, images are
uploaded and their references rewritten to `asset://` links, and every save becomes an immutable new
version. The same report is then readable, editable, and stylus-annotatable (S-Pen / Apple Pencil
where supported) on a phone or tablet, and on the web.

md-log is a **hosted service** at **https://app.md-log.com** — you don't run any server yourself.
This package is just the connector: a **thin authenticated HTTP client** that validates POSIX paths,
orchestrates asset uploads, maps errors to stable agent codes, and forwards everything to the hosted
md-log service — the single authority for auth, storage, versioning and quota. All you need is a
Personal Access Token from the web app.

## Stack

- **@modelcontextprotocol/sdk** (TypeScript) — one `McpServer` (17 tools), two transports.
- **stdio transport** (`md-log-mcp`) — JSON-RPC over stdin/stdout; the default local mode (so stdout
  is reserved for the protocol; logs go to stderr). PAT from env.
- **Streamable HTTP transport** (`md-log-mcp-http`) — the remote mode: agents connect by URL with no
  local install; the PAT is taken **per request** from the `Authorization` header. See
  [Remote (Streamable HTTP) mode](#remote-streamable-http-mode).
- **TypeScript**, bundled with **tsup** to ESM `dist/server.js` (stdio) + `dist/http.js` (HTTP).
  Runtime deps: the MCP SDK and **zod** (input schemas). Node's built-in `fetch`/`http` are the only
  network layers — no web framework.
- **PAT auth** — a md-log Personal Access Token sent to the backend as `Authorization: Bearer`.

## Requirements

- Node **22+**
- A **Personal Access Token** (PAT) minted in the md-log web app (**Settings → Tokens**; shown once)

That's it — the md-log service itself is hosted at `https://app.md-log.com`; there is nothing to
install or self-host.

## Tools (17)

Every tool returns dual output — a human-readable `content[].text` and a machine-readable
`structuredContent` — and validates the POSIX path (NFC-normalize; reject `..`/`.`, control chars,
empty/whitespace segments, backslashes, reserved names; enforce 255-byte name / 1024-byte path
limits; require `.md` for files) **before** any backend call. All requests hit the base URL in
`MDLOG_API_BASE_URL` (which already includes `/api/v1`).

| Tool | What it does |
| ---- | ------------ |
| **`save_markdown`** ⭐ | The headline tool. Create or overwrite a `.md` by path (force last-writer-wins); missing folders auto-created. Optionally uploads embedded images first (each given as `data_base64` **or** a local `file_path`) and rewrites each `placeholder` in the content to an `asset://<key>` link. Accepts `commit_message` — a recommended 1-2 line change summary shown in the version history. |
| `upload_asset` | Upload one image (reserve → presigned PUT → complete) and return an `asset://<key>` reference to embed as `![alt](asset://<key>)`. Provide the image as **either** `data_base64` (inline base64) **or** `file_path` (a local file the server reads) — exactly one; with `file_path`, `filename` defaults to the basename and `content_type` is inferred from the extension (png/jpg/jpeg/gif/webp/avif). |
| `append_to_markdown` | Append to an existing file with optimistic concurrency (GET current → concat → conditional PUT with `base_version_no`). Auto-retries once on conflict, then surfaces `CONFLICT`. Accepts `commit_message` — a recommended 1-2 line change summary shown in the version history. |
| **`edit_markdown`** | Change PART of a file by exact literal replacement (read → apply → conditional PUT with `base_version_no`; auto-retries once on conflict, re-applying every edit). Pass several changes at once as **`edits: [{old_string, new_string, replace_all?}, …]`** (max 50, applied in order) — they land as **one write = one version = one notification**; for a single change the `old_string`/`new_string` shorthand still works (never both). Each `old_string` must match **exactly once**, counting overlapping positions too (`"\n\n"` inside `"\n\n\n"` is ambiguous → `detail.overlapping: true`) — 0 matches or an ambiguous >1 rejects the **whole call** with `VALIDATION` (`detail.reason` = `NO_MATCH` / `AMBIGUOUS_MATCH`, `detail.edit_index` = the failing edit) and **nothing is written**; set `replace_all:true` to change every occurrence on purpose. Other `detail.reason`s: input shape — `MIXED_INPUT`, `MISSING_EDIT`, `EMPTY_EDITS`, `TOO_MANY_EDITS`, `EMPTY_OLD_STRING`, `IDENTICAL_STRINGS` (rejected before any read); result — `NO_CHANGE` (edits cancel out), `DOCUMENT_TOO_LARGE` (a step would pass the 25 MiB cap), `TOO_MANY_REPLACEMENTS` (more occurrences replaced in one call than the document cap allows), `BATCH_TOO_SLOW` (edits after the first stopped once the call has run 2 s — split them across calls). A match failure on the conflict retry carries `detail.after_concurrent_write: true`. Never creates a file (missing path → `NOT_FOUND`) and has no force mode — prefer it over `update_markdown` for any partial change. |
| `update_markdown` | Replace a file's ENTIRE content. Pass `expected_version` for optimistic concurrency (mismatch → `CONFLICT`); omit it to force LWW. Passing `expected_version` for a path that does **not** exist now returns `CONFLICT` (`detail.server_version_no` = `0`), not a silent create. For a partial change use `edit_markdown` instead. Accepts `commit_message` — a recommended 1-2 line change summary shown in the version history. |
| `restore_version` | Roll a file back to an earlier `version_no` (from `list_versions`): that version's content becomes a NEW current version — history is immutable, so the rollback is itself undoable. Restoring the version the file is already on is an accepted no-op. Accepts `commit_message`. |
| `get_markdown` | Read a file's content by path (materializes inline content or a presigned content URL for large docs). Pass `version` (a `version_no` from `list_versions`) to read an old immutable version. |
| `list_versions` | List a file's immutable version history, newest first (`version_no`, `commit_message`, author, `registered_at`, size). |
| `delete_markdown` | Soft-delete a file. Requires `confirm:true` (otherwise `VALIDATION`); resolves the path to a document key first. |
| `create_folder` | `mkdir -p` — create every missing segment; already-existing folders count as success. |
| `list_folders` | Return the full folder tree. |
| `list_files` | List the documents and immediate subfolders inside a folder path. |
| `search_markdown` | Search by TITLE (substring) + BODY full-text (current versions; whole-word match, ranked, body hits include a snippet). |
| `move_markdown` | Move and/or rename a `.md` by path (`from_path` → `to_path`); destination folders auto-created; the document KEEPS its key, so version history and reviewers' annotations survive. |
| `move_folder` | Move a folder (whole subtree) under a new parent (`new_parent_path` empty/omitted = root); parent auto-created; cyclic moves rejected server-side. |
| `rename_folder` | Rename a folder in place (descendant paths rewritten server-side). |
| `delete_folder` | Delete a folder. Requires `confirm:true`; by default only an EMPTY folder is deleted — pass `cascade:true` to soft-delete the whole subtree (`rm -r`). |

### Error codes surfaced to the agent

Backend failures return `{ isError: true, content:[{type:"text", ...}] }` with a mapped code in
`structuredContent.error.code`:

`NOT_FOUND` · `CONFLICT` (carries the server head `{server_version_no, server_checksum, …}` in
`detail`) · `UNAUTHORIZED` · `RATE_LIMITED` · `QUOTA_EXCEEDED` · `BACKEND_UNAVAILABLE` ·
`VALIDATION` · `FOLDER_EXISTS` (swallowed as success by `create_folder`) · `ERROR`.

## Authentication

The MCP/PC lane authenticates with a **Personal Access Token** (`mdlog_pat_…`) — minted once in the
web app's **Settings** and supplied via env. The client attaches it as `Authorization: Bearer <PAT>`
(plus `X-API-Token` for compatibility) on every request. The backend is the single source of truth
for auth and quota.

| Variable | Required | Example | Notes |
| -------- | -------- | ------- | ----- |
| `MDLOG_API_BASE_URL` | yes | `https://app.md-log.com/api/v1` | The hosted service base, **including** `/api/v1`. No version suffix is appended; a trailing slash is stripped. |
| `MDLOG_PAT` | yes | `mdlog_pat_xxxxxxxxxxxxxxxxxxxxxxxx` | Bearer PAT. **Store it securely (OS keychain) — never commit it.** |
| `MDLOG_MAX_DOCUMENT_BYTES` | no | `26214400` (25 MiB) | Client-side pre-flight for the backend's per-document body cap
aiannotationclaudeclaude-codecode-reviewcodexcursordeveloper-toolsdocumentationhuman-in-the-loopllmmarkdownmcpmodel-context-protocolvibe-coding

What people ask about md-log-mcp

What is md-log/md-log-mcp?

+

md-log/md-log-mcp is mcp servers for the Claude AI ecosystem. MCP server that saves your Claude Code, Cursor, and Codex sessions as versioned Markdown reports — with human-in-the-loop review and Apple Pencil / S Pen annotation. It has 3 GitHub stars and its last recorded update is dated 2026-10-04.

How do I install md-log-mcp?

+

You can install md-log-mcp by cloning the repository (https://github.com/md-log/md-log-mcp) or following the README instructions on GitHub. ClaudeWave also provides quick install blocks on this page.

Is md-log/md-log-mcp safe to use?

+

Our security agent has analyzed md-log/md-log-mcp and assigned a Trust Score of 95/100 (tier: Verified). See the full breakdown of passed checks and flags on this page.

Who maintains md-log/md-log-mcp?

+

md-log/md-log-mcp is maintained by md-log. The last recorded GitHub activity is dated 2026-10-04, with 0 open issues.

Are there alternatives to md-log-mcp?

+

Yes. On ClaudeWave you can browse similar mcp servers at /categories/mcp, sorted by popularity or recent activity.

Deploy md-log-mcp to your cloud

Ship this repo to production in minutes. Each platform spins up its own environment with editable env vars.

Maintain this repo? Add a badge to your README

Drop the badge into your GitHub README to show it's tracked on ClaudeWave. Each badge links back to this page and reflects the live Trust Score.

Featured on ClaudeWave: md-log/md-log-mcp
[![Featured on ClaudeWave](https://claudewave.com/api/badge/md-log-md-log-mcp)](https://claudewave.com/repo/md-log-md-log-mcp)
<a href="https://claudewave.com/repo/md-log-md-log-mcp"><img src="https://claudewave.com/api/badge/md-log-md-log-mcp" alt="Featured on ClaudeWave: md-log/md-log-mcp" width="320" height="64" /></a>

More MCP Servers

md-log-mcp alternatives