MCP Trust Attestation Integration Guide

@agentlair/mcp-trust-attestation mounts AgentLair’s BHC-S behavioral trust descriptor and per-subject attestation endpoint on any HTTP-transport MCP server. Three imports, two app.use() calls, done. The SDK handles descriptor serving, per-agent attestation proxying, JWKS caching, and the well-known route — so your server speaks the trust protocol without writing any of that machinery yourself.

Why this matters · npm: @agentlair/mcp-trust-attestation


Install

npm install @agentlair/mcp-trust-attestation

No account required to install. The package is zero-config for the descriptor. The behavioral attestation endpoint proxies to AgentLair’s trust engine, which requires a free account only if you want to issue attestations, not to serve the descriptor.


Your server ID

Every server needs a serverId. The supported forms are:

FormExample
url_sha256:<hex>SHA-256 of your server’s canonical URL, hex-encoded
agentlair_alias:<alias>Your AgentLair-registered server alias
did_key:<did>A DID key identifier

The simplest path: compute the SHA-256 of your deployment URL and use url_sha256:<hex>.


Pattern A: stdio MCP server (with sidecar HTTP for attestation)

stdio transport carries MCP tool calls; attestation routes need HTTP. Run both in the same process — the MCP server connects over stdio, the attestation surface listens on a separate port.

import { Hono } from 'hono';
import { serve } from '@hono/node-server';
import { createAttestationMiddleware, buildServerCardExtension } from '@agentlair/mcp-trust-attestation';
import { Server } from '@modelcontextprotocol/sdk/server/index.js';
import { StdioServerTransport } from '@modelcontextprotocol/sdk/server/stdio.js';

const SERVER_ID = process.env.ATTESTED_SERVER_ID ?? 'url_sha256:<your-hex>';

// Attestation HTTP sidecar (port 8787)
const app = new Hono();
app.use('/.well-known/agentlair-trust', createAttestationMiddleware({ serverId: SERVER_ID }));
app.use('/agentlair/trust-attestation/:subject', createAttestationMiddleware({ serverId: SERVER_ID }));
serve({ fetch: app.fetch, port: 8787 });

// MCP server over stdio
const mcpServer = new Server(
  { name: 'my-server', version: '1.0.0' },
  { capabilities: { tools: {} } },
);
// Spread the trust extension into your initialize extensions field:
// extensions: { ...buildServerCardExtension({ serverId: SERVER_ID }) }

const transport = new StdioServerTransport();
await mcpServer.connect(transport);

The attestation routes are now reachable at http://localhost:8787/.well-known/agentlair-trust independently from the stdio connection. Clients that support MCP + BHC-S will use the descriptor URL from your server card extension to locate the trust surface.


Pattern B: HTTP/SSE with Hono

If your MCP server already uses Hono for HTTP/SSE transport, mount the two attestation routes on the same app:

import { Hono } from 'hono';
import { createAttestationMiddleware } from '@agentlair/mcp-trust-attestation';

const app = new Hono();

// Mount attestation routes (3 lines)
app.use('/.well-known/agentlair-trust', createAttestationMiddleware({ serverId: 'url_sha256:<your-hex>' }));
app.use('/agentlair/trust-attestation/:subject', createAttestationMiddleware({ serverId: 'url_sha256:<your-hex>' }));

// Your existing MCP SSE routes go here
app.get('/sse', /* ... */);
app.post('/messages', /* ... */);

The middleware dispatches by request path — it serves the static descriptor at /.well-known/agentlair-trust and proxies per-subject attestation requests at the second route. No other configuration.


Pattern C: HTTP/SSE with Express

Same two-route pattern for Express:

import express from 'express';
import { createNodeHttpHandler } from '@agentlair/mcp-trust-attestation';

const app = express();
const SERVER_ID = 'url_sha256:<your-hex>';

// Attestation handler (wraps node:http interface)
const attestationHandler = createNodeHttpHandler({ serverId: SERVER_ID });

// Mount the well-known descriptor
app.use('/.well-known/agentlair-trust', (req, res) => attestationHandler(req, res));
// Mount the per-subject attestation route
app.use('/agentlair/trust-attestation/:subject', (req, res) => attestationHandler(req, res));

// Your existing MCP routes
app.post('/messages', /* ... */);
app.listen(3000);

createNodeHttpHandler returns a standard (req, res) => void handler compatible with Express middleware. The path dispatch is the same as Pattern B.


The verify side

A relying party (orchestrator, gateway, or another agent) verifies a server’s attestation in two steps: fetch the descriptor, then verify the JWT.

Step 1: Fetch the descriptor

curl https://your-mcp-server.example/.well-known/agentlair-trust | jq .

The descriptor lists supported_signals, attestation_endpoint_template, and jwks_uri. The jwks_uri points to https://agentlair.dev/.well-known/jwks.json — AgentLair’s EdDSA public keys.

Step 2: Get an attestation JWT

curl "https://agentlair.dev/v1/trust/server/url_sha256:<your-hex>"

Returns a signed JWT. Pass that token to verifyAttestation:

import { verifyAttestation } from '@agentlair/mcp-trust-attestation';

const token = '...'; // attestation JWT from the endpoint above
const result = await verifyAttestation(token, { issuer: 'https://agentlair.dev' });

if (result.ok) {
  const claims = result.payload as { sub: string; signals: Record<string, unknown> };
  console.log('Verified server:', claims.sub);
} else {
  console.error('Attestation failed:', result.reason, result.error);
}

verifyAttestation fetches the JWKS once and caches it per issuer. The reason field on failure is one of: expired · signature · issuer · audience · malformed · fetch · other.


Reference