nagameTW/mcp-server-malcolm

GitHub: nagameTW/mcp-server-malcolm

为 Malcolm 网络流量分析平台提供 MCP 接口,使兼容的 AI agent 能够以结构化方式安全地查询网络流量、警报和资产信息。

Stars: 3 | Forks: 0

# mcp-server-malcolm [![PyPI](https://img.shields.io/pypi/v/mcp-server-malcolm)](https://pypi.org/project/mcp-server-malcolm/) [![Python](https://img.shields.io/badge/python-3.11%2B-blue)](https://pypi.org/project/mcp-server-malcolm/) [![License: MIT](https://img.shields.io/badge/License-MIT-yellow)](LICENSE) **English** | [繁體中文](README.zh-TW.md) 首个为 [Malcolm](https://malcolm.fyi) 提供的 MCP server,Malcolm 是一个开源的网络流量分析平台(包含 Zeek + Suricata + Arkime + OpenSearch,以及可选的 NetBox)。 它为任何兼容 MCP 的 AI agent 提供了对 Malcolm 的结构化访问:搜索和聚合网络流量、发现字段名称、查询 Suricata 警报、浏览 Arkime 会话、解析 NetBox 资产以及检查系统健康状况。开启写入类别后,它还可以创建警报、为会话添加 tag、启动 hunt 以及上传 PCAP。 ## 在你主动选择前为只读 在没有任何配置的情况下,此 server 仅暴露读取工具。它的行为就像一个只读客户端,其所有操作都不会改变 Malcolm 中的数据。 该 server 将写入权限分为四个类别,每个类别都由独立的环境变量控制,且默认全部关闭。它不会注册被禁用的类别,因此该类别的工具永远不会出现在 `list_tools()` 中,也无法被调用。在启动时,它会打印出哪些类别处于开启状态: ``` [mcp-server-malcolm] write classes: alerting=off arkime-tag=off hunt-job=off pcap-upload=off ``` 每次写入都是附加的。版本 1 中没有任何工具可以删除数据、移除 tag 或触及用户账户。这是刻意为之的设计(参见 [非目标](#non-goals))。 ## 为什么需要 MCP 层 Malcolm 将所有网络元数据保存在一个 OpenSearch 索引(`arkime_sessions3-*`)中,其包含非标准的字段名称和特有的过滤语法。如果让 LLM 直接针对该索引编写原始的 OpenSearch DSL,往往会出错。此 server 代替模型承担了这项工作: - 它暴露的是 Malcolm 的过滤语法,而不是原始的 DSL。 - 它提供字段发现功能,以便模型在查询前检查字段名称。 - 它提供值枚举功能,让模型看到字段实际包含的值。 - 它封装了 Suricata 警报查询并处理字段映射(`suricata.alert.*` 对比 `rule.*`)。 - 它添加了 NetBox 资产上下文(IP 到设备的映射,网段信息)。 写入端也遵循相同的理念。该 server 并非直接将 Malcolm 已经向任何已认证用户开放的原始 OpenSearch 和 NetBox 透传接口交给 agent,而是暴露了一组经过精心挑选、命名且可审计的写入操作。有关此内容的更多信息,请参阅 [安全模型](#security-model)。 ## 读取工具 这些工具始终会被注册。 ### DSL 核心(与后端无关) 针对配置好的 endpoint 执行普通的 OpenSearch DSL(Malcolm 的 `/mapi/opensearch` 代理)。不包含特定于 Malcolm 的查询结构:只要将 base URL 指向任何兼容 OpenSearch 的后端,它们就能正常工作。 | 工具 | 描述 | |------|-------------| | `search_dsl` | 执行原始的 OpenSearch DSL 查询(命中结果 + 聚合,无隐藏时间窗口) | | `count` | 统计匹配 DSL 查询子句的文档数量 | | `list_indices` | 列出索引(名称/健康状态/状态/文档计数) | | `index_mapping` | 索引的字段映射/schema | | `cluster_health` | OpenSearch 集群健康状态 | ### 核心查询 | 工具 | 描述 | |------|-------------| | `malcolm_search` | 使用 Malcolm 过滤语法搜索网络流量 | | `malcolm_aggregate` | 按一个或多个字段聚合流量(带有计数的 Top-N) | | `malcolm_alerts` | 按特征、严重程度、IP 搜索 Suricata 警报 | ### 字段发现(防幻觉) | 工具 | 描述 | |------|-------------| | `malcolm_field_search` | 按关键字、前缀或类型搜索可用的字段名 | | `malcolm_field_values` | 列出某个字段的不同值 | | `malcolm_field_profile` | 显示哪些 `event.dataset` 类型包含该字段 | ### 系统健康状态 | 工具 | 描述 | |------|-------------| | `malcolm_service_status` | 所有 Malcolm 服务的就绪状态以及版本信息 | | `malcolm_data_coverage` | 每个 sensor 的数据新鲜度、每个 dataset 的文档计数、索引信息 | | `malcolm_ping` | 对 Malcolm API 的快速存活检测 | ### 资产上下文 | 工具 | 描述 | |------|-------------| | `malcolm_netbox_lookup` | 在 NetBox 中查找 IP、设备或网络前缀 | | `malcolm_netbox_sites` | 列出 NetBox 站点目录(id、名称、元数据) | ### Arkime | 工具 | 描述 | |------|-------------| | `arkime_sessions` | 使用 Arkime 表达式语法搜索 Arkime 会话 | | `arkime_session_detail` | 获取单个会话的所有字段(完整的 SPI 文档) | | `arkime_session_pcap` | 获取会话的 PCAP 并报告其大小和文件魔数有效性(仅元数据,不向磁盘写入任何内容) | | `arkime_unique` | 列出某个字段的所有不同值,可选择包含计数 | | `arkime_spigraph` | 某个字段的 Top 值及其时间序列图 | | `arkime_spiview` | 在一次调用中跨多个字段获取值概况 | | `arkime_connections` | 源/目的连接图(节点和链接) | ### 关联与导出 | 工具 | 描述 | |------|-------------| | `malcolm_related_sessions` | 查找与 Zeek UID 相关的所有会话 | | `malcolm_dashboard_export` | 将 OpenSearch Dashboards 保存的对象导出为 JSON | ## 写入工具(可选开启) 每个类别通过将其标志设置为 `true` 来启用。除非你主动要求,否则不会执行任何写入操作。 | 类别 | 标志 | 工具 | Endpoint | |-------|------|-------|----------| | alerting | `MALCOLM_MCP_ENABLE_ALERTING` | `malcolm_create_alert` | `POST /mapi/event` | | arkime-tag | `MALCOLM_MCP_ENABLE_ARKIME_TAGS` | `arkime_add_tags` | `POST /arkime/api/sessions/addtags` | | hunt-job | `MALCOLM_MCP_ENABLE_HUNT_JOBS` | `arkime_create_hunt`, `arkime_hunt_status` | `POST /arkime/api/hunt` | | pcap-upload | `MALCOLM_MCP_ENABLE_PCAP_UPLOAD` | `malcolm_upload_pcap` | `POST /server/php/submit.php` | - **alerting**:`malcolm_create_alert` 将分析师或 agent 生成的发现索引为一个警报文档,你可以在 Malcolm 的仪表板中看到它。它使用 `/mapi/event`,这是 Malcolm 自身内置的专用写入 endpoint,也是其他类别遵循的模板。 - **arkime-tag**:`arkime_add_tags` 用于为会话添加 tag。它仅用于添加;移除 tag 需要更高的 Arkime 角色权限及其自身的安全设计,因此被推迟实现。 - **hunt-job**:`arkime_create_hunt` 启动跨 PCAP 的数据包搜索(开销很大,因此请先确定查询范围)。`arkime_hunt_status` 用于读取任务进度,并随该类别一起提供。 - **pcap-upload**:`malcolm_upload_pcap` 将本地抓包文件发送给 Malcolm 进行摄取(ingest),并带有客户端的大小限制。 每个写入工具都带有 MCP 注解 `readOnlyHint: false` 和 `destructiveHint: false`,因此 MCP 客户端可以在调用运行前执行其自身的确认步骤。 ## 安全模型 Malcolm 的默认部署已经赋予任何已认证用户对原始 OpenSearch(`/mapi/opensearch/*`)不受限制的写入权限,以及对 NetBox 完整的 CRUD(`/mapi/netbox/*`)权限。两者都是没有进行 HTTP 动词过滤的纯粹反向代理;Malcolm 自身的只读模式是移除它们,而不是尝试对它们进行过滤。在常见的认证模式下,“已登录”即意味着具有等同管理员的权限。 在此开启某个写入类别并不会打开一扇原本关闭的门。这扇门在平台层面已经是敞开的。此 server 只是提供了一种经过精心设计的通过方式: - 提供少量、命名的写入操作集合,而不是原始的透传。 - 默认关闭,每次只能启用一个类别。 - 每次写入尝试都会有一行审计记录。 - 包含 MCP 注解,以便客户端可以要求进行确认。 此 server **不会**暴露原始的 OpenSearch 和 NetBox 写入透传,无论是否通过标志隐藏。管理(Curating)这一攻击面正是它的职责所在。 ## 审计 每次写入尝试都会输出一行 JSON,无论成功还是失败: ``` {"ts": "2026-07-06T09:12:44Z", "tool": "arkime_add_tags", "class": "arkime-tag", "target": "ids=240601-abc", "params": {"tags": "suspicious"}, "outcome": "ok"} ``` `outcome` 的值可以是 `ok`、`http_4xx`、`http_5xx` 或 `error:` 中的一种。过长的参数值会被截断,并且 PCAP 的字节流永远不会被记录。默认的输出目标是 stderr;设置 `MALCOLM_MCP_AUDIT_FILE` 可以改为将其追加到文件中。读取工具不会被审计。 ## 快速开始 ### 安装 ``` pip install mcp-server-malcolm ``` 或者从源码安装: ``` git clone https://github.com/nagameTW/mcp-server-malcolm.git cd mcp-server-malcolm pip install -e . ``` ### 配置 为你的 Malcolm 实例设置连接变量: ``` export MALCOLM_URL="https://malcolm.example" export MALCOLM_USERNAME="admin" export MALCOLM_PASSWORD="admin" export MALCOLM_SSL_VERIFY="false" # Malcolm ships self-signed certs by default export MALCOLM_TIMEOUT="30" ``` 保持写入标志未设置以在只读模式下运行。要启用某个类别,请设置其标志: ``` export MALCOLM_MCP_ENABLE_ALERTING="true" export MALCOLM_MCP_AUDIT_FILE="/var/log/malcolm-mcp-audit.jsonl" ``` ### 运行 ``` # 作为 MCP server (stdio transport) mcp-server-malcolm # 或通过 Python module python -m mcp_server_malcolm ``` ## 用法 ### MCP 客户端(配置文件) 将此 server 添加到你的 MCP 客户端配置中: ``` { "mcpServers": { "malcolm": { "command": "mcp-server-malcolm", "env": { "MALCOLM_URL": "https://malcolm.example", "MALCOLM_USERNAME": "admin", "MALCOLM_PASSWORD": "admin", "MALCOLM_SSL_VERIFY": "false" } } } } ``` 确切的配置文件位置,请查阅你的 MCP 客户端文档。许多客户端使用项目级别的 `.mcp.json` 或全局配置文件。 ### Python(直接导入) 脱离 MCP 层直接使用 `MalcolmClient`: ``` import asyncio from mcp_server_malcolm import MalcolmClient async def main(): client = MalcolmClient( base_url="https://malcolm.example", username="admin", password="admin", ) # Search network traffic results = await client.search( filters={"event.dataset": "conn", "source.ip": "192.0.2.77"}, limit=10, ) # Aggregate by protocol agg = await client.aggregate( fields="network.protocol", filters={"network.direction": ["inbound", "outbound"]}, ) # Discover field names fields = await client.search_fields(keyword="useragent") # Get distinct values datasets = await client.field_values(field="event.dataset") # Look up a NetBox asset asset = await client.netbox_get( "api/ipam/ip-addresses/", params={"address": "192.0.2.77"}, ) await client.close() asyncio.run(main()) ``` 写入原语位于 `_write_*` 方法之后。只有受控的写入工具才能调用它们,直接导入的路径无法访问。 ## Malcolm 过滤语法 Malcolm 使用简单的 JSON 过滤语法,而不是 OpenSearch DSL: ``` # 精确匹配 {"event.dataset": "conn"} # 多个值 (OR) {"network.direction": ["inbound", "outbound"]} # 否定 {"!network.transport": "icmp"} # Field 必须存在 (not null) {"!related.password": null} # 通配符 {"suricata.alert.signature": "*MALWARE*"} # 组合 (AND) {"event.dataset": "dns", "source.ip": "192.0.2.77"} ``` ## 示例 ### 搜索发往可疑域名的 DNS 查询 ``` malcolm_search( filters='{"event.dataset": "dns", "zeek.dns.query": "*example.com*"}', limit=20, time_from="7 days ago" ) ``` ### 按协议聚合顶级会话者 ``` malcolm_aggregate( fields="source.ip,destination.ip,network.protocol", filters='{"network.direction": ["inbound", "outbound"]}', limit=20 ) ``` ### 在查询前验证字段名 ``` malcolm_field_search(prefix="zeek.dns") malcolm_field_values(field="event.dataset") malcolm_field_profile(field="zeek.ssl.server_name") ``` ### 创建警报(需启用 alerting 类别) ``` malcolm_create_alert( title="Periodic beacon to 192.0.2.77", severity=2, description="60s-interval C2 candidate", source_ip="192.0.2.10", dest_ip="192.0.2.77" ) ``` ### 为会话添加待审查 tag(需启用 arkime-tag 类别) ``` arkime_add_tags(session_ids="240601-abc,240601-def", tags="review,beacon") ``` ### 启动 hunt(需启用 hunt-job 类别) ``` arkime_create_hunt( name="beacon-bytes", search="deadbeef", search_type="hex", total_sessions=42, start_time=1717200000, stop_time=1717203600, expression="ip==192.0.2.77" ) ``` ## 配置参考 | 变量 | 默认值 | 描述 | |----------|---------|-------------| | `MALCOLM_URL` | `https://localhost` | Malcolm 的 base URL | | `MALCOLM_USERNAME` | `admin` | Basic auth 用户名 | | `MALCOLM_PASSWORD` | `admin` | Basic auth 密码 | | `MALCOLM_SSL_VERIFY` | `false` | 验证 TLS 证书(接受 CA 路径) | | `MALCOLM_TIMEOUT` | `30` | HTTP 请求超时时间(秒) | | `MALCOLM_MCP_ENABLE_ALERTING` | `false` | 启用 alerting 写入类别 | | `MALCOLM_MCP_ENABLE_ARKIME_TAGS` | `false` | 启用可追加的会话 tag 标记 | | `MALCOLM_MCP_ENABLE_HUNT_JOBS` | `false` | 启用 Arkime hunt 创建和状态查询 | | `MALCOLM_MCP_ENABLE_PCAP_UPLOAD` | `false` | 启用 PCAP 上传 | | `MALCOLM_MCP_AUDIT_FILE` | 未设置 | 写入审计文件(未设置时输出到 stderr) | ## 使用到的 Malcolm API endpoint | Endpoint | 方法 | 使用者 | |----------|--------|---------| | `/mapi/document` | POST | `malcolm_search`, `malcolm_alerts`, `malcolm_related_sessions` | | `/mapi/agg/` | POST | `malcolm_aggregate`, `malcolm_field_values`, `malcolm_field_profile`, `malcolm_data_coverage` | | `/mapi/fields` | GET | `malcolm_field_search`, `malcolm_field_profile` | | `/mapi/ready`, `/mapi/version` | GET | `malcolm_service_status` | | `/mapi/ping` | GET | `malcolm_ping` | | `/mapi/ingest-stats`, `/mapi/indices` | GET | `malcolm_data_coverage` | | `/mapi/dashboard-export/` | GET | `colm_dashboard_export` | | `/mapi/opensearch//_search` | POST | `search_dsl` | | `/mapi/opensearch//_count` | POST | `count` | | `/mapi/opensearch/_cat/indices` | GET | `list_indices` | | `/mapi/opensearch//_mapping` | GET | `index_mapping` | | `/mapi/opensearch/_cluster/health` | GET | `cluster_health` | | `/mapi/netbox/*` | GET | `malcolm_netbox_lookup` | | `/mapi/netbox-sites` | GET | `malcolm_netbox_sites` | | `/mapi/event` | POST | `malcolm_create_alert` (写入) | | `/arkime/api/sessions` | GET | `arkime_sessions` | | `/arkime/api/session/` | GET | `arkime_session_detail` | | `/arkime/api/sessions.pcap` | GET | `arkime_session_pcap` | | `/arkime/api/unique` | GET | `arkime_unique` | | `/arkime/api/spigraph` | GET | `arkime_spigraph` | | `/arkime/api/spiview` | GET | `arkime_spiview` | | `/arkime/api/connections` | GET | `arkime_connections` | | `/arkime/api/sessions/addtags` | POST | `arkime_add_tags` (写入) | | `/arkime/api/hunt`, `/arkime/api/hunts` | POST, GET | `arkime_create_hunt`, `arkime_hunt_status` (写入 + 读取) | | `/server/php/submit.php` | POST | `malcolm_upload_pcap` (写入) | 这些 endpoint 路径和请求体结构匹配 Malcolm `26.06.1` 和 Arkime `v6.5.0`。两者在不同版本间会发生变动,因此如果写入工具返回意外错误,请针对你自己的版本重新检查。 ## 非目标 版本 1 刻意排除了以下内容: - 破坏性写入(删除 Arkime 会话、移除 tag、管理用户)。 - 原始的 OpenSearch 写入或原始的 NetBox CRUD 透传,无论是否通过标志启用。 - `streamable-http` 传输(仅支持 stdio)。 ## 环境要求 - Python 3.11+ - 拥有 API 访问权限的 Malcolm 实例 - 与 Malcolm 的网络连通性 ## 许可证 MIT © nagameTW
标签:MCP服务, Metaprompt, Rootkit, Suricata, Zeek, 现代安全运营, 网络安全, 逆向工具, 隐私保护