Ewiges-M/splunk-soar-mcp

GitHub: Ewiges-M/splunk-soar-mcp

一个通过 MCP 协议让 AI 助手无需浏览器即可操作 Splunk SOAR 实例的服务器,支持无头化的案例管理、playbook 编写部署与运行调试。

Stars: 1 | Forks: 0

# Splunk SOAR MCP Server 一个用于 **Splunk SOAR**(原 Phantom)的 [MCP (Model Context Protocol)](https://modelcontextprotocol.io) 服务器。它允许像 Claude Code 这样的 AI 助手无头化地操作 SOAR 实例——无需浏览器。每次调用都使用 `ph-auth-token`(或 HTTP Basic auth)直接发送到 SOAR REST API。 **你可以用它来做什么:** - 对容器(案例)进行分类:搜索、读取字段/工件、添加分析师注释 - 以编程方式编写和部署 playbook(`import_playbook` 打包路径——这是唯一一个实际上适用于现代 playbook 的写入路径) - 运行 playbook 和单个 app action,然后轮询状态、action run 和调试日志 - 管理自定义列表和资产配置 - 通过 `rest` 逃生舱回退到任何原始 REST 调用 已在 **Splunk SOAR 6.4.x** 上进行测试。 ## 要求 - Python 3.10+ - [`uv`](https://docs.astral.sh/uv/)(推荐)或 `pip install fastmcp` - 可访问你的 SOAR 实例的网络 - 拥有 auth token 的 SOAR **自动化用户**(见下文) ## 第 1 步 — 在 SOAR 中创建自动化用户和 token 1. 以管理员身份登录你的 SOAR Web UI。 2. 进入 **Administration → User Management → Users → + User**。 3. 将 **User Type** 设置为 Automation。给它起个名字,比如 `mcp-auto`。 4. 授予它具有所需权限的角色(至少包括:查看容器/playbook;如果你需要部署/运行能力,请添加 **Edit/Import Playbooks** 和 **Execute Actions**)。 5. 保存用户,然后打开它——**Authorization Configuration for REST API** 部分会显示包含 `ph-auth-token` 值的 JSON。复制该 token。 6. 记下用户的数字 **id**(在查看用户时可在 URL 中看到,或通过 `GET /rest/ph_user?_filter_type="automation"` 获取)。你将把它用作 `SOAR_OWNER_ID`——通过 `run_action` 运行单个 action 时需要它。 ## 第 2 步 — 配置环境变量 | 变量 | 必填 | 描述 | |---|---|---| | `SOAR_HOST` | ✅ | 你的 SOAR 实例的 Base URL,例如 `https://soar.example.com`(无需尾随斜杠) | | `SOAR_TOKEN` | ✅(或 用户名/密码) | 第 1 步中的 `ph-auth-token` | | `SOAR_USER` / `SOAR_PASS` | — | HTTP Basic 备用方案,仅在未设置 `SOAR_TOKEN` 时使用 | | `SOAR_OWNER_ID` | — | 自动化用户的数字 `ph_user` id(默认为 `1`)。用作 `run_action` 的 `owner` | | `SOAR_VERIFY_SSL` | — | 设置为 `true` 以验证 TLS 证书。默认为 `false`,因为大多数本地 SOAR 实例使用自签名证书 | ## 第 3 步 — 在你的 MCP 客户端中注册 ### Claude Code(项目范围) 在你的项目根目录下创建 `.mcp.json`(参见 [`.mcp.json.example`](.mcp.json.example)): ``` { "mcpServers": { "soar": { "command": "uv", "args": ["run", "--with", "fastmcp", "python", "/absolute/path/to/splunk-soar-mcp/server.py"], "env": { "SOAR_HOST": "https://YOUR-SOAR-HOST", "SOAR_TOKEN": "YOUR-PH-AUTH-TOKEN", "SOAR_OWNER_ID": "1" } } } } ``` 然后在那个项目中启动 Claude Code,并在出现提示时批准该服务器(或运行 `/mcp` 检查连接)。 ### Claude Desktop 将相同的配置块添加到 `claude_desktop_config.json`: - macOS: `~/Library/Application Support/Claude/claude_desktop_config.json` - Windows: `%APPDATA%\Claude\claude_desktop_config.json` ### 不使用 uv,改用普通 pip ``` "command": "python3", "args": ["/absolute/path/to/splunk-soar-mcp/server.py"] ``` 前提是已执行了 `pip install fastmcp`。 ## 第 4 步 — 验证连接 要求你的助手调用 `whoami` 工具。预期输出: ``` { "host": "https://YOUR-SOAR-HOST", "auth_mode": "token", "auth_ok": true, "version": "6.4.1.361", "run_as": {"id": 1, "username": "mcp-auto", "type": "automation"} } ``` 如果 `auth_ok` 为 `false`,说明 token 错误或缺少 REST 访问权限。如果服务器因 `SOAR_HOST is not set` 而无法启动,请修复你的 `env` 块。 ## 工具参考 ### 连接与通用 | 工具 | 用途 | |---|---| | `whoami()` | 检查凭证、SOAR 版本以及 action 运行时所代表的自动化用户 | | `rest(method, path, json_body)` | 通用 REST 逃生舱(`GET`/`POST`/`DELETE`,路径如 `/rest/...`) | ### 容器(案例) | 工具 | 用途 | |---|---| | `search_containers(name_contains, status, tenant, limit)` | 按名称子字符串 / 状态 / 租户查找容器 | | `get_container(container_id)` | 获取单个容器的关键字段 + `custom_fields` | | `get_artifacts(container_id, limit)` | 列出工件及其完整的 CEF 字典 | | `update_artifact(artifact_id, cef)` | 将键**合并**到工件的 CEF 中(单纯的 POST 会静默清除所有其他键——该工具会先读取后合并) | | `update_container_fields(container_id, custom_fields, status, name)` | 更新容器的 `custom_fields` / `status` / `name`。容器的 `custom_fields` 在**服务端进行合并**,因此局部写入是安全的 | | `add_note(container_id, title, content, note_type)` | 向容器添加注释 | ### Playbook — 读取与编写 | 工具 | 用途 | |---|---| | `list_playbooks(name_contains, limit)` | 按名称查找 playbook | | `get_playbook(playbook_id)` | 元数据:名称、`passed_validation`、类型、`input_spec`、是否激活 | | `get_playbook_source(playbook_id)` | 生成的 Python 代码 + 输入/输出规范——在转换 playbook 之前读取真实的 datapath | | `deploy_playbook(out_dir, name)` | 从 `out_dir/{name}.py` + `{name}.json` 构建 tgz 包,进行验证(AST 解析)、导入并检验。**每次导入都会创建一个新的 playbook id** | | `import_bundle_b64(b64, scm, force)` | 导入预构建的 base64 gzip-tarball 包 | ### Playbook 与 action — 运行与调试 | 工具 | 用途 | |---|---| | `run_playbook(container_id, playbook_id, inputs, scope)` | 触发 playbook 运行(支持输入 playbook) | | `playbook_run_status(playbook_run_id)` | 轮询单次运行:状态 + 消息 | | `wait_for_playbook_run(playbook_run_id, timeout_secs, poll_secs)` | 轮询直到运行结束,返回最终状态及其 action run | | `action_runs(playbook_run_id)` | 列出 playbook 运行产生的 action run | | `app_run_detail(action_run_id)` | 每个 app-run 的参数 + 结果消息——显示发送给 app 的确切参数 | | `playbook_run_log(playbook_run_id, contains, limit)` | 运行的调试日志——SOAR 报告真实失败的地方(例如 "phantom.collect2() returned an empty list") | | `run_action(action, asset, app_id, container_id, parameters, ...)` | 在任何 playbook 之外运行单个 app action 并等待结果 | ### 自定义列表与资产 | 工具 | 用途 | |---|---| | `get_custom_list(name)` | 按名称读取自定义列表(`decided_list`) | | `update_custom_list_rows(name, rows)` | 替换整行(`{"从 0 开始的索引": [完整行]}`)。第 0 行是表头;始终发送每一列 | | `update_asset(asset_id, config_updates)` | 将键**合并**到资产配置中(例如轮换密码)。先读取后合并——单纯的局部 POST 会丢弃其他键。Secret 绝不会回显 | ## 典型工作流:构建 → 部署 → 测试 playbook ``` 1. Produce out_dir/{NAME}.py and out_dir/{NAME}.json (playbook source + graph) 2. deploy_playbook("out_dir", "NAME") → imported id + passed_validation 3. run_playbook(container_id, id, {..inputs..}) → playbook_run_id 4. wait_for_playbook_run(run_id) → final status + action runs 5. playbook_run_log(run_id) → debug the failure if any ``` ## 惨痛教训得出的 Gotchas - `import_playbook` 总是创建一个**新**的 playbook id——它从不按名称覆盖。 - REST `DELETE /rest/playbook/{id}` 返回 **405**——playbook 只能在 UI 中删除。 - 单纯的 `POST /rest/artifact/{id} {"cef": {...}}` 会**替换**整个 CEF 并破坏所有其他键。资产配置也是如此。请使用这里的合并工具。 - 写入语义因对象而异:容器的 `custom_fields` 会**合并**(局部写入安全),工件的顶层字段(name/label/severity)会**合并**,但 `artifact.cef` 和 `asset.configuration` 会直接**替换**。 - 容器的 `status` 值很挑剔——`"in progress"` 会被拒绝;有效值为带连字符的 `in-progress`。 - `run_action` 要求 `owner` 和 `app_id` **同时**位于顶层*且*位于 target 内部,否则 SOAR 会以令人误解的错误拒绝请求。 - 一次 `phantom.collect2()` 调用会收集超过一个 block——永远不要在单个 datapath 列表中跨越两个 `playbook_input:*` 字段。 ## 安全注意事项 - 使用具有最低角色的专用**自动化用户**,切勿使用个人管理员账户。 - 将 token 保持在版本控制之外(`.mcp.json` 在此仓库的 `.gitignore` 中)。 - TLS 验证**默认关闭**(自签名证书在本地部署中是常态)。如果你的实例具有有效的证书,请设置 `SOAR_VERIFY_SSL=true`。 - 如果 token 曾泄露,请从 **User Management** 进行轮换。 ## 许可证 [MIT](LICENSE)
标签:API集成, MCP协议, SOAR, 人工智能, 可观测性, 大模型, 安全运营, 扫描框架, 用户模式Hook绕过, 自动化运维, 逆向工具