@bulwark/mcp-auth

Bulwark integration for Model Context Protocol (MCP) servers — identity and credential injection for AI tools.

Installation

npm install @bulwark/mcp-auth

Overview

@bulwark/mcp-auth wraps your MCP tool handlers to enforce agent authentication and inject credentials automatically.

Setup

import { Server } from "@modelcontextprotocol/sdk/server/index.js";
import { withBulwark } from "@bulwark/mcp-auth";

const server = new Server({ name: "my-mcp-server", version: "1.0.0" });

// Wrap the server with Bulwark authentication
withBulwark(server, {
  tenantId: process.env.BULWARK_TENANT_ID!,
  apiKey: process.env.BULWARK_API_KEY!,
  requiredScopes: ["tools:use"],
});

Tool Handler Authentication

import { BulwarkMcpContext } from "@bulwark/mcp-auth";

server.setRequestHandler(CallToolRequestSchema, async (req, context) => {
  const { agent, session } = context as BulwarkMcpContext;

  if (req.params.name === "search_github") {
    // Credential is automatically injected by Bulwark proxy
    const result = await session.proxy({
      credentialId: "cred_github",
      method: "GET",
      url: `https://api.github.com/search/repositories?q=${req.params.arguments.query}`,
    });

    return { content: [{ type: "text", text: JSON.stringify(result) }] };
  }
});

Credential Injection Middleware

import { credentialMiddleware } from "@bulwark/mcp-auth";

// Automatically injects credentials for configured providers
withBulwark(server, {
  tenantId: process.env.BULWARK_TENANT_ID!,
  apiKey: process.env.BULWARK_API_KEY!,
  credentials: {
    github: { credentialId: "cred_github" },
    slack: { credentialId: "cred_slack" },
  },
});

CIBA for Sensitive Operations

import { requireHumanApproval } from "@bulwark/mcp-auth";

server.setRequestHandler(CallToolRequestSchema, async (req, context) => {
  if (req.params.name === "send_payment") {
    const { agent, session } = context as BulwarkMcpContext;

    // Pause and request human approval
    const approval = await requireHumanApproval(session, {
      userId: agent.ownerId,
      scope: "approve:payment",
      bindingMessage: `Approve payment of $${req.params.arguments.amount}?`,
      timeout: 300,
    });

    if (!approval.granted) {
      return { content: [{ type: "text", text: "Payment denied by user." }] };
    }

    // Proceed with payment...
  }
});

Agent Context

Every authenticated request provides:

interface BulwarkMcpContext {
  agent: {
    agentId: string;
    name: string;
    trustLevel: "low" | "medium" | "high" | "critical";
    scopes: string[];
    ownerId?: string;
  };
  session: {
    sessionId: string;
    proxy: (req: ProxyRequest) => Promise<ProxyResponse>;
    attenuate: (scopes: string[], ttl?: number) => Promise<string>;
  };
}