mcpField
E
eset-mcp

eset-mcp

本地服务
github.com/maciekaz安全610 周前更新

关于 eset-mcp

eset-mcp 是面向 ESET 管理环境的 MCP 服务,可供连接 MCP 的 AI 客户端和 Agent 管理云端及本地部署。它以单一进程路由多个租户,并提供只读/读写隔离。

主要功能

  1. 01覆盖 ESET Connect 等管理 API
  2. 02支持云端与本地部署并行
  3. 03多租户凭据与令牌隔离
  4. 04只读和读写模式门控
  5. 05分页、重试与响应裁剪
  6. 06结构化日志及 Prometheus 指标

适用场景

  1. 01从 MCP 客户端查询设备与事件
  2. 02在单一服务中管理多个 ESET 租户
  3. 03限制 Agent 仅执行只读操作
  4. 04将云端和本地控制台统一接入

MCP 相关

通过工具、资源和提示词向 MCP 客户端开放 ESET 管理能力,支持 stdio 与 Streamable HTTP。请求可按租户及请求头路由到云端区域或本地控制台。

配置

本地服务的配置在各客户端中通用,复制后粘贴到客户端的 MCP 配置文件即可。

mcp.json · 通用配置
{
"mcpServers": {
"maciekaz-eset": {
"command": "docker",
"args": [
"run",
"-i",
"--rm",
"ghcr.io/maciekaz/eset-mcp:1.0.3"
]
}
}
}
启动命令docker run -i --rm ghcr.io/maciekaz/eset-mcp:1.0.3

本地服务需要在你的电脑上安装运行环境(如 Node.js 18+)。各客户端的配置文件位置不同,请参考客户端文档。

安装包
ocighcr.io/maciekaz/eset-mcp:1.0.3

工具

还没有获取到工具列表

本地服务需要在你的电脑上运行后才能读取工具,维护者暂未提供工具列表。

详细介绍

ESET-MCP

Tests License: MIT MCP spec

一个用于管理整个 ESET 管理体系的模型上下文协议服务:包括 ESET Connect (云端,涵盖所有区域)、ESET PROTECT On-Prem、ESET Inspect 和 ESET Cloud Office。可通过工具、资源和提示词,从任意 MCP 宿主(Claude Desktop、Claude Code 或自定义 Agent)管理其中任何一个产品。

专为集中管理任意数量的 ESET 部署而构建。单个进程可同时连接云端和本地控制台;客户端通过请求头选择目标。只要 MCP 收到有效凭据(Basic 身份验证,以及可选的 URL 覆盖和可选的 Cloudflare Access 服务令牌),就会将调用路由到相应后端、生成自己的令牌,并在池中隔离各租户。

⚠️ 特此说明,各位 这是一个由社区驱动的独立开源项目,与 ESET, spol. s r.o. 没有任何关联、没有获得其官方支持,也未获其认可。ESET 及其产品名称均为各自所有者的注册商标。

我们已尽一切努力确保本软件安全可靠(包括严格的只读模式限制),但本代码按“原样”提供,不附带任何形式的保证。您需自行承担使用此工具以及对 ESET 环境进行任何更改的全部责任。

目录


功能

完整的 API 覆盖范围
  • 102 个工具,根据 16 份官方 ESET Connect OpenAPI 3.0.1 规范自动生成,涵盖应用管理、资产管理、自动化、 设备管理、身份管理、事件管理、安装程序管理、 移动设备管理、网络访问保护、补丁管理、 策略管理、隔离区管理、用户管理、 漏洞管理和 Web 访问保护。
  • 4 个高级组合工具,将 3-6 次原始调用整合为一次: eset_search、device_full_profile、incident_full_context、 latest_detections。
只读 / 读写模式
  • ESET_MODE=RO → 工具目录仅展示只读工具(共 51 个)。 写入工具完全不会出现在 list_tools 中。
  • ESET_MODE=RW → 展示全部 106 个工具;修改类工具在其 MCP 注解中带有 destructiveHint: true。
  • 此模式独立于 ESET 账户的底层权限。
  • 通过纵深防御实现的内存门控会在发送任何 HTTP 请求前,于 RO 模式下拒绝 RW 工具名称。
