blauwers/opencti-mcp-server
GitHub: blauwers/opencti-mcp-server
该服务器通过 MCP 协议将 OpenCTI 威胁情报平台的各项操作工具化,使 AI 客户端能够直接查询、创建和管理威胁情报实体、报告、案例与调查。
Stars: 0 | Forks: 0
# OpenCTI MCP Server
OpenCTI MCP 服务器通过 Model Context Protocol (MCP) 暴露 OpenCTI 威胁情报操作。它使用官方的 `pycti` 客户端调用 OpenCTI GraphQL API。
该项目采用 Apache License 2.0 授权。有关详细信息,请参阅 [LICENSE](LICENSE)。
## 功能
| 类别 | 工具 |
| --- | --- |
| Indicators | `lookup_indicator`, `list_indicators`, `list_indicators_page`, `get_indicator`, `summarize_indicator_intelligence`, `add_indicator`, `update_indicator`, `promote_observable_to_indicator`, `get_indicator_relationships` |
| Observables | `lookup_observable`, `list_observables`, `list_observables_page`, `get_observable`, `summarize_observable_intelligence`, `add_observable`, `enrich_observable`, `get_observable_indicators`, `get_observable_relationships` |
| 情报实体 | `list_intelligence_entity_types`, `list_intelligence_entities`, `list_intelligence_entities_page`, `get_intelligence_entity`, `export_intelligence_entity_stix` |
| 报告 | `lookup_report`, `list_reports`, `list_reports_page`, `create_report`, `add_object_to_report`, `get_report_objects`, `summarize_report_intelligence`, `export_report_stix` |
| 案例 | `create_incident_case`, `create_rfi`, `lookup_case`, `list_cases`, `list_cases_page`, `add_object_to_case`, `update_case_status`, `summarize_case_intelligence` |
| 任务 | `create_task`, `complete_task` |
| 调查 | `create_investigation`, `get_investigation`, `list_investigations`, `list_investigations_page`, `add_to_investigation`, `export_investigation_as_report`, `start_investigation_from_container`, `start_investigation_from_entity`, `run_basic_investigation` |
| 富化 | `list_enrichment_connectors`, `enrich_entity`, `enrich_entity_and_wait`, `run_available_enrichments`, `get_enrichment_status`, `get_entity_connectors` |
| 关系 | `create_relationship`, `lookup_relationships`, `find_relationship_paths`, `create_sighting` |
| 情报上下文 | `global_search`, `resolve_entity`, `summarize_entity`, `expand_entity_context`, `find_by_stix_id`, `find_by_external_reference` |
| 系统 | `get_current_identity`, `get_server_capabilities`, `get_runtime_metrics`, `get_recent_audit_events`, `list_audit_events` |
## 资源
| URI 模板 | 描述 |
| --- | --- |
| `opencti://indicator/{indicator_id}` | Indicator 详情 |
| `opencti://observable/{observable_id}` | Observable 详情 |
| `opencti://report/{report_id}` | 报告详情及其包含的对象 |
| `opencti://case/{case_id}` | Incident、RFI 或 RFT 案例详情 |
| `opencti://investigation/{investigation_id}` | 导出为 STIX 2.1 bundle 的调查 |
| `opencti://server/capabilities` | 服务器能力、限制、后端版本以及被禁用的功能 |
## 要求
- Python 3.10 或更高版本
- 正在运行的 OpenCTI 实例
- 具备您所启用工具所需权限的 OpenCTI API token
## 安装
在仓库根目录下执行:
```
pip install -e .
```
用于开发环境:
```
pip install -r requirements.txt
pip install -r test-requirements.txt
pip install -e .
```
`requirements.txt` 和 `test-requirements.txt` 是用于本地开发的跨平台源需求文件。`requirements.docker.lock` 和 `build-requirements.docker.lock` 是用于生产容器构建的确定性 Linux/CPython 3.12 输入;它们特意不作为 Windows 或 macOS 主机的默认安装路径。
要在任何安装了 Docker 的主机上刷新容器锁文件:
```
python scripts/refresh-docker-locks.py
```
该命令会在 Dockerfile 使用的同一个固定 Python 镜像内解析依赖项,从而确保将平台特定的依赖项锁定到部署目标,而不是碰巧运行该命令的工作站上。
## 配置
服务器从环境变量中读取配置。在本地开发时,您可以通过将 `MCP_DOTENV_PATH` 设置为绝对路径来显式加载一个受信任的 dotenv 文件。系统特意禁用了对当前工作目录下 `.env` 文件的隐式发现机制。
| 变量 | 必填 | 默认值 | 描述 |
| --- | --- | --- | --- |
| `OPENCTI_URL` | 是 | | OpenCTI 实例的 Base URL,例如 `http://localhost:4000` |
| `OPENCTI_TOKEN` | 是 | | OpenCTI API bearer token |
| `OPENCTI_SSL_VERIFY` | 否 | `true` | `true`、`false` 或 CA bundle 路径 |
| `LOG_LEVEL` | 否 | `info` | Python 日志级别 |
| `MCP_TRANSPORT` | 否 | `stdio` | `stdio` 或 `sse` |
| `MCP_SSE_HOST` | 否 | `127.0.0.1` | SSE 传输的绑定主机 |
| `MCP_SSE_PORT` | 否 | `8000` | SSE 传输的绑定端口 |
| `MCP_API_KEY` | SSE 必填(除非显式禁用) | | SSE HTTP 请求所需的 bearer token |
| `MCP_IDENTITY_MODE` | 否 | `server_token` | `server_token` 使用配置的 `OPENCTI_TOKEN`;`opencti_bearer` 要求 SSE 调用者使用其自身的 OpenCTI bearer token 进行身份验证,并在该 OpenCTI principal 下执行工具。 |
| `MCP_DEFAULT_TENANT_ID` | 否 | `default` | 分配给主要 `OPENCTI_URL` / `OPENCTI_TOKEN` 连接的 Tenant ID。 |
| `MCP_TENANTS_JSON` | 否 | 未设置 | 以 Tenant ID 为键的额外可路由 tenant 的 JSON 对象。每个条目必须定义 `opencti_url` 和 `opencti_token`,并可以覆盖 `ssl_verify`。多租户路由仅支持 SSE。 |
| `MCP_COORDINATION_BACKEND_FACTORY` | 否 | 未设置 | 可选的 `module:callable` 导入路径,返回一个用于外部管理审计、配额和幂等性存储的 `CoordinationBackends` bundle。 |
| `MCP_AUDIT_BUFFER_SIZE` | 否 | `1000` | 内存中保留的已清理审计事件的最大数量,用于本地检查。 |
| `MCP_AUDIT_ACTOR_MAX_STREAMS` | 否 | `4096` | 同时保留的 actor 本地审计历史和 principal 指标流的最大数量。 |
| `MCP_PRINCIPAL_QUOTA_PER_MINUTE` | 否 | `0` | 每个 principal、每个操作的本地配额。`0` 禁用配额强制执行。 |
| `MCP_PRINCIPAL_QUOTA_MAX_ACTORS` | 否 | `4096` | 同时保留的 actor 配额窗口的最大数量。 |
| `MCP_EXPORT_MAX_OBJECTS` | 否 | `50` | 包含在一次受限报告或调查导出中的最大直接 STIX 成员数。 |
| `MCP_IDEMPOTENCY_TTL_SECONDS` | 否 | `300` | 已完成的 mutation 幂等性键的保留时间窗口(以秒为单位)。 |
| `MCP_IDEMPOTENCY_MAX_ENTRIES` | 否 | `4096` | 本地后端中保留的幂等性记录的最大数量。 |
| `MCP_REQUIRE_MUTATION_CONFIRMATION` | 否 | `false` | 在执行 mutating 工具之前要求 `confirm=true`。 |
| `MCP_IDEMPOTENCY_BACKEND` | 否 | `memory` | `memory` 用于进程本地重放保护,或 `sqlite` 用于保证重启后安全的持久重放保护。 |
| `MCP_IDEMPOTENCY_SQLITE_PATH` | 当 `MCP_IDEMPOTENCY_BACKEND=sqlite` 时必填 | | SQLite 幂等性数据库文件的绝对路径。 |
| `MCP_OBSERVABILITY_BACKEND` | 否 | `memory` | `memory` 用于进程本地的审计和配额状态,或 `sqlite` 用于保证重启安全且跨进程的可观测状态。 |
| `MCP_OBSERVABILITY_SQLITE_PATH` | 当 `MCP_OBSERVABILITY_BACKEND=sqlite` 时必填 | | SQLite 可观测性数据库文件的绝对路径。 |
| `MCP_ALLOW_UNAUTHENTICATED_SSE` | 否 | `false` | 仅供开发使用的未认证 SSE 选项 |
| `MCP_MAX_BODY_BYTES` | 否 | `1048576` | SSE HTTP 请求体的最大大小 |
| `MCP_BODY_READ_TIMEOUT` | 否 | `10` | 允许接收 SSE 请求体的正且有限的秒数;支持小数值 |
| `MCP_MAX_CONCURRENT` | 否 | `20` | 最大并发 SSE 流和普通 HTTP 请求数,按连接池独立强制执行 |
| `MCP_RATE_LIMIT_PER_MINUTE` | 否 | `60` | 每个客户端每分钟的最大 SSE HTTP 请求数 |
| `MCP_MAX_RATE_LIMIT_CLIENTS` | 否 | `4096` | 跟踪的最大 SSE 速率限制客户端标识符数量。值越大支持的唯一客户端 IP 越多,同时占用更多内存;值越小会越早剔除旧客户端。 |
| `MCP_TRUST_PROXY_HEADERS` | 否 | `false` | 使用 `X-Forwarded-For`、`Forwarded` 或 `X-Real-IP` 作为 SSE 速率限制客户端标识符。仅当请求通过会覆盖这些 header 的受信任反向代理时才启用。 |
| `MCP_TRUSTED_PROXY_SOURCES` | 否 | `127.0.0.1,::1` | 当 `MCP_TRUST_PROXY_HEADERS=true` 时,允许提供转发客户端 header 的以逗号分隔的代理源 IP 或 CIDR 范围。启用时至少需要一个源。 |
| `OPENCTI_REQUEST_TIMEOUT` | 否 | `60` | OpenCTI API 请求的超时时间(以秒为单位) |
| `MCP_MAX_ARGUMENT_BYTES` | 否 | `1048576` | 一次工具调用的最大序列化参数大小 |
| `MCP_MAX_RESPONSE_BYTES` | 否 | `4194304` | 最大序列化工具响应大小 |
## 使用方法
### stdio 传输
当 MCP 客户端直接启动服务器进程时使用 `stdio`:
```
OPENCTI_URL=http://localhost:4000 \
OPENCTI_TOKEN= \
opencti-mcp
```
MCP 客户端配置示例:
```
{
"mcpServers": {
"opencti": {
"command": "opencti-mcp",
"env": {
"OPENCTI_URL": "http://localhost:4000",
"OPENCTI_TOKEN": ""
}
}
}
}
```
### SSE 传输
当将服务器作为 HTTP endpoint 暴露时使用 `sse`。默认情况下 SSE 需要 `MCP_API_KEY`。
```
MCP_TRANSPORT=sse \
MCP_SSE_HOST=127.0.0.1 \
MCP_SSE_PORT=8000 \
MCP_API_KEY= \
OPENCTI_URL=http://localhost:4000 \
OPENCTI_TOKEN= \
opencti-mcp
```
配置 MCP 客户端使用:
```
http://localhost:8000/sse
```
客户端必须发送:
```
Authorization: Bearer
```
对于基于 OpenCTI 的调用者身份,将 SSE 切换为委托 bearer 模式:
```
MCP_TRANSPORT=sse \
MCP_IDENTITY_MODE=opencti_bearer \
OPENCTI_URL=http://localhost:4000 \
OPENCTI_TOKEN= \
opencti-mcp
```
在此模式下,`MCP_API_KEY` 必须未设置,并且每个客户端在 `Authorization` 中发送其自己的 OpenCTI bearer token。服务器使用 OpenCTI 的 `me()` 验证该 token,将解析出的 principal 绑定到 MCP 请求,并在该请求中对每个工具和资源调用重用相同的 principal。`get_current_identity` 返回当前活动的 OpenCTI principal。成功的 token 验证会被缓存五秒钟,以减少重复的 SSE 消息检查,同时保持较窄的撤销窗口。
`get_server_capabilities` 和 `opencti://server/capabilities` 暴露了当前活动的传输和身份模式、OpenCTI 后端版本、配置的限制、已注册的工具/资源清单,以及任何被故意禁用的功能系列,以便客户端在调用之前可以协商行为。
对于已发布的服务器接口,已禁用的功能清单目前为空。诸如租户路由和外部协调等可选功能会通过能力字段报告其活动配置,而不是被错误地归类为缺失的功能。
在 `opencti_bearer` 模式下,发现接口会根据调用者的 OpenCTI 能力进行过滤,未经授权的工具/资源调用会快速失败,并在调用后端之前返回稳定的 `forbidden` 响应。能力 payload 包含用于该投影的需求清单。
`get_runtime_metrics` 在 server-token 模式下暴露限制器状态以及审计和幂等计数器。在委托身份模式下,它默认为保留在有界 actor 流缓存中的 principal 本地审计计数器,并且要求 OpenCTI 的 `SETTINGS_SETACCESSES`(或 `BYPASS`)才能获取 `scope="all"` 的全局指标。在多租户委托部署中,未过滤的 `scope="all"` 指标和审计视图会被拒绝,因为所选的 OpenCTI 租户不授予跨租户的操作员权限;调用者必须保持在 `scope="self"`,或者在选定租户内提供显式的 actor 过滤器。
`get_recent_audit_events` 从配置的审计后端中暴露已清理的调用回执。HTTP 应用程序还在兼容的 `/health` endpoint 旁提供live`、`/ready` 和 `/metrics`。审计记录仅包含 actor、操作、结果和延迟;它们从不存储工具参数或响应 payload。`get_recent_audit_events` 默认为当前 actor。在委托单租户模式下,拥有 OpenCTI 的 `SETTINGS_SETACCESSES`(或 `BYPASS`)的操作员可以请求 `scope="all"` 进行跨 principal 审计检查。
`list_audit_events` 为操作员工作流添加了最新优先的不透明游标分页,这需要遍历有界审计流,而在新事件到达时不会发生偏移漂移。
高基数知识列表系列还暴露了分页变体:`list_indicators_page`、`list_observables_page`、`list_intelligence_entities_page`、`list_reports_page`、`list_cases_page` 和 `list_investigations_page`。这些工具使用由 OpenCTI 原生游标模型支持的有符号不透明连续游标,并返回一个稳定的信封,其中包含 `items`、`has_next_page`、`next_cursor`,以及后端提供时的 `total_count`。游标绑定到生成它们的工具和过滤器集合,因此调用者必须在后续请求中重用相同的查询结构。
`list_cases_page` 要求显式指定 `incident`、`rfi` 或 `rft` 的 `case_type`;合并的跨类型分页仍然保留在 `list_cases` 上,因为 OpenCTI 没有在所有三种案例集合中暴露一个稳定的游标域。
`/metrics` 默认返回 JSON 用于操作调试,并且当客户端发送 `Accept: text/plain` 或 `Accept: application/openmetrics-text` 时,还支持 Prometheus 文本展示格式。两种格式的身份验证和授权要求相同。
就绪和存活探针 endpoint 特意未设置身份验证,以便负载均衡器可以在没有 MCP 会话的情况下访问它们。`/metrics` 在 `server_token` 模式下需要配置的 SSE API 密钥,而在 `opencti_bearer` 模式下,它需要具有 `SETTINGS_SETACCESSES` 或 `BYPASS` 权限的已认证 OpenCTI principal。多租户委托部署拒绝 `/metrics`,因为服务器没有明显的跨租户操作员角色。
SSE 部署还暴露了 `/changes`,这是 OpenCTI 原生 `/stream` 订阅流的一个经过身份验证的中继。该中继转发 `Last-Event-ID` 以及受支持的 OpenCTI 流查询参数(`recover`、`listen-delete`、`no-dependencies` 和 `with-inferences`),以便使用者可以恢复交付,而无需 MCP 服务器发明自己的事件格式。
当设置了 `MCP_TENANTS_JSON` 时,每个非探针 SSE 请求都可以使用 `X-OpenCTI-Tenant` 选择一个租户。没有此 header 的请求使用 `MCP_DEFAULT_TENANT_ID`。委托 bearer 验证、pycti 客户端创建、配额/幂等性 principal 作用域以及不透明分页游标都绑定到所选的租户,从而确保 OpenCTI 身份继续从实际拥有该请求的平台流出。
对于需要托管协调服务的部署,请将 `MCP_COORDINATION_BACKEND_FACTORY` 设置为受信任的 `module:callable`。该 callable 接收加载的服务器配置,并返回一个 `opencti_mcp.coordination.CoordinationBackends` 实例,其中包含审计、配额和幂等性后端实现。这使得运行时对后端服务保持中立,同时仍允许 Redis、数据库或托管存储参与相同的已验证契约。
能力 payload 还使身份模型变得显式:`identity_provider.source` 始终为 `opencti`。服务器在 server-token 模式下可以接受静态 MCP API 密钥,或者在 `opencti_bearer` 模式下接受委托的 OpenCTI bearer token,但它不充当独立的 OAuth 颁发者。
Mutating 工具暴露了三个标准控制参数:`idempotency_key`、`dry_run` 和 `confirm`。使用相同的 actor、操作和参数重用一个幂等性键会重放第一个已完成的结果,而不会再次调用 OpenCTI;如果使用不同的参数重用,则会因 `idempotency_conflict` 而失败。`dry_run=true` 返回 mutation 请求的非执行预览元数据,并且不评估特定于工具的有效性,而操作员可以通过 `MCP_REQUIRE_MUTATION_CONFIRMATION=true` 要求对每个 mutation 进行 `confirm=true`。默认的内存后端是进程本地的;设置 `MCP_IDEMPOTENCY_BACKEND=sqlite` 并加上一个绝对路径的 `MCP_IDEMPOTENCY_SQLITE_PATH`,以便在重启和共享相同数据库文件的多个服务器进程之间保留重放保护。配置的 TTL 还会限制过期的进行中保留,因此崩溃的 worker 不能永远占用一个幂等性键。当 mutating 工具显式报告未知的提交结果时,该保留将被隔离为不确定状态,而不是作为已完成的结果进行重放。
审计保留和 principal 配额强制执行也默认使用内存存储。设置 `MCP_OBSERVABILITY_BACKEND=sqlite` 并加上一个绝对路径的 `MCP_OBSERVABILITY_SQLITE_PATH`,以便在重启后保留已清理的审计历史,并在指向相同数据库文件的多个服务器进程之间共享配额窗口。
## Docker
从仓库根目录构建 MCP 服务器镜像:
```
docker build -t opencti-mcp .
```
针对现有的 OpenCTI 实例运行它:
```
docker run --rm \
-e OPENCTI_URL=http://opencti:4000 \
-e OPENCTI_TOKEN= \
-e MCP_TRANSPORT=sse \
-e MCP_SSE_HOST=0.0.0.0 \
-e MCP_SSE_PORT=8000 \
-e MCP_API_KEY= \
-p 8000:8000 \
opencti-mcp
```
## Docker Compose
此目录中的 `docker-compose.yml` 仅启动 MCP 服务器。请从兼容的 OpenCTI 检出或现有部署中单独运行 OpenCTI,然后将 MCP 服务器指向该实例。
```
cp .env.example .env
```
编辑 `.env` 并设置:
- 将 `OPENCTI_URL` 设置为可从 MCP 容器访问的 OpenCTI 实例
- 将 `OPENCTI_TOKEN` 设置为 OpenCTI API token
- 将 `MCP_API_KEY` 设置为用于 MCP 客户端的随机 bearer token
对于在主机上运行的开发服务器,请使用:
```
OPENCTI_URL=http://host.docker.internal:4000
```
对于容器化的 OpenCTI 部署,请将 `OPENCTI_URL` 设置为可从 MCP 容器访问的 URL,例如当服务连接到同一 Docker 网络时的 `http://opencti:4000`。
启动 MCP 服务器:
```
docker compose up -d --build
```
默认 endpoint:
| 服务 | URL |
| --- | --- |
| MCP SSE endpoint | `http://127.0.0.1:8000/sse` |
| 就绪 endpoint | `http://127.0.0.1:8000/health` |
停止 MCP 服务器:
```
docker compose down
```
## 推荐工作流
这些工具旨在支持分析员驱动和智能体自动化情报工作流。有用的起始模式包括:
1. 解析并总结种子:
`resolve_entity` -> `summarize_entity` -> `expand_entity_context`
2. 调查 observable:
`lookup_observable` -> `summarize_observable_intelligence` -> `run_available_enrichments` -> `get_enrichment_status`
3. 调查 indicator:
`lookup_indicator` -> `summarize_indicator_intelligence` -> `find_relationship_paths`
4. 从种子创建调查工作区:
`run_basic_investigation` 或 `start_investigation_from_entity`
5. 审查交接上下文:
`summarize_report_intelligence` 或 `summarize_case_intelligence`
## 自动化护栏
MCP 服务器支持智能体工作流,而不会暴露广泛的管理权限。它不提供用户、组、连接器管理或删除工具。自动化工作流受明确限制的约束:
- 图扩展和路径查找会限制深度、扇出、队列大小、探索状态、后端查询和返回的路径。路径和上下文扩展响应会报告遍历何时被截断,以便调用者可以缩小过滤范围。
- SSE 流和普通 HTTP 请求具有独立的并发池,因此连接的客户端无法消耗发送其消息所需的槽位。
- 富化等待限制了超时和轮询间隔。正超时值在提交和轮询之间共享一个批处理截止时间,因此连接器数量不会使请求的超时时间成倍增加;`timeout_seconds=0` 会提交请求并跳过轮询。如果在得知工作 ID 之前提交本身就超过了正截止时间,响应将标记为 `submission_timed_out` 和 `submission_outcome_unknown`。
- 可用的富化执行仅限于与 observable 类型匹配的活动连接器,并设有执行上限。省略连接器 ID 会运行兼容的集合,每次 MCP 调用最多限制 10 个连接器,以限制外部副作用和后端负载,并返回每个连接器的结果以及去重后的工作 ID。
- 调查自动化在开始富化之前,会根据解析出的种子和受限的相关上下文创建作用域受限的调查工作区。其分阶段响应会在后续连接器工作仅部分成功时保留调查。
- 类型化搜索仅在部分扇出成功时返回部分结果警告,并在每个后端查询失败时返回显式错误。
- SSE 传输强制执行请求体、速率和并发限制。
- 阻塞式 pycti 操作在有界的 worker 池中运行,并且可超时的后台卸载操作使用单独的预算,因此它们不会在调用者超时后耗尽整个池。
- 对象引用写入每次调用最多接受 50 个标准化的对象 ID。
- STIX 导出路径在具体化之前会受到限制。实体导出支持单对象 `simple` 路径和包含直接关系及对立端点的有界单跳 `full` 图,报告导出包含最多达到 `MCP_EXPORT_MAX_OBJECTS` 的直接报告成员,而调查导出会根据一个受限的工作区快照构建一个合成报告 bundle。
调查响应在被省略成员时使用 `investigated_entities_truncated`,并在返回的快照已达到配置的写入限制时使用 `investigated_entities_at_capacity`。导出的调查报告通过 `x_opencti_membership_truncated` 和 `x_opencti_membership_at_capacity` 镜像这些信号。
## 响应契约
- `global_search` 始终返回 `results`、`partial` 和 `warnings`。完全后端失败会在保留这些键的同时,添加标准的 `error` 对象。
- 富化批次在 `requests` 下暴露连接器结果;等待的工具会在 `work_statuses` 下添加轮询记录。这些数组具有不同的含义,不会在兼容性别名下重复。
- `get_observable_indicators` 始终返回 `results`、`partial` 和 `warnings`,因此关系端点的失败或不完整解析可与完整的空结果区分开来。
- `lookup_case` 和 `list_cases` 始终返回 `results`、`partial` 和 `warnings`。跨类型案例查询会识别任何无法查询的 Incident、RFI 或 RFT 作用域。
- `summarize_report_intelligence` 和 `summarize_case_intelligence` 返回响应中包含的摘要计数,并在由于请求的限制而省略了其他链接成员时设置 `objects_truncated` / `tasks_truncated`。
- `find_by_external_reference` 最多返回 50 个已验证的匹配项,而 `get_entity_connectors` 最多返回 50 条最近的富化工作记录。
- `opencti://report/{id}` 和 `opencti://case/{id}` 资源在其受限集合省略了其他链接成员时,也会设置 `objects_truncated` / `tasks_truncated`。
- 直接的实体、indicator 和 observable 读取返回受限的公共投影,而不是不受限制的原始 OpenCTI 对象。
- 每个错误都使用 `error.code`、`error.message` 和 `error.operation`。诸如 `work_id` 或 `entity_type` 等附加上下文会被放置在错误信封旁边。
- 在 MCP 协议层,结构化的错误信封会设置 `isError=true`,并且 JSON 结果也会通过 `structuredContent` 暴露。
## 开发
```
pip install -r requirements.txt
pip install -r test-requirements.txt
pip install -e .
```
运行检查:
```
pytest tests/ -v
black --check src/ tests/
isort --check-only src/ tests/
flake8 src/ tests/
mypy src/
```
运行 MCP 覆盖率门控:
```
pytest tests/ --ignore=tests/integration \
--cov=opencti_mcp --cov-report=term-missing --cov-fail-under=95
```
实时回归测试可在 `tests/integration/` 下找到。它们默认被跳过,并且需要一个与安装的 `pycti` 客户端兼容的 OpenCTI API,以及一个允许创建和更新测试对象的 token。该套件会创建名为 `MCP regression` 或 `mcp-regression-*` 的隔离回归对象,并在会话结束后移除被跟踪的对象。仅在保留这些对象对调试有用时,才设置 `OPENCTI_MCP_PRESERVE_TEST_ARTIFACTS=true`。连接器工作记录仍受平台正常保留策略的约束。对于发布/CI 验证,请从单独的兼容 OpenCTI 检出中启动 OpenCTI,或者将运行器指向现有的兼容实例:
```
python scripts/run-mcp-regression.py \
--opencti-url http://127.0.0.1:4010 \
--opencti-token \
--run-live-regression
```
当针对已经运行的外部 OpenCTI 实例时,使用 `--use-external-opencti` 作为显式别名。仅当您确实想针对单独的本地 `client-python` 检出测试而不是声明的包依赖项时,才使用 `--client-python-path `如果只想运行快速的 95% 覆盖率门控,请省略 `--run-live-regression`。
在 Windows 上,`.\scripts\run-mcp-regression.ps1` 仍然可用,作为跨平台 Python 运行器的一个轻量级包装器。
## 安全
- 使用具有最低权限的专用 OpenCTI API token。
- 除非运行的是隔离的本地开发环境,否则不要在没有 `MCP_API_KEY` 或 `MCP_IDENTITY_MODE=opencti_bearer` 的情况下暴露 SSE。
- 除非反向代理提供 TLS、身份验证、请求限制和访问控制,否则将 SSE 绑定到 `127.0.0.1`。
- 除非 MCP 服务器仅接受来自会覆盖转发客户端 IP header 的受信任反向代理的流量,否则保持 `MCP_TRUST_PROXY_HEADERS=false`。启用它时,请将 `MCP_TRUSTED_PROXY_SOURCES` 设置为反向代理源 IP 或 CIDR 范围。
- 在生产环境中保持 `OPENCTI_SSL_VERIFY=true`。对于私有证书颁发机构,请使用 CA bundle 路径。
- 工具和资源处理程序向 MCP 客户端返回经过清理的错误,并在服务器端记录详细的异常。
- SSE 应用程序强制执行进程本地的请求体、速率和并发限制。在共享或面向互联网的部署中,这些控制不能替代反向代理限制。
- 未经身份验证的就绪 endpoint 使用单独的速率和并发限制(每个客户端每分钟 120 个请求和两个并发请求),外加单次执行的 5 秒缓存以及一个生命周期管理的异步 HTTP 连接池,以限制上游健康探针。
## 架构
```
MCP client
|
| MCP protocol (stdio or SSE)
v
opencti_mcp.server
|
| registers tools and resources
v
opencti_mcp.tools / opencti_mcp.resources
|
| pycti
v
OpenCTI GraphQL API
```
服务器保留一个引导 OpenCTI 连接,以及一组通过 `MCP_TENANTS_JSON` 声明的额外 SSE 租户路由。默认租户保持现有行为。当启用租户路由时,`X-OpenCTI-Tenant` 会为请求选择目标后端,并且运行时会将该选择保留在请求上下文中。在 `MCP_IDENTITY_MODE=server_token` 中,每个工作线程都会为所选租户延迟创建并重用 pycti 客户端。在 `MCP_IDENTITY_MODE=opencti_bearer` 中,每个经过身份验证的请求都会获得绑定到所选租户和调用者 OpenCTI 身份的线程本地 pycti 客户端,并且这些客户端在请求完成后会被释放。
标签:API集成, LLM集成, MCP服务, OpenCTI, PB级数据处理, 可观测性, 威胁情报, 安全运维, 开发者工具, 请求拦截, 逆向工具