QMD MCP
Provides search and document retrieval over collections of Markdown files, with lexical and optional semantic search, reranking, and scheduled index maintenance.
Click on "Deploy Server".
Wait a few minutes for the server to deploy. Once ready, it will show a "Started" state.
In the chat, type
@followed by the MCP server name and your instructions, e.g., "@QMD MCPsearch for setup instructions for Docker"
That's it! The server will respond to your query, and you can continue using it as needed.
Here is a step-by-step guide with screenshots.
QMD MCP
QMD MCP packages QMD as a long-running Streamable HTTP MCP server. It provides QMD search and document retrieval together with bounded index-maintenance operations, without exposing arbitrary shell execution.
This is a community-maintained integration. It is not affiliated with, endorsed by, or officially maintained by the upstream QMD project.
Feedback and contributions
Use GitHub Issues for bug reports and feature requests and pull requests for proposed changes. See CONTRIBUTING.md for the development workflow, test requirements, and coding conventions. Security issues must follow the private process in SECURITY.md.
Release changes are recorded in CHANGELOG.md.
Related MCP server: Web Search MCP Remote Server
Quick start
The public Docker image is published on GitHub Container Registry (GHCR):
ghcr.io/x1pher/qmd-mcp:v0.1.7The package is public, so Docker does not need a GitHub login to pull it.
For production deployments, use the immutable digest published in the corresponding GitHub Release rather than relying on the version tag alone.
The image supports linux/amd64 and linux/arm64. Each platform image retains only its matching QMD native llama runtime to keep the image bounded.
1. Create the directories
mkdir -p qmd/config qmd/content
cd qmdPut the Markdown files you want QMD to index in content/.
2. Create config/index.yml
global_context: >-
This is a local Markdown knowledge base. Search results are discovery evidence;
read the source document before relying on a material claim.
collections:
notes:
path: /vault
pattern: "**/*.md"
ignore:
- "archive/**"
archive:
path: /vault/archive
pattern: "**/*.md"
includeByDefault: false
append-only-log:
path: /vault/logs
pattern: "history.md"
includeByDefault: false
embedding: falsepath values refer to paths inside the container. The Compose example below mounts ./content at /vault.
embedding: false is a QMD MCP wrapper extension for collections that should remain lexical-only. The files are still indexed and available to explicit lexical (lex) searches, but they are excluded from embedding health and manual start_embed jobs. Use it for large append-only logs or other exact-lookup material where repeatedly rebuilding vectors adds cost without useful semantic recall.
3. Create compose.yml
services:
qmd-mcp:
image: ghcr.io/x1pher/qmd-mcp:v0.1.7
container_name: qmd-mcp
environment:
QMD_FORCE_CPU: "1"
QMD_REFRESH_INTERVAL_MINUTES: "15"
QMD_REFRESH_INITIAL_DELAY_SECONDS: "120"
ports:
- "127.0.0.1:8181:8181"
volumes:
- ./content:/vault:ro
- ./config:/config:ro
- qmd-data:/data
healthcheck:
test:
- CMD
- node
- -e
- >-
fetch('http://127.0.0.1:8181/health')
.then(r=>process.exit(r.ok?0:1))
.catch(()=>process.exit(1))
interval: 30s
timeout: 10s
retries: 5
start_period: 30s
restart: unless-stopped
volumes:
qmd-data:The example binds the HTTP port to loopback only. If another container must call QMD MCP directly, attach both containers to a shared Docker network and use the QMD service name instead of exposing it broadly on the host.
QMD_FORCE_CPU=1 gives a predictable CPU-only deployment. Remove it or set it to 0 if you deliberately want QMD to probe for supported acceleration.
4. Start the container
docker compose up -dCheck the service:
curl --fail http://127.0.0.1:8181/healthThe Streamable HTTP MCP endpoint is:
http://127.0.0.1:8181/mcpDocker CLI alternative
You can run the same release without Compose:
docker volume create qmd-data
docker run -d \
--name qmd-mcp \
--restart unless-stopped \
-p 127.0.0.1:8181:8181 \
-e QMD_FORCE_CPU=1 \
-e QMD_REFRESH_INTERVAL_MINUTES=15 \
-e QMD_REFRESH_INITIAL_DELAY_SECONDS=120 \
-v "$PWD/content:/vault:ro" \
-v "$PWD/config:/config:ro" \
-v qmd-data:/data \
ghcr.io/x1pher/qmd-mcp:v0.1.7What QMD MCP provides
QMD MCP keeps QMD's read-oriented MCP tools and adds bounded administration operations:
healthreports index and runtime state;start_updatestarts a bounded asynchronous filesystem reindex job;start_embedstarts a bounded asynchronous embedding job;job_statusreports recent administration jobs;scheduled refresh updates the lexical/index state only; embeddings run explicitly through
start_embed, whileembedding: falsecollections remain lexical-only;routine
queryruns with reranking disabled;query_rerankedprovides a separate CPU-heavy reranked path;query results can include an exact
source_relative_pathfor authoritative filesystem handoff whenQMD_SOURCE_RELATIVE_ROOTis configured and the source path resolves unambiguously;document retrieval returns internal text by default; user-visible MCP resource exposure requires both
exposeToUser=trueandconfirmUserApprovedExposure=true, and preview/show/open/render/inspect intent is not approval.
Only one administration job runs at a time. Completed jobs are retained in memory with a bounded history. See docs/tools.md for the complete nine-tool reference, including access level and side effects.
Runtime paths
The container uses these stable paths:
Path | Purpose |
| QMD collection configuration |
| QMD index database |
| Runtime home directory |
| Model and runtime cache |
Source collections should normally be mounted read-only. /data must remain writable because it contains the rebuildable index and model/runtime cache.
Configuration
The Dockerfile provides working defaults for the normal runtime paths and HTTP listener. Override only the settings your deployment needs.
Variable | Default | Purpose |
|
| HTTP listen address inside the container |
|
| HTTP listen port |
|
| QMD collection configuration file |
|
| QMD index database |
| unset | Optional common source root. When set, query results include exact, collision-safe |
| unset | Default collection for |
|
| Set to |
| unset | Optional QMD embedding parallelism override |
|
| Default maximum documents per explicit embedding batch; accepted range |
|
| Default maximum explicit embedding batch size in MiB; accepted range |
|
| Maximum embedding session length; accepted range |
|
| Scheduled index-refresh interval; refresh never starts embedding. |
|
| Delay before the first scheduled refresh; accepted range |
Invalid bounded numeric values fail at startup instead of being silently accepted. QMD_SOURCE_RELATIVE_ROOT never exposes its absolute path; only a relative source path is returned, and ambiguous normalized-path collisions return null rather than guessing.
Security model
The container runs as the upstream Node image's unprivileged
nodeuser.Source collections should normally be mounted read-only.
Index and cache state remain separate from source content.
Administration is limited to the exposed job operations. The wrapper calls the QMD store API directly; it does not invoke QMD CLI update hooks or expose arbitrary shell execution.
MCP request bodies are capped at 1 MiB before JSON parsing.
Error messages redact configured index and config paths.
MCP transport is not an authentication layer. Keep it on a trusted network boundary or place it behind an authenticated MCP gateway.
Production deployments should use an immutable release image digest instead of a branch,
latest, or another moving tag.
See SECURITY.md for vulnerability reporting and deployment guidance and docs/SECURE-DEVELOPMENT.md for the secure-design principles, common weakness classes, and review expectations applied to the project.
Upstream relationship
This repository is not a fork of the full QMD source tree. It consumes an exact @tobilu/qmd package version and applies a small fail-closed compatibility patch set during image build. The build fails if an expected upstream patch target no longer matches exactly.
See UPSTREAM.md for the current upstream version, patch inventory, and update process.
Validation
The container build is the primary validation boundary. It installs the locked dependency set, applies every upstream patch, runs the complete unit/property test suite, performs JavaScript syntax checks, and prunes development-only dependencies before the runtime stage. CI also starts the image, initializes the MCP protocol, verifies the exact nine-tool surface, runs a real index update against a temporary Markdown collection, and verifies the resulting document count.
Dependency and base-image updates are proposed by Dependabot. A QMD update is accepted only after the image build and functional release acceptance pass against the proposed version.
Releases
Versions use SemVer tags such as v0.1.7. A release must point to an exact CI-green commit. The tag-triggered Release workflow:
verifies that the tag matches
package.json;builds the
linux/amd64andlinux/arm64images and publishes one multi-architecture tag;publishes it to GHCR;
records the immutable image digest;
publishes SBOM/provenance and a GitHub attestation;
creates the corresponding GitHub Release.
Normal CI does not publish images or releases. Release tags are immutable and are never reused for a different commit.
License
QMD MCP's original wrapper code is MIT licensed. QMD and bundled dependencies retain their own licenses. See LICENSE and UPSTREAM.md.
This server cannot be deployed
Maintenance
Related MCP Connectors
QuLab MCP remote server (Streamable HTTP) for computational science and lab tools.
Read-only MCP server for the OrchestKit docs: full-text search + Markdown fetch. No auth.
Host your MCP tool over streamable HTTP in one command.
Remote MCP server exposing SMI Aware tools, resources, and skills over Streamable HTTP.
Related MCP Servers
- AlicenseAqualityDmaintenanceMCP server for markdown files — search, extract sections, list headings, find code blocks across docs.6135 npm5MIT
- AlicenseNot gradedqualityBmaintenanceRemote HTTP/SSE MCP server for web search with full page content extraction, search summaries, and API authentication.MIT
- AlicenseAqualityBmaintenanceMCP server for live web search and clean-markdown page fetch over the Keenable web index.259 npm5MIT
- FlicenseNot gradedqualityDmaintenanceA web search MCP server using DuckDuckGo, supporting streaming HTTP and session management.1-