MCP Agent Harness
by emmanuelol
README.md
# MCP Agent Harness
[](https://github.com/emmanuelol/mcp-agent-harness/actions/workflows/ci.yml)
[](LICENSE)
[](https://www.python.org/downloads/)
Generic, SRE-hardened Model Context Protocol (MCP) harness for autonomous agents. Designed to prevent LLM context exhaustion, enforce data boundaries, and maintain fail-closed observability across agentic workloads.
---
## Prerequisites
- **Docker** `>= 24.0`
- **Docker Compose** `>= 2.20`
- **GNU Make** `>= 4.3`
- *(Optional for local development)* **Python** `>= 3.11`
---
## Quickstart (Containerized)
No local Python environment or dependency installation required. All lifecycle steps run inside isolated containers:
```bash
# 1. Build the hardened container image
make build
# 2. Run the integration test suite
make test
# 3. Spin up the harness and verify live endpoint health
make demo
# 4. Run the security, leak, and Trivy CVE audit gate
make audit
```
---
## Architecture & Codebase Map
```text
mcp-agent-harness/
├── src/
│ └── mcp_agent_harness/
│ ├── __init__.py # Public exports: AgentHarness, guards, telemetry
│ ├── server.py # AgentHarness, ToolList, tool decorator, SSE app mounting
│ ├── guards.py # DataFrame blockade, TokenStarvationError, context & log capping
│ ├── telemetry.py # Correlated trace_id generation and context logging
│ └── __main__.py # CLI entrypoint for health checks and standalone daemon
├── tests/
│ ├── test_guards.py # Unit tests for DataFrame blockade, context truncation, log capping
│ ├── test_server.py # Sync/async tool execution, leak detection, registry checks
│ └── test_integration_sse.py # FastAPI SSE endpoint mounting and streaming tests
├── scripts/
│ ├── audit_image.sh # Fail-closed Trivy CVE scanner & prohibited file leak audit
│ └── check_blacklist.sh # Clean-room sensitive pattern scanner
├── Dockerfile # Multi-stage hardened Debian container definition
├── docker-compose.yml # Service definitions for daemon and test runner
└── Makefile # Standardized automation targets
```
---
## SRE Hardening Principles
1. **Token Starvation Guards**: Prevents raw DataFrames (`pandas`, `polars`) from leaking into LLM context windows. Enforces scalar metric summaries.
2. **Context Bounds**: Automatically truncates bulk `<DATA>` payloads and caps log output lines to prevent context window blowouts.
3. **Telemetry Tracing**: Generates correlated `trace_id` for every tool invocation.
4. **Fail-Closed Isolation**: Unhandled exceptions return structured error envelopes without terminating SSE streams.
---
## API & Configuration Reference
### `AgentHarness`
Main server class wrapping FastMCP with SRE guards.
```python
from mcp_agent_harness import AgentHarness
harness = AgentHarness(
name="analytics-mcp",
instructions="Operational analytics tools for agents.",
register_builtins=True,
)
```
| Parameter | Type | Default | Description |
| :--- | :--- | :--- | :--- |
| `name` | `str` | `"mcp-agent-harness"` | Identifier for the MCP server instance. |
| `instructions` | `str` | `"Generic SRE-hardened MCP Harness"` | System instructions exposed to MCP clients. |
| `register_builtins` | `bool` | `True` | Registers default diagnostic tools (`health`, `ping`, `diagnostics`). |
#### Methods
- `@harness.tool(*args, **kwargs)`: Decorator registering sync or `async` tools with automatic trace injection and DataFrame blockades.
- `harness.list_tools() -> ToolList`: Returns registered tool names (supports both sync iteration and async `await`).
- `harness.call_tool(name: str, *args, **kwargs) -> Any`: Directly invokes a registered tool by name.
- `harness.sse_app() -> Any`: Generates the Starlette/ASGI app for mounting into FastAPI.
---
### Guard Utilities (`mcp_agent_harness.guards`)
Configurable standalone filters to protect agent prompt budgets:
| Function | Parameters | Default | Description |
| :--- | :--- | :--- | :--- |
| `truncate_context()` | `context: Any, max_chars: int = 2000, strip_xml: bool = True` | `max_chars=2000` | Strips raw `<DATA>...</DATA>` XML blocks and truncates strings exceeding character limits. |
| `cap_log_lines()` | `text: Any, max_lines: int = 200` | `max_lines=200` | Caps multiline log dumps to prevent terminal context flooding. |
| `block_raw_dataframes()` | `obj: Any` | N/A | Recursively traverses dicts, lists, sets, and tuples, raising `TokenStarvationError` if a DataFrame is detected. |
---
## Guardrails in Action
### 1. Synchronous & Asynchronous Tools
```python
from mcp_agent_harness import AgentHarness
harness = AgentHarness(name="system-tools")
# Synchronous tool
@harness.tool()
def get_system_load() -> dict:
return {"load_1m": 0.42, "load_5m": 0.35}
# Asynchronous tool
@harness.tool()
async def fetch_cluster_metrics(region: str) -> dict:
# Non-blocking async execution
return {"region": region, "active_nodes": 12, "healthy": True}
```
### 2. Token Starvation Guard (DataFrame Blockade)
The harness blocks raw tabular data from entering LLM context. Returning a raw DataFrame immediately triggers `TokenStarvationError`, captured into a structured error envelope:
```python
import pandas as pd
from mcp_agent_harness import AgentHarness
harness = AgentHarness()
# ❌ BAD: Attempting to return raw DataFrame
@harness.tool()
def query_orders() -> pd.DataFrame:
return pd.DataFrame({"order_id": [1, 2], "amount": [99.5, 14.2]})
# Invoking this tool returns a safe error envelope instead of leaking rows:
# {
# "status": "error",
# "message": "Raw DataFrames are strictly prohibited in MCP tools. Return scalar metrics or token-compressed strings.",
# "trace_id": "mcp-3a1b4c9e"
# }
# ✅ GOOD: Return compact scalar metrics
@harness.tool()
def query_order_metrics() -> dict:
df = pd.DataFrame({"order_id": [1, 2], "amount": [99.5, 14.2]})
return {
"order_count": len(df),
"total_revenue": float(df["amount"].sum()),
"average_order": float(df["amount"].mean()),
}
```
### 3. Context & Log Bounds
```python
from mcp_agent_harness import truncate_context, cap_log_lines
raw_logs = "INFO: Step completed\n" * 500
# Safe for LLM prompts: capped at 200 lines
clean_logs = cap_log_lines(raw_logs, max_lines=200)
raw_prompt = "User query: analyze output <DATA>large blob...</DATA>"
# Strips bulk data XML tags and caps character length
bounded_prompt = truncate_context(raw_prompt, max_chars=1000)
```
---
## Telemetry & Error Envelopes
Every tool invocation automatically initializes an OpenTelemetry-compatible `trace_id` (`mcp-xxxxxxxx`).
When an unhandled exception occurs inside a tool, the harness isolates the failure:
- The underlying SSE stream remains open.
- The failure is logged with the correlated trace ID.
- The agent receives a predictable JSON envelope:
```json
{
"status": "error",
"message": "Division by zero",
"trace_id": "mcp-e4f912a7"
}
```
---
## Integration with FastAPI
Install the package in your consumer application:
```bash
pip install "git+https://github.com/emmanuelol/mcp-agent-harness.git@v0.1.0"
```
Mount into FastAPI:
```python
from fastapi import FastAPI
from mcp_agent_harness import AgentHarness
harness = AgentHarness(
name="production-harness",
instructions="Production operational agent harness.",
)
@harness.tool()
async def health_summary() -> dict:
return {"status": "operational", "uptime_pct": 99.98}
app = FastAPI(title="Agent Platform")
@app.get("/health")
def health() -> dict:
return {"status": "ok"}
# Mount MCP Server-Sent Events endpoint
app.mount("/mcp", harness.sse_app())
```
Run with Uvicorn:
```bash
uvicorn main:app --host 0.0.0.0 --port 8000
```
This server cannot be deployed
Maintenance
ActivityMaintained
ResponsivenessNo issues