Skip to main content
Glama
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)