Security model¶
This page states what markdown-vault-mcp protects and what it leaves to the operator. Authentication covers how to configure each mode, and SECURITY.md in the repository covers how to report a vulnerability.
Authentication is the boundary¶
Over HTTP, authentication is the only access control: a bearer token, a mapped bearer token file, or OIDC. A request without a valid credential is refused before it reaches a tool. It is the same model as any other MCP server reached over HTTP.
With OIDC, which credentials the server accepts depends on the mode:
oidc-proxy: the server is the OAuth client registered with the identity provider and runs the sign-in itself. Anyone the provider lets sign in to that client gets through.remote: the server is a resource server. MCP clients get tokens from the provider on their own, and the server accepts any unexpired token the provider's issuer signed, unlessMARKDOWN_VAULT_MCP_OIDC_AUDIENCEorMARKDOWN_VAULT_MCP_OIDC_REQUIRED_SCOPESnarrows that down.
The server keeps no list of allowed users, so every caller it accepts has the full tool surface. Limit who can get a credential at the provider, and in remote mode set the audience.
Running without authentication¶
With no authentication variables set, the server starts in mode none and logs auth_mode_resolved at warning level with mode=none. Every client that can open a connection to the port then has the full tool surface. Turning authentication off is a decision to trust everything that can reach the port.
The bind address decides which machines reach the port, and nothing more. Binding to 127.0.0.1 keeps other machines out. It does not keep out other processes on the host, nor a web page in a browser on the host that uses DNS rebinding. Without authentication, run the server only where everything that reaches the port is trusted, such as a single-user workstation or a private network you control.
stdio¶
Over stdio there is no network listener and no authentication. The MCP client starts the server as a child process, and the server trusts that client. Authentication variables have no effect there, and the server logs auth_configured_but_stdio_skips_enforcement when they are set.
What an authenticated caller can reach¶
An authenticated caller has every tool the instance exposes. Each tool runs with the server's own privileges: its filesystem and network access, and any credential in its configuration. MARKDOWN_VAULT_MCP_TOOLS_ALLOW and MARKDOWN_VAULT_MCP_TOOLS_DENY trim that set for an instance; see Configuration.
Every tool works inside the vault directory the server serves, and a path that resolves outside it is refused. Read tools such as search, read and get_history only read the vault. Write tools (write, edit, append, delete, rename, move_folder, fetch and the OKF write tools) change files in it. MARKDOWN_VAULT_MCP_READ_ONLY=true hides every write tool. reindex and build_embeddings stay available in that mode, since they rebuild the index and leave notes untouched.
Some tools send data beyond the vault:
fetchdownloads anhttporhttpsURL the caller names and saves the response in the vault. Only publicly routable addresses are allowed, on the first request and on every redirect, and proxy settings from the environment don't apply.- Embeddings. With a remote embedding provider (OpenAI-compatible, Voyage, or Ollama on another host), indexing sends note text to that provider, and
searchsends the query text. The local fastembed provider sends nothing. summarizesends the notes it summarizes to the OpenAI-compatible endpoint set inMARKDOWN_VAULT_MCP_SUMMARIZE_OPENAI_BASE_URL. Without a configured endpoint the tool is hidden.- Git. With a remote configured, the server pushes to it after writes and pulls from it on a timer, and
git_synclets a caller start either direction.
Callers never pass credentials to these tools. The server uses its own: MARKDOWN_VAULT_MCP_GIT_TOKEN for an HTTPS remote, or the host's SSH setup for an SSH remote, and the API keys of the embedding provider and the summarize endpoint.
What answers without a credential¶
Some routes answer anyone who can reach the port, with authentication on or off:
/healthand/health/ready.MARKDOWN_VAULT_MCP_HEALTH_DETAILdecides how much they say; see Health.- In the OIDC modes, the OAuth metadata and sign-in routes a client uses before it holds a token.
- On a server with transfer links,
/transfer/{token}. The token in the URL is the credential, good for one transfer of one file before it expires; Transfer links says what the server accepts on it.
What the operator is responsible for¶
- TLS. The server speaks plain HTTP. Terminate TLS at a reverse proxy in front of it.
- Exposure. Which interfaces and networks can reach the port. Ports covers the published port of the Docker deployment.
- Secrets. Bearer tokens, OIDC client secrets and the credentials the tools use live in the environment or in files you control. Anyone who can read them can act as the server.
- Token lifetimes. Under OIDC, a leaked access or ID token stays usable until it expires, because the server checks expiry and signature but not revocation; a refresh token stays usable until it expires or you revoke it at the provider. The lifetimes you set on the provider are that exposure window; Authentication gives the trade-off.
- The debugger port. A debug build's debugger port grants code execution to anyone who reaches it; see Remote debugging.
Host and Origin validation¶
FastMCP can refuse requests whose Host or Origin header does not name the server, which blocks DNS rebinding against a server running without authentication. It is off by default, and the model above does not depend on it. To turn it on, set FASTMCP_HTTP_HOST_ORIGIN_PROTECTION to auto, which checks requests that reach the server on a local address, or to true, which checks every request against FASTMCP_HTTP_ALLOWED_HOSTS (a JSON list of host names). Behind a reverse proxy, test it before relying on it: a request whose headers do not match is refused.
Reporting a vulnerability¶
Read this page before reporting. A finding that depends on authentication being off describes the configuration above rather than a flaw in the server. SECURITY.md covers the reporting channel, scope and response targets.
Routes that carry their own credential¶
One more kind of route answers without an MCP credential, and checks a credential of its own instead.
- Git webhooks.
/github-webhookand/gitlab-webhookexist only when a webhook secret is set. A request must carry a valid signature or token for that secret, and a valid push event makes the server pull and reindex; see Webhooks.