mcp-code-shrinker
# MCP Code Shrinker v0.4.1
**Semantic Context Compiler** — stratified L0-L3 context with exact-source escalation, stable symbol IDs, and repository-scoped isolation. MCP server for Hermes Agent.
---
## Architecture
```
┌──────────────────────────────────────────────────────────────┐
│ CONTEXT LAYERS │
│ │
│ L0: Project Map (5%) file tree + exports │
│ L1: Semantic Contracts (40%) signatures, effects, throws │
│ L2: Exact Source (40%) NO renaming, NO regex mods │
│ L3: Evidence (15%) tests, stack traces, logs │
├──────────────────────────────────────────────────────────────┤
│ SYMBOL MODEL │
│ │
│ Stable Symbol ID = f(repository-slot.root, file_path, │
│ language, node_type, qualified_name, │
│ signature) │
│ │
│ → Survives neighbor edits │
│ → NFC-normalized, forward-slash paths │
│ → Scoped to repository (different repos = different IDs) │
├──────────────────────────────────────────────────────────────┤
│ REPOSITORY ISOLATION │
│ │
│ requireRepositoryId(args) P0 guard │
│ requireIndex(repoId) slot verification │
│ isInside(slot.root, filePath) path containment │
│ resolveInsideRoot(filePath) canonical path │
│ canonicalRepoPath(path) NFC + POSIX slashes │
│ │
│ → Foreign-repo files: PATH_OUTSIDE_REPOSITORY error │
│ → watch_stop: preserves repository slot │
│ → context.expand: validates implicit targetFile │
├──────────────────────────────────────────────────────────────┤
│ PATCH WORKFLOW │
│ │
│ patch.propose → patch.validate → patch.apply │
│ │ │
│ ├─ hash re-check │
│ ├─ .bak backup │
│ ├─ repository slot bound │
│ └─ outcome → Memory Wiki │
└──────────────────────────────────────────────────────────────┘
```
## Key Guarantees
### Symbol ID Stability
- **Survives neighbor edits**: adding/removing unrelated symbols does NOT change existing IDs
- **NFC normalization**: Unicode canonical composition for cross-platform consistency
- **Forward-slash paths**: `\` → `/` for POSIX compatibility
- **Repository-scoped**: same code in different repos → different symbol IDs
### Repository Isolation
- **Every tool requires `repository_id`**: `file.contracts`, `symbol.source`, `context.create`, `context.expand`
- **Path containment**: `isInside(slot.root, filePath)` — rejects files outside repository root
- **Slot lifecycle**: `watch_stop` stops watcher but preserves repository binding
- **Canonical paths**: NFC + POSIX slashes + resolved symlinks
### Context Packet Protocol
- **Ranking**: symbols sorted by token count (descending)
- **Quality check**: contracts must pass confidence threshold
- **Coverage manifest**: tracks what symbols are already in context
- **Loss manifest**: reports missing symbols with reasons
- **No double-relative**: prevents duplicate file paths in packets
### Exact-Source Escalation
- Layer 2 returns raw source code with ZERO modifications
- No regex replacement, no renaming, no format changes
- Contract + source separation: model can verify contract accuracy
---
## Tools (29)
The MCP server publishes exactly the tools declared by `src/index.js`:
### Project, files, symbols and watchers (10)
- `project.scan`
- `project.map`
- `project.watch_start`
- `project.watch_stop`
- `project.watch_status`
- `project.snapshot`
- `project.changed_symbols`
- `file.contracts`
- `symbol.source`
- `symbol.context`
### Artifact Store (9)
- `artifact.put`
- `artifact.get`
- `artifact.get_chunk`
- `artifact.copy_text`
- `artifact.pin`
- `artifact.delete`
- `artifact.list`
- `artifact.stats`
- `artifact.gc`
### Context (3)
- `context.create`
- `context.expand`
- `context.inspect`
Targets accept equivalent plain, handle and qualified forms, for example `add`, `@add` and `Calculator.add`.
### Single-file patch workflow (3)
- `patch.propose`
- `patch.validate`
- `patch.apply`
JavaScript validation always requires syntax success. Lint, typecheck and tests are executed when available and fail validation when they run and report errors. Optional unavailable checks no longer block `patch.apply`. Strict installations can require checks with `CODE_SHRINKER_REQUIRED_CHECKS_JSON`, for example `["parse","lint","tests"]`.
### Atomic multi-file patch workflow (4)
- `patchset.propose`
- `patchset.validate`
- `patchset.apply`
- `patchset.rollback`
The removed development tools (`code.generate`, `code.review`, `debug.trace`, `exec.test` and related names) are not part of this server.
## Installation
```bash
git clone https://github.com/sbrejnev988-coder/mcp-code-shrinker.git
cd mcp-code-shrinker
npm install
npm test
```
### Hermes Integration
The Code Shrinker MCP server is registered in `~/.hermes/config.yaml`:
```yaml
mcp_servers:
code-shrinker:
command: node
args: ["src/index.js"]
cwd: "~/.hermes/workspace/mcp-code-shrinker"
```
---
## Repository-Scope Integration with Memory Wiki
```
Code Shrinker Memory Wiki
────────────── ───────────
context.create() ──coverage────────► _pack_context()
manifest │
┌─ repository_id ├─ _classify_coverage()
├─ covered: [{ │ SHA-256 normalized
│ kind: "source"|"contract" │ repository_id match
│ file_path: NFC-canonical │ hard-suppress foreign repos
│ symbol_id: stable hash │
│ content_hash: sha256:... │
│ token_count ├─ suppressed_claim_ids
│ }] │
└─ loss: [...] └─ output → context for LLM
↓
_memory_diff() — excludes suppressed
_preference_layer() — excludes suppressed
```
### Cross-Plugin Hash Protocol v2
- Both plugins normalize SHA-256: lowercase, strip `sha256:` prefix
- NFC path canonization on both sides
- `repository_id` required on all code claim operations
- `content_hash` used for exact-match deduplication
---
## P0/P1 Forensic Fixes Applied
### P0 (Repository Scope)
- ✅ `file.contracts` requires `repository_id` + slot.root guard
- ✅ `symbol.source` requires `repository_id` + slot.root guard
- ✅ Foreign-repo files rejected: `PATH_OUTSIDE_REPOSITORY`
- ✅ `context.expand` validates implicit targetFile against slot.root
- ✅ `watch_stop` preserves repository slot (does not delete from indexes)
- ✅ `createSymbolId` NFC + forward-slash normalization
- ✅ `canonicalRepoPath` double-relative fix
- ✅ Symbol ID uses `slot.root` not `rootForFile(fp)`
### P1 (Forensic)
- ✅ `patch.propose` stores repository identity/root
- ✅ `patch.validate` bound to repository slot
- ✅ `patch.apply` bound to repository slot
- ✅ MCP annotations: explicit mutation/destruction sets
---
## Path Security Model
```
Allowed Roots (from Hermes config):
~/workspace
~/plugins
~/.hermes/proxy
Symbol resolution:
slot.root → canonicalRepoPath(root) → isInside(root, filePath)
YES: ~/workspace/project/src/index.js → resolves
NO: /tmp/outside.js → PATH_OUTSIDE_REPOSITORY
NO: ~/workspace/project/../outside.js → double-relative blocked
```
---
## Performance
| Operation | Typical Time |
|---|---|
| `file.contracts` (100 symbols) | 50-200ms |
| `symbol.source` | 10-50ms |
| `context.create` (L0-L3) | 200-500ms |
| `patch.validate` (sandbox) | 500-2000ms |
| `project.map` | 100-300ms |
| Symbol ID computation | <1ms |
## License
MIT
## Integration lifecycle v0.4.0
`patch.apply` and `patchset.apply` now refresh the repository index synchronously and emit an atomic event under `$HERMES_HOME/context-coordination/inbox/code-shrinker`. Memory Wiki consumes the event idempotently, stores a structured patch outcome, and archives claims for older file revisions. Coverage manifests use Hash Protocol v2.
## Validation policy v0.4.1
Default policy requires successful syntax parsing. Available ESLint, TypeScript and test checks are still authoritative: a reported failure makes the patch invalid. A missing optional executable produces a recorded `skipped` step but no longer turns an otherwise valid JavaScript patch into `inconclusive`.
For fail-closed production policy:
```bash
export CODE_SHRINKER_REQUIRED_CHECKS_JSON='["parse","lint","tests"]'
```
For one complete repository command:
```bash
export CODE_SHRINKER_VALIDATE_CMD_JSON='["npm","test"]'
```
TDQS
Scored across 29 tools
Each tool targets a distinct domain and action (project, file, symbol, artifact, context, patch, patchset). Descriptions clearly differentiate purposes, e.g., project.scan builds call graphs while symbol.context provides callers/callees. No notable overlap.
All names follow a consistent two-part dot-separated pattern (domain.action), using snake_case for multi-word actions. No mixing of conventions across tools.
At 29 tools, the count is on the higher side but still justified given the server's broad scope (project scanning, symbol analysis, artifact storage, context construction, and patching). Each tool serves a specific function without redundancy.
The tool surface covers a full workflow from project scan and symbol extraction to context packets, artifact management, and atomic patches with rollback. No obvious gaps for the stated purpose of code shrinking/analysis.