MCP Server
Five read-only MCP tools at https://zero.ethiack.com/mcp to check installed packages against Zero entries, search new CVEs by check, exploit and KEV status, and read one entry's full record.
Endpoint: https://zero.ethiack.com/mcp, streamable HTTP.
| Ask your agent | Call it makes |
|---|---|
| Which of my installed packages have Zero entries, and what do I upgrade to? | check_packages with {"packages": [{"name": "simple-git", "version": "3.27.0", "ecosystem": "npm"}]} |
| KEV-listed vulnerabilities from the last 30 days that Ethiack can detect | search_feed with {"kev": true, "check": true, "since_days": 30} |
| How long before cve.org published CVE-2026-109954 did Ethiack have a check? | get_entry with {"handle": "CVE-2026-109954"}, then signals.check.days |
| What is Zero analysing right now? | live_runs |
| What are the median leads over cve.org, and is the feed current? | feed_summary |
The same call without a client:
curl -s https://zero.ethiack.com/mcp \
-H 'Content-Type: application/json' \
-H 'Accept: application/json, text/event-stream' \
-d '{"jsonrpc":"2.0","id":1,"method":"tools/call","params":{"name":"get_entry","arguments":{"handle":"CVE-2026-109954"}}}' \
| jq '.result.structuredContent.signals.check'{
"at": "2026-10-01T02:18:54.002123+00:00",
"days": -12.46417835505787,
"is_lower_bound": false,
"measured_at": "2026-10-13T13:27:19.012000+00:00",
"url": null
}Endpoint
| Property | Value |
|---|---|
| Transport | JSON responses. Stateless: no session id, and tools/call works without initialize. |
| Annotations | Every tool: readOnlyHint: true, destructiveHint: false, idempotentHint: true, openWorldHint: false. |
| Results | One JSON object per call, in result.structuredContent and as text in result.content[0].text. |
| Errors | Invalid arguments return isError: true with the validation message as text. |
| Request size | Bodies over 64 KB return HTTP 413. |
| Auth, license | Access |
Connect
Claude
Customize > Connectors > + Add > Add custom connector. Enter a name and https://zero.ethiack.com/mcp, select Continue, choose No sign in under Authentication, then Add.
On Team and Enterprise plans an Owner adds it under Organization settings > Connectors (Add > Custom > Web), and members connect it from Customize > Connectors.
Claude Code
claude mcp add --transport http ethiack-zero https://zero.ethiack.com/mcpAdd --scope user to make it available in every project.
ChatGPT
chatgpt.com/plugins > + > Add custom MCP server. Enter a name and description, set the connection to the public endpoint https://zero.ethiack.com/mcp with no authentication, accept the risk warning, then Create as a plugin.
Account and workspace policies decide whether custom MCP servers are allowed.
Cursor
{
"mcpServers": {
"ethiack-zero": {
"url": "https://zero.ethiack.com/mcp"
}
}
}VS Code
{
"servers": {
"ethiack-zero": {
"type": "http",
"url": "https://zero.ethiack.com/mcp"
}
}
}For every workspace, add the same entry to the user mcp.json (MCP: Open User Configuration).
Tools
check_packages
Feed entries naming each installed package, with affected ranges, fixed versions and mitigation.
| Parameter | Type | Default | Values and limits |
|---|---|---|---|
packages | array of objects | required | Up to 200; the rest are dropped and truncated is true. Keys name, version and ecosystem, all strings. Other keys are ignored, values are cut at 200 characters. |
namematches an affected package (simple-git,org.jline:jline-builtins), or a product alone or with its vendor (RouterOS,Microsoft SharePoint). Exact, case-insensitive.ecosystemnarrows the match, and entries with no ecosystem still match. Common spellings are one ecosystem:PyPI,pipandpython;npmandnode;goandgolang.- With a PyPI
ecosystem,-,_and.are equivalent in names:python_josematchespython-jose. versionis echoed back, not compared. Compare it withaffected_rangesyourself.- No entries means the feed names none, not that the package is unaffected: the feed does not cover every vulnerability (methodology).
Returns checked, with_entries, truncated and results: one item per package that has entries, with the input as package and up to 10 entries, newest first, in the compact shape.
Sent simple-git (npm) and requests (PyPI); requests has no entries, so it is not in results:
{
"checked": 2,
"with_entries": 1,
"truncated": false,
"results": [
{
"package": { "name": "simple-git", "version": "3.27.0", "ecosystem": "npm" },
"entries": [
{
"display_id": "CVE-2026-102826",
"etk_id": "ETK-2026-698",
"title": "Command injection through clone options in simple-git",
"status": "published",
"anchor_state": "anchored",
"details_pending": false,
"check": true,
"check_confidence_basis": "assessed",
"exploit": false,
"cvss_score": 8.1,
"affected": [
{
"package_name": "simple-git",
"ecosystem": "npm",
"purl": "pkg:npm/simple-git",
"affected_ranges": ["<= 3.36.0"],
"affected_notes": [],
"fixed_versions": ["4.0.0"]
}
],
"mitigation": "Upgrade the npm simple-git package to version 4.0.0 or later. ...",
"days_from_cve_publication": {
"trigger_signal": { "days": 0.0, "is_lower_bound": false },
"check": { "days": 6.247449028229167, "is_lower_bound": false }
},
"url": "https://zero.ethiack.com/e/CVE-2026-102826"
}
]
}
]
}search_feed
The feed, newest first. Each filter is the List Entries parameter in the last column.
| Parameter | Type | Default | Feed API equivalent |
|---|---|---|---|
query | string | none | q |
status | string | none | status. Any other value is an argument error. |
check | boolean | none | check |
exploit | boolean | none | exploit |
kev | boolean | none | kev |
public_poc | boolean | none | poc |
awaiting_cve | boolean | none | anchor_state: true is awaiting_cve, false is anchored. |
vendor | string | none | vendor |
product | string | none | product |
since_days | integer | none | since_days. 0 or less is ignored. |
limit | integer | 20 | Clamped to 1 to 50. |
page | integer | 1 | Below 1 reads as 1. Offset-based: to walk the whole feed, use cursor on List Entries. |
Returns total, page, pages and entries, in the compact shape.
get_entry
| Parameter | Type | Default | Values and limits |
|---|---|---|---|
handle | string | required | Any handle Get Entry takes. Cut at 64 characters. |
Returns the body of GET /api/v1/feed/{handle}, plus url as in the compact shape.
An unknown handle returns {"error": "not_found", "handle": "..."}, with isError: false.
live_runs
No parameters. Returns the body of GET /api/v1/live.
feed_summary
No parameters. Returns summary, the object of the same name in GET /api/v1/feed, and status, the GET /status body without checked_at.
{
"summary": {
"entries": 1859,
"feed_rows": 1870,
"anchored": 1704,
"awaiting_cve": 155,
"in_pipeline": 4,
"with_check": 809,
"with_exploit": 28,
"deterministic": 760,
"contextual": 1096,
"no_prior_signal": 1567,
"median_check_delta_days": 0.22095655906828704,
"median_exploit_delta_days": 0.15951611630787038,
"median_first_artifact_days": 0.22095655906828704,
"median_sample_size": 1704,
"median_minutes_to_start": 175.75760651666667,
"median_minutes_to_artifact": 396.36639615,
"watermark": "2026-10-18T01:27:28.116351+00:00"
},
"status": { "status": "ok", "reasons": [] }
}Compact entry
What check_packages and search_feed return per entry.
These keys carry the same values as in the entry: display_id, etk_id, cve_id, ghsa_id, euvd_id, title, status, details_pending, anchor_state, check, check_confidence_basis, exploit, cvss_score, vendor, product, affected, mitigation.
| Field | Meaning |
|---|---|
days_from_cve_publication | In place of signals: each signal present, with only days and is_lower_bound. |
url | https://zero.ethiack.com/e/<display_id> |
Overview
New vulnerabilities as Ethiack detects them, whether Ethiack validated exploitation with a check or an exploit, and when, relative to CVE publication on cve.org and KEV listing.
Feed API
Public, read-only JSON for every Ethiack Zero entry, its check and exploit timings against CVE publication and KEV, and the runs in progress.