threatray-mcp 1.0.2__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- threatray_mcp-1.0.2/.gitignore +81 -0
- threatray_mcp-1.0.2/CHANGELOG.md +67 -0
- threatray_mcp-1.0.2/LICENSE +21 -0
- threatray_mcp-1.0.2/PKG-INFO +191 -0
- threatray_mcp-1.0.2/README.md +152 -0
- threatray_mcp-1.0.2/pyproject.toml +100 -0
- threatray_mcp-1.0.2/src/threatray_mcp/README.md +166 -0
- threatray_mcp-1.0.2/src/threatray_mcp/__init__.py +10 -0
- threatray_mcp-1.0.2/src/threatray_mcp/__main__.py +17 -0
- threatray_mcp-1.0.2/src/threatray_mcp/client/__init__.py +55 -0
- threatray_mcp-1.0.2/src/threatray_mcp/client/_http.py +197 -0
- threatray_mcp-1.0.2/src/threatray_mcp/client/_jobs.py +61 -0
- threatray_mcp-1.0.2/src/threatray_mcp/client/_types.py +45 -0
- threatray_mcp-1.0.2/src/threatray_mcp/client/ai_analysis.py +107 -0
- threatray_mcp-1.0.2/src/threatray_mcp/client/analyses.py +72 -0
- threatray_mcp-1.0.2/src/threatray_mcp/client/capa.py +50 -0
- threatray_mcp-1.0.2/src/threatray_mcp/client/files.py +35 -0
- threatray_mcp-1.0.2/src/threatray_mcp/client/functions.py +78 -0
- threatray_mcp-1.0.2/src/threatray_mcp/client/samples.py +14 -0
- threatray_mcp-1.0.2/src/threatray_mcp/client/search.py +44 -0
- threatray_mcp-1.0.2/src/threatray_mcp/client/submissions.py +211 -0
- threatray_mcp-1.0.2/src/threatray_mcp/config.py +57 -0
- threatray_mcp-1.0.2/src/threatray_mcp/errors.py +60 -0
- threatray_mcp-1.0.2/src/threatray_mcp/formatters/__init__.py +48 -0
- threatray_mcp-1.0.2/src/threatray_mcp/formatters/_helpers.py +90 -0
- threatray_mcp-1.0.2/src/threatray_mcp/formatters/ai_analysis.py +123 -0
- threatray_mcp-1.0.2/src/threatray_mcp/formatters/analyses.py +810 -0
- threatray_mcp-1.0.2/src/threatray_mcp/formatters/capa.py +215 -0
- threatray_mcp-1.0.2/src/threatray_mcp/formatters/files.py +229 -0
- threatray_mcp-1.0.2/src/threatray_mcp/formatters/functions.py +532 -0
- threatray_mcp-1.0.2/src/threatray_mcp/formatters/samples.py +15 -0
- threatray_mcp-1.0.2/src/threatray_mcp/formatters/search.py +269 -0
- threatray_mcp-1.0.2/src/threatray_mcp/formatters/submissions.py +216 -0
- threatray_mcp-1.0.2/src/threatray_mcp/log.py +25 -0
- threatray_mcp-1.0.2/src/threatray_mcp/models/__init__.py +85 -0
- threatray_mcp-1.0.2/src/threatray_mcp/models/ai_analysis.py +67 -0
- threatray_mcp-1.0.2/src/threatray_mcp/models/analyses.py +64 -0
- threatray_mcp-1.0.2/src/threatray_mcp/models/capa.py +27 -0
- threatray_mcp-1.0.2/src/threatray_mcp/models/common.py +131 -0
- threatray_mcp-1.0.2/src/threatray_mcp/models/files.py +64 -0
- threatray_mcp-1.0.2/src/threatray_mcp/models/functions.py +108 -0
- threatray_mcp-1.0.2/src/threatray_mcp/models/samples.py +17 -0
- threatray_mcp-1.0.2/src/threatray_mcp/models/search.py +78 -0
- threatray_mcp-1.0.2/src/threatray_mcp/models/submissions.py +308 -0
- threatray_mcp-1.0.2/src/threatray_mcp/server.py +42 -0
- threatray_mcp-1.0.2/src/threatray_mcp/tools/__init__.py +21 -0
- threatray_mcp-1.0.2/src/threatray_mcp/tools/_cache.py +98 -0
- threatray_mcp-1.0.2/src/threatray_mcp/tools/_context.py +12 -0
- threatray_mcp-1.0.2/src/threatray_mcp/tools/_format.py +8 -0
- threatray_mcp-1.0.2/src/threatray_mcp/tools/ai_analysis.py +133 -0
- threatray_mcp-1.0.2/src/threatray_mcp/tools/analyses.py +137 -0
- threatray_mcp-1.0.2/src/threatray_mcp/tools/capa.py +73 -0
- threatray_mcp-1.0.2/src/threatray_mcp/tools/files.py +108 -0
- threatray_mcp-1.0.2/src/threatray_mcp/tools/functions.py +196 -0
- threatray_mcp-1.0.2/src/threatray_mcp/tools/samples.py +38 -0
- threatray_mcp-1.0.2/src/threatray_mcp/tools/search.py +130 -0
- threatray_mcp-1.0.2/src/threatray_mcp/tools/submissions.py +224 -0
|
@@ -0,0 +1,81 @@
|
|
|
1
|
+
# Byte-compiled / optimized / DLL files
|
|
2
|
+
__pycache__/
|
|
3
|
+
*.py[cod]
|
|
4
|
+
*$py.class
|
|
5
|
+
|
|
6
|
+
# C extensions
|
|
7
|
+
*.so
|
|
8
|
+
|
|
9
|
+
# Distribution / packaging
|
|
10
|
+
.Python
|
|
11
|
+
build/
|
|
12
|
+
develop-eggs/
|
|
13
|
+
dist/
|
|
14
|
+
downloads/
|
|
15
|
+
eggs/
|
|
16
|
+
.eggs/
|
|
17
|
+
lib/
|
|
18
|
+
lib64/
|
|
19
|
+
parts/
|
|
20
|
+
sdist/
|
|
21
|
+
var/
|
|
22
|
+
wheels/
|
|
23
|
+
*.egg-info/
|
|
24
|
+
.installed.cfg
|
|
25
|
+
*.egg
|
|
26
|
+
|
|
27
|
+
# PyInstaller
|
|
28
|
+
*.manifest
|
|
29
|
+
*.spec
|
|
30
|
+
|
|
31
|
+
# Installer logs
|
|
32
|
+
pip-log.txt
|
|
33
|
+
pip-delete-this-directory.txt
|
|
34
|
+
|
|
35
|
+
# Unit test / coverage reports
|
|
36
|
+
htmlcov/
|
|
37
|
+
.tox/
|
|
38
|
+
.nox/
|
|
39
|
+
.coverage
|
|
40
|
+
.coverage.*
|
|
41
|
+
.cache
|
|
42
|
+
nosetests.xml
|
|
43
|
+
coverage.xml
|
|
44
|
+
*.cover
|
|
45
|
+
*.py,cover
|
|
46
|
+
.hypothesis/
|
|
47
|
+
.pytest_cache/
|
|
48
|
+
tests/coverage/
|
|
49
|
+
|
|
50
|
+
# Translations
|
|
51
|
+
*.mo
|
|
52
|
+
*.pot
|
|
53
|
+
|
|
54
|
+
# Environments
|
|
55
|
+
.env
|
|
56
|
+
.venv
|
|
57
|
+
env/
|
|
58
|
+
venv/
|
|
59
|
+
ENV/
|
|
60
|
+
env.bak/
|
|
61
|
+
venv.bak/
|
|
62
|
+
|
|
63
|
+
# IDEs
|
|
64
|
+
.idea/
|
|
65
|
+
.vscode/
|
|
66
|
+
*.swp
|
|
67
|
+
*.swo
|
|
68
|
+
*~
|
|
69
|
+
|
|
70
|
+
# mypy
|
|
71
|
+
.mypy_cache/
|
|
72
|
+
.dmypy.json
|
|
73
|
+
dmypy.json
|
|
74
|
+
|
|
75
|
+
# ruff
|
|
76
|
+
.ruff_cache/
|
|
77
|
+
|
|
78
|
+
# OS
|
|
79
|
+
.DS_Store
|
|
80
|
+
Thumbs.db
|
|
81
|
+
|
|
@@ -0,0 +1,67 @@
|
|
|
1
|
+
# Changelog
|
|
2
|
+
|
|
3
|
+
All notable changes to `threatray-mcp` are documented here. Format follows
|
|
4
|
+
[Keep a Changelog](https://keepachangelog.com/en/1.1.0/); versioning follows
|
|
5
|
+
[Semantic Versioning](https://semver.org/spec/v2.0.0.html).
|
|
6
|
+
|
|
7
|
+
## [1.0.2] — 2026-06-09
|
|
8
|
+
|
|
9
|
+
### Overview
|
|
10
|
+
|
|
11
|
+
`threatray-mcp` is a Model Context Protocol server for the Threatray malware
|
|
12
|
+
analysis and threat intelligence platform. It runs over stdio so MCP-aware
|
|
13
|
+
clients (Claude Code, Claude Desktop, Cursor, Cline, Windsurf, …) can query
|
|
14
|
+
samples, run code-similarity retrohunts, fetch CAPA capabilities and AI
|
|
15
|
+
analyses, aggregate IOCs, and submit files for analysis.
|
|
16
|
+
|
|
17
|
+
### Tools
|
|
18
|
+
|
|
19
|
+
28 tools, aligned with the public
|
|
20
|
+
[Threatray API taxonomy](https://docs.threatray.com/reference/overview-api):
|
|
21
|
+
|
|
22
|
+
- **Search:** `threatray_search`, `threatray_retrohunt_sample`
|
|
23
|
+
- **Samples:** `threatray_get_sample`
|
|
24
|
+
- **Submissions (read):** `threatray_list_submissions`, `threatray_get_task`, `threatray_get_task_by_analysis`, `threatray_list_tasks`
|
|
25
|
+
- **Submissions (write):** `threatray_submit_sample`, `threatray_submit_url`, `threatray_submit_endpoint_scan_archive`, `threatray_submit_minidump`, `threatray_submit_mans_file`
|
|
26
|
+
- **Analyses:** `threatray_get_analysis`, `threatray_get_osint`, `threatray_list_analyses`, `threatray_list_endpoint_scan_analyses`
|
|
27
|
+
- **Files:** `threatray_get_file_metadata`, `threatray_get_strings`, `threatray_download_file`
|
|
28
|
+
- **Functions:** `threatray_list_functions`, `threatray_get_code_detections`, `threatray_retrohunt_functions`, `threatray_diff_functions`
|
|
29
|
+
- **CAPA:** `threatray_get_capa`
|
|
30
|
+
- **AI Analysis:** `threatray_get_ai_analysis`, `threatray_get_ai_analysis_by_id`, `threatray_list_ai_analyses`, `threatray_get_latest_ai_job`
|
|
31
|
+
|
|
32
|
+
All tools accept `response_format=markdown` (default) or `response_format=json`.
|
|
33
|
+
|
|
34
|
+
### Configuration
|
|
35
|
+
|
|
36
|
+
Settings via environment variables (prefix `THREATRAY_`):
|
|
37
|
+
|
|
38
|
+
| Env var | Default | Purpose |
|
|
39
|
+
|---|---|---|
|
|
40
|
+
| `THREATRAY_API_KEY` | (required) | API key for the realm |
|
|
41
|
+
| `THREATRAY_API_URL` | (required) | API endpoint for the realm your key belongs to |
|
|
42
|
+
| `THREATRAY_LOG_LEVEL` | `WARNING` | `DEBUG` / `INFO` / `WARNING` / `ERROR` |
|
|
43
|
+
| `THREATRAY_TRANSPORT` | `stdio` | `stdio` (default) or `http` (standalone server) |
|
|
44
|
+
| `THREATRAY_HOST` | `0.0.0.0` | Bind address when `THREATRAY_TRANSPORT=http` |
|
|
45
|
+
| `THREATRAY_PORT` | `8000` | TCP port when `THREATRAY_TRANSPORT=http` |
|
|
46
|
+
|
|
47
|
+
### Notable
|
|
48
|
+
|
|
49
|
+
- **Transports:** stdio (default — JSON-RPC over stdin/stdout, stdout reserved
|
|
50
|
+
for the protocol, logs to stderr) and streamable HTTP (standalone server on
|
|
51
|
+
`THREATRAY_HOST:THREATRAY_PORT/mcp`, for containerized deployments where the
|
|
52
|
+
consuming client cannot spawn the server as a subprocess). No app-level auth
|
|
53
|
+
on HTTP — restrict ingress at the network layer.
|
|
54
|
+
- **Errors:** typed exception hierarchy surfaced as MCP `tool_error` results so
|
|
55
|
+
agents see structured failures rather than success-shaped strings.
|
|
56
|
+
- **AI analysis flow:** `threatray_get_ai_analysis` supports a
|
|
57
|
+
`trigger_only=True` fire-and-forget mode for slow files; the agent can poll
|
|
58
|
+
later via `threatray_get_latest_ai_job`. Sync wait is configurable
|
|
59
|
+
(`max_wait_seconds`, default 600s, upper bound 3600s).
|
|
60
|
+
- **Python support:** 3.11, 3.12, 3.13.
|
|
61
|
+
|
|
62
|
+
### Acknowledgments
|
|
63
|
+
|
|
64
|
+
- **TiQ Labs** — contributed the streamable HTTP transport (server-side
|
|
65
|
+
config + dispatch, compose service, integration test) plus a fix for a
|
|
66
|
+
test-runner bug where Compose-passed empty env vars (`${VAR:-}`) silenced
|
|
67
|
+
`os.environ.setdefault` defaults.
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 Threatray
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
|
@@ -0,0 +1,191 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: threatray-mcp
|
|
3
|
+
Version: 1.0.2
|
|
4
|
+
Summary: MCP server for the Threatray malware analysis and threat intelligence platform
|
|
5
|
+
Project-URL: Homepage, https://www.threatray.com
|
|
6
|
+
Project-URL: Repository, https://github.com/threatray/threatray-mcp
|
|
7
|
+
Project-URL: Issues, https://github.com/threatray/threatray-mcp/issues
|
|
8
|
+
Project-URL: Documentation, https://github.com/threatray/threatray-mcp#readme
|
|
9
|
+
Project-URL: Threatray API reference, https://docs.threatray.com/reference/overview-api
|
|
10
|
+
Author-email: Threatray <operations@threatray.com>
|
|
11
|
+
License-Expression: MIT
|
|
12
|
+
License-File: LICENSE
|
|
13
|
+
Keywords: capa,ioc,malware,mcp,threat-intelligence,threatray,yara
|
|
14
|
+
Classifier: Development Status :: 4 - Beta
|
|
15
|
+
Classifier: Environment :: Console
|
|
16
|
+
Classifier: Intended Audience :: Information Technology
|
|
17
|
+
Classifier: License :: OSI Approved :: MIT License
|
|
18
|
+
Classifier: Operating System :: OS Independent
|
|
19
|
+
Classifier: Programming Language :: Python :: 3
|
|
20
|
+
Classifier: Programming Language :: Python :: 3.11
|
|
21
|
+
Classifier: Programming Language :: Python :: 3.12
|
|
22
|
+
Classifier: Programming Language :: Python :: 3.13
|
|
23
|
+
Classifier: Topic :: Security
|
|
24
|
+
Requires-Python: <3.14,>=3.11
|
|
25
|
+
Requires-Dist: fastmcp<4,>=3
|
|
26
|
+
Requires-Dist: httpx~=0.27
|
|
27
|
+
Requires-Dist: pydantic-settings~=2.0
|
|
28
|
+
Requires-Dist: pydantic~=2.0
|
|
29
|
+
Provides-Extra: dev
|
|
30
|
+
Requires-Dist: coverage~=7.6; extra == 'dev'
|
|
31
|
+
Requires-Dist: mypy~=1.11; extra == 'dev'
|
|
32
|
+
Requires-Dist: pyhamcrest~=2.1; extra == 'dev'
|
|
33
|
+
Requires-Dist: pytest~=8.0; extra == 'dev'
|
|
34
|
+
Requires-Dist: requests-mock~=1.12; extra == 'dev'
|
|
35
|
+
Requires-Dist: respx~=0.22; extra == 'dev'
|
|
36
|
+
Requires-Dist: ruff~=0.8; extra == 'dev'
|
|
37
|
+
Requires-Dist: vulture~=2.11; extra == 'dev'
|
|
38
|
+
Description-Content-Type: text/markdown
|
|
39
|
+
|
|
40
|
+
# threatray-mcp
|
|
41
|
+
|
|
42
|
+
[](LICENSE)
|
|
43
|
+
|
|
44
|
+
MCP server for the [Threatray](https://www.threatray.com) malware analysis and threat intelligence platform. Lets MCP-aware clients (Claude Code, Claude Desktop, Cursor, Cline, Windsurf, …) query samples, run code-similarity retrohunts, fetch CAPA capabilities, pull AI analyses, and aggregate IOCs through a single uniform tool surface.
|
|
45
|
+
|
|
46
|
+
## Quick start
|
|
47
|
+
|
|
48
|
+
Requires a Threatray API key and Python 3.11+. Install from PyPI:
|
|
49
|
+
|
|
50
|
+
```bash
|
|
51
|
+
uvx threatray-mcp # run directly, no install
|
|
52
|
+
# or
|
|
53
|
+
pip install threatray-mcp
|
|
54
|
+
```
|
|
55
|
+
|
|
56
|
+
### Claude Code
|
|
57
|
+
|
|
58
|
+
```bash
|
|
59
|
+
claude mcp add threatray -s user \
|
|
60
|
+
-e THREATRAY_API_KEY=YOUR_API_KEY \
|
|
61
|
+
-e THREATRAY_API_URL=https://api-<your-realm>.analysis.threatray.com \
|
|
62
|
+
-- uvx threatray-mcp
|
|
63
|
+
|
|
64
|
+
claude mcp list # should show "threatray: ... connected"
|
|
65
|
+
```
|
|
66
|
+
|
|
67
|
+
Both env vars are required — no default URL. Replace `<your-realm>` with the realm your API key belongs to (provided by your Threatray account team).
|
|
68
|
+
|
|
69
|
+
### Generic MCP client config
|
|
70
|
+
|
|
71
|
+
Most MCP-aware editors accept the same JSON shape. Drop this block into the relevant config file (paths below):
|
|
72
|
+
|
|
73
|
+
```json
|
|
74
|
+
{
|
|
75
|
+
"mcpServers": {
|
|
76
|
+
"threatray": {
|
|
77
|
+
"command": "uvx",
|
|
78
|
+
"args": ["threatray-mcp"],
|
|
79
|
+
"env": {
|
|
80
|
+
"THREATRAY_API_KEY": "YOUR_API_KEY",
|
|
81
|
+
"THREATRAY_API_URL": "https://api-<your-realm>.analysis.threatray.com"
|
|
82
|
+
}
|
|
83
|
+
}
|
|
84
|
+
}
|
|
85
|
+
}
|
|
86
|
+
```
|
|
87
|
+
|
|
88
|
+
A copy of this snippet is in [`examples/mcp-config.json`](examples/mcp-config.json).
|
|
89
|
+
|
|
90
|
+
| Client | Config file |
|
|
91
|
+
|---|---|
|
|
92
|
+
| Claude Code | `~/.claude.json` (managed via `claude mcp add ...`) |
|
|
93
|
+
| Claude Desktop | macOS: `~/Library/Application Support/Claude/claude_desktop_config.json`. Windows: `%APPDATA%\Claude\claude_desktop_config.json` |
|
|
94
|
+
| Cursor | `~/.cursor/mcp.json` (global) or `<project>/.cursor/mcp.json` (per-project) |
|
|
95
|
+
| Cline (VS Code) | Cline UI → "MCP Servers" → edit JSON, or `~/.cline/mcp_settings.json` |
|
|
96
|
+
| Windsurf | `~/.codeium/windsurf/mcp_config.json` |
|
|
97
|
+
|
|
98
|
+
After editing, restart the client.
|
|
99
|
+
|
|
100
|
+
## Configuration
|
|
101
|
+
|
|
102
|
+
All settings via env vars (prefix `THREATRAY_`):
|
|
103
|
+
|
|
104
|
+
| Variable | Default | Description |
|
|
105
|
+
|---|---|---|
|
|
106
|
+
| `THREATRAY_API_KEY` | (required) | API key from your Threatray realm |
|
|
107
|
+
| `THREATRAY_API_URL` | (required) | API endpoint for the realm your key belongs to (form: `https://api-<your-realm>.analysis.threatray.com`). Pick a wrong realm and you'll just get auth errors — no default. Provided by your Threatray account team. |
|
|
108
|
+
| `THREATRAY_LOG_LEVEL` | `WARNING` | `DEBUG` / `INFO` / `WARNING` / `ERROR` (stderr only, never stdout — stdout carries the JSON-RPC stream) |
|
|
109
|
+
| `THREATRAY_TRANSPORT` | `stdio` | `stdio` (default, server runs as subprocess of an MCP client) or `http` (standalone server, see Deployment below) |
|
|
110
|
+
| `THREATRAY_HOST` | `0.0.0.0` | Bind address, used only when `THREATRAY_TRANSPORT=http` |
|
|
111
|
+
| `THREATRAY_PORT` | `8000` | TCP port, used only when `THREATRAY_TRANSPORT=http` |
|
|
112
|
+
|
|
113
|
+
Markdown output wraps hashes in clickable links to the Threatray UI; the UI URL is derived automatically from `THREATRAY_API_URL`.
|
|
114
|
+
|
|
115
|
+
### Deployment
|
|
116
|
+
|
|
117
|
+
Two transports are supported:
|
|
118
|
+
- **`stdio`** (default) — the MCP client spawns `threatray-mcp` as a subprocess. This is what `uvx threatray-mcp` and `claude mcp add` give you.
|
|
119
|
+
- **`http`** — long-lived standalone server on `THREATRAY_HOST:THREATRAY_PORT/mcp` (streamable HTTP). Use when the consuming client can't spawn the server (containerized clients, network-segmented deployments). Example: `docker compose --profile http up`. **No app-level auth** — restrict ingress at the network layer.
|
|
120
|
+
|
|
121
|
+
## Tools
|
|
122
|
+
|
|
123
|
+
Grouped by [Threatray public API taxonomy](https://docs.threatray.com/reference/overview-api). All 28 tools below; see [`src/threatray_mcp/README.md`](src/threatray_mcp/README.md) for per-tool descriptions.
|
|
124
|
+
|
|
125
|
+
| Section | Tools |
|
|
126
|
+
|---|---|
|
|
127
|
+
| Search | `threatray_search`, `threatray_retrohunt_sample` |
|
|
128
|
+
| Samples | `threatray_get_sample` |
|
|
129
|
+
| Submissions (read) | `threatray_list_submissions`, `threatray_get_task`, `threatray_get_task_by_analysis`, `threatray_list_tasks` |
|
|
130
|
+
| Submissions (write) | `threatray_submit_sample`, `threatray_submit_url`, `threatray_submit_endpoint_scan_archive`, `threatray_submit_minidump`, `threatray_submit_mans_file` |
|
|
131
|
+
| Analyses | `threatray_get_analysis`, `threatray_get_osint`, `threatray_list_analyses`, `threatray_list_endpoint_scan_analyses` |
|
|
132
|
+
| Files | `threatray_get_file_metadata`, `threatray_get_strings`, `threatray_download_file` |
|
|
133
|
+
| Functions | `threatray_list_functions`, `threatray_get_code_detections`, `threatray_retrohunt_functions`, `threatray_diff_functions` |
|
|
134
|
+
| CAPA Analysis | `threatray_get_capa` |
|
|
135
|
+
| AI Analysis | `threatray_get_ai_analysis`, `threatray_get_ai_analysis_by_id`, `threatray_list_ai_analyses`, `threatray_get_latest_ai_job` |
|
|
136
|
+
|
|
137
|
+
All tools accept `response_format=markdown` (default) or `response_format=json`.
|
|
138
|
+
|
|
139
|
+
Features not enabled for your account (e.g. AI analysis on some realms) surface as a clean `ThreatrayFeatureUnavailable` tool error rather than an empty result, so the agent gets an actionable signal instead of looping.
|
|
140
|
+
|
|
141
|
+
## Security
|
|
142
|
+
|
|
143
|
+
The MCP server runs as a subprocess of your editor under your local user — it inherits read access to every file you can read. The `threatray_submit_*` tools accept a `file_path` argument and upload the file's contents to your configured Threatray realm. Combined with prompt injection (a sample's strings, an OSINT report, a web page rendered in the editor), an attacker could attempt to convince the agent to call e.g. `threatray_submit_sample(file_path="~/.ssh/id_rsa")`.
|
|
144
|
+
|
|
145
|
+
Mitigations to consider when integrating in a shared or unattended environment:
|
|
146
|
+
|
|
147
|
+
1. **Don't run the server as a user with read access to secrets** — run it under a least-privilege account or in a sandbox/container without access to your `~`/credentials/git working trees.
|
|
148
|
+
2. **Watch for surprising `threatray_submit_*` tool calls** — Claude Code surfaces every tool call before sending it; pay attention to the `file_path` argument before approving.
|
|
149
|
+
|
|
150
|
+
The same least-privilege account that protects the read side also bounds where `threatray_download_file` can write — the tool relies on OS file-system permissions, not an application-level directory allowlist.
|
|
151
|
+
|
|
152
|
+
## Troubleshooting
|
|
153
|
+
|
|
154
|
+
**MCP server not connecting** — verify with `claude mcp list` (or your client's equivalent). If not connected:
|
|
155
|
+
1. Confirm Python 3.11+ is on `PATH`.
|
|
156
|
+
2. Test the entrypoint directly: `THREATRAY_API_KEY=xxx uvx threatray-mcp` (it'll hang waiting for stdio input — Ctrl-C to exit; absence of an error means startup succeeded).
|
|
157
|
+
3. Set `THREATRAY_LOG_LEVEL=DEBUG` and re-launch via the client; check stderr.
|
|
158
|
+
|
|
159
|
+
**`ThreatrayAuthError`** — API key missing/invalid, OR your key belongs to a different realm than `THREATRAY_API_URL` points at. The error message includes the URL the server tried — confirm it matches your realm.
|
|
160
|
+
|
|
161
|
+
**`ThreatrayForbiddenError`** — authenticated but the key lacks the required scope.
|
|
162
|
+
|
|
163
|
+
**`ThreatrayFeatureUnavailable`** — the feature (AI analysis, function diffing, …) isn't enabled for your account. Contact your Threatray account team.
|
|
164
|
+
|
|
165
|
+
**Connection errors** — `ThreatrayConnectionError` includes the URL it tried; confirm `THREATRAY_API_URL` is reachable from where the MCP server runs.
|
|
166
|
+
|
|
167
|
+
## Development
|
|
168
|
+
|
|
169
|
+
```bash
|
|
170
|
+
git clone https://github.com/threatray/threatray-mcp
|
|
171
|
+
cd threatray-mcp
|
|
172
|
+
pip install -e ".[dev]"
|
|
173
|
+
|
|
174
|
+
# Run all tests (unit + integration)
|
|
175
|
+
make test
|
|
176
|
+
make unit-tests # respx-mocked client + formatters + models
|
|
177
|
+
make int-tests # in-process fastmcp.Client end-to-end
|
|
178
|
+
|
|
179
|
+
# Lint and type check
|
|
180
|
+
make lint
|
|
181
|
+
make type-check
|
|
182
|
+
|
|
183
|
+
# Without Docker
|
|
184
|
+
python -m unittest discover tests
|
|
185
|
+
```
|
|
186
|
+
|
|
187
|
+
For contributor-facing architecture and the per-section package layout, see [`src/threatray_mcp/README.md`](src/threatray_mcp/README.md). Release notes live in [CHANGELOG.md](CHANGELOG.md).
|
|
188
|
+
|
|
189
|
+
## License
|
|
190
|
+
|
|
191
|
+
MIT — see [LICENSE](LICENSE).
|
|
@@ -0,0 +1,152 @@
|
|
|
1
|
+
# threatray-mcp
|
|
2
|
+
|
|
3
|
+
[](LICENSE)
|
|
4
|
+
|
|
5
|
+
MCP server for the [Threatray](https://www.threatray.com) malware analysis and threat intelligence platform. Lets MCP-aware clients (Claude Code, Claude Desktop, Cursor, Cline, Windsurf, …) query samples, run code-similarity retrohunts, fetch CAPA capabilities, pull AI analyses, and aggregate IOCs through a single uniform tool surface.
|
|
6
|
+
|
|
7
|
+
## Quick start
|
|
8
|
+
|
|
9
|
+
Requires a Threatray API key and Python 3.11+. Install from PyPI:
|
|
10
|
+
|
|
11
|
+
```bash
|
|
12
|
+
uvx threatray-mcp # run directly, no install
|
|
13
|
+
# or
|
|
14
|
+
pip install threatray-mcp
|
|
15
|
+
```
|
|
16
|
+
|
|
17
|
+
### Claude Code
|
|
18
|
+
|
|
19
|
+
```bash
|
|
20
|
+
claude mcp add threatray -s user \
|
|
21
|
+
-e THREATRAY_API_KEY=YOUR_API_KEY \
|
|
22
|
+
-e THREATRAY_API_URL=https://api-<your-realm>.analysis.threatray.com \
|
|
23
|
+
-- uvx threatray-mcp
|
|
24
|
+
|
|
25
|
+
claude mcp list # should show "threatray: ... connected"
|
|
26
|
+
```
|
|
27
|
+
|
|
28
|
+
Both env vars are required — no default URL. Replace `<your-realm>` with the realm your API key belongs to (provided by your Threatray account team).
|
|
29
|
+
|
|
30
|
+
### Generic MCP client config
|
|
31
|
+
|
|
32
|
+
Most MCP-aware editors accept the same JSON shape. Drop this block into the relevant config file (paths below):
|
|
33
|
+
|
|
34
|
+
```json
|
|
35
|
+
{
|
|
36
|
+
"mcpServers": {
|
|
37
|
+
"threatray": {
|
|
38
|
+
"command": "uvx",
|
|
39
|
+
"args": ["threatray-mcp"],
|
|
40
|
+
"env": {
|
|
41
|
+
"THREATRAY_API_KEY": "YOUR_API_KEY",
|
|
42
|
+
"THREATRAY_API_URL": "https://api-<your-realm>.analysis.threatray.com"
|
|
43
|
+
}
|
|
44
|
+
}
|
|
45
|
+
}
|
|
46
|
+
}
|
|
47
|
+
```
|
|
48
|
+
|
|
49
|
+
A copy of this snippet is in [`examples/mcp-config.json`](examples/mcp-config.json).
|
|
50
|
+
|
|
51
|
+
| Client | Config file |
|
|
52
|
+
|---|---|
|
|
53
|
+
| Claude Code | `~/.claude.json` (managed via `claude mcp add ...`) |
|
|
54
|
+
| Claude Desktop | macOS: `~/Library/Application Support/Claude/claude_desktop_config.json`. Windows: `%APPDATA%\Claude\claude_desktop_config.json` |
|
|
55
|
+
| Cursor | `~/.cursor/mcp.json` (global) or `<project>/.cursor/mcp.json` (per-project) |
|
|
56
|
+
| Cline (VS Code) | Cline UI → "MCP Servers" → edit JSON, or `~/.cline/mcp_settings.json` |
|
|
57
|
+
| Windsurf | `~/.codeium/windsurf/mcp_config.json` |
|
|
58
|
+
|
|
59
|
+
After editing, restart the client.
|
|
60
|
+
|
|
61
|
+
## Configuration
|
|
62
|
+
|
|
63
|
+
All settings via env vars (prefix `THREATRAY_`):
|
|
64
|
+
|
|
65
|
+
| Variable | Default | Description |
|
|
66
|
+
|---|---|---|
|
|
67
|
+
| `THREATRAY_API_KEY` | (required) | API key from your Threatray realm |
|
|
68
|
+
| `THREATRAY_API_URL` | (required) | API endpoint for the realm your key belongs to (form: `https://api-<your-realm>.analysis.threatray.com`). Pick a wrong realm and you'll just get auth errors — no default. Provided by your Threatray account team. |
|
|
69
|
+
| `THREATRAY_LOG_LEVEL` | `WARNING` | `DEBUG` / `INFO` / `WARNING` / `ERROR` (stderr only, never stdout — stdout carries the JSON-RPC stream) |
|
|
70
|
+
| `THREATRAY_TRANSPORT` | `stdio` | `stdio` (default, server runs as subprocess of an MCP client) or `http` (standalone server, see Deployment below) |
|
|
71
|
+
| `THREATRAY_HOST` | `0.0.0.0` | Bind address, used only when `THREATRAY_TRANSPORT=http` |
|
|
72
|
+
| `THREATRAY_PORT` | `8000` | TCP port, used only when `THREATRAY_TRANSPORT=http` |
|
|
73
|
+
|
|
74
|
+
Markdown output wraps hashes in clickable links to the Threatray UI; the UI URL is derived automatically from `THREATRAY_API_URL`.
|
|
75
|
+
|
|
76
|
+
### Deployment
|
|
77
|
+
|
|
78
|
+
Two transports are supported:
|
|
79
|
+
- **`stdio`** (default) — the MCP client spawns `threatray-mcp` as a subprocess. This is what `uvx threatray-mcp` and `claude mcp add` give you.
|
|
80
|
+
- **`http`** — long-lived standalone server on `THREATRAY_HOST:THREATRAY_PORT/mcp` (streamable HTTP). Use when the consuming client can't spawn the server (containerized clients, network-segmented deployments). Example: `docker compose --profile http up`. **No app-level auth** — restrict ingress at the network layer.
|
|
81
|
+
|
|
82
|
+
## Tools
|
|
83
|
+
|
|
84
|
+
Grouped by [Threatray public API taxonomy](https://docs.threatray.com/reference/overview-api). All 28 tools below; see [`src/threatray_mcp/README.md`](src/threatray_mcp/README.md) for per-tool descriptions.
|
|
85
|
+
|
|
86
|
+
| Section | Tools |
|
|
87
|
+
|---|---|
|
|
88
|
+
| Search | `threatray_search`, `threatray_retrohunt_sample` |
|
|
89
|
+
| Samples | `threatray_get_sample` |
|
|
90
|
+
| Submissions (read) | `threatray_list_submissions`, `threatray_get_task`, `threatray_get_task_by_analysis`, `threatray_list_tasks` |
|
|
91
|
+
| Submissions (write) | `threatray_submit_sample`, `threatray_submit_url`, `threatray_submit_endpoint_scan_archive`, `threatray_submit_minidump`, `threatray_submit_mans_file` |
|
|
92
|
+
| Analyses | `threatray_get_analysis`, `threatray_get_osint`, `threatray_list_analyses`, `threatray_list_endpoint_scan_analyses` |
|
|
93
|
+
| Files | `threatray_get_file_metadata`, `threatray_get_strings`, `threatray_download_file` |
|
|
94
|
+
| Functions | `threatray_list_functions`, `threatray_get_code_detections`, `threatray_retrohunt_functions`, `threatray_diff_functions` |
|
|
95
|
+
| CAPA Analysis | `threatray_get_capa` |
|
|
96
|
+
| AI Analysis | `threatray_get_ai_analysis`, `threatray_get_ai_analysis_by_id`, `threatray_list_ai_analyses`, `threatray_get_latest_ai_job` |
|
|
97
|
+
|
|
98
|
+
All tools accept `response_format=markdown` (default) or `response_format=json`.
|
|
99
|
+
|
|
100
|
+
Features not enabled for your account (e.g. AI analysis on some realms) surface as a clean `ThreatrayFeatureUnavailable` tool error rather than an empty result, so the agent gets an actionable signal instead of looping.
|
|
101
|
+
|
|
102
|
+
## Security
|
|
103
|
+
|
|
104
|
+
The MCP server runs as a subprocess of your editor under your local user — it inherits read access to every file you can read. The `threatray_submit_*` tools accept a `file_path` argument and upload the file's contents to your configured Threatray realm. Combined with prompt injection (a sample's strings, an OSINT report, a web page rendered in the editor), an attacker could attempt to convince the agent to call e.g. `threatray_submit_sample(file_path="~/.ssh/id_rsa")`.
|
|
105
|
+
|
|
106
|
+
Mitigations to consider when integrating in a shared or unattended environment:
|
|
107
|
+
|
|
108
|
+
1. **Don't run the server as a user with read access to secrets** — run it under a least-privilege account or in a sandbox/container without access to your `~`/credentials/git working trees.
|
|
109
|
+
2. **Watch for surprising `threatray_submit_*` tool calls** — Claude Code surfaces every tool call before sending it; pay attention to the `file_path` argument before approving.
|
|
110
|
+
|
|
111
|
+
The same least-privilege account that protects the read side also bounds where `threatray_download_file` can write — the tool relies on OS file-system permissions, not an application-level directory allowlist.
|
|
112
|
+
|
|
113
|
+
## Troubleshooting
|
|
114
|
+
|
|
115
|
+
**MCP server not connecting** — verify with `claude mcp list` (or your client's equivalent). If not connected:
|
|
116
|
+
1. Confirm Python 3.11+ is on `PATH`.
|
|
117
|
+
2. Test the entrypoint directly: `THREATRAY_API_KEY=xxx uvx threatray-mcp` (it'll hang waiting for stdio input — Ctrl-C to exit; absence of an error means startup succeeded).
|
|
118
|
+
3. Set `THREATRAY_LOG_LEVEL=DEBUG` and re-launch via the client; check stderr.
|
|
119
|
+
|
|
120
|
+
**`ThreatrayAuthError`** — API key missing/invalid, OR your key belongs to a different realm than `THREATRAY_API_URL` points at. The error message includes the URL the server tried — confirm it matches your realm.
|
|
121
|
+
|
|
122
|
+
**`ThreatrayForbiddenError`** — authenticated but the key lacks the required scope.
|
|
123
|
+
|
|
124
|
+
**`ThreatrayFeatureUnavailable`** — the feature (AI analysis, function diffing, …) isn't enabled for your account. Contact your Threatray account team.
|
|
125
|
+
|
|
126
|
+
**Connection errors** — `ThreatrayConnectionError` includes the URL it tried; confirm `THREATRAY_API_URL` is reachable from where the MCP server runs.
|
|
127
|
+
|
|
128
|
+
## Development
|
|
129
|
+
|
|
130
|
+
```bash
|
|
131
|
+
git clone https://github.com/threatray/threatray-mcp
|
|
132
|
+
cd threatray-mcp
|
|
133
|
+
pip install -e ".[dev]"
|
|
134
|
+
|
|
135
|
+
# Run all tests (unit + integration)
|
|
136
|
+
make test
|
|
137
|
+
make unit-tests # respx-mocked client + formatters + models
|
|
138
|
+
make int-tests # in-process fastmcp.Client end-to-end
|
|
139
|
+
|
|
140
|
+
# Lint and type check
|
|
141
|
+
make lint
|
|
142
|
+
make type-check
|
|
143
|
+
|
|
144
|
+
# Without Docker
|
|
145
|
+
python -m unittest discover tests
|
|
146
|
+
```
|
|
147
|
+
|
|
148
|
+
For contributor-facing architecture and the per-section package layout, see [`src/threatray_mcp/README.md`](src/threatray_mcp/README.md). Release notes live in [CHANGELOG.md](CHANGELOG.md).
|
|
149
|
+
|
|
150
|
+
## License
|
|
151
|
+
|
|
152
|
+
MIT — see [LICENSE](LICENSE).
|
|
@@ -0,0 +1,100 @@
|
|
|
1
|
+
[project]
|
|
2
|
+
name = "threatray-mcp"
|
|
3
|
+
version = "1.0.2"
|
|
4
|
+
description = "MCP server for the Threatray malware analysis and threat intelligence platform"
|
|
5
|
+
authors = [{name = "Threatray", email = "operations@threatray.com"}]
|
|
6
|
+
readme = "README.md"
|
|
7
|
+
requires-python = ">=3.11,<3.14"
|
|
8
|
+
license = "MIT"
|
|
9
|
+
keywords = ["mcp", "threatray", "malware", "threat-intelligence", "yara", "capa", "ioc"]
|
|
10
|
+
classifiers = [
|
|
11
|
+
"Development Status :: 4 - Beta",
|
|
12
|
+
"Environment :: Console",
|
|
13
|
+
"Intended Audience :: Information Technology",
|
|
14
|
+
"License :: OSI Approved :: MIT License",
|
|
15
|
+
"Operating System :: OS Independent",
|
|
16
|
+
"Programming Language :: Python :: 3",
|
|
17
|
+
"Programming Language :: Python :: 3.11",
|
|
18
|
+
"Programming Language :: Python :: 3.12",
|
|
19
|
+
"Programming Language :: Python :: 3.13",
|
|
20
|
+
"Topic :: Security",
|
|
21
|
+
]
|
|
22
|
+
dependencies = [
|
|
23
|
+
"fastmcp>=3,<4",
|
|
24
|
+
"httpx~=0.27",
|
|
25
|
+
"pydantic~=2.0",
|
|
26
|
+
"pydantic-settings~=2.0",
|
|
27
|
+
]
|
|
28
|
+
|
|
29
|
+
[project.urls]
|
|
30
|
+
Homepage = "https://www.threatray.com"
|
|
31
|
+
Repository = "https://github.com/threatray/threatray-mcp"
|
|
32
|
+
Issues = "https://github.com/threatray/threatray-mcp/issues"
|
|
33
|
+
Documentation = "https://github.com/threatray/threatray-mcp#readme"
|
|
34
|
+
"Threatray API reference" = "https://docs.threatray.com/reference/overview-api"
|
|
35
|
+
|
|
36
|
+
[project.optional-dependencies]
|
|
37
|
+
dev = [
|
|
38
|
+
"ruff~=0.8",
|
|
39
|
+
"vulture~=2.11",
|
|
40
|
+
"coverage~=7.6",
|
|
41
|
+
"mypy~=1.11",
|
|
42
|
+
"pytest~=8.0",
|
|
43
|
+
"PyHamcrest~=2.1",
|
|
44
|
+
"requests-mock~=1.12",
|
|
45
|
+
"respx~=0.22",
|
|
46
|
+
]
|
|
47
|
+
|
|
48
|
+
[project.scripts]
|
|
49
|
+
threatray-mcp = "threatray_mcp.__main__:main"
|
|
50
|
+
|
|
51
|
+
[build-system]
|
|
52
|
+
requires = ["hatchling"]
|
|
53
|
+
build-backend = "hatchling.build"
|
|
54
|
+
|
|
55
|
+
[tool.hatch.build.targets.wheel]
|
|
56
|
+
packages = ["src/threatray_mcp"]
|
|
57
|
+
|
|
58
|
+
[tool.hatch.build.targets.sdist]
|
|
59
|
+
include = ["src/threatray_mcp", "README.md", "CHANGELOG.md", "pyproject.toml"]
|
|
60
|
+
|
|
61
|
+
[tool.ruff]
|
|
62
|
+
line-length = 120
|
|
63
|
+
target-version = "py311"
|
|
64
|
+
|
|
65
|
+
[tool.ruff.lint]
|
|
66
|
+
select = [
|
|
67
|
+
"E", # pycodestyle errors
|
|
68
|
+
"W", # pycodestyle warnings
|
|
69
|
+
"F", # pyflakes
|
|
70
|
+
"I", # isort
|
|
71
|
+
"PLC", # pylint convention
|
|
72
|
+
"PLE", # pylint error
|
|
73
|
+
"PLR", # pylint refactor
|
|
74
|
+
"PLW", # pylint warning
|
|
75
|
+
"RUF", # Ruff-specific rules
|
|
76
|
+
]
|
|
77
|
+
|
|
78
|
+
ignore = [
|
|
79
|
+
"PLR2004", # magic value comparison
|
|
80
|
+
"RUF012", # mutable-class-default
|
|
81
|
+
]
|
|
82
|
+
|
|
83
|
+
[tool.ruff.lint.per-file-ignores]
|
|
84
|
+
"tests/**" = ["PLR2004"]
|
|
85
|
+
"vulture_whitelist.py" = ["ALL"]
|
|
86
|
+
|
|
87
|
+
[tool.ruff.lint.pylint]
|
|
88
|
+
max-args = 6
|
|
89
|
+
max-branches = 12
|
|
90
|
+
max-returns = 6
|
|
91
|
+
max-statements = 50
|
|
92
|
+
max-nested-blocks = 5
|
|
93
|
+
max-public-methods = 20
|
|
94
|
+
|
|
95
|
+
[tool.mypy]
|
|
96
|
+
python_version = "3.11"
|
|
97
|
+
ignore_missing_imports = true
|
|
98
|
+
strict = false
|
|
99
|
+
warn_return_any = true
|
|
100
|
+
warn_unused_configs = true
|