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.
Files changed (57) hide show
  1. threatray_mcp-1.0.2/.gitignore +81 -0
  2. threatray_mcp-1.0.2/CHANGELOG.md +67 -0
  3. threatray_mcp-1.0.2/LICENSE +21 -0
  4. threatray_mcp-1.0.2/PKG-INFO +191 -0
  5. threatray_mcp-1.0.2/README.md +152 -0
  6. threatray_mcp-1.0.2/pyproject.toml +100 -0
  7. threatray_mcp-1.0.2/src/threatray_mcp/README.md +166 -0
  8. threatray_mcp-1.0.2/src/threatray_mcp/__init__.py +10 -0
  9. threatray_mcp-1.0.2/src/threatray_mcp/__main__.py +17 -0
  10. threatray_mcp-1.0.2/src/threatray_mcp/client/__init__.py +55 -0
  11. threatray_mcp-1.0.2/src/threatray_mcp/client/_http.py +197 -0
  12. threatray_mcp-1.0.2/src/threatray_mcp/client/_jobs.py +61 -0
  13. threatray_mcp-1.0.2/src/threatray_mcp/client/_types.py +45 -0
  14. threatray_mcp-1.0.2/src/threatray_mcp/client/ai_analysis.py +107 -0
  15. threatray_mcp-1.0.2/src/threatray_mcp/client/analyses.py +72 -0
  16. threatray_mcp-1.0.2/src/threatray_mcp/client/capa.py +50 -0
  17. threatray_mcp-1.0.2/src/threatray_mcp/client/files.py +35 -0
  18. threatray_mcp-1.0.2/src/threatray_mcp/client/functions.py +78 -0
  19. threatray_mcp-1.0.2/src/threatray_mcp/client/samples.py +14 -0
  20. threatray_mcp-1.0.2/src/threatray_mcp/client/search.py +44 -0
  21. threatray_mcp-1.0.2/src/threatray_mcp/client/submissions.py +211 -0
  22. threatray_mcp-1.0.2/src/threatray_mcp/config.py +57 -0
  23. threatray_mcp-1.0.2/src/threatray_mcp/errors.py +60 -0
  24. threatray_mcp-1.0.2/src/threatray_mcp/formatters/__init__.py +48 -0
  25. threatray_mcp-1.0.2/src/threatray_mcp/formatters/_helpers.py +90 -0
  26. threatray_mcp-1.0.2/src/threatray_mcp/formatters/ai_analysis.py +123 -0
  27. threatray_mcp-1.0.2/src/threatray_mcp/formatters/analyses.py +810 -0
  28. threatray_mcp-1.0.2/src/threatray_mcp/formatters/capa.py +215 -0
  29. threatray_mcp-1.0.2/src/threatray_mcp/formatters/files.py +229 -0
  30. threatray_mcp-1.0.2/src/threatray_mcp/formatters/functions.py +532 -0
  31. threatray_mcp-1.0.2/src/threatray_mcp/formatters/samples.py +15 -0
  32. threatray_mcp-1.0.2/src/threatray_mcp/formatters/search.py +269 -0
  33. threatray_mcp-1.0.2/src/threatray_mcp/formatters/submissions.py +216 -0
  34. threatray_mcp-1.0.2/src/threatray_mcp/log.py +25 -0
  35. threatray_mcp-1.0.2/src/threatray_mcp/models/__init__.py +85 -0
  36. threatray_mcp-1.0.2/src/threatray_mcp/models/ai_analysis.py +67 -0
  37. threatray_mcp-1.0.2/src/threatray_mcp/models/analyses.py +64 -0
  38. threatray_mcp-1.0.2/src/threatray_mcp/models/capa.py +27 -0
  39. threatray_mcp-1.0.2/src/threatray_mcp/models/common.py +131 -0
  40. threatray_mcp-1.0.2/src/threatray_mcp/models/files.py +64 -0
  41. threatray_mcp-1.0.2/src/threatray_mcp/models/functions.py +108 -0
  42. threatray_mcp-1.0.2/src/threatray_mcp/models/samples.py +17 -0
  43. threatray_mcp-1.0.2/src/threatray_mcp/models/search.py +78 -0
  44. threatray_mcp-1.0.2/src/threatray_mcp/models/submissions.py +308 -0
  45. threatray_mcp-1.0.2/src/threatray_mcp/server.py +42 -0
  46. threatray_mcp-1.0.2/src/threatray_mcp/tools/__init__.py +21 -0
  47. threatray_mcp-1.0.2/src/threatray_mcp/tools/_cache.py +98 -0
  48. threatray_mcp-1.0.2/src/threatray_mcp/tools/_context.py +12 -0
  49. threatray_mcp-1.0.2/src/threatray_mcp/tools/_format.py +8 -0
  50. threatray_mcp-1.0.2/src/threatray_mcp/tools/ai_analysis.py +133 -0
  51. threatray_mcp-1.0.2/src/threatray_mcp/tools/analyses.py +137 -0
  52. threatray_mcp-1.0.2/src/threatray_mcp/tools/capa.py +73 -0
  53. threatray_mcp-1.0.2/src/threatray_mcp/tools/files.py +108 -0
  54. threatray_mcp-1.0.2/src/threatray_mcp/tools/functions.py +196 -0
  55. threatray_mcp-1.0.2/src/threatray_mcp/tools/samples.py +38 -0
  56. threatray_mcp-1.0.2/src/threatray_mcp/tools/search.py +130 -0
  57. 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](https://img.shields.io/badge/license-MIT-blue.svg)](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](https://img.shields.io/badge/license-MIT-blue.svg)](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