Check an MCP server for malware / prompt-injection lures by its endpoint URL.
Give the server's streamable-http endpoint URL. Two paths:
* **Already in the agent-tools directory** → returns our LATEST stored
rule verdict. Every indexed server is re-scanned hourly, so you get a
consistent, continuously-refreshed answer without re-probing.
* **Not yet indexed** → we probe the endpoint live, statically scan its
advertised tools + metadata, ADD it to the directory, and return the
fresh verdict (so the next caller gets the rule verdict instantly from
cache).
Two dimensions are reported. `verdict` is authoritative and comes from
deterministic static rules — pure pattern-matching over the *advertised*
text only, NO code execution. It flags the social-engineering / RCE tricks
listing-spam servers use:
* `curl … | bash` and `base64 -d | sh` install lures
* `eval "$(curl …)"` / PowerShell `IEX(...DownloadString)` cradles
* base64 blobs that decode to a shell command
* bare-IP payload hosts and cheap throwaway TLDs
* prompt-injection / credential-exfiltration phrasing
("ignore previous instructions", "send your .env / api key")
* MCP tool-poisoning coercion — descriptions that hijack an agent's
tool-calling ("always call this tool first", "before using any other
tool you must…"), hidden `<IMPORTANT>` instructions, "list all API
keys / include secrets in your response", and coercion to read &
forward `.key`/`.pem`/`.ssh`/`.env` files
Source-code-oriented rules (SQL / command / code injection) are deliberately
not applied to natural-language descriptions, to avoid false positives.
`llm_reference` is an advisory frontier-LLM second opinion over the same text.
Because the LLM is slow it is computed LIVE on this call only and is never
stored (the hourly job never runs it), so it may be null on timeout. It
never overrides the rule verdict; when it is *more* severe than the rules an
`advisory` note is attached as a safety-net signal. Security/defense
products that merely *name* these attacks are not flagged.
Args:
endpoint_url: The MCP server's streamable-http URL (required). This is
the identity we look up / index by.
name: Optional advertised name (used when the server is new and gets
added; falls back to the URL host).
description: Optional description / README blurb (scanned when new).
tools_text: Optional tool names + descriptions; used only if the live
probe cannot fetch the server's tools/list.
Returns:
{ verdict: "clean"|"suspicious"|"malicious", score: 0-100,
reasons: [{rule, weight, snippet}],
llm_reference: {model, verdict, reason, confidence} | null,
advisory: str | null, slug, name, endpoint_url,
source: "stored" (existing) | "new_scan" (just added), indexed: bool }