Kontrol Freek
# Kontrol Freek — AI Assumption Firewall for MCP Agents
[](https://pypi.org/project/kontrol-freek-mcp/)
[](https://pypi.org/project/kontrol-freek-mcp/)
[](LICENSE)
[](https://modelcontextprotocol.io)
**Kontrol Freek** is an open-source [Model Context Protocol (MCP)](https://modelcontextprotocol.io) server that acts as an **AI safety guardrail** for autonomous agents. It intercepts AI assumptions before they cause irreversible mistakes, verifies every decision against a persistent project log, detects contradictions, scores risk, and routes human approval requests through Telegram, Slack, or native MCP elicitation — all without blocking your workflow.
> Gate every AI assumption. Keep humans in the loop. Prevent agentic mistakes before they happen.
---
## Why Kontrol Freek?
AI agents and coding assistants make implicit assumptions constantly — about architecture choices, file locations, API designs, and deployment targets. Without a structured checkpoint, these assumptions silently accumulate into hard-to-reverse technical debt or outright mistakes.
**Kontrol Freek solves the human-in-the-loop problem for MCP agents**: it sits between your AI agent and every risky decision, comparing new assumptions against your project's history, flagging contradictions, and routing approval requests to you — wherever you are.
Kontrol Freek adds a **decision firewall** between your AI agent and every risky action:
```
AI: "I'll use PostgreSQL for this project" ← assumption
↓
check_assumption("Use PostgreSQL", risk="medium", category="architecture")
↓
Kontrol Freek: query past decisions → detect contradictions → score risk
↓
├─ Low risk + past approval match → ✅ Auto-approve, continue
├─ Medium risk / new decision → 🔍 Notify human (Telegram / Slack / elicit)
└─ Contradiction or critical risk → ⛔ Block + require explicit approval
```
---
## Key Features
| Feature | Description |
|---------|-------------|
| **Assumption interception** | Catches AI guesses before they execute |
| **SQLite decision log** | Persists every decision per project |
| **Semantic similarity** | Finds related past decisions using TF-IDF or sentence-transformers |
| **Contradiction detection** | Blocks decisions that conflict with approved history |
| **Risk scoring** | Adaptive policy engine — auto-approve low risk, gate high risk |
| **Time-based decay** | Old decisions lose weight; prevents stale approvals |
| **Telegram polling** | Background loop processes `/kf approve/reject/answer` commands |
| **Multi-channel routing** | ctx.elicit() → Telegram → Slack → Web dashboard |
| **HMAC-SHA256 audit trail** | Cryptographically signed, hash-chained decision log |
| **Per-project isolation** | Each project gets its own DB, audit log, and config |
| **MCP native** | Works with any MCP-compatible client |
---
## How It Compares
| Feature | clarify-mcp | CONTINUITY | mcp-human-loop | VantaGate | **Kontrol Freek** |
|---------|:-----------:|:----------:|:--------------:|:---------:|:-----------------:|
| ctx.elicit() support | ✅ | ❌ | ❌ | ❌ | ✅ |
| SQLite decision log | ❌ | ✅ | ❌ | ❌ | ✅ |
| Risk scoring | ❌ | ❌ | ✅ | ❌ | ✅ |
| Semantic similarity | ❌ | ❌ | ❌ | ❌ | ✅ |
| Contradiction detection | ❌ | ❌ | ❌ | ❌ | ✅ |
| Cryptographic audit trail | ❌ | ❌ | ❌ | ✅ | ✅ |
| Time-based decision decay | ❌ | ❌ | ❌ | ❌ | ✅ |
| Telegram interactive approval | ❌ | ❌ | ❌ | ❌ | ✅ |
| Per-project isolation | ❌ | ❌ | ❌ | ❌ | ✅ |
| Adaptive policy engine | ❌ | ❌ | Basic | Static | **Adaptive** |
---
## Installation
### pip (recommended)
```bash
pip install kontrol-freek-mcp
```
### One-command setup (macOS / Linux / Windows)
```bash
git clone https://github.com/berkbayri/kontrol-freek-mcp.git
cd kontrol-freek-mcp
python install.py
```
The installer:
1. Installs the Python package
2. Generates a `.env` with a random HMAC secret
3. Registers a system service (auto-start on boot, crash recovery)
4. Registers the MCP server with compatible clients automatically
### Manual install
```bash
pip install -e ".[full]" # Full: Telegram + Web + sentence-transformers embeddings
pip install -e ".[lite]" # Lite: Telegram + Web (no embeddings)
pip install -e . # Minimal: stdio only
```
---
## Configuration
### MCP client config
Add to your MCP client's server configuration (`mcpServers` block):
```json
{
"mcpServers": {
"kontrol-freek": {
"command": "kontrol-freek",
"env": {
"KF_HMAC_SECRET": "your-secret",
"KF_TELEGRAM_TOKEN": "your-bot-token",
"KF_TELEGRAM_CHAT_ID": "your-chat-id"
}
}
}
}
```
Or using `python -m` if installed without the entry point:
```json
{
"mcpServers": {
"kontrol-freek": {
"command": "python",
"args": ["-m", "kontrol_freek_mcp"],
"env": {
"KF_HMAC_SECRET": "your-secret"
}
}
}
}
```
### Per-project config (`.kontrol-freek.json`)
Place this file in your project root to override global credentials and set a project name:
```json
{
"project_name": "my-app",
"telegram_token": "bot-token-override",
"telegram_chat_id": "chat-id-override",
"slack_webhook": ""
}
```
Per-project config is detected automatically — no restart required when the file changes.
### HTTP server mode (remote / multi-user)
```bash
kontrol-freek --transport streamable-http --port 8765
```
```json
{
"mcpServers": {
"kontrol-freek": {
"transport": "streamable-http",
"url": "http://localhost:8765/mcp"
}
}
}
```
---
## Telegram Setup
1. Message **@BotFather** → `/newbot` → copy the token
2. Start a DM with your bot or add it to a group
3. Get your chat ID: `https://api.telegram.org/bot<TOKEN>/getUpdates`
4. Set credentials in `.env` or `.kontrol-freek.json`
### Telegram commands
```
/kf approve <id> Approve a pending assumption
/kf reject <id> [reason] Reject with an optional reason
/kf answer <id> <answer> Answer a direct question
```
Kontrol Freek runs a **background long-poll loop** — no webhook setup needed. Commands are processed in real time while the MCP server is running.
---
## MCP Tools Reference
Always pass `project_root` as your current working directory so decisions are isolated per project.
| Tool | When to use |
|------|-------------|
| `check_assumption` | At every decision point — architecture, file paths, API choices, etc. |
| `confirm_decision` | To record a finalized decision; set `is_irreversible=True` for destructive actions |
| `ask_human` | When genuinely uncertain — prompts human via Telegram/Slack/elicitation |
| `query_decisions` | At the start of a task — load prior context before making new decisions |
| `revoke_decision` | When a past decision is no longer valid — prevents it from influencing future auto-approvals |
| `get_firewall_stats` | View approval rates, total decisions, and activity by category |
| `healthcheck` | Verify DB, audit chain, and notification channel health |
| `setup_project` | Initialize per-project config on first use |
### `check_assumption` response statuses
| Status | Meaning | Agent should… |
|--------|---------|---------------|
| `auto_approved` | Low risk, matches prior approved decision | Proceed |
| `pending_review` | Human review recommended (architecture / security / deployment) | Proceed with caution — call `confirm_decision()` when task is done |
| `blocked` | Contradiction detected or critical risk | **Stop** — do not proceed without explicit human approval |
| `human_approved` | Human approved via Telegram/Slack | Proceed |
| `human_rejected` | Human rejected | Stop and reconsider |
---
## How It Works
### Decision flow
```
AI calls check_assumption(assumption, risk_level, category, project_root)
│
├── Query SQLite for similar past decisions
├── Compute semantic similarity score (TF-IDF or sentence-transformers)
├── Run contradiction analysis
├── Policy engine → auto_approve / review / block
│
├── auto_approve → log, return status: "auto_approved"
├── pending_review → log, return status: "pending_review" (non-blocking)
│ optionally notify Telegram/Slack in background
└── block → log, return status: "blocked"
if Telegram/Slack configured → notify + wait (3 min max)
│
├── Telegram bot (/kf approve/reject <id>)
└── Slack webhook (text instructions)
```
### Policy rules
| Condition | Verdict |
|-----------|---------|
| `critical` risk | ⛔ Block — always requires human approval |
| Contradiction with approved decision | ⛔ Block |
| Category: `security`, `architecture`, `deployment` | 🔍 Human review |
| Low risk + ≥78% similarity + prior approval | ✅ Auto-approve |
| `high` risk | 🔍 Human review |
| Default | 🔍 Human review |
### Time-based decision decay
Older decisions carry less weight in similarity matching, preventing stale approvals from auto-approving new assumptions:
| Age | Weight |
|-----|--------|
| 0 days | 1.00 |
| 30 days | 0.72 |
| 90 days | 0.37 |
| 180 days | 0.14 |
### Cryptographic audit trail
Every action is written to an HMAC-SHA256 signed, hash-chained JSONL file:
```json
{
"action": "human_approve",
"text": "Use PostgreSQL",
"detail": "Approved via Telegram",
"decision_id": 42,
"ts": "2025-01-15T14:30:00Z",
"prev": "a1b2c3...",
"hash": "d4e5f6..."
}
```
Verify audit chain integrity:
```python
from kontrol_freek_mcp.audit import AuditTrail
trail = AuditTrail("~/.kontrol-freek/projects/my-app/audit.jsonl", "your-secret")
valid, count = trail.verify_chain()
print(f"Chain valid: {valid} — {count} entries")
```
---
## Auto-Start & Crash Recovery
`python install.py` configures an OS-native service:
| Platform | Mechanism | Details |
|----------|-----------|---------|
| **macOS** | LaunchAgent | `~/Library/LaunchAgents/com.kontrol-freek.mcp.plist` — starts at login, `KeepAlive` restarts on crash |
| **Linux** | systemd user service | `~/.config/systemd/user/kontrol-freek.service` — `Restart=on-failure`, persists across logouts via `loginctl enable-linger` |
| **Windows** | Task Scheduler | `schtasks` — triggers at logon |
The wrapper script includes **exponential backoff** (5s → 10s → 20s → ..., max 10 restarts).
```bash
python install.py --status # Health check
python install.py --uninstall # Clean removal
```
---
## Project Structure
```
kontrol-freek-mcp/
├── src/kontrol_freek_mcp/
│ ├── server.py # MCP server — 7 tools, 2 resources, 1 prompt
│ ├── db.py # SQLite decision database
│ ├── policy.py # Adaptive policy engine (risk scoring, decay)
│ ├── similarity.py # Semantic similarity (TF-IDF + sentence-transformers)
│ ├── notifier.py # Multi-channel routing + Telegram polling loop
│ ├── audit.py # HMAC-SHA256 hash-chain audit trail
│ └── web.py # FastAPI approval dashboard
├── tests/
├── install.py # One-command installer
├── pyproject.toml
├── .env.example
└── README.md
```
---
## License
MIT — free to use, modify, and distribute.
TDQS
Scored across 8 tools
Decision-related tools are mostly distinct: check_assumption verifies, confirm_decision records, query_decisions searches, revoke_decision invalidates. Some overlap exists between check_assumption and ask_human since both can involve seeking human input, but their primary purposes remain distinguishable.
Most tool names follow a clear verb_noun snake_case pattern: check_assumption, confirm_decision, query_decisions, revoke_decision, get_firewall_stats, setup_project. The single deviation is 'healthcheck', which is a compound noun without an explicit verb separator, but it is still readable and consistent in style.
Eight tools is a well-scoped set for a decision-management server. Each tool has a clear role in the lifecycle, and the count is within the ideal range without redundancy or bloat.
The decision lifecycle is well covered: setup, assumption checking, confirmation, querying, revocation, and human escalation are all present. Minor gaps exist, such as no explicit update_decision operation, but revoke_decision handles superseding, and healthcheck/stat tools round out operational coverage.