身份验证
  • ESET_AUTH_MODE=env - 单租户,凭据来自 .env。
  • ESET_AUTH_MODE=basic - 多租户,客户端在每次请求中传递 Authorization: Basic <base64(user:password)>(还可选用 X-ESET-Region 指定其他云区域,或用 X-ESET-Server-URL 将 请求路由到本地部署的 PROTECT 控制台)。一个服务可为多个 ESET 账户提供服务,并在同一进程中混合使用云端和本地部署。
  • 每个租户的 OAuth 令牌会按 (user, password_hash, deployment, region-or-server-url, cf_secret_hash) 进行池化和隔离。 轮换密码或 Cloudflare Access 服务令牌时会创建新客户端;同一用户的云端和本地部署客户端绝不会共享池条目。
传输方式
  • stdio - 面向本地主机,通过 stdin/stdout 传输 JSON-RPC。
  • Streamable HTTP - 当前的 MCP 传输方式(2025 年 11 月规范)。
多区域

eu / de / us / ca / jpn。在 env 模式下通过 ESET_REGION 固定; 在 basic 模式下通过每次请求中的 X-ESET-Region 指定。

在同一进程中使用云端和本地部署

除云区域外,单个 MCP 服务还可为客户托管的 ESET PROTECT On-Prem 控制台提供服务。系统会透明处理本地部署的身份验证线路格式 (使用 camelCase 响应的 POST /GetTokens)以及每个主机的 URL 结构;客户端通过每次请求中的 X-ESET-Server-URL 标头选择目标。请参阅 本地部署的 ESET PROTECT 支持。

Cloudflare Access(可选)

当本地部署的控制台位于 Cloudflare Access 隧道后方时,MCP 会通过服务令牌进行身份验证 (使用环境变量默认值,或在每次请求中传递 X-ESET-CF-Access-Client-Id / X-ESET-CF-Access-Client-Secret),并通过隧道连接到源站。CF 令牌是额外的入口层, 位于 ESET 账户凭据之前,而非其替代品。云端请求绝不会携带这些标头。

弹性
  • OAuth2 会在令牌过期前约 5 分钟主动刷新,并在收到 401 时强制刷新 并重试。
  • 对 429 进行指数退避重试(最多 3 次,并遵循 Retry-After)。
  • 自动遍历分页(nextPageToken)。
  • 通过 response-id 标头进行 202 长轮询,最长 10 分钟。
响应整形(保护上下文窗口)

一次未设上限的 list_* 调用可能返回数百 KB 的数据,足以 超出大模型的上下文窗口。每个工具响应都会经过以下两项转换:

  • fields 投影 - 每个 GET 工具都提供可选的 fields: [string] 参数,用于筛选列表中的每一项,仅保留 请求的键(例如 ["uuid", "displayName"])。获取数据后在服务端应用。
  • 字节上限(ESET_MCP_RESPONSE_BYTES_MAX,默认 100 KB)- 如果 负载仍超出预算,则截短最长的列表,同时保留 所有顶层字段(nextPageToken、totalSize……),并附加 _capped 元数据块,其中包含可操作的提示, 说明如何继续获取数据。Agent 可通过分页继续完整访问数据。
便于 Agent 处理的错误

HTTP 错误会映射为易读的提示:403 → 检查 ESET PROTECT Hub 中的 Permission Sets;401 → 服务会自动刷新令牌;429 → 退避;5xx → 稍后重试。

可观测性(日志 + Prometheus)
  • 结构化日志写入 stderr。开发环境默认使用文本格式,生产环境的日志采集器可通过 ESET_MCP_LOG_FORMAT=json 使用 JSON Lines 格式。每次工具调用、令牌刷新、HTTP 重试和连接池淘汰都会生成带有低基数值字段(tool、deployment、status、duration_ms、response_bytes,……)的类型化 event 记录。
  • Prometheus 指标通过可选的 /metrics 端点提供(设置 ESET_MCP_METRICS_ENABLED=true,需要执行 pip install eset-mcp[metrics])。计数器用于统计工具调用、令牌刷新、HTTP 重试和触顶次数;直方图用于统计工具耗时和响应大小;仪表用于统计客户端连接池大小。
  • 绝不会进入日志或指标的内容:密码、Authorization 标头、CF Access 密钥、请求/响应正文、查询字符串、替换后的路径参数(可能泄露 UUID)。日志记录器会通过防御性拒绝列表,在任何格式化器处理前剔除已知敏感键。
  • 故障隔离:遥测数据的生成由 try/except 包裹,因此损坏的指标注册表或格式化器绝不会将成功的工具调用变成 Agent 的错误。如果 /metrics 的数据导出过程中发生异常,则返回 500(而不是 503),工作进程会继续运行。
  • 在生产环境中降低日志输出:设置 ESET_LOG_LEVEL=WARNING 可关闭每次调用的 INFO 事件,同时保留重试/错误信息;设置 ESET_LOG_LEVEL=ERROR 可隐藏除严重故障外的所有信息。设置 ESET_MCP_METRICS_ENABLED=false(默认值)可完全禁用指标。这三个设置彼此独立。

