| name | mcp-narsil |
| description | Deep code intelligence via Narsil MCP providing 76 tools for security scanning (OWASP, CWE, taint analysis), call graph analysis (CFG, DFG, callers/callees), structural queries (symbols, definitions, references), and supply chain security (SBOM, license compliance). Accessed via Code Mode for token efficiency. |
| allowed-tools | Read, Bash, mcp__code_mode__call_tool_chain, mcp__code_mode__search_tools, mcp__code_mode__list_tools |
| version | 1.0.0 |
Narsil MCP - Deep Code Intelligence
Rust-powered code intelligence providing 76 specialized tools for security scanning, call graph analysis, and structural queries. Accessed via Code Mode for token-efficient on-demand access (~700 tokens vs ~6,000-8,000 native).
Core Principle: Unified code intelligence - Narsil handles STRUCTURE, SECURITY, and SEMANTIC search.
1. 🎯 WHEN TO USE
Activation Triggers
Use when:
- Security vulnerability scanning needed (OWASP, CWE, injections)
- Call graph or control flow analysis required
- Finding symbols, definitions, or references
- Dead code detection or complexity analysis
- SBOM generation or license compliance
- Git blame, history, or hotspot analysis
Keyword Triggers:
- Security: "security scan", "vulnerability", "injection", "OWASP", "CWE", "taint"
- Call Graph: "call graph", "callers", "callees", "who calls", "what calls"
- Structure: "find symbols", "find functions", "project structure", "references"
- Quality: "dead code", "unreachable", "complexity", "unused"
- Supply Chain: "SBOM", "dependencies", "licenses", "CVE"
- Git: "git blame", "hotspots", "contributors", "history"
Use Cases
Security Auditing
- Full security scan with OWASP Top 10 and CWE Top 25
- SQL injection, XSS, command injection detection
- Taint analysis tracing untrusted data flow
- Secret and credential detection
Code Understanding
- Project structure overview
- Symbol search (functions, classes, structs)
- Call graph visualization
- Dependency analysis
Code Quality
- Dead code and unreachable code detection
- Complexity metrics (cyclomatic, cognitive)
- Unused assignments and uninitialized variables
Supply Chain Security
- SBOM generation (CycloneDX, SPDX)
- CVE checking against OSV database
- License compliance verification
When NOT to Use
Do not use for:
- Simple text pattern search → Use Grep
- File path/name matching → Use Glob
For semantic search: Use narsil_neural_search - Narsil's neural backend handles meaning-based queries.
2. 🧭 SMART ROUTING
Activation Detection
TASK CONTEXT
│
├─► Security scanning needed
│ └─► Load: references/security_guide.md
│ └─► Tools: scan_security, find_injection_vulnerabilities, trace_taint
│
├─► Call graph / code flow analysis
│ └─► Load: references/call_graph_guide.md
│ └─► Tools: get_call_graph, get_callers, get_callees
│
├─► Quick overview / first use
│ └─► Load: references/quick_start.md
│ └─► Tools: get_project_structure, find_symbols
│
├─► Full tool reference needed
│ └─► Load: references/tool_reference.md
│ └─► All 76 tools documented
│
└─► Simple structural query
└─► Use SKILL.md only
└─► Tools: find_symbols, get_project_structure
Resource Router
def route_narsil_resources(task):
"""
Resource Router for mcp-narsil skill
Load references based on task context
"""
# ──────────────────────────────────────────────────────────────────
# SECURITY SCANNING
# Purpose: OWASP, CWE, injection detection, taint analysis
# Key Insight: Start with scan_security for overview, drill into specifics
# ──────────────────────────────────────────────────────────────────
if task.involves_security or task.mentions_vulnerability:
return load("references/security_guide.md") # Security workflow
# ──────────────────────────────────────────────────────────────────
# CALL GRAPH ANALYSIS
# Purpose: CFG, DFG, callers/callees, complexity metrics
# Key Insight: Start with get_call_graph, then drill with callers/callees
# ──────────────────────────────────────────────────────────────────
if task.involves_call_graph or task.mentions_code_flow:
return load("references/call_graph_guide.md") # Analysis workflow
# ──────────────────────────────────────────────────────────────────
# QUICK START
# Purpose: First-time usage, verification, basic commands
# Key Insight: Fastest path to working state
# ──────────────────────────────────────────────────────────────────
if task.is_first_use or task.needs_verification:
return load("references/quick_start.md") # Getting started
# ──────────────────────────────────────────────────────────────────
# COMPLETE REFERENCE
# Purpose: All 76 tools with descriptions and priority
# Key Insight: Use for discovery or when unsure which tool
# ──────────────────────────────────────────────────────────────────
if task.needs_tool_discovery or task.needs_full_reference:
return load("references/tool_reference.md") # All tools
# Default: SKILL.md covers basic structural queries
# ══════════════════════════════════════════════════════════════════════
# STATIC RESOURCES (always available, not conditionally loaded)
# ══════════════════════════════════════════════════════════════════════
# assets/tool_categories.md → Priority categorization of all 76 tools
# scripts/update-narsil.sh → Script to update Narsil binary
3. 🛠️ HOW IT WORKS
Code Mode Invocation
Narsil is accessed via Code Mode's call_tool_chain() for token efficiency.
Naming Convention:
narsil.narsil_{tool_name}
Process Flow:
STEP 1: Discover Tools
├─ Use search_tools() for capability-based discovery
├─ Use tool_info() for specific tool details
└─ Output: Tool name and parameters
↓
STEP 2: Execute via Code Mode
├─ Use call_tool_chain() with TypeScript code
├─ Await narsil.narsil_{tool_name}({params})
└─ Output: Tool results
↓
STEP 3: Process Results
└─ Parse and present findings
Tool Invocation Examples
Important: Most Narsil tools require a
repoparameter. Uselist_repos()to discover the repo name (typically "unknown" if not explicitly named).
// Discover security tools
search_tools({ task_description: "security vulnerability scanning" });
// Get tool details
tool_info({ tool_name: "narsil.narsil_scan_security" });
// First: Discover repo name
call_tool_chain({
code: `
const repos = await narsil.narsil_list_repos({});
return repos; // Returns repo name (e.g., "unknown")
`
});
// Execute security scan (repo required)
call_tool_chain({
code: `
const findings = await narsil.narsil_scan_security({
repo: "unknown"
});
return findings;
`
});
// Find all functions (repo required, use symbol_type not kind)
call_tool_chain({
code: `
const symbols = await narsil.narsil_find_symbols({
repo: "unknown",
symbol_type: "function"
});
return symbols;
`
});
// Get call graph (repo required, use function not function_name)
call_tool_chain({
code: `
const graph = await narsil.narsil_get_call_graph({
repo: "unknown",
function: "main"
});
return graph;
`
});
// Get symbol definition (repo required, use symbol not name)
call_tool_chain({
code: `
const def = await narsil.narsil_get_symbol_definition({
repo: "unknown",
symbol: "myFunction"
});
return def;
`
});
Unified Code Search
Narsil provides both structural AND semantic search capabilities:
| Query Type | Tool | Reason |
|---|---|---|
| "How does authentication work?" | narsil_neural_search |
Semantic meaning |
| "Find code similar to this" | narsil_neural_search |
Vector similarity |
| "List all auth functions" | narsil_find_symbols |
Structural query |
| "Scan for vulnerabilities" | narsil_scan_security |
Security analysis |
| "Show call graph for login" | narsil_get_call_graph |
Code flow |
Neural Semantic Search
Narsil supports three neural embedding backends for semantic code search:
| Backend | Model | API Key | Dimensions | Best For |
|---|---|---|---|---|
| Voyage AI | voyage-code-2 |
VOYAGE_API_KEY |
1536 | Code search (RECOMMENDED) |
| OpenAI | text-embedding-3-small |
OPENAI_API_KEY |
1536 | General purpose |
| Local ONNX | Built-in | None required | 384 | Offline/privacy |
Configuration Examples:
# Voyage AI (recommended for code)
--neural --neural-backend api --neural-model voyage-code-2
# Requires: VOYAGE_API_KEY in .env
# OpenAI
--neural --neural-backend api --neural-model text-embedding-3-small
# Requires: OPENAI_API_KEY in .env
# Local ONNX (no API key needed)
--neural --neural-backend onnx
# No API key required - runs locally
Tool: narsil_neural_search
Fallback: BM25 search if neural unavailable
// Example: Semantic code search
call_tool_chain({
code: `
const results = await narsil.narsil_neural_search({
query: "how does authentication work",
top_k: 10
});
return results;
`
});
See references/tool_reference.md for complete tool documentation.
Error Handling Patterns
Narsil tools can fail for various reasons. Use these patterns for robust error handling.
Pattern 1: Check Index Status Before Search
call_tool_chain({
code: `
const status = await narsil.narsil_get_index_status({});
if (!status.neural_ready || status.embedding_count === 0) {
console.log("Neural index building, using structural query");
const symbols = await narsil.narsil_find_symbols({
repo: "unknown",
symbol_type: "function",
name_pattern: "auth"
});
return { fallback: true, results: symbols };
}
const results = await narsil.narsil_neural_search({
query: "authentication flow"
});
return { fallback: false, results };
`
});
Pattern 2: Try-Catch with Retry
call_tool_chain({
code: `
try {
const findings = await narsil.narsil_scan_security({ repo: "unknown" });
return { success: true, findings };
} catch (error) {
if (error.message?.includes("not found")) {
await narsil.narsil_reindex({});
const findings = await narsil.narsil_scan_security({ repo: "unknown" });
return { success: true, retried: true, findings };
}
throw error;
}
`,
timeout: 60000
});
Pattern 3: Graceful Degradation
call_tool_chain({
code: `
async function robustSearch(query) {
try {
const neural = await narsil.narsil_neural_search({ query, top_k: 10 });
if (neural.results?.length > 0) return { method: "neural", results: neural.results };
} catch (e) { console.log("Neural unavailable:", e.message); }
try {
const semantic = await narsil.narsil_semantic_search({ repo: "unknown", query });
if (semantic.results?.length > 0) return { method: "semantic", results: semantic.results };
} catch (e) { console.log("Semantic unavailable:", e.message); }
const symbols = await narsil.narsil_find_symbols({
repo: "unknown",
name_pattern: query.split(" ")[0]
});
return { method: "symbols", results: symbols };
}
return await robustSearch("authentication handler");
`
});
4. 📋 RULES
✅ ALWAYS
ALWAYS use Code Mode for Narsil invocation
- Call via
call_tool_chain()with TypeScript - Saves ~5,300 tokens vs native MCP
- Call via
ALWAYS use full tool naming convention
- Format:
narsil.narsil_{tool_name} - Example:
narsil.narsil_scan_security({})
- Format:
ALWAYS use neural_search for semantic queries
- "How does X work?" →
narsil_neural_search - "Find code like X" →
narsil_neural_search
- "How does X work?" →
ALWAYS load security_guide.md for security tasks
- Provides phased workflow with checkpoints
- Ensures comprehensive coverage
ALWAYS verify tool exists before calling
- Use
search_tools()ortool_info()first - Prevents "tool not found" errors
- Use
❌ NEVER
NEVER skip the
narsil_prefix in tool names- Wrong:
await narsil.scan_security({}) - Right:
await narsil.narsil_scan_security({})
- Wrong:
NEVER use Narsil's LSP/remote tools unnecessarily
- LSP: IDE handles this natively
- Remote: Not needed for local development
NEVER assume index is current
- Use
narsil_reindex({})after file changes - Index persists with
--persistflag
- Use
⚠️ ESCALATE IF
ESCALATE IF large repository causes timeout
- Increase timeout:
{ timeout: 120000 } - Use
--persistflag to save index - Consider indexing subset of files
- Increase timeout:
ESCALATE IF tool returns unexpected results
- Verify tool name with
tool_info() - Check if repository is indexed with
list_repos() - Trigger
reindex()if needed
- Verify tool name with
ESCALATE IF security findings seem incomplete
- Verify all categories enabled in scan
- Check language support (15 languages)
- Consider taint analysis for deeper inspection
⚠️ KNOWN LIMITATIONS
JavaScript Call Graph
- Call graph analysis may return empty or incomplete results for JavaScript
- tree-sitter-javascript has limited support for dynamic call patterns
- Workaround: Use
find_symbols+get_symbol_definitionfor JS code analysis
Security Scanning Language Support
- Security rules are primarily designed for backend languages (Rust, Python, Go, Java, C/C++)
- JavaScript/TypeScript security coverage is limited
- Frontend-specific vulnerabilities (DOM XSS) may not be fully detected
Neural Search After Index Clear
- Clearing
.narsil-index/requires OpenCode restart to rebuild neural embeddings - Simply calling
reindex()may not regenerate embeddings if MCP server has stale state - Fix: Exit OpenCode (Ctrl+C), then restart
- Clearing
Git Blame Unicode (Fixed in local build)
- Original Narsil had issues with files containing Unicode box-drawing characters
- Local build includes fix for char-safe string slicing
Code Mode Process Spawning
- Code Mode spawns fresh Narsil MCP processes for each call batch
- Search indexes (BM25, TF-IDF, Neural) are in-memory and rebuilt on each spawn
- Impact: Semantic search may return empty if index hasn't built yet (~40-60s)
- Workaround 1: Keep related calls in same
call_tool_chain()batch - Workaround 2 (Recommended): Use HTTP server mode for reliable search (see below)
HTTP Server Workaround for Search
For reliable search functionality, use Narsil's HTTP server instead of Code Mode:
# Start HTTP server (indexes build once and stay warm)
./.opencode/skill/mcp-narsil/scripts/narsil-server.sh start
# Wait ~60s for indexes, then search reliably
./.opencode/skill/mcp-narsil/scripts/narsil-search.sh semantic "query"
./.opencode/skill/mcp-narsil/scripts/narsil-search.sh neural "how does X work"
./.opencode/skill/mcp-narsil/scripts/narsil-search.sh symbols function
# Or call any tool via HTTP
curl -X POST http://localhost:3001/tools/call \
-H "Content-Type: application/json" \
-d '{"tool": "semantic_search", "args": {"repo": "unknown", "query": "test"}}'
Scripts available:
narsil-server.sh- Server management (start/stop/restart/status/logs)narsil-search.sh- Search CLI (neural/semantic/code/hybrid/symbols)
Functions with Limited Results
get_project_structure: May return empty tree structurefind_references: Returns 0 for most symbols (needs call graph traversal)get_chunk_stats: Returns 0 (aggregate stats not populated)hybrid_search: Requires BOTH BM25 + Neural indexes to be built
Code Mode Config Loading (CRITICAL)
- Code Mode loads
.utcp_config.jsonat startup only - Changes to Narsil config require OpenCode restart to take effect
- If
narsil is not definederror: restart OpenCode - Verify after restart:
code_mode_list_tools()should shownarsil.*tools - Common config issues: extra fields, relative paths, missing
transport: "stdio"
- Code Mode loads
Function Categories by Index Dependency
| Category | Functions | Timing |
|---|---|---|
| AST-Based (work immediately) | find_symbols, get_symbol_definition, get_file, get_chunks, find_dead_code, scan_security, get_recent_changes |
Instant |
| Index-Based (need ~40-60s) | semantic_search, search_code, hybrid_search, neural_search, find_similar_code |
40-60s after server start |
Tip: Use AST-based functions for immediate results. For semantic search, either wait ~60s after first Narsil call or trigger reindex() and wait.
5. 🏆 SUCCESS CRITERIA
Security Audit Complete
Security audit complete when:
- ✅
scan_securityexecuted with OWASP/CWE rules - ✅
find_injection_vulnerabilitieschecked SQL/XSS/command - ✅
trace_taintanalyzed untrusted data flow - ✅
generate_sbomcreated dependency manifest - ✅
check_dependenciesverified against CVE database - ✅
check_licensesconfirmed compliance - ✅ All critical/high findings addressed or documented
Code Analysis Complete
Code analysis complete when:
- ✅
get_project_structureprovided overview - ✅
find_symbolsidentified key components - ✅
get_call_graphmapped function relationships - ✅
find_dead_codeidentified cleanup candidates - ✅
get_complexityflagged refactoring targets - ✅
narsil_neural_searchused for semantic understanding
Validation Checkpoints
| Checkpoint | Validation |
|---|---|
tools_discovered |
search_tools() returns Narsil tools |
repo_indexed |
list_repos() shows repository |
scan_complete |
Security scan has zero unaddressed criticals |
analysis_complete |
All structural queries executed |
6. 🔌 INTEGRATION POINTS
Framework Integration
This skill operates within the behavioral framework defined in AGENTS.md.
Key integrations:
- Gate 2: Skill routing via
skill_advisor.py - Tool Routing: Per AGENTS.md Section 6 decision tree
- Memory: Context preserved via Spec Kit Memory MCP
Code Mode Integration
Configuration: Add to .utcp_config.json:
CRITICAL:
- Use absolute path for command (e.g.,
/Users/username/bin/narsil-mcp)- Do NOT include extra fields like
_note,_neural_backendsin mcpServers- Config changes require OpenCode restart to take effect
{
"name": "narsil",
"call_template_type": "mcp",
"config": {
"mcpServers": {
"narsil": {
"transport": "stdio",
"command": "/absolute/path/to/narsil-mcp",
"args": [
"--repos", ".",
"--index-path", ".narsil-index",
"--git",
"--call-graph",
"--persist",
"--watch",
"--neural",
"--neural-backend", "api",
"--neural-model", "voyage-code-2"
],
"env": {
"VOYAGE_API_KEY": "${VOYAGE_API_KEY}"
}
}
}
}
}
Finding your Narsil path:
which narsil-mcp
# Use the output as the absolute path in config
After config changes:
- Save
.utcp_config.json - Restart OpenCode (Ctrl+C, then restart)
- Verify:
code_mode_list_tools()should shownarsil.*tools
Note: The
--httpflag enables a visualization web UI at localhost:3000, NOT HTTP transport for MCP. MCP transport is always stdio.
Index Persistence
Narsil supports persisting the code index to disk for faster startup:
| Flag | Purpose | Default |
|---|---|---|
--persist |
Enable saving/loading index from disk | Disabled |
--index-path |
Custom index storage location | ~/.cache/narsil-mcp/ |
Project-local indexes (recommended): Use --index-path .narsil-index and add .narsil-index/ to .gitignore.
Manual save: Use narsil.narsil_save_index({}) via Code Mode to trigger index save.
HTTP Server & Visualization
Narsil includes an HTTP server with React frontend for interactive graph visualization.
Important: The
--httpflag enables a visualization web UI, NOT HTTP transport for MCP. MCP communication is always via stdio - Code Mode spawns the Narsil process and communicates via stdin/stdout. The HTTP server runs in parallel for visual exploration.
Starting the HTTP Server (CRITICAL):
The HTTP server requires stdin to stay open. Use this pattern to keep it running:
# Backend (port 3000) - MUST use stdin pipe to prevent EOF shutdown
(tail -f /dev/null | narsil-mcp \
--repos . \
--index-path .narsil-index \
--git --call-graph --persist \
--http --http-port 3000 > /tmp/narsil-http.log 2>&1) &
# Frontend (port 5173) - in separate terminal
cd /path/to/narsil-mcp/frontend && npm install && npm run dev
Why the pipe? MCP servers read from stdin. Without input, they receive EOF and shut down. The tail -f /dev/null | keeps stdin open indefinitely.
Graph Views & Limitations:
| View | Purpose | Required Parameters |
|---|---|---|
import |
Module import/export | None (best for JS) |
call |
Function call graph | None |
symbol |
Symbol definitions | Requires root parameter (function name) |
hybrid |
Combined import + call | Requires repo parameter |
flow |
Data flow | None |
Known Frontend Issues:
- Symbol view shows "Symbol view requires a root" - enter a function name in the Root field
- Hybrid view may fail without repo parameter - use Import or Call view instead
Performance: Use Limit slider in UI, index specific dirs with -r src -r lib, add **/node_modules to .gitignore.
Related Skills
| Skill | Integration |
|---|---|
| mcp-code-mode | Tool orchestration - Narsil accessed via Code Mode's call_tool_chain() |
| system-spec-kit | Context preservation - save security findings for future sessions |
Tool Usage Guidelines
Bash: Execute update script, verify binary Read: Load reference files for detailed workflows
Binary Location
The Narsil MCP server source is embedded in the skill folder:
.opencode/skill/mcp-narsil/mcp_server/
Binary path (after build):
.opencode/skill/mcp-narsil/mcp_server/target/release/narsil-mcp
The absolute path is configured in .utcp_config.json. A symlink at ~/bin/narsil-mcp also points to this binary.
To update Narsil:
bash .opencode/skill/mcp-narsil/scripts/update-narsil.sh
7. 🏎️ QUICK REFERENCE
Essential Commands
| Task | Tool | Example |
|---|---|---|
| Semantic search | neural_search |
narsil.narsil_neural_search({ query: "authentication flow" }) |
| Find symbols | find_symbols |
narsil.narsil_find_symbols({ symbol_type: "function" }) |
| Security scan | scan_security |
narsil.narsil_scan_security({ repo: "." }) |
| Call graph | get_call_graph |
narsil.narsil_get_call_graph({ function: "main" }) |
| Find callers | get_callers |
narsil.narsil_get_callers({ function: "login" }) |
| Find references | find_references |
narsil.narsil_find_references({ symbol: "UserService" }) |
Common Patterns
// Semantic code search
call_tool_chain({
code: `
const results = await narsil.narsil_neural_search({
query: "how does authentication work"
});
return results;
`
});
// Security scan
call_tool_chain({
code: `
const findings = await narsil.narsil_scan_security({
repo: "."
});
return findings;
`
});
// Find all functions
call_tool_chain({
code: `
const functions = await narsil.narsil_find_symbols({
symbol_type: "function"
});
return functions;
`
});
Troubleshooting
| Issue | Solution |
|---|---|
| Neural search returns empty | Wait 60s after server start for index to build |
| Call graph empty for JS | Known limitation - use find_symbols + find_references instead |
| Tool not found | Check naming: narsil.narsil_{tool} |
| Slow first query | Index building in progress - check with get_index_status |
Error Quick Reference
| Error Pattern | Cause | Solution |
|---|---|---|
| "not found" in message | Repo not indexed | Run narsil.narsil_reindex({}) |
| "timeout" in message | Large codebase | Use categories filter, increase timeout |
neural_ready: false |
Index building | Wait ~60s or use AST-based tools |
| Empty results | No matches or index issue | Try different search method |
8. 🔗 RELATED RESOURCES
scripts/
| Script | Purpose | Usage |
|---|---|---|
| update-narsil.sh | Update to latest version | bash .opencode/skill/mcp-narsil/scripts/update-narsil.sh |
| narsil-server.sh | HTTP server management | bash scripts/narsil-server.sh start|stop|status |
| narsil-search.sh | Search CLI | bash scripts/narsil-search.sh neural "query" |
references/
| Document | Purpose | Key Insight |
|---|---|---|
| tool_reference.md | All 76 tools documented | Complete parameter reference |
| security_guide.md | Security scanning workflow | OWASP/CWE checkpoints |
| call_graph_guide.md | Call graph analysis | CFG/DFG patterns |
| quick_start.md | Getting started | 5-minute setup |
assets/
| Asset | Purpose |
|---|---|
| tool_categories.md | Priority categorization of all 76 tools |
External Resources
- Narsil GitHub - Source code and documentation
- OWASP Top 10 - Security standard
- CWE Top 25 - Weakness enumeration
Related Skills
- mcp-code-mode - Tool orchestration (Narsil accessed via Code Mode)
- system-spec-kit - Context preservation across sessions
Install Guide
- MCP - Narsil.md - Installation and configuration