attestive-mcp-example

attestive-mcp-example

A thin MCP server wrapper that automatically audits all tool calls via Attestive's AuditClient, logging decisions and enabling verification of the hash chain. It provides an example server with audited tools and demonstrates end-to-end recording and verification through the MCP protocol.

Category
Visit Server

README

attestive-mcp-example

A thin wrapper that hooks Attestive's AuditClient.record() into an MCP server's tool-call lifecycle — the natural interception point on the server side of MCP, the same way attestive-agent-sdk-example's PostToolUse hook is the natural interception point on the client side. One line — auditMcpServer(server, auditClient) — and every tool registered on that server from then on gets its calls recorded automatically, no matter which MCP host (Claude Desktop, Claude Code, or anything else speaking MCP) ends up calling it.

Extracted from Attestive's main repo (git subtree split) so it's readable and runnable on its own. The canonical, currently-maintained version of AuditClient lives at github.com/magves56/Attestive; see "Standalone vs. canonical source" below for what that means here.

  • attestive-audit.ts — the reusable wrapper. withAudit() wraps one tool callback; auditMcpServer() wraps server.registerTool so every future registration gets withAudit() applied automatically. This is the file to read if you're integrating this into your own server — everything else here is example scaffolding.
  • demo-server.ts — a real MCP server with two tools a support agent might call (check_order_status, a read-only lookup; issue_refund, an actual decision with a real approve/deny outcome), both audited via one call to auditMcpServer(). Runs on stdio, exactly like any MCP server a real host spawns.
  • run-example.ts — the real thing: spawns demo-server.ts as an actual subprocess, connects a real MCP Client over StdioClientTransport, calls both tools through the real MCP protocol, then exports and verifies the resulting chain with the actual published attestive-verify package.
  • smoke-test.ts — exercises withAudit() directly against fake tool callbacks (both MCP callback shapes, plus a callback that throws), no MCP server or subprocess involved. Useful for iterating on the wrapper itself.
  • attestive-client.ts — a self-contained copy of AuditClient and the hash-chain/framework-citation logic it depends on, so this repo runs on its own with nothing but npm install. See its own header comment, and "Standalone vs. canonical source" below.

Steps: npm install → first verified logged decision

npm install
npm run smoke-test    # proves the wrapping logic works in isolation
npm run start         # the real thing -- spawns a real MCP server, calls real tools, verifies the chain

Neither command needs any credentials — MCP tool-calling doesn't require an LLM in the loop to demonstrate, unlike the Claude Agent SDK example, which needs ANTHROPIC_API_KEY or a Claude Code login to run the live agent path. That's a real difference worth knowing if you're choosing which example to try first: this one you can fully verify end to end with nothing but Node installed.

Honest timing

Measured against this repo, standalone, on a clean install:

Step Time
npm install (97 packages, cold) ~9s
npm run smoke-test instant; proves withAudit() → record() → exportEvidence() → verifyChain(), including a simulated thrown error
npx tsc --noEmit against the installed SDK's real .d.ts clean, no errors
npm run start — spawn a real subprocess, connect a real MCP Client, call two real tools through the real protocol, export, verify ~2.4s wall clock, all in

Total, start to a verified logged decision: under 15 seconds, no external accounts needed.

What "real running MCP server" means here

run-example.ts doesn't mock anything: demo-server.ts is spawned as a genuine child process (node demo-server.ts, via the SDK's own StdioClientTransport, which is exactly how Claude Desktop and Claude Code launch MCP servers), and every tool call crosses a real stdio pipe as real JSON-RPC messages, dispatched by the real @modelcontextprotocol/sdk McpServer. The one piece of demo-only plumbing is _export_chain, a third tool registered before auditMcpServer() runs (so it isn't itself audited — exporting a chain isn't a decision) purely so run-example.ts has a way to read back what the subprocess recorded in its own memory, the same way a real integrator's own tooling would need to reach into wherever they point ChainStore.

