SentinelOps
Sends security alerts and notifications to a Telegram chat.
Click on "Install Server".
Wait a few minutes for the server to deploy. Once ready, it will show a "Started" state.
In the chat, type
@followed by the MCP server name and your instructions, e.g., "@SentinelOpsCheck if 185.220.101.1 is malicious and block it if yes."
That's it! The server will respond to your query, and you can continue using it as needed.
Here is a step-by-step guide with screenshots.
SentinelOps
AI-Powered Security Operations with Human-in-the-Loop Safety
An intelligent security operations platform demonstrating safe LLM agent design through multi-layered guardrails. Built with the Model Context Protocol (MCP), SentinelOps shows how to give AI agents access to destructive operations while maintaining rigorous human control.
What It Does
SentinelOps is a conversational security copilot that can investigate threats, recommend actions, and execute security responses—but only after explicit human approval for any destructive operation.
Core workflow:
User describes a security concern in natural language
Agent retrieves context (IP reputation, incident history, logs)
Agent proposes actions (block IP, quarantine file, create alert)
Human reviews preview and explicitly confirms or declines
Confirmed actions execute with full audit trail
Example session:
You: check if 185.220.101.1 is malicious
Agent: [calls check_ip_reputation(185.220.101.1)]
AbuseIPDB reports this IP has a 100% abuse confidence score
with 172 reports. It's associated with malware distribution.
Would you like me to block it?
You: yes, block that IP
Agent: [calls propose_block_ip(185.220.101.1, reason="malware distribution")]
PREVIEW: Would block IP 185.220.101.1
Reason: Malware distribution, 100% abuse score
Token: a3f7c491
[Confirm] [Decline]
[You click Confirm]
Agent: [execute_pending_action(a3f7c491) called by Flask /confirm route]
SUCCESS: Blocked IP 185.220.101.1
Firewall rule created: data/firewall_sandbox/block_185_220_101_1.ruleRelated MCP server: SecMCP
Architecture
The Challenge: Safe Tool Access for LLMs
LLMs are powerful but unreliable. Giving an agent tools like "block this IP" or "quarantine this file" creates real risk:
The model might hallucinate threats that don't exist
Parameter injection could trick the model into dangerous actions
A simple
confirmed=trueparameter can be bypassed by a clever adversarial prompt
SentinelOps addresses this through layered guardrails rather than trusting the model to make safe choices.
Layer 1: Evidence Chain Integrity
Problem: Model says "this IP is malicious" — how do you know it actually checked?
Solution: Chain-integrity tokens.
When the agent calls check_ip_reputation(ip), the server returns:
{
"ip": "185.220.101.1",
"abuse_score": 100,
"is_malicious": true,
"result_token": "f5bce9c4"
}If the agent then tries to create a high-severity incident about that IP, it must provide the result_token:
create_incident(
summary="Malicious IP detected: 185.220.101.1",
severity="high",
evidence_token="f5bce9c4" # REQUIRED for high/critical severity
)The server validates:
Token exists in recent reputation checks
Token's IP matches the incident claim
Token's data actually shows
is_malicious: true
Result: The model cannot fabricate high-severity incidents. It must provide evidence it actually retrieved.
Layer 2: Human-in-the-Loop Execution Gate
Problem: Even with evidence, we don't want the LLM to execute destructive actions directly. A confirmed=true parameter is too easy for the model to add on its own.
Solution: Propose/execute split enforced by separate processes.
Propose phase (agent has access):
result = propose_block_ip(
ip="185.220.101.1",
reason="Malware distribution"
)
# Returns: "PREVIEW: Would block IP... Token: a3f7c491"
# NO actual execution happens hereExecute phase (agent does NOT have access):
# This tool exists, but agent is never given access to it
execute_pending_action(token="a3f7c491")Instead, the Flask web UI provides /confirm/<token> and /decline/<token> routes that humans trigger by clicking buttons. The agent sees the proposal result but cannot proceed without the human's explicit POST request to Flask.
Why this works:
The agent cannot call
execute_pending_actionbecause it's never in its tool listEven if the agent tries to manipulate its own context, the execution happens in a separate process (Flask) that only responds to HTTP requests from the user's browser session
Tokens are session-scoped—even if the agent somehow got a valid token, it couldn't forge the session cookie
Layer 3: Multi-Gate Validation
Even with human confirmation, Flask validates three gates before executing:
# Gate 1: Token exists
if token not in pending_actions:
return 404
# Gate 2: Token belongs to your session
if action['session_id'] != current_session:
return 403
# Gate 3: Token hasn't been used already
if action['status'] != 'pending':
return 400Result: No replay attacks, no cross-session hijacking, no double-execution.
Architecture Diagram
┌─────────────────────────────────────────────────────┐
│ User (Browser) │
│ │ │
│ ├─ Sends query: "block 1.2.3.4" │
│ ├─ Views proposal preview │
│ └─ Clicks [Confirm] → POST /confirm/a3f7c491 │
└─────────────┬───────────────────────────────────────┘
│
┌─────▼──────┐
│ Flask │ Step 2: Propose phase
│ (web_ui) │ - Spawns MCP subprocess
│ │ - Agent gets tool list (NO execute_pending_action)
└─────┬──────┘ - Returns proposal with token
│
┌─────▼──────┐
│ Groq LLM │ Step 3: Agent reasoning
│ (LLaMA 3.3)│ - Calls check_ip_reputation (evidence)
│ │ - Calls propose_block_ip (preview)
└─────┬──────┘ - Returns "Token: a3f7c491"
│
┌─────▼──────┐
│ MCP Server │ Step 4: Tool execution
│ (server.py)│ - propose_block_ip: writes pending_actions.json
│ │ - execute_pending_action: NOT in agent's tool list
└─────┬──────┘
│
┌─────▼────────────────┐
│ File-Based Storage │ Step 5: Single source of truth
│ pending_actions.json │ - Both Flask and MCP read/write this file
└──────────────────────┘ - Prevents desynch bugs
│
┌─────▼──────┐
│ Flask │ Step 6: Execute phase (human-triggered)
│ /confirm │ - Validates 3 gates
│ │ - Spawns NEW MCP subprocess
└─────┬──────┘ - Calls execute_pending_action(token)
│
┌─────▼──────┐
│ MCP Server │ Step 7: Actual execution
│ (server.py)│ - Creates firewall rule in sandbox
│ │ - Marks action as 'executed'
└────────────┘ - Returns successKey insight: The agent process that proposes actions and the Flask process that executes them are separate. The agent cannot execute. Flask will not execute without human confirmation. This separation is enforced at the process level, not by trusting the model.
Setup
Prerequisites
Python 3.11+
Docker (optional, for containerized deployment)
API keys (all free tiers available):
Quick Start (Docker)
Clone and configure:
git clone https://github.com/yourusername/sentinelops.git
cd sentinelops
cp .env.example .env
# Edit .env with your API keysStart:
docker compose up -dAccess:
Open http://localhost:5000
Local Development
Install dependencies:
python -m venv venv
source venv/bin/activate # Linux/Mac
venv\Scripts\activate # Windows
pip install -r requirements.txtConfigure environment:
cp .env.example .env
# Edit .env with your API keysInitialize sandbox (first-time setup):
python setup_sandbox.py
python ingest_sample_logs.py # Optional: seed ChromaDBRun:
python web_ui.py # Web interface at http://localhost:5000
# OR
python cli.py # Terminal interfaceConfiguration
Required in .env:
GROQ_API_KEY=gsk_... # Get from console.groq.com
ABUSEIPDB_API_KEY=... # Get from abuseipdb.com/api
TELEGRAM_BOT_TOKEN=... # From @BotFather (optional)
TELEGRAM_CHAT_ID=... # Your chat ID (optional)
# Production settings
USE_REAL_APIS=true # false = stub mode for testing
ENABLE_DEBUG_ENDPOINTS=false # NEVER true in productionDesign Decisions
Why Not Just a confirmed Parameter?
Rejected approach:
@mcp.tool()
def block_ip(ip: str, confirmed: bool = False) -> str:
if not confirmed:
return "Please confirm this action"
# Execute blockProblem: The model can trivially set confirmed=True itself:
Agent: [calls block_ip("1.2.3.4", confirmed=True)]Even if you try to hide it:
def block_ip(ip: str) -> str:
"""Block an IP. Returns a confirmation token."""
# Show preview, return tokenThe model learns from examples and documentation that confirmed=True is the pattern, and will attempt it. Adversarial prompts can manipulate this further.
The fix: Execution is not a tool parameter. It's a separate HTTP endpoint in a different process that the agent cannot access.
Why Evidence Tokens?
Problem observed: In early versions, the agent would write incident reports claiming "this IP is malicious" without actually calling check_ip_reputation first. The model "knew" certain IP ranges were bad and fabricated justifications.
The fix: High-severity incidents require an evidence_token from a prior API call. The server validates the chain:
Was
check_ip_reputationcalled?Did it return a token?
Does that token's data support the severity claim?
Now the agent must actually retrieve evidence, not fabricate it.
Why File-Based Storage?
Problem: Flask (web UI) and MCP (agent tools) run in separate processes. Early versions used in-memory dicts, causing desynch:
Agent proposes action → writes to MCP's in-memory dict
User clicks Confirm → Flask reads from its own empty in-memory dict → 404
The fix: pending_actions.json is the single source of truth. Both processes read and write to the same file. No desynch possible.
Why Sandbox-Only Execution?
All destructive operations target sandboxed directories:
Firewall rules →
data/firewall_sandbox/(not actual iptables)Quarantined files →
data/sentinelops_sandbox/quarantine/(path-validated)
Rationale: This is a demonstration/development platform. In production, you'd replace the sandbox with real integrations (actual firewall API, real quarantine system), but the confirmation flow remains the same.
Testing
Unit Tests (Fast)
python -m pytest tests/test_unit.py -v
# 7 tests, <5 secondsIntegration Tests (Requires APIs)
python -m pytest tests/test_integration.py -v -m integration
# Full MCP stack, ~30 secondsSecurity Gate Tests
# Flask must be running on localhost:5000
python tests/test_security_gates.pyValidates:
✅ Valid token + correct session → executes
✅ Fake token → 404
✅ Reused token → 400
✅ Cross-session token → 403
✅ Declined action → no execution
Docker Validation
# Before building
python validate_docker.py
# After docker compose up
python tests/test_docker_deployment.pyTech Stack
LLM: Groq (LLaMA 3.3 70B) - Fast inference, function calling
MCP: Model Context Protocol - Standardized tool interface
Web: Flask - Lightweight web framework
Vector DB: ChromaDB - Semantic log search (future feature)
APIs: AbuseIPDB (IP reputation), Telegram (alerts)
Deployment: Docker + docker-compose
Project Structure
sentinelops/
├── server.py # MCP server - defines tools
├── agent_shared.py # Agent loop logic (reused by CLI and web)
├── cli.py # Terminal interface
├── web_ui.py # Flask web interface + confirmation routes
├── templates/
│ └── index.html # Web UI
├── tests/
│ ├── test_unit.py # Fast unit tests
│ ├── test_integration.py # Full stack tests
│ ├── test_security_gates.py # Security validation
│ └── ... # Additional test files
├── data/ # Runtime (gitignored)
│ ├── pending_actions.json
│ ├── firewall_sandbox/
│ └── chromadb_sentinelops/
├── Dockerfile
├── docker-compose.yml
├── requirements.txt
└── README.mdProduction Considerations
This is a demonstration platform. For production:
Security:
Add HTTPS (nginx reverse proxy)
Use secrets management (Docker secrets, Vault)
Enable rate limiting
Add authentication (OAuth, JWT)
Audit logging to immutable storage
Reliability:
Replace sandbox with real integrations
Add monitoring (Prometheus + Grafana)
Set up log aggregation
Configure resource limits
Implement health checks
Compliance:
SOC 2 controls for change management
Audit trail for all executed actions
Role-based access control
See ARCHITECTURE.md for detailed design rationale and Makefile for common operations.
Troubleshooting
Port 5000 in use:
# Use different port in docker-compose.yml
ports:
- "8080:5000"Groq rate limit (free tier: 100k tokens/day):
Wait for reset (error shows time)
Upgrade tier at console.groq.com
Use
USE_REAL_APIS=falsefor testing without API calls
ChromaDB slow first request (~30s):
This is normal (model loading)
Subsequent requests are fast
Happens once per container start
Docker build fails:
docker system prune -a # Clear cache
docker compose build --no-cacheLicense
MIT License - see LICENSE file
Acknowledgments
Built to demonstrate safe agent design patterns:
Evidence chains - Prevent AI hallucination in critical decisions
Propose/execute split - Separate planning from execution
Multi-gate validation - Defense in depth
Process isolation - Agent cannot bypass human confirmation
Inspired by real security operations workflows where humans remain accountable for destructive actions, even when AI suggests them.
This server cannot be installed
Maintenance
Resources
Unclaimed servers have limited discoverability.
Looking for Admin?
If you are the server author, to access and configure the admin panel.
Related MCP Servers
- Flicense-qualityDmaintenanceA unified MCP server providing observability, safety control, and behavior evolution for high-agency AI agents through tracing, replaying, and auditing. It features real-time firewall guardrails and ML-driven anomaly detection to monitor, block, or fork agent actions based on risk.Last updated19
- Alicense-qualityDmaintenanceMCP servers exposing security operations tools (VirusTotal, MITRE Caldera, LimaCharlie) to AI agents with defense-in-depth safety controls.Last updated2MIT
- Alicense-qualityCmaintenanceAn MCP server that provides on-demand safety for AI coding workflows, enabling inspection, review, checkpointing, and rollback of risky actions.Last updated771MIT
- Alicense-qualityBmaintenanceMCP server that provides impact preview and approval workflow for AI agent actions, allowing users to see diffs and risk assessments before any changes are executed.Last updated1MIT
Related MCP Connectors
Security firewall for AI agents — scans MCP calls for injection, secrets, and risks.
Let AI operate servers without SSH. Choose actions, approve risky changes, and audit every step.
MCP server for AI agents to plan, verify, and deploy Cloudflare-native apps.
Latest Blog Posts
- Who's Calling? MCP Hosts Are an Identity Blind Spot (And the Spec Knows It)By Om-Shree-0709 on .mcpAgent IdentityOAuth 2.1
- Your AI Chatbot Just Exposed Your CEO's Salary to an InternBy Om-Shree-0709 on .Agent IdentityMCP SecurityOAuth Delegation
- Why MCP Servers Need Execution Sandboxing (And Why Your Current Stack Isn't Enough)By Om-Shree-0709 on .Agentic AiPrompt InjectionWebAssembly
MCP directory API
We provide all the information about MCP servers via our MCP API.
curl -X GET 'https://glama.ai/api/mcp/v1/servers/ishachandan/SentinelOps'
If you have feedback or need assistance with the MCP directory API, please join our Discord server