MCP Adapter for Caracal Core
This module provides integration between Caracal budget enforcement and the Model Context Protocol (MCP) ecosystem.
Overview
The MCP Adapter intercepts MCP tool calls and resource reads, enforces budget policies, and emits metering events. This enables budget enforcement for MCP-based agents.
Components
MCPAdapter
Main adapter class that coordinates budget enforcement for MCP operations.
Key Methods:
intercept_tool_call(): Intercepts MCP tool invocations, checks budget, forwards to MCP server, and emits metering eventsintercept_resource_read(): Intercepts MCP resource reads, checks budget, fetches resource, and emits metering events
Requirements Implemented:
- 11.1: Intercept MCP tool invocation requests before execution
- 11.2: Extract agent identity from MCP context
- 11.3: Perform budget check via Caracal Core
- 11.4: Forward tool invocation to MCP server
- 11.5: Emit metering event with actual resource usage
- 12.1: Intercept MCP resource read requests
- 12.2: Calculate cost based on resource type and size
- 12.3: Emit metering event to Caracal Core
MCPCostCalculator
Calculates costs for MCP operations based on the pricebook.
Key Methods:
estimate_tool_cost(): Estimates cost for tool invocationscalculate_actual_tool_cost(): Calculates actual cost from tool resultsestimate_resource_cost(): Estimates cost for resource reads
Cost Estimation Strategies:
- LLM Tools: Based on estimated token usage (input + output tokens)
- API Tools: Based on endpoint and data size
- Resource Reads: Based on resource type and size
- Default: Flat rate per operation
MCPContext
Context information for MCP requests containing agent ID and metadata.
MCPResult
Result of an MCP operation with success status, result data, and metadata.
MCPResource
Represents an MCP resource with URI, content, MIME type, and size.
Usage Example
from caracal.mcp import MCPAdapter, MCPContext, MCPCostCalculator
from caracal.core.policy import PolicyEvaluator
from caracal.core.metering import MeteringCollector
from caracal.core.pricebook import Pricebook
# Initialize components
pricebook = Pricebook("pricebook.csv")
policy_evaluator = PolicyEvaluator(policy_store, ledger_query)
metering_collector = MeteringCollector(pricebook, ledger_writer)
cost_calculator = MCPCostCalculator(pricebook)
# Create MCP adapter
adapter = MCPAdapter(
policy_evaluator=policy_evaluator,
metering_collector=metering_collector,
cost_calculator=cost_calculator
)
# Intercept tool call
context = MCPContext(
agent_id="agent-uuid",
metadata={"source": "mcp-client"}
)
result = await adapter.intercept_tool_call(
tool_name="llm_completion",
tool_args={
"prompt": "Hello, world!",
"max_tokens": 100,
"model": "gpt-4"
},
mcp_context=context
)
if result.success:
print(f"Tool result: {result.result}")
print(f"Cost: {result.metadata['actual_cost']} USD")
else:
print(f"Error: {result.error}")
Pricebook Configuration
Add MCP-specific prices to your pricebook:
resource_type,price_per_unit,currency,updated_at
mcp.tool.default,0.01,USD,2024-01-01T00:00:00Z
mcp.resource.default,0.001,USD,2024-01-01T00:00:00Z
mcp.llm.gpt-4.input_tokens,0.00003,USD,2024-01-01T00:00:00Z
mcp.llm.gpt-4.output_tokens,0.00006,USD,2024-01-01T00:00:00Z
mcp.resource.file.per_mb,0.0001,USD,2024-01-01T00:00:00Z
mcp.api.default,0.001,USD,2024-01-01T00:00:00Z
Testing
Unit tests: tests/unit/test_mcp_adapter.py
Integration tests: tests/integration/test_mcp_integration.py
Run tests:
pytest tests/unit/test_mcp_adapter.py -v
pytest tests/integration/test_mcp_integration.py -v
Implementation Notes
v0.2 Limitations
- MCP server forwarding is simulated (placeholder implementation)
- Actual HTTP/gRPC calls to MCP servers will be implemented in v0.3
- Resource fetching is simulated with placeholder content
Future Enhancements (v0.3)
- Real MCP server integration via HTTP/gRPC
- Support for MCP prompt access metering
- Support for MCP sampling request metering
- Decorator pattern for in-process integration
- Standalone service deployment mode
- Advanced cost calculation rules
- Custom cost calculation functions per resource type
Architecture
┌─────────────────┐
│ MCP Client │
└────────┬────────┘
│
▼
┌─────────────────┐
│ MCPAdapter │◄──────┐
└────────┬────────┘ │
│ │
├────────────────┼──► PolicyEvaluator (budget check)
│ │
├────────────────┼──► MCPCostCalculator (cost estimation)
│ │
├────────────────┼──► MCP Server (tool execution)
│ │
└────────────────┴──► MeteringCollector (emit events)
Error Handling
The adapter implements fail-closed semantics:
- Budget check failures raise
BudgetExceededError - Missing agent ID raises
CaracalError - Other errors return
MCPResultwithsuccess=Falseand error message - Metering events are only emitted for successful operations
Logging
The adapter logs:
- Tool call interceptions (DEBUG)
- Resource read interceptions (DEBUG)
- Cost estimations (DEBUG)
- Budget check results (INFO)
- Metering events (INFO)
- Errors (ERROR)
Configure logging level in your application:
import logging
logging.getLogger("caracal.mcp").setLevel(logging.DEBUG)