Skip to main content
Glama
MSPbotsAI

fieldeffect-mcp

by MSPbotsAI
README.md
# fieldeffect-mcp

MCP server for **Field Effect** (Covalence MDR — managed detection &
response). Exposes the Field Effect MDR Portal REST API's organization,
endpoint device, and Active Response reporting endpoints as MCP tools.

> Naming note: MSPbots' own integration is registered as "Field Effect"
> (`subjectCode=FIELDEFFECT`); the vendor's product name is "Covalence" /
> "Field Effect MDR". This MCP covers exactly the 4 GET endpoints MSPbots
> itself has configured — see **Known Gaps** below for why the scope stops
> there.

## Overview

- Stateless HTTP service. No credentials are ever persisted — each request
  supplies its own API key via a header, used only for the lifetime of
  that single request.
- Supports concurrent requests; per-request credential isolation is done via
  Python `contextvars`, not a global/shared client instance.
- Entry points: `POST /mcp` (MCP protocol) and `GET /health` (health check).
- Default port: `8080` (configurable via `MCP_HTTP_PORT`).

## Authentication

Field Effect authenticates with a static **API key**, created in the API
section of the Field Effect MDR Portal. MSPbots' own integration convention
sends this key as an `Authorization: Bearer <api-key>` header, and this
server forwards it exactly that way.

### HEADER 授权参数说明

| Header | 类型 | 是否必填 | 默认值 | 枚举值 | 字段描述 | Example |
|---|---|---|---|---|---|---|
| `X-FieldEffect-Api-Key` | string | 是 | 无 | 无 | Field Effect MDR Portal API Key,转发为上游 `Authorization: Bearer <key>` 请求头 | `a1b2c3d4e5f6...` |

Missing the header returns `401`:
```json
{
  "error": "Missing credentials",
  "message": "This server requires the X-FieldEffect-Api-Key header",
  "required_headers": ["X-FieldEffect-Api-Key"],
  "optional_headers": []
}
```

## Environment Variables

| Variable | 类型 | 是否必填 | 默认值 | 说明 |
|---|---|---|---|---|
| `MCP_HTTP_PORT` | int | 否 | `8080` | HTTP 监听端口 |
| `MCP_HTTP_HOST` | string | 否 | `0.0.0.0` | HTTP 监听地址 |
| `FIELDEFFECT_BASE_URL` | string | 否 | `https://services.fieldeffect.net/v1` | Field Effect API 基础 URL |

## MCP Endpoint

- `POST /mcp` — MCP protocol (streamable HTTP transport)
- `GET /health` — health check, returns `{"status": "ok"}` (pure local probe, does not depend on the Field Effect API)

## Tool List

All 4 tools are plain `GET` calls, matching exactly how MSPbots itself
calls this integration today. All are read-only (`readOnlyHint=True`).

| Tool | 功能 | 参数 |
|---|---|---|
| `fieldeffect_get_organizations` | 列出该 API Key 可见的所有组织(客户) | 无 |
| `fieldeffect_get_endpoint_devices` | 列出所有端点设备(含风险等级/分数),分页返回 | `page`(可选), `per_page`(可选,默认 50,硬上限 200,见 Known Gaps) |
| `fieldeffect_get_endpoint_device_antivirus_details` | 获取指定端点设备的杀毒软件状态详情 | `device_id`(必填) |
| `fieldeffect_get_active_response_actions` | 列出 Active Response 响应事件(如设备隔离),分页返回 | `page`(可选), `per_page`(可选,默认 50,硬上限 200,见 Known Gaps) |

工具返回值统一为紧凑 JSON 字符串(`ensure_ascii=False`,无 `indent`),单次返回超过 20,000
字符时会自动截断最大的列表字段并附带 `truncated`/`original_count` 标记。出错时返回结构化
错误信封 `{"error": {"code", "message", "retryable"}}`(`code` 取自固定词汇表:
`not_configured` / `unauthorized` / `not_found` / `invalid_argument` / `rate_limited` /
`upstream_error`),不抛异常。

## 测试示例

```bash
# Health check
curl -s http://localhost:8080/health

# Call a tool via the MCP protocol (streamable HTTP) — requires an
# initialize handshake first per the MCP spec; abbreviated example below
# shows the tool-call request body only:
curl -s -X POST http://localhost:8080/mcp \
  -H "X-FieldEffect-Api-Key: <your-fieldeffect-api-key>" \
  -H "Content-Type: application/json" \
  -H "Accept: application/json, text/event-stream" \
  -H "mcp-session-id: <session-id-from-initialize>" \
  -d '{
    "jsonrpc": "2.0",
    "id": 1,
    "method": "tools/call",
    "params": {
      "name": "fieldeffect_get_organizations",
      "arguments": {}
    }
  }'
```

**Live-verified** (2026-07-29) against a real MDR Portal API key: all 4
tools were called end-to-end through this running server —
`fieldeffect_get_organizations` returned 41 real organizations,
`fieldeffect_get_endpoint_devices` returned a paginated list (1719 devices
total across 18 pages), `fieldeffect_get_endpoint_device_antivirus_details`
returned successfully (204, no AV data for that particular device — not an
error), and `fieldeffect_get_active_response_actions` returned 200.

## API Reference

- Overview (public, no login required): https://support.fieldeffect.com/en/support/solutions/articles/16000206018-field-effect-apis-overview
- The full interactive Swagger/OpenAPI documentation is only accessible
  from inside the MDR Portal's own Support section — it requires being
  logged into a Field Effect MDR Portal account, not just having an API
  key. No public Swagger/OpenAPI spec was found, and probing common
  spec paths (`/swagger.json`, `/v1/openapi.json`, `/v1/api-docs`, etc.)
  directly against `services.fieldeffect.net` all returned `404`.

## Known Gaps

- **Scope is exactly MSPbots' 4 configured endpoints, not the vendor's
  full API surface** — same situation as `bvoip-mcp`/`contactscience-mcp`/
  `dropsuite-mcp` earlier in this program: the vendor's fuller API
  reference requires a portal login this session doesn't have, so there
  was no larger accessible spec to weigh a broader scope against.
- **`page`/`per_page` parameters on `get_endpoint_devices` and
  `get_active_response_actions` are inferred, not confirmed** — the vendor
  doesn't publish these endpoints' accepted query parameters anywhere
  accessible. They were added because the live response shape
  (`{"items": [...], "page": 1, "per_page": 100, "total": ..., "pages": ...,
  "has_next": ..., "has_prev": ...}`) strongly suggests a standard
  page/per_page pagination scheme, but this has not been verified by
  actually passing those parameters and confirming a changed result.
  Because the vendor's own real per-page maximum is unconfirmed, this
  server does not defer to it and instead applies the Vendor MCP SOP's own
  fallback ceiling: `per_page` defaults to 50 when omitted and is clamped
  to 200 server-side regardless of what's requested.
- Response field shapes are whatever the live API returns — not
  independently verified against a schema, since none is publicly
  available.