opencti-mcp
> [!IMPORTANT]
> **This repository has been retired.** It is no longer maintained.
>
> This package is now part of the **[AppliedIR/sift-mcp](https://github.com/AppliedIR/sift-mcp)** monorepo.
>
> Documentation: [appliedir.github.io/aiir](https://appliedir.github.io/aiir/)
---
# OpenCTI MCP Server
An MCP (Model Context Protocol) server providing comprehensive threat intelligence access to OpenCTI for Claude Code and other MCP clients.
> **Note:** Validate and harden appropriately for your environment before production use.
## Installation Options
### Option A: As Part of Claude-IR (Recommended)
This MCP is designed as a component of the [Claude-IR](https://github.com/scriptedstatement/claude-ir) AI-assisted incident response workstation.
```bash
git clone https://github.com/scriptedstatement/claude-ir.git
cd claude-ir
./setup.sh
claude
```
**Benefits of Claude-IR installation:**
- Guided setup with component selection
- Pre-configured MCP integration
- Works alongside forensic-rag-mcp (knowledge search) and windows-triage-mcp (file validation)
- Forensic discipline rules and investigation workflows
**Note:** This MCP requires an OpenCTI instance. See `SETUP.md` for guidance on connecting to or deploying OpenCTI.
### Option B: Standalone Installation
Use standalone when you only need threat intelligence lookups without the full IR workstation.
```bash
git clone https://github.com/scriptedstatement/opencti-mcp.git
cd opencti-mcp
# Create virtual environment
python3 -m venv .venv
source .venv/bin/activate
# Install
pip install -e .
# Configure (requires OpenCTI instance - see SETUP.md)
export OPENCTI_TOKEN="your-api-token"
export OPENCTI_URL="http://localhost:8080" # Local Docker
# export OPENCTI_URL="https://opencti.example.com" # Remote/cloud
# Run server
python -m opencti_mcp
```
**For OpenCTI setup guidance:** See `SETUP.md`
## Features
### Search Operations (32 tools, 28 visible in read-only mode)
| Category | Tools | Description |
|----------|-------|-------------|
| **Unified Search** | `search_threat_intel` | Search across all entity types |
| **Threats** | `search_threat_actor`, `search_campaign` | APT groups, campaigns |
| **Arsenal** | `search_malware`, `search_tool`, `search_vulnerability` | Malware, tools, CVEs |
| **Techniques** | `search_attack_pattern`, `search_course_of_action` | MITRE ATT&CK, mitigations |
| **Observations** | `search_observable`, `search_sighting` | IOCs, detection events |
| **Events** | `search_incident` | Security incidents |
| **Analysis** | `search_reports`, `search_grouping`, `search_note` | Reports, groupings, notes |
| **Entities** | `search_organization`, `search_sector` | Organizations, industries |
| **Locations** | `search_location` | Countries, regions, cities |
| **Infrastructure** | `search_infrastructure` | C2, hosting, botnets |
### Entity Operations
| Tool | Description |
|------|-------------|
| `lookup_ioc` | Get full IOC context with relationships |
| `lookup_hash` | Look up file hash (MD5/SHA1/SHA256) |
| `get_entity` | Get any entity by ID |
| `get_relationships` | Get entity relationships |
| `get_recent_indicators` | Get indicators from last N days |
### Write Operations (requires `OPENCTI_READ_ONLY=false`)
| Tool | Description |
|------|-------------|
| `create_indicator` | Create new IOC |
| `create_note` | Add analyst note to entities |
| `create_sighting` | Record detection event |
| `trigger_enrichment` | Trigger VirusTotal/Shodan enrichment |
### System Operations
| Tool | Description |
|------|-------------|
| `get_health` | Check OpenCTI connectivity |
| `list_connectors` | List enrichment connectors |
| `get_network_status` | View adaptive metrics and recommendations |
| `force_reconnect` | Force reconnection (clears caches, resets circuit breaker) |
| `get_cache_stats` | View response cache statistics |
## Advanced Filtering
All search tools support advanced filtering:
```json
{
"query": "APT29",
"limit": 10,
"offset": 0,
"labels": ["tlp:amber", "apt"],
"confidence_min": 70,
"created_after": "2024-01-01",
"created_before": "2024-12-31"
}
```
## Configuration
Settings are loaded via `Config.load()` classmethod (`config.py`) with `SecretStr` token protection and helper parsers for typed env vars.
### Environment Variables
| Variable | Default | Description |
|----------|---------|-------------|
| `OPENCTI_URL` | `http://localhost:8080` | OpenCTI instance URL (use `https://` for remote) |
| `OPENCTI_TOKEN` | - | API token (required) |
| `OPENCTI_READ_ONLY` | `true` | Disable write operations |
| `OPENCTI_TIMEOUT` | `60` | Request timeout in seconds |
| `OPENCTI_MAX_RESULTS` | `100` | Maximum results per query |
| `OPENCTI_MAX_RETRIES` | `3` | Retry attempts for failures |
| `OPENCTI_RETRY_DELAY` | `1.0` | Initial retry delay (seconds) |
| `OPENCTI_RETRY_MAX_DELAY` | `30.0` | Maximum retry delay (seconds) |
| `OPENCTI_SSL_VERIFY` | `true` | Verify SSL certificates (set `false` for self-signed) |
| `OPENCTI_CIRCUIT_THRESHOLD` | `5` | Failures before circuit opens |
| `OPENCTI_CIRCUIT_TIMEOUT` | `60` | Seconds before circuit recovery |
| `OPENCTI_EXTRA_OBSERVABLE_TYPES` | - | Custom observable types (comma-separated) |
| `OPENCTI_EXTRA_PATTERN_TYPES` | - | Custom pattern types (comma-separated) |
| `OPENCTI_LOG_FORMAT` | `json` | Log format: "json" or "text" |
### Feature Flags
Control optional features via environment variables (prefix: `FF_`):
| Variable | Default | Description |
|----------|---------|-------------|
| `FF_STARTUP_VALIDATION` | `true` | Test API connectivity on server start |
| `FF_RESPONSE_CACHING` | `false` | Cache search results (reduces API calls) |
| `FF_GRACEFUL_DEGRADATION` | `true` | Return cached results when service unavailable |
| `FF_NEGATIVE_CACHING` | `true` | Cache "not found" results |
### Token Configuration
**Option 1: Environment variable (recommended for production)**
```bash
export OPENCTI_TOKEN="your-api-token"
```
**Option 2: Token file**
```bash
mkdir -p ~/.config/opencti-mcp
echo "your-api-token" > ~/.config/opencti-mcp/token
chmod 600 ~/.config/opencti-mcp/token
```
**Option 3: .env file (development)**
```
OPENCTI_TOKEN=your-api-token
```
### Custom Types for Extended OpenCTI
If your OpenCTI instance has custom observable types or pattern types (e.g., proprietary IOC formats, additional detection languages), configure them via environment variables:
```bash
# Add custom observable types (case-sensitive, comma-separated)
export OPENCTI_EXTRA_OBSERVABLE_TYPES="Internal-Host,Cloud-Resource,Custom-IOC"
# Add custom pattern types (case-insensitive, comma-separated)
export OPENCTI_EXTRA_PATTERN_TYPES="osquery,kql,custom-sig"
```
These extend the built-in allow-lists without removing standard STIX types.
### Claude Code Configuration
Add to your project-local `.mcp.json` (or see the parent [claude-ir](https://github.com/scriptedstatement/claude-ir) project for automated setup):
```json
{
"mcpServers": {
"opencti": {
"command": "/path/to/venv/bin/python",
"args": ["-m", "opencti_mcp"],
"cwd": "/path/to/opencti-mcp",
"env": {
"PYTHONPATH": "/path/to/opencti-mcp/src",
"OPENCTI_TOKEN": "your-api-token",
"OPENCTI_URL": "http://localhost:8080",
"OPENCTI_READ_ONLY": "true",
"OPENCTI_SSL_VERIFY": "true"
}
}
}
}
```
## Project Structure
```
opencti-mcp/
├── src/opencti_mcp/
│ ├── __init__.py # Package exports
│ ├── __main__.py # Entry point (with startup validation)
│ ├── server.py # MCP server (32 tools)
│ ├── client.py # OpenCTI API client (with caching)
│ ├── config.py # Configuration management
│ ├── validation.py # Input validation
│ ├── errors.py # Error hierarchy
│ ├── logging.py # Structured logging
│ ├── adaptive.py # Network metrics
│ ├── cache.py # TTL-based response caching
│ └── feature_flags.py # Feature flag management
├── tests/ # Test suite (1530 tests)
├── docs/ # Documentation
├── README.md # This file
├── CLAUDE.md # Development guide
├── IMPLEMENTATION.md # Technical architecture
└── pyproject.toml # Package configuration
```
## Development
### Run Tests
```bash
# Install dev dependencies
pip install -e ".[dev]"
# Run all tests
pytest
# With coverage
pytest --cov=opencti_mcp --cov-report=html
# Type checking
mypy src/opencti_mcp
```
### Test with MCP Inspector
```bash
npx @anthropic/mcp-inspector python -m opencti_mcp
```
### Key Commands
```bash
# Run MCP server
python -m opencti_mcp
# Test connection (original CLI)
python opencti_query.py "APT29" --type threat_actor
# Quick health check
python -c "from opencti_mcp import OpenCTIClient, Config; c = OpenCTIClient(Config.load()); print('OK' if c.is_available() else 'FAIL')"
```
## Production Considerations
### Local Docker vs Remote/Cloud
The default `OPENCTI_URL=http://localhost:8080` matches OpenCTI's standard Docker deployment, where the platform serves HTTP on port 8080. This is correct for local instances — traffic never leaves the machine.
For remote or cloud instances, use HTTPS. OpenCTI supports TLS either natively (`APP__HTTPS_CERT__*` env vars) or via a reverse proxy (Nginx, Caddy, Traefik) — the reverse proxy approach is more common in production.
### Recommended Settings for Remote/Cloud Instances
```bash
export OPENCTI_URL=https://opencti.example.com # HTTPS for remote
export OPENCTI_TIMEOUT=120 # Higher for cloud (default 60 may be tight for complex queries)
export OPENCTI_MAX_RETRIES=3 # Retry on transient failures
export OPENCTI_SSL_VERIFY=true # Always for production (false only for self-signed certs)
export OPENCTI_READ_ONLY=true # Unless writes needed
```
> **Cloud users:** If you experience timeouts or circuit breaker trips, increase `OPENCTI_TIMEOUT` to 120-180. Complex threat intel queries on remote instances can take 60+ seconds under load.
### Adaptive Metrics
Use `get_network_status` tool to view:
- Latency statistics (P50/P95/P99)
- Success rates
- Circuit breaker state
- Recommended timeout/retry settings
## Requirements
- Python 3.10+
- OpenCTI 6.x instance
- pycti 6.x
- mcp 1.x
## Acknowledgments
Architecture and direction by Steve Anson. Implementation by Claude Code (Anthropic).
## License
MIT
TDQS
Scored across 28 tools
Most tools are neatly separated by STIX entity type via the search_<entity> family, so an agent can usually pick the right one. However, search_threat_intel broadly overlaps with every specific search, and lookup_ioc vs. lookup_hash creates ambiguity for hash lookups.
Tool names consistently follow a lowercase snake_case verb_noun structure, with search_<entity> dominating the set. The mix of search, lookup, get, list, and force verbs is mostly predictable, though force_reconnect and the generic search_threat_intel are minor deviations from the clearer noun patterns.
At 28 tools this is on the heavy side, but the count is largely driven by comprehensive coverage of OpenCTI's many STIX entity types. Several operational tools like get_cache_stats and get_network_status add bulk and could be trimmed, yet each search tool has a distinct target.
For a read-only threat intelligence investigation server, the surface is quite complete: it covers major STIX entities, IOC lookup, generic entity details, relationships, recent indicators, and health/connector status. It lacks create/update/delete operations, but the tool names suggest the server is intentionally query-focused, so this is a minor gap rather than a critical one.