架构一览

最简单的配置:在 .env 中设置凭据,使用一个 MCP 主机和一个 ESET 云区域。适用于个人使用、单个团队,或 Claude Desktop、Claude Code 这类桌面 AI 客户端。

单租户:一个 ESET 帐户、一个部署

对于真正的多租户或企业级部署,可在 ESET-MCP 前端接入凭据管理器。下图展示了使用 IBM mcp-context-forge 作为“凭据管理”层的一种模式;任何功能相当的 MCP 网关(或自建的身份验证代理)都能以同样的方式工作:

多租户:多个客户端、一个 MCP、多个后端

Forge 为每个租户保存密钥,并在每个请求中注入 Authorization: Basic、X-ESET-Region、X-ESET-Server-URL 和 X-ESET-CF-Access-* 标头。ESET-MCP 会将每个请求路由到正确的后端(云区域、本地 PROTECT 控制台,或 Cloudflare Access 后的本地服务),而按租户隔离的 LRU 客户端连接池会确保各租户的 OAuth 令牌完全隔离。这是经过实际验证的模式,并非设想;此处介绍的标头、连接池键和路由规则均已在 tests/test_concurrency.py 和 tests/test_onprem.py 的测试套件中覆盖。


安全性

凭据
  • 在 env 模式下,密码会在启动时读取一次并保存在内存中。
  • 在 basic 模式下,密码仅在请求期间通过网络传输,并且只会在对应租户的客户端处于 LRU 连接池中时保存在内存中。密码绝不会被记录到日志中。
  • 连接池键使用密码的 SHA-256 哈希,而不是密码本身。
  • OAuth 访问令牌/刷新令牌按租户保存;在单个会话中,令牌绝不会跨越租户边界。
身份验证模式与传输方式
模式允许的传输方式凭据来源
envstdio 或 http.env(ESET_USER / ESET_PASSWORD)
basic仅 http每个请求中的 Authorization: Basic 标头

通过明文 HTTP 使用 basic 模式会泄露密码。服务在启动时会强制 basic 模式使用 HTTP 传输方式,但不会强制使用 TLS——这由部署方负责。prod docker-compose 配置 会通过 Caddy + Let's Encrypt 提供前置代理。

在 basic 模式下,缺少或格式错误的 Authorization → 返回带有 WWW-Authenticate: Basic 挑战的 HTTP 401。X-ESET-Region 中的未知区域 → 返回 HTTP 401。

RO / RW 隔离

两个独立层:

  1. 目录隐藏 - 在 RO 模式下,list_tools 会过滤掉所有非 GET 工具。 Agent 看不到写入工具。
  2. 纵深防御门控 - 在发出任何 HTTP 请求前,call_tool 会根据 ESET_MODE 验证工具声明的模式。硬编码客户端、提示词注入尝试和过时的 Agent 快照都会触发 此门控,并收到结构化的 ModeForbiddenError 文本响应(不抛出异常,也不发起网络请求)。

在 RW 模式下,修改类工具带有 destructiveHint: true,因此遵循注释的 MCP 主机 可以要求每次调用前确认。

按租户隔离(basic-auth 模式)
  • 身份验证标头由专用的 ASGI 中间件解析,并存入 ContextVar;它们不会进入请求正文或日志。
  • 每个请求都会解析为一个由 (user, password_hash, region) 确定的 Credentials 实例。
  • 客户端池的 LRU 上限可防止随机凭据滥用导致内存无限增长。
网络暴露面
  • 在开发环境中(docker compose up),MCP 服务会发布 :8765。
  • 在 prod 配置中,MCP 容器不会发布端口—— Caddy 会加入同一个 docker bridge 网络,并代理 HTTPS 流量。主机上仅开放 80(HTTP-01 ACME)和 443(HTTPS)。
  • 除了访问 *.eset.systems(身份验证 + API)外,不会有任何出站流量。
