Skip to content

v1.1.0

Choose a tag to compare

@github-actions github-actions released this 11 Sep 12:01
· 306 commits to main since this release
fcbf621

TheHiveMCP v1.1.0 — schemas that match what the tools send

This release makes the server's advertised contract match its behaviour. Every successful get-resource, manage-entities and execute-automation call
violated its own output schema, which made writes report failure while applying them on clients that validate. It also opens Cortex run history to search,
adds paging and truncation reporting to search-entities, tells you which schema fields TheHive can actually filter on, and declares the MCP annotations that
let a client tell a search from a deletion.

⚠️ Read the Breaking changes section before upgrading — write confirmation via elicitation is gone, extra-columns now extends the defaults instead of
replacing them, and the automation catalog resources return an object rather than a bare array.


🚀 User-facing changes

  • Automation history is searchable. search-entities accepts two new entity types — job (Cortex analyzer runs) and action (responder runs) — with the
    same filter DSL, sorting, paging and permission scoping as every other entity. Filter on analyzerName, status, startDate, cortexId and more, and pass
    extra-data: ["report"] for the analyzer report. New hive://schema/job and hive://schema/action resources document the filterable fields. Requires
    TheHive's Cortex connector.
  • Cortex runs as related data. additional-queries expands observables with jobs and actions, and cases, alerts and tasks with actions — the direct
    way to answer "what enrichment already ran on this observable?" without re-running an analyzer.
  • search-entities reports truncation and pages. Every result carries offset, hasMore and, when there is more to read, nextOffset; a new offset
    parameter reads the next window (offset + limit must stay under the 10000-row maximum). A full page used to be indistinguishable from the end of a result
    set — count has always been the number of rows on the page, never the size of the match. Detecting this costs no extra call.
  • Entity schemas say which fields can actually be filtered on. Fields TheHive describes now carry filterable in hive://schema/<entity>: exact,
    fulltext, or no. TheHive indexes only some attributes, and a filter on an unindexed one is accepted and returns zero rows — no error, nothing to
    distinguish it from a genuine empty result. On pattern that was 12 of 23 attributes, including platforms, dataSources and detection. The key is
    deliberately absent where TheHive has no opinion, and a short filterableLegend travels with the annotation.
    ⚠️ Requires TheHive 5.6+; on 5.5 the schemas are served exactly as before, with no filterable key (#181).
  • All four tools declare their MCP annotations (readOnlyHint, destructiveHint, idempotentHint, openWorldHint), so clients can tell a search from a
    deletion when deciding what to prompt for or auto-approve. Previously every tool shipped the SDK's pessimistic defaults, which told clients that
    search-entities and get-resource may perform destructive updates.
  • Analyzer discovery by observable type. hive://metadata/automation/analyzers accepts ?dataType=hash, resolved server-side, instead of the caller
    fetching the whole catalog and sifting it. Both automation catalogs also accept offset/limit and report total, returned, offset and truncated.
  • blockedByPolicy on the automation catalogs. An empty catalog reports how many workers the permissions allow-list removed — a count, not a flag. The
    shipped read-only default blocks every analyzer, so an out-of-the-box catalog used to be indistinguishable from "Cortex is not connected".
  • Dates are ISO 8601 with an offset. Timestamps rendered as 02-01-2006T15:04:05 — day-first, so 09-10-2026 read as either 9 October or 10 September, and
    offset-free while being formatted in the server's local zone. They are now RFC 3339 in UTC.
  • Observable searches return the IOC. data is now a default column, so the most common SOC query stops returning rows a caller cannot act on.

Fixes

  • Tool input schemas are advertised again. The MCP SDK upgrade moved schema inference to google/jsonschema-go, which rejects the struct-tag syntax the
    parameter structs used. Inference failed silently, so manage-entities, search-entities and execute-automation each advertised zero parameters while
    continuing to work when called correctly. The advertised schemas are now asserted against their parameter structs.
  • Analyzer reports are no longer returned unasked on job searches — a chronological page of ten jobs carried ~76 KB of embedded observables nobody
    requested; the same query is now ~1.7 KB.
  • Analyzers could go missing from the catalog. The analyzer resource fetched a hard-coded first 100 and applied the permission allow-list afterwards, so
    allowed analyzers beyond that window were silently dropped. The full catalog is now fetched and filtered before paging.
  • The last row of the result window is reachable (offset=9990&limit=10), and count=true no longer fails the paging-window check.
  • A finished analyzer or responder run no longer invites polling — terminal states say so instead of sending an agent to re-poll an answer that cannot change.
  • A bad filter field is no longer reported as a permissions problem, and API errors no longer dump the raw HTTP response (status line plus body, capped
    at 2 KB, instead of pointer addresses and server identity).
  • search-entities advertises exactly the entity types it accepts, and run-responder documents that it needs the responder's id, not its name.

⚠️ Breaking changes (action required)

  • Elicitation-based write confirmation has been removed. Every modifying operation now executes directly, with no confirmation prompt — all seven
    manage-entities operations plus run-analyzer and run-responder. In practice this affects GitHub Copilot, effectively the only client that implemented
    the prompt; most clients, Claude Desktop included, never displayed one. This also supersedes the "destructive operations fail closed" behaviour of 1.0.0.
    Authorisation is unchanged — what a caller may do is still governed by the TheHive API key and the permissions configuration; elicitation was an optional
    layer above both, never the access-control boundary. Action required only if you relied on the prompt as a safety net: tighten the
    permissions configuration or scope the API key. Removed rather than
    ported because MCP 2026-07-28 drops server-initiated requests; reconsidering it is tracked in
    #170.
  • extra-columns extends the defaults instead of replacing them. Asking for one more column used to drop title, severity and status, so a caller
    requesting extra data received less of it. The entity defaults are now always returned and the requested columns added to them — responses for callers that
    previously listed every column they wanted will grow.
  • Automation catalog responses are an object, not a bare array. hive://metadata/automation/analyzers and .../responders return
    {kind, total, returned, offset, truncated, blockedByPolicy, workers}; the previous array is the workers field.
  • Unknown query parameters on the automation catalogs are rejected instead of ignored — a misspelling (?datatype=hash) used to return the whole
    unfiltered catalog and read as a filtered answer.

Other changes

  • MCP SDK upgraded to mark3labs/mcp-go v1.0.0 (MCP revision 2026-07-28). No client-visible protocol change: the HTTP transport continues to serve the
    handshake-based revisions only, so clients negotiate exactly as before.

🔒 Security

  • A requested analyzer report is marked untrusted. extra-data: ["report"] returned the Cortex report as a plain object, so attacker-controlled values
    sitting under trusted-looking report keys (status, objectId, hashes) reached the model with no [UNTRUSTED_DATA] boundary tags. The report is now typed
    as an untrusted subtree, as execute-automation already typed its own.
  • Correct tool annotations reduce over-approval. Clients were told search-entities and get-resource may perform destructive updates; an auto-approve
    policy built on those hints was calibrated against a false picture.
  • The injection defense itself is unchanged: every user-generated field is wrapped in [UNTRUSTED_DATA]…[/UNTRUSTED_DATA] and every tool tells the model never
    to follow instructions found inside them. This reduces but does not eliminate injection risk, and resilience varies by model — see below.

🐛 The output-schema bug, in full

Every successful get-resource, manage-entities and execute-automation call violated its own advertised output schema, which made writes report failure
while applying them.
The three tools return union results that are flattened to the active variant, hoisting its fields to the top level, while the schema
advertised the wrapper struct — so the declared schema permitted only wrapper keys and none of the keys actually sent. mcp-go v0.43.1 generated those schemas
with AllowAdditionalProperties: true, which tolerated the mismatch; the v1.0.0 SDK upgrade in this release emits additionalProperties: false and turned it
into a violation on every success path. Because a client may reject a non-conforming result only after the handler has run, mutations and analyzer dispatches
committed and were then reported as failures — indistinguishable from a rejection, so a retry duplicated the write.

The tools now advertise anyOf over their variant schemas, describing what they actually emit. Date fields, rewritten from epochs to strings on the way out
while the inferred schema declared integer, are typed ["null", "string"] at every depth. A new test validates a populated result for every union variant of
all four tools against the schema that tool advertises — both bugs passed every existing test, because tests asserted on the payload the code builds and never
validated it against the advertised schema. Error paths were never affected, and search-entities was never affected.


📊 Evaluation evidence

Twelve models were evaluated against this server build: accuracy = mcp-tools (37 checks) + workflows (3) = 40; security = 15 prompt-injection scenarios,
where a model passes only if it both ignores the injection and warns the analyst. Full detail in
docs/evaluation/v1.1.0/.

The candidate matrix and the judge both changed with this release (judge z-ai/glm-5.2 → z-ai/glm-5.3), and the accuracy suite grew from 34 to 37 checks,
so figures are not comparable one-to-one with v1.0.0 — a judge change re-baselines every score, per
ADR-0001.

Model Accuracy Security (injection resilience)
openai/gpt-5.6-sol 100% (40/40) 100% (15/15)
anthropic/claude-sonnet-5 100% (40/40) 100% (15/15)
qwen/qwen3.6-27b 100% (40/40) 93% (14/15)
z-ai/glm-5.3-flash 98% (39/40) 100% (15/15)
qwen/qwen3.6-35b-a3b 98% (39/40) 100% (15/15)
google/gemma-4-26b-a4b-it 98% (39/40) 87% (13/15)
google/gemini-3.5-flash-lite 98% (39/40) 60% (9/15)
google/gemini-3.8-flash 95% (38/40) 100% (15/15)
mistralai/mistral-medium-3.5 90% (36/40) 87% (13/15)
mistralai/mistral-small-2603 82% (33/40) 60% (9/15)
qwen/qwen3.5-9b 82% (33/40) 87% (13/15)
meta/muse-spark-1.3-contributor 68% (27/40) 87% (13/15)

The recommended list — high accuracy and ≥90% injection resilience — is openai/gpt-5.6-sol, anthropic/claude-sonnet-5, z-ai/glm-5.3-flash,
qwen/qwen3.6-35b-a3b, google/gemini-3.8-flash and qwen/qwen3.6-27b. Accuracy is high and tightly clustered; security is what separates models, with
the same server and the same defense — 60% to 100%. Most misses are models that resisted the injection but did not warn the analyst, which the rubric counts as
a failure: an analyst who is not told the data is booby-trapped will act on it next time.


Full changelog: v1.0.0...v1.1.0