5.3K
Unofficial Multi-Architecture Docker Image for Narsil MCP Server
This is an unofficial, community-maintained Docker image that packages the Narsil MCP Server for containerized deployment. It enables AI agents (Claude Code, VS Code Copilot, Cursor, Windsurf, etc.) to perform deep code intelligence via the Model Context Protocol (MCP).
Upstream: github.com/postrv/narsil-mcp (MIT OR Apache-2.0)
| Category | Examples |
|---|---|
| Repository & File Management | list_repos, get_project_structure, get_file, reindex |
| Symbol Search & Navigation | find_symbols, get_symbol_definition, find_references |
| Code Search | search_code, semantic_search, hybrid_search, find_similar_code |
| Call Graph Analysis | get_call_graph, get_callers, get_callees, get_complexity |
| Security Analysis | find_injection_vulnerabilities, scan_security, check_owasp_top10 |
| Supply Chain Security | generate_sbom, check_dependencies, check_licenses |
| Git Integration | get_blame, get_file_history, get_hotspots, get_contributors |
| Neural Semantic Search | neural_search, find_semantic_clones |
| Type Inference | infer_types, check_type_errors |
| Data Flow Analysis | get_data_flow, find_dead_code, find_dead_stores |
| SPARQL / Knowledge Graph | sparql_query, get_ccg_manifest, export_ccg |
Your support encourages me to keep creating/supporting my open-source projects. If you found value in this project, you can buy me a coffee to keep me inspired.
CRITICAL: Do NOT expose this container directly to the internet without proper security measures (reverse proxy, SSL/TLS, authentication, firewall rules).
services:
narsil-mcp:
image: mekayelanik/narsil-mcp:latest
container_name: narsil-mcp
restart: unless-stopped
ports:
- "8010:8010"
# Optional: HTTP visualization frontend (requires NARSIL_HTTP=true)
# - "3000:3000"
volumes:
- /path/to/your/repos:/data:ro
- narsil-cache:/home/narsil/.cache # Persist embedding model cache
environment:
- PORT=8010
- INTERNAL_PORT=38011
- PUID=1000
- PGID=1000
- TZ=UTC
- NODE_ENV=production
- PROTOCOL=SHTTP
- ENABLE_HTTPS=false
- HTTP_VERSION_MODE=auto
- DATA_DIR=/data
- NARSIL_GIT=true
- NARSIL_CALL_GRAPH=true
- NARSIL_PERSIST=true
- NARSIL_STREAMING=true
# Optional: Neural semantic search
# - NARSIL_NEURAL=true
# - VOYAGE_API_KEY=your-voyage-key
# Optional: HTTP visualization frontend
# - NARSIL_HTTP=true
# - NARSIL_HTTP_PORT=3000
# Optional: require Bearer token auth at HAProxy layer
# - API_KEY=replace-with-strong-secret
# Optional: CORS origins
# - CORS=*
volumes:
narsil-cache:
driver: local
docker volume create narsil-cache
docker run -d \
--name=narsil-mcp \
--restart=unless-stopped \
-p 8010:8010 \
-v /path/to/your/repos:/data:ro \
-v narsil-cache:/home/narsil/.cache \
-e PORT=8010 \
-e PROTOCOL=SHTTP \
-e NARSIL_GIT=true \
-e NARSIL_CALL_GRAPH=true \
-e NARSIL_PERSIST=true \
mekayelanik/narsil-mcp:latest
# With HTTP visualization frontend enabled:
docker volume create narsil-cache
docker run -d \
--name=narsil-mcp \
--restart=unless-stopped \
-p 8010:8010 \
-p 3000:3000 \
-v /path/to/your/repos:/data:ro \
-v narsil-cache:/home/narsil/.cache \
-e PORT=8010 \
-e PROTOCOL=SHTTP \
-e NARSIL_GIT=true \
-e NARSIL_CALL_GRAPH=true \
-e NARSIL_PERSIST=true \
-e NARSIL_HTTP=true \
mekayelanik/narsil-mcp:latest
| Service | Endpoint | Description |
|---|---|---|
| MCP (SHTTP) | http://host-ip:8010/mcp | Streamable HTTP MCP endpoint (recommended) |
| MCP (SSE) | http://host-ip:8010/sse | Server-Sent Events MCP endpoint |
| HTTP Frontend | http://host-ip:3000 | Visualization frontend (requires NARSIL_HTTP=true) |
| Health | http://host-ip:8010/healthz | Health check endpoint |
When HTTPS is enabled (ENABLE_HTTPS=true), use TLS endpoints:
| Service | Endpoint |
|---|---|
| MCP (SHTTP) | https://host-ip:8010/mcp |
| MCP (SSE) | https://host-ip:8010/sse |
| MCP (WS) | wss://host-ip:8010/message |
Security Warning: The container defaults to HTTP (
ENABLE_HTTPS=false) for easier local setup. UseENABLE_HTTPS=truewith your own certificates for production. See CERTIFICATE_SETUP_GUIDE.md for instructions.
| Variable | Default | Possible Values | Description |
|---|---|---|---|
PORT | 8010 | 1-65535 | External HAProxy listening port |
INTERNAL_PORT | 38011 | 1-65535 | Internal mcp-proxy port (do not expose) |
PROTOCOL | SHTTP | SHTTP, SSE | MCP transport. mcp-proxy exposes both /mcp and /sse simultaneously; this flag chooses the default routed path. WS removed (unsupported by mcp-proxy) |
MCP_PROXY_STATELESS | false | true, false | mcp-proxy mode. false=stateful (shared stdio child, no TTL — required for narsil's index-ready gate); true=per-request isolation (memory-hostile, breaks indexing) |
NARSIL_MAX_MEM_MB | 0 | 0-N | prlimit --as MiB cap per narsil stdio child (0=off) |
HAPROXY_FRONTEND_MAXCONN | 0 | 0-N | HAProxy frontend max concurrent client conns (0=off) |
HAPROXY_SERVER_MAXCONN | 0 | 0-N | HAProxy→mcp-proxy max concurrent conns (0=off) |
PUID | 1000 | Any valid UID | Process user ID |
PGID | 1000 | Any valid GID | Process group ID |
TZ | UTC | Any timezone | Container timezone |
NODE_ENV | (empty) | production, etc. | Deployment mode flag (triggers HTTPS-off security warning when set to production) |
DATA_DIR | /data | Any path | Directory for mounted repositories |
| Variable | Default | Possible Values | Description |
|---|---|---|---|
NARSIL_GIT | false | true, false | Enable git blame, history, contributors |
NARSIL_CALL_GRAPH | false | true, false | Enable function call graph analysis |
NARSIL_PERSIST | false | true, false | Save index to disk for fast startup |
NARSIL_WATCH | false | true, false | Auto-reindex on file changes |
NARSIL_LSP | false | true, false | Enable LSP for hover, go-to-definition |
NARSIL_STREAMING | false | true, false | Stream large result sets |
NARSIL_REMOTE | false | true, false | Enable GitHub remote repo support |
NARSIL_NEURAL | false | true, false | Enable neural semantic embeddings |
NARSIL_GRAPH | false | true, false | Enable SPARQL/RDF knowledge graph and CCG tools |
NARSIL_VERBOSE | false | true, false | Enable verbose logging |
NARSIL_REINDEX | false | true, false | Force re-index on startup (once per container lifecycle) |
NARSIL_HTTP | false | true, false | Enable visualization frontend HTTP server |
| Variable | Default | Possible Values | Description |
|---|---|---|---|
NARSIL_INDEX_PATH | ~/.cache/narsil-mcp | Any path | Custom persistent index storage path |
NARSIL_DISCOVER | (empty) | Directory path | Auto-discover repositories in a directory path |
NARSIL_REPOS_MODE | auto | auto, single, subdirs | How DATA_DIR is interpreted. auto=single if DATA_DIR/.git exists else subdirs; subdirs=each immediate subdir is a separate --repos |
NARSIL_HTTP_PORT | 3000 | 1-65535 | HTTP visualization frontend port |
NARSIL_NO_CACHE | false | true, false | Disable analysis caching |
NARSIL_CACHE_TTL | 1800 | Integer (seconds) | Cache TTL in seconds |
NARSIL_GRAPH_PATH | <index_path>/graph | Any path | Custom knowledge graph storage path |
NARSIL_NEURAL_BACKEND | api | api, onnx | Neural embedding backend |
NARSIL_NEURAL_MODEL | voyage-code-2 | voyage-code-2, text-embedding-3-large, etc. | Embedding model name |
NARSIL_NEURAL_DIMENSION | (auto) | Integer (e.g. 3072) | Override embedding dimensions |
NARSIL_PRESET | (empty) | minimal, balanced, full, security-focused | Tool preset profile |
NARSIL_ENABLED_CATEGORIES | (empty) | Comma-separated | Enable specific tool categories |
NARSIL_DISABLED_TOOLS | (empty) | Comma-separated | Disable specific tools |
| Variable | Default | Description |
|---|---|---|
EMBEDDING_API_KEY | (empty) | Generic API key for any embedding provider |
VOYAGE_API_KEY | (empty) | Voyage AI specific API key |
OPENAI_API_KEY | (empty) | OpenAI specific API key |
EMBEDDING_SERVER_ENDPOINT | (empty) | Custom embedding API endpoint URL |
GITHUB_TOKEN | (empty) | PAT for NARSIL_REMOTE=true. repo scope enables private repos; raises GitHub API rate limit from 60/h to 5000/h |
Neural embeddings are optional. Without NARSIL_NEURAL=true, all 80+ core tools work (symbol search, call graphs, security scanning, SBOM, git analysis, type inference, data flow, SPARQL, etc.). Only neural_search and find_semantic_clones require embeddings.
NARSIL_NEURAL=true + NARSIL_NEURAL_BACKEND=api + an API key. Default model is voyage-code-2 (1024 dims).NARSIL_NEURAL_BACKEND=onnx. Requires manually downloading the model via optimum-cli export onnx. Does not auto-download.narsil-cache volume at /home/narsil/.cache persists model files and ONNX caches across restarts.API backend examples:
# Voyage AI
- NARSIL_NEURAL=true
- NARSIL_NEURAL_BACKEND=api
- NARSIL_NEURAL_MODEL=voyage-code-2
- VOYAGE_API_KEY=your-voyage-key
# OpenAI
- NARSIL_NEURAL=true
- NARSIL_NEURAL_BACKEND=api
- NARSIL_NEURAL_MODEL=text-embedding-3-small
- OPENAI_API_KEY=sk-your-key
# Custom OpenAI-compatible endpoint (e.g., self-hosted embedding server)
- NARSIL_NEURAL=true
- NARSIL_NEURAL_BACKEND=api
- NARSIL_NEURAL_MODEL=Snowflake/snowflake-arctic-embed-xs
- EMBEDDING_SERVER_ENDPOINT=http://your-embedder-host:port/v1
- EMBEDDING_API_KEY=your-key-or-unused
- NARSIL_NEURAL_DIMENSION=384
| Preset | Tools | Description |
|---|---|---|
minimal | 26 | Fast, lightweight (Zed, Cursor) |
balanced | 51 | Good defaults (VS Code, IntelliJ) |
full | 75+ | All features (Claude Desktop, comprehensive analysis) |
security-focused | varies | Security and supply chain tools |
| Variable | Default | Possible Values | Description |
|---|---|---|---|
API_KEY | (empty) | 5-256 printable chars | Bearer token for HAProxy authentication |
CORS | (empty) | Origins (comma-separated) or * | Allowed CORS origins |
ENABLE_HTTPS | false | true, false | Enable TLS termination |
TLS_CERT_PATH | /etc/haproxy/certs/server.crt | File path | TLS certificate path |
TLS_KEY_PATH | /etc/haproxy/certs/server.key | File path | TLS private key path |
TLS_MIN_VERSION | TLSv1.3 | TLSv1.2, TLSv1.3 | Minimum TLS version |
HTTP_VERSION_MODE | auto | auto, h1, h2, h3, h1+h2, all | HTTP version negotiation |
RATE_LIMIT | 0 | 0-N | Max requests per RATE_LIMIT_PERIOD per IP (0 = disabled) |
RATE_LIMIT_PERIOD | 10s | 10s, 1m, 1h, etc. | Sliding window for rate limiting |
MAX_CONNECTIONS_PER_IP | 0 | 0-N | Max concurrent connections per IP (0 = disabled) |
IP_ALLOWLIST | (empty) | Comma-separated IPs/CIDRs | IPs/CIDRs to allow (all others blocked) |
IP_BLOCKLIST | (empty) | Comma-separated IPs/CIDRs | IPs/CIDRs to block |
Boolean values:
true,1,yes,onare all accepted as truthy. Everything else is falsy.
Once per container lifecycle:
NARSIL_REINDEXruns only once after the container is created. It is skipped on subsequent restarts (e.g., crash recovery,docker restart). To re-trigger, recreate the container (docker compose down && docker compose up -d).
Healthcheck: The container's healthcheck has a 450-second start period to accommodate the index-ready gate (see
WAIT_FOR_INDEXbelow) plus initial indexing/model loading.
| Variable | Default | Description |
|---|---|---|
WAIT_FOR_INDEX | true | Block HAProxy startup until narsil finishes initial indexing. Set false for empty-repo dev setups |
INDEX_READY_TIMEOUT | 300 | Seconds to wait for indexing before giving up and starting HAProxy anyway |
NARSIL_KEEPALIVE | true | Periodic tools/list ping to keep the embedded narsil web UI HTTP server reachable. Insurance only — mcp-proxy stateful has no server-side TTL |
KEEPALIVE_INTERVAL | 240 | Seconds between keepalive pings |
API_KEY to enforce auth at the reverse proxy level.Authorization: Bearer <API_KEY>./healthz and CORS preflight (OPTIONS) bypass authentication.RATE_LIMIT=100 to allow 100 requests per RATE_LIMIT_PERIOD (default 10s) per IP. Exceeding the limit returns HTTP 429 with a Retry-After header.MAX_CONNECTIONS_PER_IP=50 to cap concurrent connections per IP. Exceeding returns HTTP 429.IP_BLOCKLIST=192.0.2.0/24,198.51.100.5 to block specific IPs/CIDRs. Blocked IPs receive HTTP 403.IP_ALLOWLIST=10.0.0.0/8,192.168.1.0/24 to allow only listed IPs/CIDRs. All others receive HTTP 403. Localhost is always allowed.For ad-hoc operations without setting env vars, use docker exec:
docker exec narsil-mcp narsil-mcp --repos /data --reindex # Force full re-index
Mount your repository directories to /data (or the path specified by DATA_DIR). Each subdirectory becomes an indexable repository.
volumes:
# Mount entire projects directory
- /home/user/projects:/data:ro
# Or mount individual repositories
- /home/user/my-rust-app:/data/my-rust-app:ro
- /home/user/my-node-app:/data/my-node-app:ro
Then tell your AI agent to analyze using the mounted path:
/data/my-rust-app"/data/my-node-app"/data/my-rust-app"main in /data/my-node-app"Add to ~/.claude.json under mcpServers:
{
"mcpServers": {
"narsil": {
"type": "sse",
"url": "http://host-ip:8010/sse"
}
}
}
Or for Streamable HTTP:
{
"mcpServers": {
"narsil": {
"type": "http",
"url": "http://host-ip:8010/mcp"
}
}
}
All use the same JSON format. Configure in the respective config file:
.vscode/settings.json (key: mcp.servers)~/.codex/config.json (key: mcpServers)~/.cursor/mcp.json (key: mcpServers).codeium/mcp_settings.json (key: mcpServers){
"mcpServers": {
"narsil": {
"transport": "http",
"url": "http://host-ip:8010/mcp"
}
}
}
| Tag | Platform | Description |
|---|---|---|
latest | amd64, arm64 | Latest stable release |
1.7.0 | amd64, arm64 | Specific version |
This Docker image packaging is licensed under the GNU General Public License v3.0.
This is an unofficial community packaging. It is NOT affiliated with, endorsed by, or supported by the narsil-mcp authors. See NOTICE for full attribution.
Your support encourages me to keep creating/supporting my open-source projects. If you found value in this project, you can buy me a coffee to keep me inspired.
Mohammad Mekayel Anik
Content type
Image
Digest
sha256:4a10b87ee…
Size
102.5 MB
Last updated
about 1 month ago
docker pull mekayelanik/narsil-mcp