依赖与代码审计
  • Snyk Code:eset_mcp/ 中有 0 个问题。
  • Ruff:检查通过(select = E F W I B UP RUF)。
  • 运行时依赖:mcp、httpx、pydantic、python-dotenv。 运行 HTTP 时还需要 starlette + uvicorn。
按设计不在范围内
  • 不接收 Webhook。
  • 不进行持久化存储;日志写入 stdout。
  • 不在磁盘上缓存 OAuth 令牌。
  • 不将 basic 模式凭据写回磁盘。
负责任披露

请提交私密安全公告,而非公开问题: https://github.com/maciekaz/ESET-MCP/security/advisories/new。


快速开始

最快的方式是使用已发布的 Docker 镜像。无需安装 Python,无需 venv,也无需检出源代码——只需 .env + docker run。该镜像支持多架构(amd64 + arm64), 使用 cosign 签名,附带 SBOM + 构建来源证明,并在每次发布时推送到 GHCR。

cp .env.example .env          # fill in ESET_USER / ESET_PASSWORD / ESET_REGION
docker run --rm -i --env-file .env ghcr.io/maciekaz/eset-mcp:1

版本固定策略:

  • :1 - 最新的 1.x.x(在主版本内自动更新)
  • :1.0 - 最新的 1.0.x(在次版本内自动更新)
  • :1.0.1 - 精确版本(生产环境)
  • :latest - 最新的稳定版本
  • :main / :sha-<short> - 来自主分支的边缘构建(不用于生产环境)
接入 Claude Desktop / Claude Code(stdio)
// claude_desktop_config.json
{
  "mcpServers": {
    "eset": {
      "command": "docker",
      "args": ["run", "--rm", "-i", "--env-file", "/absolute/path/to/.env",
               "ghcr.io/maciekaz/eset-mcp:1"]
    }
  }
}
HTTP 传输(单租户或置于自有代理之后)
docker run -d --name eset-mcp \
  --env-file .env -p 8765:8765 \
  -e ESET_MCP_TRANSPORT=http \
  ghcr.io/maciekaz/eset-mcp:1
# MCP endpoint: http://localhost:8765/mcp
验证镜像(cosign 无密钥模式)
cosign verify \
  --certificate-identity-regexp '^https://github.com/maciekaz/ESET-MCP/' \
  --certificate-oidc-issuer https://token.actions.githubusercontent.com \
  ghcr.io/maciekaz/eset-mcp:1
从源代码开始(贡献者 / 本地开发)
git clone https://github.com/maciekaz/ESET-MCP.git
cd ESET-MCP
cp .env.example .env
python -m venv .venv && source .venv/bin/activate
pip install -e ".[dev]"
eset-mcp
Docker Compose(使用已发布的镜像)
docker compose up -d eset-mcp-http
# MCP endpoint: http://localhost:8765/mcp

默认情况下,compose 文件会拉取 ghcr.io/maciekaz/eset-mcp:1——无需本地 构建,首次启动速度快。编辑 docker-compose.yml 中的 image: 行即可固定 特定版本。

通过 compose 单次运行 stdio:

docker compose --profile stdio run --rm eset-mcp-stdio

要基于源代码进行开发?使用 dev 配置从本地检出版本构建,而不是拉取镜像:

docker compose --profile dev up --build eset-mcp-http-dev

配置

所有设置都保存在 .env 中。必填字段已在 .env.example 中标出。

