MCP Quickstart
Attest checks every MCP tool call against a scoped credential before it executes. No credential, no action. Wrong scope, blocked. Every call logged with a signed receipt.
server.tool("run_sql", schema, async ({ query }) => {
// Agent calls this with anything.
// DROP TABLE? Sure. DELETE FROM users? Sure.
return db.execute(query);
});
The agent has full access to every tool. Nothing checks whether it should be allowed to run that specific action.
protectedServer.tool("run_sql", schema, async ({ query }) => {
// Only executes if caller holds db:read or db:write.
// db:admin required for DDL. No credential = blocked.
return db.execute(query);
});
Every call checked against the caller's credential scope. Wrong scope or no credential: rejected before your handler runs.
npm install @attest-dev/sdk @modelcontextprotocol/sdk
Four lines. Your existing tools keep working. Attest intercepts each call and checks the caller's credential before your handler runs.
import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio.js";
import { withAttest } from "@attest-dev/sdk/mcp";
const server = new McpServer({ name: "my-tools", version: "1.0.0" });
const attest = withAttest(server, {
issuerUri: "https://api.attestdev.com",
});
// This tool only executes if the caller holds "email:send" scope
attest.tool("send_email", { to: { type: "string" }, body: { type: "string" } },
async ({ to, body }) => {
await sendEmail(to, body);
return { content: [{ type: "text", text: `Sent to ${to}` }] };
}
);
const transport = new StdioServerTransport();
await server.connect(transport);
Create a workspace, then issue a credential with only the scopes the agent needs. Nothing more.
# Create a workspace (one-time setup)
curl -s -X POST https://api.attestdev.com/v1/orgs \
-H "Content-Type: application/json" \
-d '{"name":"acme-corp"}'
# Returns: { "id": "org_...", "api_key": "att_live_..." }
# Issue a credential scoped to email:send only
curl -s -X POST https://api.attestdev.com/v1/credentials \
-H "Authorization: Bearer att_live_..." \
-H "Content-Type: application/json" \
-d '{
"agent_id": "support-bot",
"user_id": "alice@acme.com",
"scope": ["email:send"],
"ttl": 3600
}'
The credential is a signed JWT. It expires in 1 hour. The agent can call send_email but cannot call run_sql, delete_user, or anything else outside its scope.
Every allowed and blocked call is recorded. Open the dashboard to see the audit trail, or export a signed evidence packet and verify it independently.
# Export the evidence packet for this task
curl -s https://api.attestdev.com/v1/evidence/task_8f3a...c91d \
-H "Authorization: Bearer att_live_..." \
-o evidence.json
# Verify it (or use attestdev.com/verify in browser)
npx @attest-dev/sdk verify evidence.json
Extracts the credential from the call context. If the required scope is missing, the call is rejected before your handler runs.
Records who called what, with which credential, at what time. Every entry is hash-chained so the log cannot be silently altered.
Produces a signed evidence packet you can export, verify independently, and hand to an auditor months later.