Skip to main content

Claude Agent SDK + AxonFlow Integration

Prerequisites: Node.js 18+, AxonFlow running (Getting Started), npm install @axonflow/sdk


What the Claude Agent SDK Is

The Claude Agent SDK is Anthropic's framework for building custom AI agents that use MCP-based tools. It provides a structured way to define tools, manage agent loops, and handle tool execution results. Agents built with the SDK can connect to MCP servers for database access, API calls, file operations, and other external interactions.

The SDK handles the agent loop (prompt, tool selection, execution, response), tool result formatting, and conversation management. When an agent decides to use a tool, the SDK manages the serialization of inputs, dispatches the call, and feeds the result back into the conversation for the next reasoning step.

What the SDK does not provide is governance over those tool calls. There is no built-in mechanism for policy enforcement on tool inputs, PII detection on tool outputs, or compliance-ready audit trails for tool execution. These are the concerns AxonFlow addresses.


How AxonFlow Integrates

The Claude Agent SDK uses the MCP protocol for tool execution. AxonFlow's TypeScript SDK already includes mcpCheckInput() and mcpCheckOutput() methods that evaluate MCP tool calls against your policy engine. No new SDK code or adapters are needed.

The integration pattern is straightforward: call mcpCheckInput() before executing a tool to enforce input policies (SQL injection, PII in queries, dangerous operations), then call mcpCheckOutput() after execution to enforce output policies (PII redaction, exfiltration detection, response filtering).

Agent Loop → Tool Selected → mcpCheckInput() → Tool Execution

Agent Response ← mcpCheckOutput() ← Tool Result

This works with any MCP tool the agent uses, whether it connects to a database, calls an API, or accesses a file system.


TypeScript Integration Pattern

Wrap your agent's tool execution with AxonFlow policy checks:

import { AxonFlow } from '@axonflow/sdk';

const client = new AxonFlow({
endpoint: process.env.AXONFLOW_ENDPOINT!,
clientId: process.env.AXONFLOW_CLIENT_ID!,
clientSecret: process.env.AXONFLOW_CLIENT_SECRET,
});

// Before tool execution: check input against policies
async function checkToolInput(
toolName: string,
toolInput: Record<string, unknown>
): Promise<{ allowed: boolean; blockReason?: string }> {
const inputCheck = await client.mcpCheckInput({
connectorType: `agent_sdk.${toolName}`,
statement: JSON.stringify(toolInput),
operation: 'execute',
});

if (!inputCheck.allowed) {
return { allowed: false, blockReason: inputCheck.block_reason };
}

return { allowed: true };
}

// After tool execution: check output for PII, exfiltration
async function checkToolOutput(
toolName: string,
toolResult: unknown
): Promise<{ data: unknown; redacted: boolean }> {
const outputCheck = await client.mcpCheckOutput({
connectorType: `agent_sdk.${toolName}`,
message: typeof toolResult === 'string' ? toolResult : JSON.stringify(toolResult),
});

if (outputCheck.redacted_data) {
return { data: outputCheck.redacted_data, redacted: true };
}

return { data: toolResult, redacted: false };
}

Full Agent Example

import { AxonFlow } from '@axonflow/sdk';

const client = new AxonFlow({
endpoint: process.env.AXONFLOW_ENDPOINT!,
clientId: process.env.AXONFLOW_CLIENT_ID!,
clientSecret: process.env.AXONFLOW_CLIENT_SECRET,
});

// Governed tool execution wrapper
async function executeGovernedTool(
toolName: string,
toolInput: Record<string, unknown>,
executeFn: (input: Record<string, unknown>) => Promise<unknown>
): Promise<{ result: unknown; blocked: boolean; redacted: boolean }> {
// 1. Pre-execution policy check
const inputCheck = await client.mcpCheckInput({
connectorType: `agent_sdk.${toolName}`,
statement: JSON.stringify(toolInput),
operation: 'execute',
});

if (!inputCheck.allowed) {
console.log(`Tool "${toolName}" blocked: ${inputCheck.block_reason}`);
return { result: null, blocked: true, redacted: false };
}

// 2. Execute the tool
const rawResult = await executeFn(toolInput);

// 3. Post-execution policy check
const outputCheck = await client.mcpCheckOutput({
connectorType: `agent_sdk.${toolName}`,
message: typeof rawResult === 'string' ? rawResult : JSON.stringify(rawResult),
});

if (outputCheck.redacted_data) {
return { result: outputCheck.redacted_data, blocked: false, redacted: true };
}

return { result: rawResult, blocked: false, redacted: false };
}