变量默认值用途
ESET_AUTH_MODEenvenv(单租户)或 basic(多租户)
ESET_USER-API 用户(env 模式下必填)
ESET_PASSWORD-API 密码(env 模式下必填)
ESET_MODERORO(只读目录)或 RW
ESET_REGIONeueu / de / us / ca / jpn
ESET_MCP_TRANSPORTstdiostdio 或 http
ESET_MCP_HTTP_HOST127.0.0.1HTTP 绑定地址
ESET_MCP_HTTP_PORT8765HTTP 端口
ESET_MCP_RESPONSE_BYTES_MAX100000每次调用的响应字节数上限;0 表示禁用
ESET_LOG_LEVELINFODEBUG / INFO / WARNING / ERROR
ESET_MCP_LOG_FORMATtexttext(开发环境,人类可读)或 json(生产环境日志收集器)
ESET_MCP_METRICS_ENABLEDfalse挂载 Prometheus /metrics;需要 eset-mcp[metrics]
ESET_MCP_METRICS_PATH/metrics指标端点的挂载位置
ESET_DEPLOYMENTcloudcloud(ESET Connect)或 onprem(客户自托管的 PROTECT)
ESET_ONPREM_SERVER_URL-本地部署控制台的 https://host[:port](env+onprem 模式下必填)
ESET_ONPREM_VERIFY_SSLtrue对使用自签名证书的本地部署控制台设置为 false
ESET_ONPREM_CF_ACCESS_CLIENT_ID-Cloudflare Access Service Token 客户端 ID(位于 CF 后方的本地部署环境)
ESET_ONPREM_CF_ACCESS_CLIENT_SECRET-Cloudflare Access Service Token 客户端密钥(与上项配套)
ESET_PUBLIC_DOMAIN-Caddy 为其签发 TLS 证书的域名(仅限 prod 配置)
ESET_ACME_EMAIL-Let's Encrypt 用于续期的电子邮件(仅限 prod 配置)

请使用专用 API 用户,而非控制台登录账户。在 ESET PROTECT Hub / ESET Business Account → API users 中创建。


多租户部署(基本身份验证模式)

# .env
ESET_AUTH_MODE=basic
ESET_MCP_TRANSPORT=http
ESET_REGION=eu   # default region; clients can override per request

每个 HTTP 请求都必须携带:

