Skip to main content
Glama
README.md
# ensemble-mcp

A **harness infrastructure layer** delivered as a Python MCP server — providing **vector memory**, **drift detection**, **model routing**, **skills discovery**, **session management**, **codebase indexing**, and **context compression** for AI agent pipelines.

All intelligence is local — zero LLM/API calls. Uses ONNX Runtime embeddings (~5ms), numpy cosine similarity, and SQLite storage.

---

## What is an Agent Harness?

**Agent = Model + Harness.** A harness is every piece of code, configuration, and execution logic that wraps a model to turn it into a useful agent. Without a harness, a model can only take in text and output text — it can't maintain state, execute code, access tools, or learn from past work.

A complete agent harness typically includes:

- **System prompts & configuration** — instructions that shape agent behavior
- **Tools, Skills & MCPs** — capabilities the agent can invoke
- **Execution environment** — filesystem, bash, sandbox, browser
- **Orchestration logic** — subagent spawning, handoffs, model routing
- **Memory & context management** — compaction, skills, session persistence
- **Hooks & middleware** — deterministic checks like linting, formatting, drift detection

> *For a deeper dive, see [The Anatomy of an Agent Harness](https://www.langchain.com/blog/the-anatomy-of-an-agent-harness) by LangChain.*

## Where ensemble-mcp Fits

Agent harnesses like Claude Code, Codex, and Cursor provide the **execution layer** — filesystem, bash, sandbox. ensemble-mcp provides the **intelligence infrastructure layer** that plugs into any harness via MCP:

```
┌─────────────────────────────────────────────────────────┐
│                    AGENT HARNESS                        │
│                                                         │
│  ┌───────────────────────────────────────────────────┐  │
│  │            Execution Layer                        │  │
│  │    (provided by Claude Code / Codex / Cursor)     │  │
│  │                                                   │  │
│  │  ┌──────────┐ ┌──────────┐ ┌──────────────────┐  │  │
│  │  │Filesystem│ │  Bash /  │ │   Sandbox /      │  │  │
│  │  │  & Git   │ │  Code    │ │   Browser        │  │  │
│  │  └──────────┘ └──────────┘ └──────────────────┘  │  │
│  └───────────────────────────────────────────────────┘  │
│                                                         │
│  ┌───────────────────────────────────────────────────┐  │
│  │       Intelligence Infrastructure Layer           │  │
│  │         (provided by ensemble-mcp via MCP)        │  │
│  │                                                   │  │
│  │  ┌────────┐ ┌────────┐ ┌───────┐ ┌───────────┐  │  │
│  │  │ Memory │ │ Skills │ │ Drift │ │  Context  │  │  │
│  │  │& Search│ │        │ │Detect │ │Compression│  │  │
│  │  └────────┘ └────────┘ └───────┘ └───────────┘  │  │
│  │  ┌────────┐ ┌────────┐ ┌───────┐ ┌───────────┐  │  │
│  │  │ Model  │ │Session │ │Code   │ │ Project   │  │  │
│  │  │Routing │ │Persist.│ │Index  │ │ Snapshot  │  │  │
│  │  └────────┘ └────────┘ └───────┘ └───────────┘  │  │
│  └───────────────────────────────────────────────────┘  │
│                                                         │
│  ┌───────────────────────────────────────────────────┐  │
│  │          Orchestration Layer                       │  │
│  │   (agent pipeline, subagent spawning, handoffs)   │  │
│  └───────────────────────────────────────────────────┘  │
│                                                         │
│                    ┌───────────┐                        │
│                    │   MODEL   │                        │
│                    └───────────┘                        │
└─────────────────────────────────────────────────────────┘
```

---

## Features

ensemble-mcp provides these harness primitives:

| Harness Primitive | Feature | What It Does |
|-------------------|---------|-------------|
| **Memory & Search** | Pattern Memory | Semantic vector search over stored pipeline patterns (MiniLM-L6-v2, 384-dim) |
| **Drift Detection** | Drift Check | Cosine similarity between task description and code changes |
| **Model Routing** | Model Recommend | Recommend model tier (best/mid/cheapest) per agent and task complexity |
| **Skills (Progressive Disclosure)** | Skills Discovery | Scan `.ai/skills/`, `.claude/skills/`, `.cursor/rules/` etc. with semantic search |
| **Skills (Progressive Disclosure)** | Skill Intelligence | Auto-detect recurring patterns and suggest converting them to reusable skills |
| **Long Horizon Execution** | Session Management | Pipeline checkpoint save/load with optimistic versioning |
| **Codebase Awareness** | Codebase Indexing | File-level index with exports, imports, roles — incremental via mtime |
| **Context Rot Prevention** | Context Compression | Compress verbose text into token-efficient form, rule-based |
| **Context Rot Prevention** | Prompt Caching | Order and prepare prompt sections for optimal LLM cache hit rates |
| **Codebase Awareness** | Codebase Snapshots | Generate compact project baseline summaries from the codebase index |
| **Harness Setup** | Auto-Installer | Detect AI tools and register the MCP server in their configs |
| **Observability** | Web Dashboard | Local browser UI at `localhost:8787` for visualizing patterns, skills, projects, drift, and sessions |

## Quick Start

### Install from source

```bash
git clone https://github.com/LynkByte/ensemble.git
cd ensemble
pip install -e ".[dev]"
```

### Install via uvx (after PyPI publish)

```bash
uvx ensemble-mcp
```

### Run the server

```bash
# Start the MCP server (stdio protocol)
ensemble-mcp

# Or explicitly
ensemble-mcp serve
```

### Other CLI commands

```bash
# Auto-detect AI tools and register the MCP server
ensemble-mcp install

# Remove MCP server registration from AI tool configs
ensemble-mcp uninstall

# Copy agent files to a project (no MCP registration needed)
ensemble-mcp add-agents --tools opencode

# Copy skill files to a project (no MCP registration needed)
ensemble-mcp add-skills --tools opencode
```

### Web Dashboard

A local-only browser dashboard for visualizing patterns, skills, projects, drift history, and sessions.

```bash
# Start the dashboard (opens browser to http://localhost:8787)
ensemble-mcp web

# Custom port
ensemble-mcp web --port 9000

# Start without auto-opening the browser
ensemble-mcp web --no-open

# Specify a reports directory (auto-detected from ./reports or git root otherwise)
ensemble-mcp web --reports-dir /path/to/reports
```

The dashboard reads directly from the same SQLite database the MCP server writes to (WAL mode, no contention). It binds to `127.0.0.1` only — never exposed to the network, no authentication needed.

#### Dashboard Pages

| Page | What It Shows |
|------|--------------|
| **Overview** | Summary cards (patterns, skills, projects, drift checks), drift score trend chart, recent activity |
| **Patterns** | All stored patterns with match counts, project filtering, search |
| **Skills** | Pending skill suggestions with confidence scores, stale skill detection |
| **Projects** | Indexed projects with language breakdown pie charts, file role bar charts, export counts |
| **Drift** | Drift check history with scores, verdicts, flagged files, project filtering |
| **Sessions** | Session list with lifecycle status, click-through to step-by-step detail |

#### API Endpoints

All endpoints return the standard `ok/data/error/meta` envelope:

| Endpoint | Description |
|----------|-------------|
| `GET /api/summary` | Aggregate counts and recent activity |
| `GET /api/patterns` | Paginated pattern list (filter by `project`) |
| `GET /api/patterns/:id` | Single pattern detail with embedding metadata |
| `GET /api/skills` | Skill suggestions (filter by `project`, `status`) |
| `GET /api/skills/stale` | Skills not matched within threshold days |
| `GET /api/projects` | Indexed projects with file/export counts |
| `GET /api/projects/:path` | Project detail with language and role breakdown |
| `GET /api/drift` | Drift history (filter by `project`, `from`, `to`) |
| `GET /api/sessions` | Paginated session list (filter by `project`, `status`) |
| `GET /api/sessions/:id` | Session detail with steps |
| `GET /api/health` | Server health, version, DB size |

## MCP Client Configuration

### OpenCode

Add to `~/.config/opencode/config.json` or project `config.json`:

```json
{
  "$schema": "https://opencode.ai/config.json",
  "mcp": {
    "ensemble": {
      "type": "local",
      "command": ["uvx", "ensemble-mcp"]
    }
  }
}
```

Or for a local development install:

```json
{
  "$schema": "https://opencode.ai/config.json",
  "mcp": {
    "ensemble": {
      "type": "local",
      "command": ["/path/to/venv/bin/ensemble-mcp"]
    }
  }
}
```

### Claude Code

Add to `~/.claude.json`:

```json
{
  "mcpServers": {
    "ensemble": {
      "command": "uvx",
      "args": ["ensemble-mcp"]
    }
  }
}
```

### GitHub Copilot (VS Code)

Add to `.vscode/mcp.json`:

```json
{
  "servers": {
    "ensemble": {
      "command": "uvx",
      "args": ["ensemble-mcp"]
    }
  }
}
```

### Cursor

Add to `~/.cursor/mcp.json`:

```json
{
  "mcpServers": {
    "ensemble": {
      "command": "uvx",
      "args": ["ensemble-mcp"]
    }
  }
}
```

### Windsurf

Add to `~/.windsurf/mcp.json`:

```json
{
  "mcpServers": {
    "ensemble": {
      "command": "uvx",
      "args": ["ensemble-mcp"]
    }
  }
}
```

### Auto-Install

Instead of manual configuration, run the installer to auto-detect installed AI tools and register the server:

```bash
# Detect tools and register (interactive)
ensemble-mcp install

# Register specific tools only
ensemble-mcp install --tools opencode,cursor

# Preview without making changes
ensemble-mcp install --dry-run

# Non-interactive
ensemble-mcp install --yes
```

The installer automatically detects how `ensemble-mcp` is available on your system and registers the appropriate command:

| Priority | Detection | Registered Command |
|----------|-----------|-------------------|
| 1st | `ensemble-mcp` on PATH (pip/pipx install) | `ensemble-mcp` |
| 2nd | `uvx` on PATH | `uvx ensemble-mcp` |
| 3rd | Neither found | `/path/to/python -m ensemble_mcp` (current interpreter) |

## 19 MCP Tools

### Patterns (semantic memory)

| Tool | Description |
|------|-------------|
| `patterns_search` | Semantic search over stored patterns |
| `patterns_store` | Store a new pattern with embedding |
| `patterns_prune` | Remove old/unused patterns |

### Drift Detection

| Tool | Description |
|------|-------------|
| `drift_check` | Cosine similarity between task and changes (0-1 score) |

### Model Routing

| Tool | Description |
|------|-------------|
| `model_recommend` | Recommend model tier for agent + task complexity |

### Skills

| Tool | Description |
|------|-------------|
| `skills_discover` | Scan skill directories with optional semantic search |
| `skills_suggest` | Detect recurring patterns, propose as reusable skills |
| `skills_generate` | Accept, dismiss, or defer a skill suggestion |

### Session

| Tool | Description |
|------|-------------|
| `session_save` | Save pipeline checkpoint with optimistic versioning |
| `session_load` | Load latest or specific checkpoint |
| `session_search` | Search sessions by semantic similarity |

### Codebase Indexer

| Tool | Description |
|------|-------------|
| `project_index` | Build/refresh file-level codebase index |
| `project_query` | Query index by language, path, or text |
| `project_dependencies` | Get import/dependency graph for a file |
| `project_snapshot` | Generate compact project baseline summary (cached) |

### Context Compression

| Tool | Description |
|------|-------------|
| `context_compress` | Compress verbose text into terse, token-efficient form while preserving technical content |
| `context_prepare` | Order prompt sections for optimal LLM cache hit rates (static → project → task) |

### Utility

| Tool | Description |
|------|-------------|
| `health` | Server health check |
| `reset` | Reset all data (destructive, requires confirmation) |

## Response Envelope

Every tool returns a standardized envelope:

```json
{
  "ok": true,
  "data": { "matches": [...] },
  "error": null,
  "meta": {
    "duration_ms": 12,
    "source": "sqlite",
    "confidence": "exact"
  }
}
```

Confidence indicators: `exact` (direct data), `partial` (mixed sources), `estimated` (heuristic).

## Architecture

ensemble-mcp is structured as a harness infrastructure layer with clear separation between tool implementations and shared engine components:

```
ensemble-mcp/
  src/ensemble_mcp/
    server.py             # MCP server + tool registration
    config/               # Settings, defaults
    contracts/            # Response envelope, error taxonomy
    memory/               # ONNX embeddings, SQLite vector store, cosine similarity
    security/             # Secret redaction, trust boundaries
    state/                # Session/step lifecycle, idempotency, locks
    tools/                # 19 MCP tool implementations + call-recording utility
    installer/            # AI tool detection + MCP registration
    dashboard/            # Web dashboard (aiohttp server, JSON API, SPA frontend)
    compress/             # Rule-based text compression engine (context rot prevention)
    cli/                  # Startup banner
    data/                 # Bundled agent and skill files (AGENTS.md, skills)
```

### Technology Stack

| Component | Choice |
|-----------|--------|
| Language | Python 3.11+ |
| Distribution | `uvx` (zero-hassle cross-platform) |
| MCP Framework | `mcp` (official Python SDK) |
| Embeddings | ONNX Runtime + MiniLM-L6-v2 (~22MB, 384-dim) |
| Vector Storage | SQLite + numpy cosine similarity |
| Tokenizer | HuggingFace `tokenizers` (for MiniLM input) |
| Package Size | ~90MB (including ONNX + model) |

### Local Storage

| Path | Contents |
|------|----------|
| `~/.cache/ensemble-mcp/data.db` | SQLite database (WAL mode) |
| `~/.cache/ensemble-mcp/models/` | ONNX MiniLM-L6-v2 model (~22MB) |
| `~/.config/ensemble-mcp/config.toml` | Global user configuration |

## Configuration

Layered config with deterministic merge order:

1. Package defaults (built-in)
2. Global config (`~/.config/ensemble-mcp/config.toml`)
3. Project config (`.ensemble-mcp.toml`)
4. Environment variables (`ENSEMBLE_MCP_*`)

```toml
# ~/.config/ensemble-mcp/config.toml
drift_threshold_aligned = 0.25
default_top_k = 5
cluster_similarity_threshold = 0.8
```

## Development

```bash
# Install with dev dependencies
pip install -e ".[dev]"

# Run tests
python -m pytest tests/ -v

# Lint
ruff check src/ tests/

# Format
ruff format src/ tests/

# Type check
mypy src/

# Build package
python -m build
```

### Docker

```bash
docker build -t ensemble-mcp .
docker run --rm -v ~/.cache/ensemble-mcp:/home/app/.cache/ensemble-mcp ensemble-mcp
```

## Eval Framework

Benchmark suite for measuring tool effectiveness:

```bash
# Run eval benchmarks
python evals/runner.py

# Or via pytest
python -m pytest evals/ -v
```

## Supported AI Tools

| AI Tool | Config Format | Auto-Install |
|---------|--------------|--------------|
| OpenCode | JSON | Yes |
| Claude Code | JSON | Yes |
| GitHub Copilot (VS Code) | JSON | Yes |
| Cursor | JSON | Yes |
| Windsurf | JSON | Yes |
| Devin CLI | JSON | Yes |

## License

[MIT](LICENSE)