MCP Integration
Integrate Shadow Executor with Model Context Protocol (MCP) servers.
Overview
MCP is Anthropic's standard protocol for connecting AI models to external tools and data sources. Shadow Executor provides middleware that wraps MCP tool handlers to enforce policies before execution.
Installation
npm install @shadow-executor/sdk @modelcontextprotocol/sdk
Basic Usage
import { Server } from '@modelcontextprotocol/sdk/server/index.js';
import { StdioServerTransport } from '@modelcontextprotocol/sdk/server/stdio.js';
import { wrapToolHandler } from '@shadow-executor/sdk/mcp';
// Create MCP server
const server = new Server(
{
name: 'my-mcp-server',
version: '1.0.0',
},
{
capabilities: {
tools: {},
},
}
);
// Original tool handler
async function deleteDatabase(args: { instance_id: string }) {
// Delete database logic
return { success: true };
}
// Wrap with Shadow Executor
const protectedDeleteDatabase = wrapToolHandler(
deleteDatabase,
{
toolName: 'aws_rds_delete_db_instance',
policyPath: './shadow-exec.policy.yaml',
logPath: '~/.shadow-exec/audit.ndjson',
logSecret: process.env.SHADOW_EXEC_LOG_SECRET,
enableIPIDetection: true,
}
);
// Register wrapped tool
server.setRequestHandler(ListToolsRequestSchema, async () => ({
tools: [
{
name: 'aws_rds_delete_db_instance',
description: 'Delete an RDS database instance',
inputSchema: {
type: 'object',
properties: {
instance_id: { type: 'string' },
},
required: ['instance_id'],
},
},
],
}));
server.setRequestHandler(CallToolRequestSchema, async (request) => {
if (request.params.name === 'aws_rds_delete_db_instance') {
return await protectedDeleteDatabase(request.params.arguments);
}
});
// Start server
const transport = new StdioServerTransport();
await server.connect(transport);
Wrapping All Tools
Use wrapAllToolHandlers to protect multiple tools at once:
import { wrapAllToolHandlers } from '@shadow-executor/sdk/mcp';
const tools = {
aws_rds_delete_db_instance: async (args) => { /* ... */ },
aws_s3_delete_object: async (args) => { /* ... */ },
aws_iam_attach_user_policy: async (args) => { /* ... */ },
};
const protectedTools = wrapAllToolHandlers(tools, {
policyPath: './shadow-exec.policy.yaml',
logPath: '~/.shadow-exec/audit.ndjson',
logSecret: process.env.SHADOW_EXEC_LOG_SECRET,
enableIPIDetection: true,
});
// Use protectedTools in your MCP server
Tool Name Conversion
Shadow Executor automatically converts MCP tool names to AgentAction format:
| MCP Tool Name | Service | Operation |
|---|---|---|
aws_rds_delete_db_instance | rds | DeleteDBInstance |
aws_s3_delete_object | s3 | DeleteObject |
aws_iam_attach_user_policy | iam | AttachUserPolicy |
aws_ec2_terminate_instances | ec2 | TerminateInstances |
Conversion rules:
- Tool name format:
aws_{service}_{operation_snake_case} - Service: Extracted as-is (lowercase)
- Operation: Converted to PascalCase with acronym preservation
delete_db_instance→DeleteDBInstance(DB preserved)put_bucket_acl→PutBucketAcl(ACL preserved)
Custom tool names: Provide a custom convertToAgentAction function in config:
wrapToolHandler(handler, {
toolName: 'custom_tool_name',
policyPath: './shadow-exec.policy.yaml',
convertToAgentAction: (toolName, args) => ({
service: 'my-service',
operation: 'MyOperation',
parameters: args,
timestamp: new Date().toISOString(),
}),
});
Resource Tag Extraction
Shadow Executor extracts resource_tags from tool parameters automatically:
// Tool call with tags in parameters
{
instance_id: 'prod-db-01',
tags: {
Environment: 'production',
Tier: 'critical'
}
}
// Converted to AgentAction
{
service: 'rds',
operation: 'DeleteDBInstance',
resource: 'prod-db-01',
resource_tags: {
Environment: 'production',
Tier: 'critical'
}
}
Tag parameter names: tags, resource_tags, Tags, or ResourceTags
Error Handling
When a policy blocks an action, BlockedActionError is thrown:
import { BlockedActionError } from '@shadow-executor/sdk/mcp';
try {
await protectedDeleteDatabase({ instance_id: 'prod-db-01' });
} catch (error) {
if (error instanceof BlockedActionError) {
console.error('Action blocked by policy:', error.decision.reason);
console.error('Matched rule:', error.decision.matched_rule_id);
// error.decision contains full PolicyDecision object
} else {
throw error;
}
}
Configuration Options
interface ShadowExecutorConfig {
/** Path to policy YAML file */
policyPath: string;
/** Path to audit log file (default: ~/.shadow-exec/audit.ndjson) */
logPath?: string;
/** HMAC secret for audit log signing (required) */
logSecret: string;
/** Enable IPI detection (default: false) */
enableIPIDetection?: boolean;
/** Agent ID for tracking (default: 'mcp-agent') */
agentId?: string;
/** Custom tool name to AgentAction converter */
convertToAgentAction?: (toolName: string, args: unknown) => AgentAction;
/** Approval timeout in minutes (default: 30) */
approvalTimeoutMinutes?: number;
}
Policy Example
version: "1.0"
name: "MCP Server Protection Policy"
rules:
- id: MCP-001
name: Block production RDS deletion
severity: CRITICAL
action: BLOCK
match:
service: rds
operation: DeleteDBInstance
resource_tags:
Environment: production
- id: MCP-002
name: Require approval for IAM changes
severity: HIGH
action: REQUIRE_APPROVAL
match:
service: iam
operation: [AttachUserPolicy, PutUserPolicy]
- id: MCP-003
name: Block high IPI score operations
severity: CRITICAL
action: BLOCK
match:
operation: "Delete*"
ipi_score: ">= 0.7"
Testing
Test your MCP integration with the Shadow Executor demo:
import { wrapToolHandler } from '@shadow-executor/sdk/mcp';
// Mock tool for testing
const mockDeleteDB = async (args: { instance_id: string }) => {
console.log(`Deleting database: ${args.instance_id}`);
return { success: true };
};
// Wrap with policy
const protectedMockDeleteDB = wrapToolHandler(mockDeleteDB, {
toolName: 'aws_rds_delete_db_instance',
policyPath: './test-policy.yaml',
logSecret: 'test-secret',
});
// Test blocked action
try {
await protectedMockDeleteDB({
instance_id: 'prod-customer-data',
tags: { Environment: 'production' }
});
} catch (error) {
console.log('Action blocked as expected:', error.message);
}
Full Example
See examples/mcp/demo.mjs in the repository for a complete working example.
Next Steps
- Policy Reference — Define policies for your MCP tools
- Audit Logging — Query and verify audit logs
- IPI Detection — Understand IPI scoring