AssemblyLine MCP
by SauceTaster
README.md
<!-- mcp-name: io.github.SauceTaster/assemblyline-mcp -->
# AssemblyLine MCP
A [Model Context Protocol](https://modelcontextprotocol.io) (MCP) server for
[AssemblyLine 4](https://cybercentrecanada.github.io/assemblyline4_docs/) — the
Canadian Centre for Cyber Security's open-source **file triage and malware
analysis** platform. It lets MCP-compatible AI clients (Claude Desktop, Claude
Code, Cursor, VS Code, …) submit files, hashes, and URLs for analysis, retrieve
results, search across AssemblyLine indices, and triage alerts.
[](https://pypi.org/project/assemblyline-mcp/)
[](https://pypi.org/project/assemblyline-mcp/)
[](https://github.com/SauceTaster/assemblyline-mcp/actions/workflows/ci.yml)
[](https://github.com/SauceTaster/assemblyline-mcp/actions/workflows/test.yml)
[](https://codecov.io/gh/SauceTaster/assemblyline-mcp)
[](LICENSE)
[](https://github.com/astral-sh/ruff)
[](https://github.com/astral-sh/uv)
[](https://modelcontextprotocol.io)
---
## Features
- **Built for agents, not just API parity** — `al_analyze` submits and waits, then
returns a concise **verdict digest** (verdict, flagged services, heuristics, AV
hits, network IOCs, children) instead of a raw blob; `al_submission_iocs` and
`al_find_related` cover IOC extraction and pivoting. Guided **MCP prompts**
(`triage_file`, `investigate_hash`, `review_alert`) ship the AssemblyLine triage
workflow and scoring semantics **inside the server — no skill install required**.
- **Full AssemblyLine 4 coverage** — submit/ingest, inspect submissions and
per-file results, Lucene search across every index, alert triage, and system
metadata, built on the official [`assemblyline-client`](https://github.com/CybercentreCanada/assemblyline_client).
- **Safe by default** — destructive/admin operations (deletes, workflow runs,
user/service/system management) are **not even registered** unless you opt in
with `AL_ALLOW_ADMIN=true`, and every tool carries MCP `readOnlyHint` /
`destructiveHint` annotations so clients can prompt before risky actions.
- **Two transports** — `stdio` for local desktop clients and **streamable HTTP**
for networked/containerized deployments (with optional `admin`-scope auth).
- **Built-in end-to-end self-test** — `assemblyline-mcp selftest` boots an
in-process mock AssemblyLine, exercises every tool, and prints a PASS/FAIL
report. No live server, no pytest, any architecture.
- **Production-ready packaging** — `uvx`-installable, typed (`py.typed`),
multi-arch Docker image, and a published [MCP registry](https://github.com/modelcontextprotocol/registry) manifest.
## Available tools
All tools are prefixed `al_`. Read-only tools are always available; write tools
change state but are non-destructive; **admin** tools require `AL_ALLOW_ADMIN=true`.
| Group | Tools |
|-------|-------|
| **Analysis (agentic)** | `al_analyze` (submit + wait + verdict digest), `al_submission_digest`, `al_submission_iocs`, `al_find_related` |
| **Submission** | `al_submit`, `al_ingest`, `al_ingest_get_messages`, `al_submission`, `al_submission_full`, `al_submission_summary`, `al_submission_tree`, `al_submission_report`, `al_submission_file`, `al_submission_is_completed`, `al_submission_list`, `al_submission_set_verdict` |
| **Search** | `al_search`, `al_search_facet`, `al_search_stats`, `al_search_histogram`, `al_search_grouped`, `al_search_fields` |
| **Files / results** | `al_file_info`, `al_file_result`, `al_file_score`, `al_file_children`, `al_file_strings`, `al_file_hex`, `al_file_ascii`, `al_file_ai_summary`, `al_file_download`, `al_result`, `al_error`, `al_hash_search` |
| **Alerts** | `al_alert`, `al_alert_list`, `al_alert_grouped`, `al_alert_statistics`, `al_alert_label`, `al_alert_set_priority`, `al_alert_set_status`, `al_alert_set_verdict`, `al_alert_take_ownership` |
| **System** | `al_whoami`, `al_user_quotas`, `al_help_configuration`, `al_help_constants`, `al_help_classification`, `al_heuristics` |
| **Admin** *(gated)* | `al_submission_delete`, `al_file_delete_from_filestore`, `al_alert_remove_label`, `al_workflow_run`, `al_workflow_delete`, `al_signature_change_status`, `al_signature_delete`, `al_badlist_delete`, `al_safelist_delete`, `al_service_delete`, `al_system_set_message`, `al_system_clear_message` |
### Guided workflows (MCP prompts — no skill required)
The server registers MCP **prompts** that encode the AssemblyLine triage workflow
and scoring semantics, so the agent interprets results correctly out of the box.
These surface natively in any MCP client (Claude Desktop/Code, Cursor, …):
- **`triage_file`** — triage a file/hash and report a verdict.
- **`investigate_hash`** — known results, IOCs, and related activity for a hash.
- **`review_alert`** — assess an alert as true/false positive.
A richer, Claude-specific **Agent Skill** is also available under
[`skills/assemblyline-triage/`](skills/assemblyline-triage/) — but it's optional;
the server is fully usable without installing anything.
## Installation
You need a running [AssemblyLine 4](https://cybercentrecanada.github.io/assemblyline4_docs/installation/overview/)
instance and an API key (or username/password).
```bash
# Run without installing (recommended)
uvx assemblyline-mcp
# Or with pipx / pip
pipx install assemblyline-mcp
pip install assemblyline-mcp
```
### Docker
```bash
docker run --rm -i \
-e AL_URL=https://al.example.org \
-e AL_APIKEY_USER=analyst \
-e AL_APIKEY=your-keyname:secret \
ghcr.io/SauceTaster/assemblyline-mcp:latest
```
## Configuration
Configuration is via `AL_`-prefixed environment variables (or a `.env` file).
| Variable | Required | Default | Description |
|----------|:--------:|---------|-------------|
| `AL_URL` | ✅ | – | Base URL of the AssemblyLine instance (e.g. `https://al.example.org`). |
| `AL_APIKEY_USER` | ✅¹ | – | Username paired with `AL_APIKEY`. |
| `AL_APIKEY` | ✅¹ | – | API key secret (`keyname:secret`). |
| `AL_USERNAME` | ✅¹ | – | Username (for password auth). |
| `AL_PASSWORD` | ✅¹ | – | Password (for password auth). |
| `AL_VERIFY_SSL` | | `true` | Verify the AssemblyLine TLS certificate. |
| `AL_TIMEOUT` | | `60` | Per-request timeout (seconds). |
| `AL_RETRIES` | | `3` | Finite retry count (never infinite). |
| `AL_ALLOW_ADMIN` | | `false` | Register admin/destructive tools. |
| `AL_MAX_DOWNLOAD_BYTES` | | `10485760` | Cap on `al_file_download` output. |
| `AL_TRANSPORT` | | `stdio` | `stdio` or `http`. |
| `AL_HOST` / `AL_PORT` / `AL_PATH` | | `127.0.0.1` / `8000` / `/mcp/` | HTTP transport bind settings. |
| `AL_ALLOW_INSECURE_BIND` | | `false` | Permit binding http to a non-loopback host (no built-in auth). |
| `AL_MASK_ERROR_DETAILS` | | `true` | Hide internal exception details from clients. |
¹ Provide **either** `AL_APIKEY_USER` + `AL_APIKEY` **or** `AL_USERNAME` + `AL_PASSWORD`.
### Claude Code
```bash
claude mcp add assemblyline \
--env AL_URL=https://al.example.org \
--env AL_APIKEY_USER=analyst \
--env AL_APIKEY=your-keyname:secret \
-- uvx assemblyline-mcp
```
### Claude Desktop
Add to `claude_desktop_config.json`
([see example](examples/claude_desktop_config.json)):
```json
{
"mcpServers": {
"assemblyline": {
"command": "uvx",
"args": ["assemblyline-mcp"],
"env": {
"AL_URL": "https://al.example.org",
"AL_APIKEY_USER": "analyst",
"AL_APIKEY": "your-keyname:secret"
}
}
}
}
```
### VS Code
See [examples/vscode_mcp.json](examples/vscode_mcp.json).
## Usage
```bash
assemblyline-mcp # serve over stdio (default)
assemblyline-mcp serve -t http -p 8000 # serve over streamable HTTP
assemblyline-mcp selftest # run the built-in end-to-end self-test
assemblyline-mcp doctor # validate config + connectivity to a real AL
assemblyline-mcp version
```
`doctor` performs the AssemblyLine connection handshake and reports the
authenticated user — useful as a container `HEALTHCHECK` and for first-run setup.
## Development
```bash
git clone https://github.com/SauceTaster/assemblyline-mcp
cd assemblyline-mcp
uv sync # creates .venv with Python 3.12 and all dev deps
uv run ruff check . # lint
uv run ruff format --check . # formatting
uv run mypy # type-check
uv run pytest # full test suite (unit + integration + e2e, mock-backed)
uv run assemblyline-mcp selftest # the shippable e2e diagnostic
```
The whole test suite runs against an in-process **mock AssemblyLine** server, so
no live instance is required and it works on any architecture (including Apple
Silicon). An opt-in suite exercises a real instance — see
[CONTRIBUTING.md](CONTRIBUTING.md).
### Debugging with the MCP Inspector
```bash
uv run fastmcp dev src/assemblyline_mcp/server.py
```
### End-to-end with Docker Compose
```bash
docker compose -f docker-compose.e2e.yml up --build
# MCP server (http) on http://localhost:8000/mcp/, backed by the mock AssemblyLine
```
## Security
- Credentials are read only from the environment and never logged.
- Destructive tools are gated behind `AL_ALLOW_ADMIN`; on the HTTP transport they
additionally require an `admin`-scoped token.
- `al_file_download` returns base64 bytes only — samples are **never executed**;
oversized files (`AL_MAX_DOWNLOAD_BYTES`) are refused without being fetched.
- **The HTTP transport ships with no built-in authentication for read/write
tools.** It refuses to bind a non-loopback address unless you set
`AL_ALLOW_INSECURE_BIND=true`; before exposing it, front the server with an
auth-enforcing reverse proxy or a FastMCP `AuthProvider`.
See [SECURITY.md](SECURITY.md) for the disclosure policy.
## Acknowledgements
- [AssemblyLine 4](https://github.com/CybercentreCanada/assemblyline) and the
[`assemblyline-client`](https://github.com/CybercentreCanada/assemblyline_client)
by the Canadian Centre for Cyber Security.
- Built with [FastMCP](https://gofastmcp.com).
## License
[MIT](LICENSE)
This server cannot be deployed
Maintenance
ActivityInactive
ResponsivenessNo issues