Docs navigation

MCP tool verification

An agent that talks to MCP servers, governed end-to-end: approved servers flow, unknown ones are blocked and scored, and every call is chained.

1 · Approve the servers you trust

curl -X POST https://www.proofledger.dev/api/tools \
  -H "authorization: Bearer $PROOFLEDGER_API_KEY" \
  -H "content-type: application/json" \
  -d '{ "name": "github_mcp", "type": "mcp",
        "mcpServerUrl": "mcp://github-mcp.internal",
        "approved": true, "riskLevel": "medium",
        "allowedAgents": ["ci-agent", "release-agent"] }'

2 · Log every MCP call before it runs

import { ProofLedger, PolicyBlockedError } from "@proofledger/sdk";

ProofLedger.enable({
  apiKey: process.env.PROOFLEDGER_API_KEY,
  agentName: "ci-agent",
  framework: "custom",
  policyMode: "enforce",
});
await ProofLedger.registerAgent();

/** Gate any MCP tool invocation through ProofLedger. */
async function callMcpTool(server: string, tool: string, args: unknown) {
  try {
    await ProofLedger.logToolCall({
      toolName: tool,
      toolType: "mcp",
      mcpServer: server,
      inputSummary: JSON.stringify(args).slice(0, 300),
    });
  } catch (err) {
    if (err instanceof PolicyBlockedError) {
      // Unknown/unapproved server: blocked, security event raised,
      // trust score reduced, entry auto-registered for operator review.
      console.warn(`MCP call blocked: ${err.evaluation.reason}`);
      return null;
    }
    throw err;
  }
  return mcpClient.call(server, tool, args);
}

await callMcpTool("mcp://github-mcp.internal", "create_pr", { title: "…" }); // allowed
await callMcpTool("mcp://random-scraper.example", "scrape", { url: "…" });  // blocked

3 · Review in the dashboard

The blocked server appears under Tools & MCP as unapproved (high risk) with its usage count; the block lands on the Security page and in the agent's timeline; the agent's trust score drops with a written reason. Approving the entry turns future calls into allow — no code change.

Note

Registered-but-unapproved MCP servers get a warn instead of a block — useful for a staged rollout where you observe first and approve after.