标头必需说明
Authorization是Basic <base64(user:password)>
X-ESET-Region否覆盖默认区域(eu/de/us/ca/jpn)
X-ESET-Server-URL否将此请求路由到本地部署的 PROTECT 控制台(例如 https://protect.example.com:9443)——参见本地部署 ESET PROTECT 支持
X-ESET-CF-Access-Client-Id否Cloudflare Access Service Token 客户端 ID(位于 CF Access 后方的本地部署环境)
X-ESET-CF-Access-Client-Secret否与上项配套;两项都必须发送

Python 客户端示例:

import base64
from mcp import ClientSession
from mcp.client.streamable_http import streamablehttp_client

token = base64.b64encode(b"[email protected]:secret").decode()
headers = {"Authorization": f"Basic {token}", "X-ESET-Region": "us"}

async with streamablehttp_client(
    "https://eset-mcp.example.com/mcp/", headers=headers
) as (r, w, _):
    async with ClientSession(r, w) as session:
        await session.initialize()
        tools = await session.list_tools()

⚠️ 不使用 TLS 的基本身份验证会泄露凭据。 请始终在 HTTPS 后运行 basic 模式。


本地部署的 ESET PROTECT 支持

ESET 以云服务(*.eset.systems 上的 ESET Connect API)和客户可自托管的本地控制台两种形式提供 PROTECT。本地 REST API 位于单台主机上(默认端口为 9443),并使用不同的身份验证端点——通过 JSON 请求体调用 POST /GetTokens,响应采用驼峰命名法;除此之外,其 URL 结构与云 API 相同。ESET-MCP 同时支持两种形式,并且可在同一进程中运行。

服务如何判断是云端还是本地部署
ESET_AUTH_MODE每个请求的部署方式由什么控制
env静态:ESET_DEPLOYMENT(云端),或 ESET_DEPLOYMENT=onprem + ESET_ONPREM_SERVER_URL
basic按请求决定:存在 X-ESET-Server-URL 时,该请求切换到本地部署;不存在时,回退到环境默认值(云端或本地部署)

因此,单个 MCP 服务可以为大多数客户端提供云端服务,同时将特定请求路由到一个或多个本地控制台——路由完全取决于各客户端在 X-ESET-Server-URL 中发送的 URL。

单租户本地部署(env 模式)
# .env
ESET_AUTH_MODE=env
ESET_DEPLOYMENT=onprem
ESET_ONPREM_SERVER_URL=https://protect.company.local:9443
ESET_ONPREM_VERIFY_SSL=true     # set to false only for self-signed certs you trust
[email protected]
ESET_PASSWORD=...
多租户本地部署(basic 身份验证,按请求指定 URL)
# .env
ESET_AUTH_MODE=basic
ESET_MCP_TRANSPORT=http
ESET_DEPLOYMENT=cloud            # default; clients opt into on-prem per-request
# ESET_ONPREM_SERVER_URL is optional - if set it becomes the on-prem default

将客户端请求路由到本地部署:

headers = {
    "Authorization": f"Basic {token}",
    "X-ESET-Server-URL": "https://protect.client-a.local:9443",
}

同一 MCP 服务,不同请求——使用相同的标头,但不包含 X-ESET-Server-URL——将继续连接云端。

本地部署与云端支持的功能

两种部署的工具目录相同(所有 102 个基于 OpenAPI 的工具,以及 4 个组合工具)。调用时,服务会根据凭据使用云端或本地部署对应的路径。

  • 两种部署均支持并已验证:device_*、asset_groups_*、policy_* 和大多数 task_*(Automation)在云端和本地部署上均可正常使用。
  • 仅限云端的模块:incident_*、mobile_*、wap_*、nap_*、quarantine_* 和大多数 vuln_* 对应于独立的 ESET 产品(ESET Inspect、Cloud Office Security、MDM),这些产品不属于本地 PROTECT 安装的一部分。对本地控制台调用这些工具时,ESET 会直接返回 404;服务会将其作为 ESET API error: 404 文本响应传递给 Agent,不做特殊处理。
  • 路径覆盖:少数端点在本地部署上使用不同的 URL,例如 POST /v1/devices/{uuid}:rename 在本地部署上为 :renameDevice。这些规则定义在 eset_mcp/openapi/onprem-path-overrides.json 中,并会在请求目标为本地部署时自动应用。
在本地控制台前使用 Cloudflare Access

当本地 PROTECT 控制台通过 Cloudflare 隧道公开,并由 Cloudflare Access 保护时,MCP 可以使用服务令牌进行身份验证。调用链变为 MCP → Cloudflare Access → ESET 本地部署。

每对令牌包含两个值,可通过 .env 提供:

ESET_ONPREM_CF_ACCESS_CLIENT_ID=abc1234567890.access
ESET_ONPREM_CF_ACCESS_CLIENT_SECRET=<long-secret>

……也可在 basic 身份验证模式下按请求提供(会覆盖环境默认值——适用于每个租户都有自己的隧道和服务令牌的情况):

headers = {
    "Authorization": f"Basic {token}",
    "X-ESET-Server-URL": "https://protect.client-a.local:9443",
    "X-ESET-CF-Access-Client-Id": "abc1234567890.access",
    "X-ESET-CF-Access-Client-Secret": "<long-secret>",
}

MCP 会将输入标头 X-ESET-CF-* 转换为 Cloudflare Access 所需的实际标头 CF-Access-Client-Id / CF-Access-Client-Secret,并将其附加到每次出站调用中——包括 POST /GetTokens 身份验证握手,以及之后的每个 ESET API 请求。

CF 密钥的处理方式与密码相同:绝不记录日志,只有其 SHA-256 哈希值会进入客户端池密钥。轮换密钥会生成新的客户端和新的 ESET 令牌。无论环境默认值如何,云端请求绝不会携带 CF Access 标头——ESET Connect 是公开的 SaaS 服务。

本地部署的安全说明
  • X-ESET-Server-URL 只接受不带路径、查询参数或片段的 https:// URL。末尾的斜杠会被移除。其他格式都会返回 HTTP 400。
  • ESET_ONPREM_VERIFY_SSL=false 会禁用 TLS 证书验证,使连接面临中间人攻击风险。禁用该设置时,服务会在每次构造客户端时记录一条 WARNING。仅在使用无法替换的自签名证书的可信内部网上使用。
  • 本地部署令牌按 (user, password_hash, server_url, cf_secret_hash) 保存在内存中,隔离规则与云令牌相同。令牌池会为它们分别建立键,因此云端和本地部署客户端不会发生冲突;两个客户端访问同一本地部署 URL,但使用不同的 CF 服务令牌时,也会获得单独的令牌池条目。
  • 只发送两个 X-ESET-CF-* 标头中的一个时,会返回 HTTP 400,而不是静默回退到环境变量默认值(这几乎可以确定是操作人员的输入错误)。

生产环境部署(通过 Caddy 使用 HTTPS)

prod docker-compose 配置文件会在 MCP 服务前启动 Caddy。Caddy 首次启动时会获取 Let's Encrypt 证书(HTTP-01 挑战——80 / 443 端口必须可从公共互联网访问),并将 HTTPS 请求代理到内部 MCP 容器。

# .env
ESET_AUTH_MODE=basic
ESET_PUBLIC_DOMAIN=eset-mcp.example.com
[email protected]

docker compose --profile prod up -d
# MCP endpoint: https://eset-mcp.example.com/mcp

你将获得:

  • 443 端口上的 HTTPS,以及自动续期的 Let's Encrypt 证书。
  • 80 端口上的 HTTP-01 挑战。
  • MCP 容器仅绑定到 Docker 桥接网络,不发布端口。
  • gzip / zstd 压缩,以及输出到 stdout 的 JSON 访问日志。

工具、资源和提示词

组合式高级工具
工具返回内容
eset_search(query, kinds?, limit_per_kind?)按子串进行不区分大小写的匹配,搜索设备 / 用户 / 策略 / 组
device_full_profile(deviceUuid)设备记录 + 最近的检测结果 + 漏洞 + 最近的扫描
incident_full_context(incidentUuid)事件 + 评论 + 相关检测结果 + 受影响的设备
latest_detections(hours=24, limit=10, severity_min?)指定时间范围内最新的检测结果,按 occurTime 降序排列;v2 → v1 回退

如果子调用返回 403/404(例如租户缺少某个模块),每个组合式工具都会优雅降级。在适用的情况下,结果中会包含 skipped / truncated 标记。

资源
  • eset://config/mode - RO 或 RW。
  • eset://config/region - 当前区域(在基本身份验证模式下按请求获取)。
  • eset://config/deployment - 此请求使用的 cloud 或 onprem (<server-url>)。
  • eset://config/tools-catalog - 包含全部 106 个工具的 JSON 目录(名称、模式、方法、路径、服务、描述)。
  • eset://docs/rate-limits - 关于 10 req/s 上限的简要提示。
提示词
  • audit_inactive_devices(days=30) - 待离职用户的候选设备。
  • vulnerability_report - 按设备整理的 CVE 报告。
  • incident_triage - 未处理事件 + 相关检测结果。

架构

eset_mcp/
├── __main__.py         # entrypoint - stdio or HTTP, wires resolver + pool
├── server.py           # MCP server (tools / resources / prompts) + telemetry
├── credentials.py      # Credentials + EnvResolver / BasicAuthResolver + ContextVar
├── middleware.py       # ASGI Basic-auth middleware (basic mode only)
├── client_pool.py      # LRU pool of EsetHttpClient keyed by (user, region, ...)
├── http_client.py      # async httpx + 202 polling + 429 retry + 401 refresh
├── auth.py             # CloudTokenManager (OAuth2) + OnPremTokenManager (/GetTokens)
├── regions.py          # cloud region → per-service domains + on-prem URL resolver
├── modes.py            # RO/RW gate
├── errors.py           # HTTP error → agent-friendly text
├── config.py           # .env loading
├── response_shaping.py # fields projection + byte cap
├── composite_tools.py  # hand-written high-level tools
├── tools_loader.py     # generator: tools from OpenAPI specs + on-prem path overrides
├── observability/      # JSON/text structured logging + Prometheus metrics
└── openapi/            # 16 ESET Connect OpenAPI 3.0.1 specs + onprem path overrides

测试

pytest                  # full suite (RO smoke + unit + integration)
pytest -m "not rw"      # RO only (default in CI)
pytest -m rw            # RW (requires an account with RW permissions)

集成测试会访问真实的 ESET 租户——凭据通过同一个 .env 文件提供。CI 工作流: .github/workflows/integration.yml 会在 PR、推送到 main 时以及每天 UTC 时间 03:17 运行。定时任务可以发现服务端与 ESET 发布的 OpenAPI 规范之间的差异。


刷新 OpenAPI 规范

cd eset_mcp/openapi
for name in business-account application-management asset-management automation \
            device-management iam incident-management installer-management \
            mobile-device-management network-access-protection patch-management \
            policy-management quarantine-management user-management \
            vulnerability-management web-access-protection; do
  curl -sO "https://eu.esetconnect.eset.systems/swagger/api/${name}.json"
done

刷新后,tests/test_catalog_vs_openapi.py 会标记任何新增或变更的操作。


许可证

MIT

评论

支持 Markdown

第一次接触 MCP?

从协议是什么,到在客户端里装上第一个服务,这几条回答覆盖了大多数入门问题。

一个开放协议,规定了 AI 应用如何以统一方式连接外部工具与数据源。客户端负责与模型对话,MCP 服务负责提供工具、资源和提示模板,两者通过标准消息通信,同一个服务可以被不同客户端复用。