Canonical URL
https://trusteed.xyz/.well-known/mcp-tools-manifest.json
- Cache-Control:
- public, max-age=3600, s-maxage=3600
- Content-Type:
- application/json
Trusteed supports signing the public MCP tools manifest with Ed25519 (compact JWS, detached payload). Each tool carries separate SHA-256 hashes of its description and inputSchema, letting agents and operators detect any silent change before executing a tool.
Spec capability — coming soon
The manifest is available at a stable canonical URL with HTTP headers that expose the signature and hash directly, without needing to parse the JSON body for quick verification.
https://trusteed.xyz/.well-known/mcp-tools-manifest.json
The signature follows the JWS Compact Serialization profile (RFC 7515) with detached payload: the manifest JSON is not included inside the JWS token, it is only signed as raw bytes.
EdDSA (Ed25519) — 255-bit key, 64-byte signature, resistant to side-channel attacks.
alg: "EdDSA", crv: "Ed25519"
Published at the standard JWKS endpoint. The kid field in the JWS header identifies which key to use.
https://trusteed.xyz/.well-known/jwks.json
Grace period: the previous key remains in the JWKS after the new key is introduced. Both are valid during that window to allow seamless transitions.
In addition to the global manifest signature, each tool entry includes two independent SHA-256 hashes covering the tool's description and inputSchema.
description_sha256SHA-256 hash of the tool description. Allows detecting changes to the agent-visible text without needing to compare the full manifest.
input_schema_sha256SHA-256 hash of the tool inputSchema. Schema changes (new parameters, types, required fields) always alter this hash, even if the description stays the same.
{
"name": "search_products",
"description": "Search for products in a merchant store...",
"hashes": {
"description_sha256": "a3f2...c1d9",
"input_schema_sha256": "7b04...e82a"
}
}"Tool poisoning" (MCP-08 in the MCP-38 taxonomy) consists of silently modifying a tool's description or inputSchema to induce the agent to escalate privileges, exfiltrate data, or execute unauthorized actions. Manifest signing enables three protection levels:
The Ed25519 JWS signature over the full manifest guarantees that no content has been modified in transit or on the server. A signature failure invalidates the entire manifest.
A client can store the hashes of the tools it uses and compare on each invocation. If description_sha256 or input_schema_sha256 change without a version bump, the client can reject the call.
Separate hashes for description and inputSchema enable distinct policies: an operator can tolerate cosmetic changes to the description while rejecting any schema mutation.
The version field follows the YYYY-MM-DD.N format, where N is an ordinal counter incremented if more than one manifest is issued on the same day. The superseded_at field indicates when an older version stops being valid, enabling graceful transitions.
{
"version": "2026-05-02.1",
"previous_version": "2026-04-15.1",
"superseded_at": "2026-05-09T00:00:00Z",
"tools": [ ... ]
}The following snippet downloads the manifest and JWKS, verifies the JWS signature, and checks the hashes of a specific tool. Requires the jose package (v5+) and Node.js 18+.
import { createHash } from 'node:crypto';
import { compactVerify, createLocalJWKSet } from 'jose';
const MANIFEST_URL = 'https://trusteed.xyz/.well-known/mcp-tools-manifest.json';
const JWKS_URL = 'https://trusteed.xyz/.well-known/jwks.json';
async function fetchJson(url) {
const res = await fetch(url);
if (!res.ok) throw new Error(`HTTP ${res.status} fetching ${url}`);
return res.json();
}
// 1. Fetch manifest and JWKS
const manifest = await fetchJson(MANIFEST_URL);
const jwks = await fetchJson(JWKS_URL);
const keySet = createLocalJWKSet(jwks);
// 2. Reconstruct compact JWS with the manifest body as detached payload
// The server provides the signature via X-JWS-Signature header (<kid>:<jws>)
// or the manifest body includes a top-level "_jws" field as fallback.
const rawJws = manifest._jws; // e.g. "eyJhbGciOiJFZERTQSIsImtpZCI6Ii4uLiJ9..eyJ..."
if (!rawJws) throw new Error('No _jws field found in manifest');
// 3. Verify Ed25519 signature — jose rejects tampered payloads automatically
const manifestBytes = Buffer.from(JSON.stringify(manifest, null, 0));
const { protectedHeader } = await compactVerify(rawJws, keySet, {
algorithms: ['EdDSA'],
});
// => Signature OK — kid: <opaque_key_id>
// => Manifest version: 2026-05-02.1
// 4. Verify per-tool hashes for a specific tool
const toolName = 'search_products';
const tool = manifest.tools?.find(t => t.name === toolName);
if (!tool) throw new Error(`Tool "${toolName}" not found in manifest`);
const descHash = createHash('sha256').update(tool.description, 'utf8').digest('hex');
const schemaHash = createHash('sha256')
.update(JSON.stringify(tool.inputSchema), 'utf8')
.digest('hex');
if (descHash !== tool.hashes.description_sha256) {
throw new Error('description_sha256 mismatch — possible tool poisoning!');
}
if (schemaHash !== tool.hashes.input_schema_sha256) {
throw new Error('input_schema_sha256 mismatch — possible schema mutation!');
}
// => Tool "search_products" hashes verified OK
// => description_sha256 : a1b2c3...
// => input_schema_sha256: d4e5f6...For a minimal curl + signature verification script, see also the parent page: MCP Security.
The Ed25519 public keys used to sign the manifest are published at the standard RFC 7517 JWKS endpoint. Use the use and kid values from the JWS header to select the correct key.
{
"keys": [
{
"kty": "OKP",
"crv": "Ed25519",
"use": "sig",
"alg": "EdDSA",
"kid": "<opaque_key_id>",
"x": "<base64url_encoded_public_key>"
}
]
}https://trusteed.xyz/.well-known/jwks.json — 3600s cache. Updated automatically during key rotation.