Coverage and limits, stated plainly

  • Only the current, recommended registerTool() API is wrapped by auditMcpServer(). The deprecated .tool() overloads are not intercepted automatically — migrate to registerTool() first (the MCP SDK already recommends this regardless of auditing), or call withAudit() directly around a .tool() callback if you can't migrate yet: server.tool("name", schema, withAudit("name", auditClient, handler)).
  • The default agentId is the MCP transport's sessionId if one is available (Streamable HTTP provides this), falling back to "mcp-server" otherwise. Stdio transports are typically one server process per session already, so one chain per process is a reasonable default there — but for a multi-tenant server where sessionId alone isn't the right audit boundary, pass agentId: (extra) => yourOwnId(extra) to auditMcpServer().
  • The default decisionType is "automated_decision" — the same value the Claude Agent SDK example uses, which suggestControlsForDecisionType() maps to human-oversight and record-keeping citations. Pass decisionType to auditMcpServer() (or per-tool to withAudit()) if a more specific type fits your tools better.
  • An audit-logging failure (the backing ChainStore throws) is caught and logged to stderr, never allowed to change what the MCP client actually receives back from the tool call — verified in smoke-test.ts's thrown-error case.

Standalone vs. canonical source

attestive-client.ts in this repo is a deliberate copy of AuditClient, not an import of it — AuditClient isn't published as an installable package yet (unlike attestive-verify, which this example genuinely depends on via npm install), and the monorepo paths it lives at only resolve inside that monorepo's own layout. If you're evaluating Attestive, treat github.com/magves56/Attestive's src/client.ts as the source of truth; this copy exists purely so this repo runs on its own. The monorepo guards the two from silently drifting apart with a cross-check test that isn't (and can't be) included here — see attestive-client.ts's own header comment.

Swapping in the real backend

This example uses InMemoryChainStore — the point is proving the MCP integration works, not standing up a database. For a real deployment, swap in a persistent ChainStore implementation (see attestive-client.ts's ChainStore interface, and src/store/supabase-chain-store.ts in the main Attestive repo for how the hosted product backs it with Postgres), and pass a real organizationId/apiKey to AuditClient instead of the "local-demo" placeholder used here.

License

MIT — see LICENSE.

Recommended Servers

playwright-mcp

playwright-mcp

A Model Context Protocol server that enables LLMs to interact with web pages through structured accessibility snapshots without requiring vision models or screenshots.

Official
Featured
TypeScript
Magic Component Platform (MCP)

Magic Component Platform (MCP)

An AI-powered tool that generates modern UI components from natural language descriptions, integrating with popular IDEs to streamline UI development workflow.

Official
Featured
Local
TypeScript
Audiense Insights MCP Server

Audiense Insights MCP Server

Enables interaction with Audiense Insights accounts via the Model Context Protocol, facilitating the extraction and analysis of marketing insights and audience data including demographics, behavior, and influencer engagement.

Official
Featured
Local
TypeScript
VeyraX MCP

VeyraX MCP

Single MCP tool to connect all your favorite tools: Gmail, Calendar and 40 more.

Official
Featured
Local
graphlit-mcp-server

graphlit-mcp-server

The Model Context Protocol (MCP) Server enables integration between MCP clients and the Graphlit service. Ingest anything from Slack to Gmail to podcast feeds, in addition to web crawling, into a Graphlit project - and then retrieve relevant contents from the MCP client.

Official
Featured
TypeScript
Kagi MCP Server

Kagi MCP Server

An MCP server that integrates Kagi search capabilities with Claude AI, enabling Claude to perform real-time web searches when answering questions that require up-to-date information.

Official
Featured
Python
E2B

E2B

Using MCP to run code via e2b.

Official
Featured
Neon Database

Neon Database

MCP server for interacting with Neon Management API and databases

Official
Featured
Exa Search

Exa Search

A Model Context Protocol (MCP) server lets AI assistants like Claude use the Exa AI Search API for web searches. This setup allows AI models to get real-time web information in a safe and controlled way.

Official
Featured
Qdrant Server

Qdrant Server

This repository is an example of how to create a MCP server for Qdrant, a vector search engine.

Official
Featured