SecMCP
by scthornton
README.md
# SecMCP
MCP servers exposing security operations tools (VirusTotal, MITRE Caldera, LimaCharlie) to AI agents with defense-in-depth safety controls. Built for SANS SEC598 by Scott Thornton.
**3 servers, 20 tools, 7 resources, 153 tests.** All write/destructive operations are disabled by default with fail-closed safety controls.
<p align="center">
<img src="docs/images/secmcp-demo.png" alt="SecMCP terminal demo" width="700">
</p>
## Background
The [Model Context Protocol](https://modelcontextprotocol.io/) (MCP) is an open standard for connecting AI agents to external tools and data sources. SecMCP fills a gap in the AI security tooling ecosystem: no published MCP servers wrap common security operations platforms with production-grade safety controls.
Each server wraps a security platform's REST API and exposes it as MCP tools with:
- **Input validation** on all parameters (hashes, IPs, UUIDs, technique IDs)
- **Audit logging** with automatic sensitive value redaction
- **MCP ToolAnnotations** declaring each tool's read/write/destructive nature
- **Per-tool enable flags** and **dry-run mode** for write/destructive operations
## Repository Layout
```
secmcp/
├── packages/
│ ├── secmcp-shared/ # Thin shared library (config, errors, audit)
│ ├── secmcp-virustotal/ # 6 tools — threat intelligence lookups + file submission
│ ├── secmcp-caldera/ # 7 tools — adversary emulation with 6-layer safety
│ └── secmcp-limacharlie/ # 7 tools — EDR sensors, D&R rules, YARA scanning
├── tests/ # 153 tests across all packages + MCP protocol compliance
├── docs/
│ ├── architecture.md # System design and principles
│ ├── security-guide.md # Threat model and safety controls
│ └── servers/ # Per-server tool reference
├── .github/workflows/ci.yml # GitHub Actions: lint, format, test
├── .env.example # All config vars with safe defaults
└── pyproject.toml # uv workspace root
```
## Servers
| Server | Platform | Tools | Safety Controls |
|--------|----------|-------|-----------------|
| `secmcp-virustotal` | VirusTotal API v3 | 6 (5 read, 1 write) | Rate limiter (4 req/min free tier) |
| `secmcp-caldera` | MITRE Caldera | 7 (5 read, 1 write, 1 destructive) | Per-tool flags, group allowlist, dry-run, audit |
| `secmcp-limacharlie` | LimaCharlie EDR | 7 (4 read, 2 write, 1 destructive) | Per-tool flags, dry-run, JWT auth |
## Quick Start
**1. Clone and install**
```bash
git clone https://github.com/scthornton/secmcp.git
cd secmcp
uv sync --all-packages
```
**2. Configure**
```bash
cp .env.example .env
# Edit .env with your API keys
```
**3. Run tests**
```bash
uv run pytest tests/ -v
```
**4. Add to Claude Code**
```bash
# VirusTotal server
export SECMCP_VT_VT_API_KEY="your-key"
claude mcp add virustotal -- uv run python -m secmcp_virustotal
# Caldera server (safe defaults: dry-run on, all write tools disabled)
export SECMCP_CALDERA_CALDERA_API_KEY="your-key"
claude mcp add caldera -- uv run python -m secmcp_caldera
# LimaCharlie server (safe defaults: dry-run on, all write tools disabled)
export SECMCP_LC_LC_OID="your-org-id"
export SECMCP_LC_LC_API_KEY="your-key"
claude mcp add limacharlie -- uv run python -m secmcp_limacharlie
```
**5. Add to Claude Desktop**
Add to `~/Library/Application Support/Claude/claude_desktop_config.json`:
```json
{
"mcpServers": {
"secmcp-virustotal": {
"command": "uv",
"args": ["run", "--project", "/path/to/secmcp", "python", "-m", "secmcp_virustotal"],
"env": {
"SECMCP_VT_VT_API_KEY": "your-key"
}
},
"secmcp-caldera": {
"command": "uv",
"args": ["run", "--project", "/path/to/secmcp", "python", "-m", "secmcp_caldera"],
"env": {
"SECMCP_CALDERA_CALDERA_URL": "http://localhost:8888",
"SECMCP_CALDERA_CALDERA_API_KEY": "your-key",
"SECMCP_CALDERA_DRY_RUN": "true",
"SECMCP_CALDERA_ENABLE_CREATE_OPERATION": "false",
"SECMCP_CALDERA_ENABLE_EXECUTE_ABILITY": "false",
"SECMCP_CALDERA_ALLOWED_GROUPS_STR": ""
}
},
"secmcp-limacharlie": {
"command": "uv",
"args": ["run", "--project", "/path/to/secmcp", "python", "-m", "secmcp_limacharlie"],
"env": {
"SECMCP_LC_LC_OID": "your-org-id",
"SECMCP_LC_LC_API_KEY": "your-key",
"SECMCP_LC_DRY_RUN": "true",
"SECMCP_LC_ENABLE_DEPLOY_RULE": "false",
"SECMCP_LC_ENABLE_DELETE_RULE": "false",
"SECMCP_LC_ENABLE_YARA_SCAN": "false"
}
}
}
}
```
## Safety Controls
The Caldera and LimaCharlie servers implement independent, composable safety layers:
| Layer | Description | Default |
|-------|-------------|---------|
| **Per-tool enable flags** | Each write/destructive tool must be explicitly enabled | Disabled |
| **Group allowlist** (Caldera) | Operations can only target listed agent groups | Empty = all blocked |
| **Dry-run mode** | Write tools describe what they *would* do without executing | Enabled |
| **Input validation** | UUIDs, paw IDs, technique IDs, group names, rule names validated | Always on |
| **Audit logging** | JSON lines with redacted parameters, full output for destructive tools | Always on |
| **MCP ToolAnnotations** | `destructiveHint=True` triggers human confirmation in AI clients | Always on |
All safety defaults are **fail-closed**. An unconfigured server blocks all write operations.
## Architecture
```
AI Host (Claude Code / Claude Desktop / Cursor)
|
| MCP Protocol (stdio transport)
|
+-- secmcp-virustotal --> VirusTotal API v3 (HTTPS, API key header)
+-- secmcp-caldera --> Caldera REST API (HTTP, KEY header)
+-- secmcp-limacharlie --> LimaCharlie API (HTTPS, JWT exchange)
|
+-- secmcp-shared (config, errors, audit)
```
## Tech Stack
- **Python 3.12+** with `uv` workspaces for monorepo management
- **MCP SDK** (`mcp` 1.16+) with FastMCP for high-level tool/resource registration
- **httpx** for async HTTP clients, **Pydantic v2** for models and config
- **pytest** + **respx** for async testing with mocked HTTP responses
- **ruff** for linting and formatting
## Important Notes
- **stdio transport only** (v1) — servers run as child processes of the MCP host. HTTP transport with OAuth 2.1 is planned for v2.
- **API keys in environment variables** — never committed to the repo. Copy `.env.example` to `.env` and fill in your values.
- **Rate limiting** — VirusTotal free tier allows 4 requests/minute. The server enforces this automatically.
- **Caldera must be running** locally (default: `http://localhost:8888`) for the Caldera server to connect.
## Contributing
1. Fork the repository
2. Create a feature branch (`git checkout -b feature/my-feature`)
3. Run tests (`uv run pytest tests/ -v`) and lint (`uv run ruff check packages/ tests/`)
4. Submit a pull request
## License
MIT — see [LICENSE](LICENSE) for details.
---
## Contact
**Scott Thornton** — AI Security Researcher
- Website: [perfecxion.ai](https://perfecxion.ai/)
- Email: [scott@perfecxion.ai](mailto:scott@perfecxion.ai)
- LinkedIn: [linkedin.com/in/scthornton](https://www.linkedin.com/in/scthornton)
- ORCID: [0009-0008-0491-0032](https://orcid.org/0009-0008-0491-0032)
- GitHub: [@scthornton](https://github.com/scthornton)
**Security Issues**: Please report via [SECURITY.md](SECURITY.md)
This server cannot be deployed
Maintenance
ActivityInactive
ResponsivenessNo issues