npm md-log-mcpstdioMITupdated 1mo ago
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.
O que dá para fazer com md log mcp?
md-log-mcp
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.
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 theAuthorizationheader. See 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-infetch/httpare 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
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:
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: 웹 앱에서 발급받은 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.)
# Claude Code
claude mcp add --transport http md-log https://mcp.md-log.com/mcp \
--header "Authorization: Bearer mdlog_pat_xxxxxxxxxxxxxxxxxxxxxxxx"
// 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 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.
{
"mcpServers": {
"md-log": {
"command": "npx",
"args": ["-y", "md-log-mcp"],
"env": {
"MDLOG_API_BASE_URL": "https://app.md-log.com/api/v1",
"MDLOG_PAT": "mdlog_pat_xxxxxxxxxxxxxxxxxxxxxxxx"
}
}
}
}
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:
security add-generic-password -a "$USER" -s md-log-pat -w "mdlog_pat_xxxx" export MDLOG_PAT="$(security find-generic-password -a "$USER" -s md-log-pat -w)"If a PAT leaks, revoke it in the web app and mint a new one.
Remote (Streamable HTTP) mode
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:
- PAT per request. The token is not read from env; each request carries its own
Authorization: Bearer <mdlog_pat_…>header, so one endpoint serves many users — each with their own md-log token. (MDLOG_PATis ignored in this mode.) - Stateless. A fresh client + server per request; no session store (replica / autoscale friendly).
- No local files. The
file_pathimage source is refused (it would read the server's disk); send images inline asdata_base64. Everything else is identical.
Run it
npm run build
MDLOG_API_BASE_URL="https://app.md-log.com/api/v1" \
node dist/http.js # or: npm run start:http
# → md-log-mcp-http ready — POST http://127.0.0.1:8787/mcp
Configuration (env)
| 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).
Connect an agent by URL
{
"mcpServers": {
"md-log": {
"type": "http",
"url": "https://your-host.example/mcp",
"headers": { "Authorization": "Bearer mdlog_pat_xxxxxxxxxxxxxxxxxxxxxxxx" }
}
}
}
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.
Scripts
npm run build— bundle todist/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).
Instalação
Adicione md log mcp ao seu cliente. Escolha o que você usa.
claude mcp add md-log-mcp -- npx -y md-log-mcpcodex mcp add md-log-mcp -- npx -y md-log-mcpamp mcp add md-log-mcp -- npx -y md-log-mcp{
"mcpServers": {
"md-log-mcp": {
"command": "npx",
"args": [
"-y",
"md-log-mcp"
]
}
}
}Add to `claude_desktop_config.json`, then restart Claude Desktop.
{
"mcpServers": {
"md-log-mcp": {
"command": "npx",
"args": [
"-y",
"md-log-mcp"
]
}
}
}Add to `~/.cursor/mcp.json`, or `.cursor/mcp.json` for a single project.
code --add-mcp '{"name":"md-log-mcp","command":"npx","args":["-y","md-log-mcp"]}'Or add the block manually to `.vscode/mcp.json` under `servers`.
{
"mcpServers": {
"md-log-mcp": {
"command": "npx",
"args": [
"-y",
"md-log-mcp"
]
}
}
}Add to `~/.codeium/windsurf/mcp_config.json`.
{
"mcpServers": {
"md-log-mcp": {
"command": "npx",
"args": [
"-y",
"md-log-mcp"
]
}
}
}Add to `cline_mcp_settings.json` via the MCP Servers panel.
{
"mcpServers": {
"md-log-mcp": {
"command": "npx",
"args": [
"-y",
"md-log-mcp"
]
}
}
}Add to `~/.gemini/settings.json`.
{
"mcpServers": {
"md-log-mcp": {
"type": "local",
"command": "npx",
"args": [
"-y",
"md-log-mcp"
],
"tools": [
"*"
]
}
}
}Add to `~/.copilot/mcp-config.json`, or run `/mcp add` inside the CLI.
{
"context_servers": {
"md-log-mcp": {
"command": {
"path": "npx",
"args": [
"-y",
"md-log-mcp"
]
}
}
}
}Add to your Zed `settings.json`.
npx -y md-log-mcpRun `goose configure`, choose **Add Extension → Command-line Extension**, and paste this command.
14 ferramentas
md log mcp expõe 14 ferramentas a um agente conectado.
- 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`).
Pontuação
80 / 100
Excelente
- Documentação25/25
- Manutenção22/25
- Confiança13/20
- Capacidade8/15
- Instalação12/15
- Documents what it does and how to connect
- Has a resolvable package or endpoint
- Exposes at least one tool, prompt or resource
- README has substantive content
- Includes a code example
- Documents its configuration
- Mentions credentials or security posture
- Last commit 36 days ago
- Has a release history
- Repository is not archived
- Licensed MIT
- Namespace verified in the official MCP registry
- Claimed by its owner
- Published under an organisation
- 14 tool(s) documented
- Provides prompt templates
- Provides resources
- 12 documented install method(s)
- Published to a package registry
- Offers a hosted endpoint — no local install
Histórico de versões
| Versões | Publicada |
|---|---|
| 1.1.4Mais recente | 27 de jul. de 2026 |
| 1.1.3 | 23 de jul. de 2026 |
| 1.1.2 | 22 de jul. de 2026 |
| 1.1.1 | 16 de jul. de 2026 |
| 1.1.0 | 16 de jul. de 2026 |
| 1.0.8 | 14 de jul. de 2026 |