md-log MCP: save/update/fetch markdown by path (stdio + remote HTTP, PAT auth).
Copy the AI prompt to install this server into Claude Code, Cursor, or another agent β or use 1-click editor setup below.
π‘ Paste into ~/Library/Application Support/Claude/claude_desktop_config.json (macOS) or %APPDATA%\Claude\claude_desktop_config.json (Windows)
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, 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 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.
McpServer (15 tools), two transports.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.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.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.Authorization: Bearer.That's it β the md-log service itself is hosted at https://app.md-log.com; there is nothing to
install or self-host.
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). |
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.
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.
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:
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: μΉ μ±μμ λ°κΈλ°μ MCP ν€(PAT) λ‘ URL μ°κ²°(κΆμ₯) λλ
npxλ‘컬 μ°κ²° (Claude Code Β· Desktop Β· Codex Β· Cursor).
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.)
Over the remote endpoint, embed images inline (base64); uploading a local image by path
(file_path) works only with the local method below.
npx)Runs this connector as a local subprocess (needs Node 22+; npx fetches the published package, nothing
to build). Use it if you prefer a local process, need local-file (file_path) image uploads, or
self-host md-log without a hosted MCP endpoint.
Mint & secure the PAT. Create it in the web Settings β Tokens (it is shown only once) and keep it out of version control β prefer the OS keychain. On macOS, for example:
If a PAT leaks, revoke it in the web app and mint a new one.
The second bin, md-log-mcp-http, serves the same 15 tools over MCP's
Streamable HTTP transport β a single
POST /mcp endpoint β so agents connect by URL with no local install. Use it when you want to
host the connector centrally (a container / small VM behind a TLS reverse proxy) instead of every
user running npx.
How it differs from stdio:
Authorization: Bearer <mdlog_pat_β¦> header, so one endpoint serves many users β each with
their own md-log token. (MDLOG_PAT is ignored in this mode.)file_path image source is refused (it would read the server's disk);
send images inline as data_base64. Everything else is identical.| Variable | Required | Default | Notes |
|---|---|---|---|
MDLOG_API_BASE_URL | yes | β | Hosted md-log base, including /api/v1. |
MDLOG_HTTP_HOST | no | 127.0.0.1 | Bind interface. Localhost-only by default; set 0.0.0.0 only behind a TLS reverse proxy. |
MDLOG_HTTP_PORT | no | 8787 | TCP port. |
MDLOG_HTTP_PATH | no | /mcp | The MCP endpoint path. |
MDLOG_HTTP_ALLOWED_ORIGINS | no | (none) | Comma-separated browser Origin allowlist (DNS-rebinding defense). A request that carries an Origin not on the list is 403d; non-browser clients (no Origin) are always allowed. |
MDLOG_HTTP_ALLOWED_HOSTS | no | (none) | Optional comma-separated Host allowlist (extra DNS-rebinding defense). |
MDLOG_HTTP_MAX_BODY_BYTES | no | 33554432 (32 MiB) | Max request body (base64 images inflate ~33%). |
Security posture (per the MCP spec): binds to 127.0.0.1 by default, requires a Bearer token on
every MCP request, validates Origin against the allowlist to defeat DNS-rebinding, and caps the body
size. A GET /health liveness probe (no auth) returns {"status":"ok"}. GET/DELETE on the MCP
endpoint return 405 (stateless: no standalone SSE stream, no session to terminate).
Client config shape varies (Claude Code / Cursor / etc.) β the essentials are the endpoint URL and an
Authorization: Bearer <PAT>header. Always terminate TLS in front of a public deployment; the PAT rides on every request.
npm run build β bundle to dist/server.js (stdio) + dist/http.js (Streamable HTTP) (tsup, ESM, Node 22).npm run dev β rebuild on change (tsup --watch).npm run typecheck β tsc --noEmit.npm run smoke β stdio smoke test against a live backend (needs env + a build).npm run smoke:http β backend-free HTTP-transport smoke test (handshake + auth/origin/file_path guards).npm start β run the built stdio server (node dist/server.js).npm run start:http β run the built HTTP server (node dist/http.js).Showcase your server listing on GitHub or your project documentation. Embed this dynamic SVG badge to highlight official listing status and live engagement.
[](https://allmcps.com/mcp/md-log-mcp)<a href="https://allmcps.com/mcp/md-log-mcp"><img src="https://allmcps.com/api/badge/md-log-mcp?style=directory" alt="Md Log Mcp on AllMCPs" /></a>