使用说明
Narsil MCP Server - Docker Image
Unofficial Multi-Architecture Docker Image for Narsil MCP Server
Overview
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)
Key Features
- Multi-Architecture Support - Native support for x86-64 and ARM64
- Modern MCP Bridge - mcp-proxy stdio↔StreamableHTTP/SSE; stateful, one shared child per session (no spawn-per-request leak)
- 90 Code Intelligence Tools - Symbol search, call graphs, security analysis, SBOM, and more
- 32 Language Support - Rust, Python, TypeScript, Go, Java, C#, and 26 more via Tree-sitter
- Secure by Design - API key auth (case-insensitive Bearer), CORS, TLS termination, security headers
- High Performance - HAProxy with QUIC/HTTP3 support, ZSTD compression
Available Narsil MCP Tool Categories
| 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 |
Buy Me a Coffee
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.
Quick Start
Prerequisites
- Docker Engine: 23.0+
CRITICAL: Do NOT expose this container directly to the internet without proper security measures (reverse proxy, SSL/TLS, authentication, firewall rules).
Docker Compose (Recommended)
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 Run
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
Access Endpoints
| 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.
Configuration
Complete Environment Variables Reference
Core Settings
| 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 |
Narsil MCP Feature Flags
| 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 |
Narsil MCP String Settings
| 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 |
Neural Embedding API Keys
| 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 Embedding Notes
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.
- API backend (default): Set
NARSIL_NEURAL=true+NARSIL_NEURAL_BACKEND=api+ an API key. Default model isvoyage-code-2(1024 dims). - ONNX backend (local, no API key): Set
NARSIL_NEURAL_BACKEND=onnx. Requires manually downloading the model viaoptimum-cli export onnx. Does not auto-download. - Cache persistence: The
narsil-cachevolume at/home/narsil/.cachepersists 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
Narsil MCP Presets
| 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 |
Security Settings
| 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.
Gateway & Startup Lifecycle
| 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 Authentication Notes
- Set
API_KEYto enforce auth at the reverse proxy level. - Header:
Authorization: Bearer <API_KEY>. /healthzand CORS preflight (OPTIONS) bypass authentication.
Rate Limiting and IP Access Control
- Rate limiting: Set
RATE_LIMIT=100to allow 100 requests perRATE_LIMIT_PERIOD(default10s) per IP. Exceeding the limit returns HTTP 429 with aRetry-Afterheader. - Connection limiting: Set
MAX_CONNECTIONS_PER_IP=50to cap concurrent connections per IP. Exceeding returns HTTP 429. - IP blocklist: Set
IP_BLOCKLIST=192.0.2.0/24,198.51.100.5to block specific IPs/CIDRs. Blocked IPs receive HTTP 403. - IP allowlist: Set
IP_ALLOWLIST=10.0.0.0/8,192.168.1.0/24to allow only listed IPs/CIDRs. All others receive HTTP 403. Localhost is always allowed. - All features default to disabled. Combine as needed — blocklist is checked before allowlist.
One-Shot Operations
For ad-hoc operations without setting env vars, use docker exec:
docker exec narsil-mcp narsil-mcp --repos /data --reindex # Force full re-index
Mounting Repositories for Analysis
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:
- "Search for symbols in
/data/my-rust-app" - "Find injection vulnerabilities in
/data/my-node-app" - "Generate an SBOM for
/data/my-rust-app" - "Get the call graph for
mainin/data/my-node-app"
MCP Client Configuration
Claude Code
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"
}
}
}
VS Code / Codex / Cursor / Windsurf
All use the same JSON format. Configure in the respective config file:
- VS Code:
.vscode/settings.json(key:mcp.servers) - Codex:
~/.codex/config.json(key:mcpServers) - Cursor:
~/.cursor/mcp.json(key:mcpServers) - Windsurf:
.codeium/mcp_settings.json(key:mcpServers)
{
"mcpServers": {
"narsil": {
"transport": "http",
"url": "http://host-ip:8010/mcp"
}
}
}
Available Tags
| Tag | Platform | Description |
|---|---|---|
latest |
amd64, arm64 |
Latest stable release |
1.7.2 |
amd64, arm64 |
Specific version |
License
This Docker image packaging is licensed under the GNU General Public License v3.0.
Upstream Licenses
- Narsil MCP Server: MIT License OR Apache License 2.0 - Copyright (c) 2024 postrv
- mcp-proxy: MIT License (stdio↔SHTTP/SSE bridge; replaces supergateway)
- HAProxy: GNU General Public License v2.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.
Buy Me a Coffee
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.
Maintainer
Mohammad Mekayel Anik
- Docker Hub: mekayelanik
- GitHub: MekayelAnik
