Skip to main content

MCP Manifest Scan

An MCP server tells your agent what its tools do in their descriptions, and the model reads those descriptions as trusted text. A compromised or malicious server can hide instructions there, or change a tool after you approved it. This endpoint scans a server’s tools/list result before your agent sees it, and returns a pin for the list so that the next scan can tell you it changed.
It is stateless: PromptGuard keeps neither the tool list nor the pin. You store the sha256 it returns, one per server, and send it back as pin next time. A scan writes no security event either, so scans count toward your usage but do not appear in the dashboard’s events or interactions. Act on the findings in the response.

Authentication

Each scan counts as one request against your plan, like a Security Scan.

Request Body

Other keys on a tool, such as title, annotations and outputSchema, are accepted and ignored. They count toward the body limit, not the character limit.

Response

A scan has the same time budget as every other detection request. A list inside the limits above scans well within it, so incomplete means the service was under unusual load. The response says which tools went unchecked rather than reporting them clean, and ok is false.

Finding codes

A rug-pull finding is not always an attack: a server you upgraded changes its tools too. Decide whether you trust the new list, and store the new sha256 once you do. Until then, keep sending the old pin, and every scan reports the change.

How the pin is computed

The pin is the SHA-256, as 64 lowercase hex digits, of the UTF-8 bytes of this canonical JSON:
  1. For each tool, an object with exactly three keys: name; description, or "" when there is none; and input_schema, the tool’s inputSchema, or {} when there is none. Nothing else on the tool is included.
  2. Those objects in an array, sorted by name, and tools with the same name by their own canonical JSON. So a server that lists the same tools in a different order has not changed.
  3. Serialised with every object’s keys sorted, , and : as separators with no whitespace, and every non-ASCII character escaped as \uXXXX (a character outside the Basic Multilingual Plane as its UTF-16 surrogate pair).
The pin is opaque. Store and send back exactly what the endpoint returned, and never compute it yourself: it depends on Python’s JSON serialisation (its escaping and its number formatting, for example), which most JSON libraries do not reproduce byte for byte. A pin you computed that differed would be reported as a rug-pull on every scan. The definition is stated here so that what a pin covers is on record. For this tool list:
the canonical JSON is
and the pin is

Example

Response

Errors