- name
- sdl-mcp-symbol-delta-ledger
- description
- Policy-centered context budget layer that turns sprawling codebases into compact, high-signal context for AI coding agents using symbol graphs and precision tools
- triggers
- ["index this codebase for better context","get symbol information without reading the whole file","analyze code dependencies and call graphs","show me the blast radius of this change","give me compact context for this task","search the codebase semantically","what's the impact of this PR","build a token-efficient code slice"]
# SDL-MCP: Symbol Delta Ledger
> Skill by [ara.so](https://ara.so) — MCP Skills collection.
SDL-MCP is a policy-centered context budget layer for coding agents that transforms sprawling codebases into compact, high-signal context. It indexes code into a searchable symbol graph, providing 4-20x token savings by serving precisely the right amount of context through the Iris Gate Ladder escalation system.
## What SDL-MCP Does
- **Symbol Cards**: Every function, class, interface, type, and variable becomes a ~100 token metadata record instead of ~2,000 tokens of raw code
- **Graph Slicing**: Follow dependency graphs (not directory boundaries) to get the N most relevant symbols within a token budget
- **Iris Gate Ladder**: Four-rung context escalation from compact cards to full source (policy-gated)
- **Delta Packs & Blast Radius**: Semantic change intelligence showing what changes mean and who's affected
- **Live Indexing**: Real-time code intelligence reflecting unsaved editor changes
- **Task-Shaped Retrieval**: Context engine that selects the right rungs and evidence for debug/review/implement/explain tasks
## Installation
**Prerequisites**: Node.js 24+ required
### Global Installation
```bash
# Install globally
npm install -g sdl-mcp
# Non-interactive setup with auto-indexing
sdl-mcp init -y --auto-index
# Start MCP server
sdl-mcp serve --stdio
```
### Using npx
```bash
# Quick start with wrapper
npx create-sdl-mcp
# Or direct npx usage
npx --yes sdl-mcp@latest init -y --auto-index
npx --yes sdl-mcp@latest serve --stdio
```
### MCP Client Configuration
Add to your MCP client configuration (e.g., Claude Desktop):
```json
{
"mcpServers": {
"sdl-mcp": {
"command": "sdl-mcp",
"args": ["serve", "--stdio"]
}
}
}
```
Or with npx:
```json
{
"mcpServers": {
"sdl-mcp": {
"command": "npx",
"args": ["--yes", "sdl-mcp@latest", "serve", "--stdio"]
}
}
}
```
## Key Commands (CLI)
```bash
# Initialize repository
sdl-mcp init # Interactive setup
sdl-mcp init -y --auto-index # Non-interactive with auto-index
sdl-mcp init --config-only # Generate config without indexing
# Indexing
sdl-mcp index # Full index
sdl-mcp index --incremental # Only changed files
sdl-mcp index --force # Force re-index all files
# Server
sdl-mcp serve --stdio # Start MCP server
sdl-mcp serve --stdio --verbose # Verbose logging
# Health & Diagnostics
sdl-mcp health # Run health checks
sdl-mcp summary --task "debug auth" # Generate portable context summary
# Configuration
sdl-mcp config get # Show current config
sdl-mcp config set key=value # Update config value
```
## MCP Tools API
### Symbol Cards & Search
**Get Symbol Card** (Rung 1: ~100 tokens)
```typescript
// Request minimal symbol metadata
{
"name": "sdl.symbol.card",
"arguments": {
"symbolId": "src/auth/validate.ts::validateToken",
"format": "compact" // or "full"
}
}
```
**Search Symbols**
```typescript
{
"name": "sdl.symbol.search",
"arguments": {
"query": "authenticate user",
"limit": 10,
"confidence": 0.7,
"filters": {
"kind": ["function", "class"],
"filePath": "src/auth/**"
}
}
}
```
### Graph Slicing
**Build Token-Budgeted Slice**
```typescript
{
"name": "sdl.slice.build",
"arguments": {
"entrySymbols": ["src/auth/validate.ts::validateToken"],
"tokenBudget": 800,
"direction": "both", // "upstream" | "downstream" | "both"
"weights": {
"call": 1.0,
"config": 0.8,
"import": 0.6
}
}
}
```
**Auto-Discovery from Task**
```typescript
{
"name": "sdl.slice.build",
"arguments": {
"taskText": "Fix authentication timeout issue",
"tokenBudget": 1000,
"autoDiscover": true
}
}
```
**Refresh Slice (Delta Updates)**
```typescript
{
"name": "sdl.slice.refresh",
"arguments": {
"sliceHandle": "slice_abc123",
"deltaOnly": true // Only return changed symbols
}
}
```
### Iris Gate Ladder Escalation
**Rung 2: Skeleton (signature + structure)**
```typescript
{
"name": "sdl.iris.skeleton",
"arguments": {
"symbolId": "src/auth/AuthService.ts::AuthService",
"includeSignatures": true,
"includeTypes": true
}
}
```
**Rung 3: Hot Path (specific lines/blocks)**
```typescript
{
"name": "sdl.iris.hotPath",
"arguments": {
"symbolId": "src/auth/validate.ts::validateToken",
"targetIdentifiers": ["cache", "decrypt"],
"contextLines": 3
}
}
```
**Rung 4: Raw Source (policy-gated)**
```typescript
{
"name": "sdl.iris.rawSource",
"arguments": {
"symbolId": "src/auth/validate.ts::validateToken",
"reason": "Need to see complete error handling logic for timeout bug",
"expectedIdentifiers": ["TimeoutError", "retry", "backoff"],
"expectedLineCount": 45,
"bypassPolicy": false
}
}
```
### Task-Shaped Context
**Get Context for Task**
```typescript
{
"name": "sdl.context",
"arguments": {
"task": "debug", // "debug" | "review" | "implement" | "explain"
"description": "User authentication failing after token refresh",
"tokenBudget": 2000,
"focusPaths": ["src/auth/**"],
"options": {
"semantic": true, // Use hybrid retrieval
"includeTests": true
}
}
}
```
### Delta & Blast Radius
**Semantic Diff**
```typescript
{
"name": "sdl.delta.pack",
"arguments": {
"baseRef": "main",
"headRef": "HEAD",
"options": {
"includeBlastRadius": true,
"maxBlastDepth": 3
}
}
}
```
**PR Risk Analysis**
```typescript
{
"name": "sdl.pr.risk.analyze",
"arguments": {
"baseRef": "main",
"headRef": "feature/auth-refactor",
"options": {
"includeFanInTrend": true,
"testRecommendations": true
}
}
}
```
### Live Indexing
**Push Buffer Changes**
```typescript
{
"name": "sdl.buffer.push",
"arguments": {
"filePath": "src/auth/validate.ts",
"content": "export async function validateToken(token: string): Promise<User> {\n // ...\n}",
"version": 42
}
}
```
**Clear Buffer**
```typescript
{
"name": "sdl.buffer.clear",
"arguments": {
"filePath": "src/auth/validate.ts"
}
}
```
### Runtime Execution (Sandboxed)
**Execute Code**
```typescript
{
"name": "sdl.runtime.execute",
"arguments": {
"executable": "npm",
"args": ["test", "auth.test.ts"],
"cwd": "./",
"outputMode": "minimal", // "minimal" | "summary" | "intent"
"timeout": 30000
}
}
```
**Query Execution Output**
```typescript
{
"name": "sdl.runtime.queryOutput",
"arguments": {
"executionId": "exec_xyz789",
"query": "Show me the failing test assertions"
}
}
```
### Feedback Loop
**Record Symbol Usefulness**
```typescript
{
"name": "sdl.agent.feedback",
"arguments": {
"contextId": "ctx_abc123",
"useful": ["src/auth/validate.ts::validateToken"],
"missing": ["src/auth/TokenCache.ts::get"],
"irrelevant": ["src/utils/logger.ts::debug"]
}
}
```
## Configuration
SDL-MCP stores configuration in `.sdl-mcp/config.json`:
```json
{
"repoRoot": "/path/to/repo",
"languages": {
"typescript": { "enabled": true },
"python": { "enabled": true },
"go": { "enabled": true }
},
"indexing": {
"exclude": ["node_modules/**", "dist/**", "*.test.ts"],
"maxFileSize": 1048576,
"parallelism": 4
},
"governance": {
"rawSourceGate": {
"enabled": true,
"requireReason": true,
"requireIdentifiers": true,
"maxLineCount": 500
},
"runtime": {
"enabled": true,
"allowedExecutables": ["npm", "node", "python3"],
"cwdJail": true,
"timeout": 30000
}
},
"codeMode": {
"exclusive": true,
"autoSlicing": true,
"defaultBudget": 1500
},
"retrieval": {
"hybridThreshold": 0.7,
"semanticDefault": "auto"
}
}
```
### Update Configuration
```bash
# Set specific values
sdl-mcp config set governance.rawSourceGate.maxLineCount=1000
sdl-mcp config set codeMode.defaultBudget=2000
# Enable/disable features
sdl-mcp config set governance.runtime.enabled=false
sdl-mcp config set codeMode.exclusive=false
```
## Common Patterns
### Pattern 1: Efficient Code Understanding
Instead of reading entire files:
```typescript
// ❌ Old way: Read whole file (~2000 tokens)
const fileContent = await readFile('src/auth/validate.ts');
// ✅ SDL-MCP way: Get symbol card (~100 tokens)
const card = await mcp.call('sdl.symbol.card', {
symbolId: 'src/auth/validate.ts::validateToken',
format: 'compact'
});
// Returns: signature, parameters, return type, dependencies, ~100 tokens
```
### Pattern 2: Dependency-Aware Context
Instead of directory-based context:
```typescript
// ❌ Old way: Read all files in directory (~16,000 tokens)
const authFiles = await glob('src/auth/**/*.ts');
// ✅ SDL-MCP way: Graph slice within budget (~800 tokens)
const slice = await mcp.call('sdl.slice.build', {
taskText: 'Fix token validation timeout',
tokenBudget: 800,
autoDiscover: true
});
// Returns: Only relevant symbols following dependency graph
```
### Pattern 3: Controlled Escalation
Only read raw code when necessary:
```typescript
// Start with card (Rung 1)
在 GitHub 查看