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.
claude mcp add md-log-mcp -- npx -y md-log-mcp{
"mcpServers": {
"md-log-mcp": {
"command": "npx",
"args": ["-y", "md-log-mcp"],
"env": {
"MDLOG_API_BASE_URL": "<mdlog_api_base_url>"
}
}
}
}MDLOG_API_BASE_URLMCP Servers overview
# md-log-mcp
[](https://www.npmjs.com/package/md-log-mcp)
[](https://registry.modelcontextprotocol.io/v0/servers?search=md-log)
[](./LICENSE)
[](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` (15 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 (15)
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 ``. 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. |
| `update_markdown` | Replace a file's content. Pass `expected_version` for optimistic concurrency (mismatch → `CONFLICT`); omit it to force LWW. Accepts `commit_message` — a recommended 1-2 line change summary shown in the version history. |
| `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.** |
The server fails fast at startup with a clear message if either var is missing or the base URL is
malformed.
## Build
```bash
npm install
npm run build # tsup → dist/server.js (ESM, Node 22)
npm run typecheck # tsc --noEmit (optional)
```
## Smoke test
`scripts/smoke.mjs` spawns the **built** server over stdio (MCP SDK `Client` +
`StdioClientTransport`), then runs `initialize` → `tools/list` → `save_markdown` (a small report
embedding a tiny `data:` PNG) → `get_markdown` (reads it back, checks the marker) →
`search_markdown` — printing PASS/FAIL per step and exiting non-zero on any failure. Run it against
a **live** backend with a real PAT:
```bash
npm run build
MDLOG_API_BASE_URL="http://localhost:8080/api/v1" \
MDLOG_PAT="mdlog_pat_xxxx" \
node scripts/smoke.mjs # or: npm run smoke
```
## Connect a client
Mint the PAT in the web app's **Settings → Tokens**, store it securely, then add md-log to your MCP
client. **Never commit a PAT.**
> 📄 **연결 가이드 (HTML)** — [md-log.com/guides/customer-guide.html](https://www.md-log.com/guides/customer-guide.html): 웹 앱에서 발급받은 **MCP 키(PAT)** 로 URL 연결(권장) 또는 `npx` 로컬 연결 (Claude Code · Desktop · Codex · Cursor).
### Recommended — remote (URL), no install
Point your client at the **hosted endpoint** and pass the PAT as a Bearer header. **Nothing to
install — no Node.js, no `npx`.** (You don't even need this package for the hosted connection.)
```bash
# Claude Code
claude mcp add --transport http md-log https://mcp.md-log.com/mcp \
--header "Authorization: Bearer mdlog_pat_xxxxxxxxxxxxxxxxxxxxxxxx"
```
```jsonc
// Cursor / Claude Desktop / any client that takes JSON — the `type` field MUST be "http"
{
"mcpServers": {
"md-log": {
"type": "http",
"url": "https://mcp.md-log.com/mcp",
"headers": { "Authorization": "Bearer mdlog_pat_xxxxxxxxxxxxxxxxxxxxxxxx" }
}
}
}
```
Over the remote endpoint, embed images inline (base64); uploading a local image **by path**
(`file_path`) works only with the local method below.
### Alternative — local (stdio via `npx`)
Runs this connector as a local subprocess (needs Node 22+; `npx` fetches the publishWhat 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 was last updated today.
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?
+
md-log/md-log-mcp has not been audited yet by our security agent. Review the original repository on GitHub before using it in production.
Who maintains md-log/md-log-mcp?
+
md-log/md-log-mcp is maintained by md-log. The last recorded GitHub activity is from today, 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.
[](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
Fair-code workflow automation platform with native AI capabilities. Combine visual building with custom code, self-host or cloud, 400+ integrations.
User-friendly AI Interface (Supports Ollama, OpenAI API, ...)
An open-source AI agent that brings the power of Gemini directly into your terminal.
The fastest path to AI-powered full stack observability, even for lean teams.
🕷️ An adaptive Web Scraping framework that handles everything from a single request to a full-scale crawl!
Real-time global intelligence dashboard. AI-powered news aggregation, geopolitical monitoring, and infrastructure tracking in a unified situational awareness interface