Skip to main content
Glama
proactive-agent-mcp

proactive-agent-mcp

by MishaelOliva
README.md
# proactive-agent-mcp

A [Model Context Protocol](https://modelcontextprotocol.io) server in Python that exposes a proactive
triage queue, document compliance validation, grounded knowledge retrieval, and server-enforced
guardrails for autonomous agents. Speaks JSON-RPC 2.0 over stdio.

[![CI](https://github.com/MishaelOliva/proactive-agent-mcp/actions/workflows/ci.yml/badge.svg)](https://github.com/MishaelOliva/proactive-agent-mcp/actions/workflows/ci.yml)
[![License: MIT](https://img.shields.io/badge/License-MIT-blue.svg)](LICENSE)
[![Python: 3.10+](https://img.shields.io/badge/Python-3.10%2B-brightgreen.svg)](https://python.org)
[![MCP: 2025-06-18](https://img.shields.io/badge/MCP-2025--06--18-orange.svg)](https://modelcontextprotocol.io)

## What it does

- **Proactive triage with leases.** `poll_event_queue` claims unprocessed events and takes a time-boxed
  lease on each. If the agent dies mid-triage the lease lapses and the event returns to the queue.
  `complete_event` and `release_event` settle or hand back work explicitly.
- **Document compliance evaluation.** `evaluate_document_compliance` checks extracted document fields
  against a declared schema, reporting missing fields, regex violations, a confidence score, and a
  risk level.
- **Grounded retrieval.** `query_rag_knowledge` ranks an in-repository corpus with sparse TF-IDF
  vectors and cosine similarity, returning measured latency and an explicit grounding verdict.
- **Human-in-the-loop gates.** `request_human_approval` parks a sensitive action behind an
  HMAC-SHA256 signed ticket. `verify_approval_token` checks a supervisor's confirmation code.
- **Cost enforcement.** `track_cost_budget` books token spend, and the server refuses further tool
  calls for any session that has exhausted its budget.

## Architecture

```
+--------------------------------------------------+
|        Client (Claude Desktop / Cursor / IDE)     |
+----------------------+---------------------------+
                       |
                       |  JSON-RPC 2.0 over stdio
                       v
+--------------------------------------------------+
|              proactive-agent-mcp                  |
|                                                  |
|  server.py     dispatch, negotiation, budgets    |
|  protocol.py   JSON-RPC + MCP primitives         |
|  validation.py pydantic argument enforcement     |
|                                                  |
|  tools/     triage, compliance, knowledge,       |
|             guardrails (HITL + cost)             |
|  resources/ system://health, compliance://standards
|  prompts/   autonomous_triage_loop,              |
|             compliance_audit_brief                |
+--------------------------------------------------+
```

The event queue and knowledge corpus are in-memory reference implementations. They reset on restart
and are not shared between replicas.

## Quick start

```bash
git clone https://github.com/MishaelOliva/proactive-agent-mcp.git
cd proactive-agent-mcp
pip install -e ".[dev]"
python -m proactive_agent_mcp.server
```

To watch a full triage session, including the human-approval round trip and budget enforcement:

```bash
python examples/run_client_demo.py
```

## Configuration

### Claude Desktop

```json
{
  "mcpServers": {
    "proactive-agent": {
      "command": "python",
      "args": ["-m", "proactive_agent_mcp.server"],
      "env": {
        "PYTHONUNBUFFERED": "1",
        "MCP_SIGNING_SECRET": "generate-with-openssl-rand-hex-32"
      }
    }
  }
}
```

### Cursor (`.cursor/mcp.json`)

```json
{
  "mcpServers": {
    "proactive-agent": {
      "command": "python",
      "args": ["-m", "proactive_agent_mcp.server"],
      "env": {
        "MCP_SIGNING_SECRET": "generate-with-openssl-rand-hex-32"
      }
    }
  }
}
```

### Environment variables

| Variable | Purpose | Default |
| :--- | :--- | :--- |
| `MCP_SIGNING_SECRET` | Key for HMAC-SHA256 approval codes. **Set this.** An unset value produces a random per-process secret and logs a warning, so tokens do not survive a restart. | random, per process |
| `MCP_SESSION_BUDGET_USD` | Default per-session spend ceiling. | `5.0` |
| `MCP_LOG_LEVEL` | Log level for the stderr stream. | `INFO` |
| `PYTHONUNBUFFERED` | Flush stdout so responses are not buffered. | `1` recommended |

## Tools

| Tool | Purpose |
| :--- | :--- |
| `poll_event_queue` | Claim events under a lease. |
| `complete_event` | Settle a claimed event. |
| `release_event` | Return a claimed event to the queue. |
| `push_event` | Record an observation onto the queue. |
| `evaluate_document_compliance` | Validate extracted document fields. |
| `query_rag_knowledge` | Rank the corpus by TF-IDF cosine similarity. |
| `request_human_approval` | Park a sensitive action for human authorization. |
| `verify_approval_token` | Verify a supervisor's confirmation code. |
| `track_cost_budget` | Book token spend against a session. |
| `set_active_session` | Choose which session the budget guard charges. |

## Security model

The human-in-the-loop gate is a **worked pattern, not a production authorization system**. What it
does guarantee:

- Approval codes are **full 256-bit HMAC-SHA256** values, base32-encoded for legibility. They are not
  truncated.
- The signed payload binds the ticket id, action name, a SHA-256 digest of the action parameters, and
  the absolute expiry. A code cannot be re-pointed at a different action, swapped for different
  parameters, or replayed after expiry.
- The code is **recomputed** at verification time rather than read from a stored expected value, so a
  tampered ticket record invalidates its own code.
- Tickets are **single-use**, compared in **constant time**, and garbage-collected once settled.
- The confirmation code is **never returned** by `request_human_approval`. It must arrive through a
  channel the agent cannot reach.
- The signing secret has **no hardcoded default**. With `MCP_SIGNING_SECRET` unset, a random secret
  is generated at start-up, so a code cannot be derived from knowledge of this repository.

What it does **not** guarantee, and what a real deployment must add:

- Binding approvals to an authenticated human principal. The gate proves a holder of the secret
  approved, not *who*.
- Surviving a restart or spanning replicas. Tickets live in process memory.
- An authenticated delivery channel for the confirmation code.
- Protection against a sufficiently privileged caller with in-process access.

The budget guard **enforces** rather than advises: once a session exceeds its ceiling, the server
refuses non-guardrail tool calls. Accounting tools stay reachable so the agent can report honestly
rather than dead-ending.

## Testing

```bash
python -m unittest discover -s tests -t .
```

116 tests covering protocol conformance (initialization gating, notification suppression, version
negotiation, batching, pagination, error codes), tool behaviour, the HITL security properties, budget
enforcement, and an end-to-end stdio session against a real subprocess.

Several tests are explicit regression guards for defects fixed in v1.1.0: a confidence score that
capped a perfect document at 0.571, a hardcoded retrieval latency, a forgeable approval secret,
a mid-session budget change that was silently ignored, and an event queue that stranded work when an
agent crashed.

CI runs the suite on Python 3.10-3.12 with and without `MCP_SIGNING_SECRET` set, lints with ruff,
verifies the wheel installs in a clean environment, and smoke tests the container entrypoint.

## Limitations

- **Single process.** State is in memory, so the event queue, tickets, and budget ledger reset on
  restart and are not shared across replicas.
- **stdio only.** Streamable HTTP transport is not implemented.
- **Lexical retrieval.** TF-IDF cosine matches vocabulary, not meaning. Paraphrased queries retrieve
  poorly. Dense embeddings would be the natural upgrade; the interface would not change.
- **Deterministic compliance.** Field and regex validation only. It says nothing about whether
  extracted values are truthful.
- **Illustrative pricing.** `MODEL_PRICING` in `tools/guardrails.py` is a static table that needs
  periodic refreshing. Treat it as configuration.

## License

[MIT](LICENSE).

---
*Built by [Mishael Oliva](https://github.com/MishaelOliva) • [LinkedIn](https://www.linkedin.com/in/mishael-oliva-96a31b3a2)*

TDQS

A3.9/5.0

Scored across 10 tools

Disambiguation4/5

The tools cluster into four clear domains: event-queue lifecycle (poll/complete/release/push), approval (request/verify), budget (track/set_active_session), and two standalone capabilities (compliance, RAG). complete_event vs release_event could be momentarily confused, but the descriptions clearly distinguish settling from returning to the pool. set_active_session and track_cost_budget are related but have distinct roles.

Naming Consistency5/5

Every tool follows a consistent verb_noun snake_case pattern (poll_event_queue, complete_event, verify_approval_token, track_cost_budget, etc.). No mixed conventions or vague verbs anywhere in the set.

Tool Count5/5

Ten tools is well within the sweet spot for a triage/guardrail agent, and each tool earns its place by covering a distinct operation rather than duplicating another. No bloat or thin coverage.

Completeness4/5

The event queue has full lifecycle coverage (push/poll/complete/release), approval has request+verify, and budget has tracking plus session selection. Minor gaps like inspecting queue depth or listing pending events exist, but agents can work around them via polling.

Maintenance

ActivitySlowing
ResponsivenessNo recent community issues