// Usage with a database query tool
const { result, blocked, redacted } = await executeGovernedTool(
'query_customers',
{ query: 'SELECT name, email FROM customers WHERE region = $1', params: ['US'] },
async (input) => {
// Your actual tool execution logic
return [
{ name: 'Jane Smith', email: '[email protected]' },
{ name: 'Bob Johnson', email: '[email protected]' },
];
}
);

if (blocked) {
console.log('Tool execution was blocked by policy');
} else if (redacted) {
console.log('Tool result contained PII that was redacted');
}

Connector Type Naming Convention

When calling mcpCheckInput() and mcpCheckOutput(), use the connectorType field to identify the tool. The recommended convention for Claude Agent SDK tools is:

agent_sdk.{tool_name}

Examples:

ToolConnector Type
Database query toolagent_sdk.query_customers
File reader toolagent_sdk.read_file
API caller toolagent_sdk.call_api
Email sender toolagent_sdk.send_email

This naming convention lets you write policies that target specific tools or all Agent SDK tools:

  • All Agent SDK tools: Match agent_sdk.* in your policy conditions
  • Specific tool: Match agent_sdk.query_customers for per-tool rules
  • Tool categories: Use naming like agent_sdk.db_* for all database tools

What Gets Governed

Input Checks (mcpCheckInput)

CheckWhat It CatchesExample
SQL injection detectionMalicious SQL in tool inputsDROP TABLE users; --
PII in queriesSensitive data sent to toolsSSN or credit card in search parameters
Dangerous operationsDestructive actionsDELETE FROM without WHERE clause
Custom policiesYour tenant-specific rulesBlock production database access

Output Checks (mcpCheckOutput)

CheckWhat It CatchesExample
PII redactionSensitive data in resultsEmail, phone, SSN in returned records
Exfiltration detectionLarge-scale data extractionTool returning 10,000+ rows
Response filteringPolicy-matched contentCredit card numbers in API responses
Custom policiesYour tenant-specific rulesBlock certain data classifications

Every check (both input and output) creates an audit entry. Blocked requests never reach the tool. Redacted responses replace sensitive values with placeholders like [REDACTED:ssn] before the data returns to the agent.

For details on configuring these policies, see MCP Policy Enforcement. System policies (PII, SQL injection) are active by default. Tenant policies let you add custom rules for specific tools or data classifications.


Latency Impact

OperationTypical Latency
mcpCheckInput2-5ms
mcpCheckOutput2-5ms
Audit write (async)0ms (non-blocking)
Total per tool call4-10ms

For agent workflows where tool calls typically take 50-500ms (database queries, API calls), the governance overhead is negligible.


Differences from Claude Code Integration

If you are also using Claude Code, here is how the two integrations compare:

AspectClaude CodeClaude Agent SDK
Integration pointShell hooks (pre/post tool)TypeScript SDK methods
ProtocolHTTP calls to AxonFlow agentmcpCheckInput / mcpCheckOutput
ScopeDeveloper CLI tool governanceCustom agent tool governance
RuntimeBash scriptsNode.js / TypeScript
Use caseGoverning developer interactionsGoverning production agent tools

Both integrations use the same AxonFlow policy engine and audit trail. Policies configured for one apply to the other when the connector types match.


Observe Mode

If you want to evaluate AxonFlow's governance without blocking any tool calls, start in observe mode. Set the PII_ACTION environment variable to log on your AxonFlow instance:

PII_ACTION=log

In this mode, all policy evaluations are logged and audited, but no tool calls are blocked and no responses are redacted. Review the audit trail to understand what policies would have triggered, then switch to redact or block when you are ready to enforce.



Platform Version: v5.4.0 | SDKs: Python v5.4.0, Go/TypeScript/Java v4.3.0