Docs/Adapters/SecureAnthropic

SecureAnthropic

Drop-in replacement for the Anthropic Python SDK. All Claude models supported with full policy enforcement, cryptographic signing, and audit logging.

Compatible with anthropic≥0.18Anthropic API Reference ↗

Quick Start

Before
from anthropic import Anthropic

client = Anthropic()
message = client.messages.create(
    model="claude-sonnet-4-20250514",
    max_tokens=1024,
    messages=[{"role": "user", "content": "Hello"}]
)
After
from macaw_adapters.anthropic import SecureAnthropic

client = SecureAnthropic(app_name="my-app")
message = client.messages.create(
    model="claude-sonnet-4-20250514",
    max_tokens=1024,
    messages=[{"role": "user", "content": "Hello"}]
)

When to Use Each Path

SecureAnthropic supports three usage patterns depending on your identity requirements:

PathWhen to UseIdentity
client.messages.create()Simple scripts, single-user appsApp-level only
bind_to_user()Multi-user SaaS, per-user policiesUser JWT + app
invoke_tool()Agent-to-agent, explicit controlFull A2A chain

Constructor

class SecureAnthropic:
    def __init__(
        self,
        api_key: str = None,           # Anthropic API key (or ANTHROPIC_API_KEY env)
        app_name: str = None,          # Application name for MACAW registration
        intent_policy: dict = None,    # Application-defined MACAW intent policy
        jwt_token: str = None,         # User JWT for user-mode (creates user agent)
        user_name: str = None          # Optional user name for user mode
    )

Two Modes

  • Service mode (default): No jwt_token - creates service agent, registers tools
  • User mode: With jwt_token - creates user agent with identity for direct calls

MACAW-Protected Methods

These methods route through MACAW PEP for policy enforcement, signing, and audit:

messages.create()
message = client.messages.create(
    model="claude-sonnet-4-20250514",
    max_tokens=1024,
    messages=[{"role": "user", "content": "Hello"}],
    system="You are a helpful assistant",
    tools=[...],                        # Tool calls enforced by policy
    stream=False                        # Streaming supported
)
messages.stream()
# Context manager style streaming
with client.messages.stream(
    model="claude-sonnet-4-20250514",
    max_tokens=1024,
    messages=[{"role": "user", "content": "Tell me a story"}]
) as stream:
    for text in stream.text_stream:
        print(text, end="")
completions.create()
# Legacy completions API (Claude 2.x)
completion = client.completions.create(
    model="claude-2.1",
    prompt="\n\nHuman: Hello\n\nAssistant:",
    max_tokens_to_sample=256
)

Pass-through APIs

These delegate directly to the underlying Anthropic client (no MACAW protection):

APIDescription
betaBeta features (message batches, etc.)
count_tokens()Token counting utility

bind_to_user()

For multi-user SaaS scenarios, bind the service to a user's MACAWClient:

from macaw_adapters.anthropic import SecureAnthropic
from macaw_client import MACAWClient

# Create shared service (once at startup)
service = SecureAnthropic(app_name="my-saas")

# Per-request: create user client and bind
user_client = MACAWClient(
    user_name="alice",
    iam_token=request.headers["Authorization"],
    agent_type="user"
)
user_client.register()

# Bind service to user - all calls now use user's identity
user_claude = service.bind_to_user(user_client)

# Use exactly like regular client
message = user_claude.messages.create(
    model="claude-sonnet-4-20250514",
    max_tokens=1024,
    messages=[{"role": "user", "content": "Hello"}]
)

# Cleanup when done
user_claude.unbind()

BoundSecureAnthropic

The bind_to_user() method returns a BoundSecureAnthropic wrapper that routes all calls through the user's MACAWClient to the service. This enables per-user identity and policy enforcement. Call unbind() when done to invalidate the binding.


Streaming Responses

Use messages.stream() for real-time token streaming. Policy enforcement happens before the first chunk is returned — blocked requests never start streaming.

# Streaming response - works identically to Anthropic
with client.messages.stream(
    model="claude-3-haiku-20240307",
    max_tokens=400,
    messages=[{"role": "user", "content": "Write a poem"}]
) as stream:
    for text in stream.text_stream:
        print(text, end="", flush=True)

Streaming Security

Policy checks (model, max_tokens, etc.) are validated before streaming begins. Each chunk is logged for audit compliance. The underlying invoke_tool(stream=True) handles this automatically.


A2A: invoke_tool()

For agent-to-agent (A2A) systems or when you need explicit control over tool routing. Returns raw dict instead of SDK types.

# Service registers tools
service = SecureAnthropic(app_name="anthropic-service")

# User agent calls invoke_tool directly
result = user.invoke_tool(
    tool_name="tool:anthropic-service/generate",  # MAPL name
    parameters={
        "model": "claude-3-haiku-20240307",
        "max_tokens": 100,
        "messages": [{"role": "user", "content": "Hello"}]
    },
    target_agent=service.server_id
)

# Result is raw dict (not Message)
content = result["content"][0]["text"]

MAPL Tool Names

SecureAnthropic registers tools with MAPL-compliant names for policy targeting:

MethodMAPL Tool NameExample
messages.create()tool:<app>/generatetool:my-app/generate
messages.stream()tool:<app>/generatetool:my-app/generate
completions.create()tool:<app>/completetool:my-app/complete

Policy Integration

Target SecureAnthropic methods in MAPL policies using the tool names above:

{
  "constraints": {
    "parameters": {
      "tool:my-app/generate": {
        "model": {
          "allowed_values": [
            "claude-3-haiku-20240307",
            "claude-sonnet-4-20250514"
          ]
        },
        "max_tokens": {
          "type": "integer",
          "max": 4096
        }
      }
    }
  }
}

Examples

Tool Use with Policy
from macaw_adapters.anthropic import SecureAnthropic

client = SecureAnthropic(app_name="assistant")

tools = [{
    "name": "get_weather",
    "description": "Get weather for a location",
    "input_schema": {
        "type": "object",
        "properties": {
            "location": {"type": "string"}
        }
    }
}]

message = client.messages.create(
    model="claude-sonnet-4-20250514",
    max_tokens=1024,
    tools=tools,
    messages=[
        {"role": "user", "content": "What's the weather in SF?"}
    ]
)

# Tool calls logged and policy-checked
for block in message.content:
    if block.type == "tool_use":
        print(f"Tool: {block.name}, Input: {block.input}")

Official API Reference

SecureAnthropic maintains API compatibility with the official Anthropic Python SDK:

SDK Compatibility: anthropic-sdk-python ≥0.18.0 • Messages API v1


Related Topics