Skip to main content

Anthropic SDK

The gateway supports the Anthropic Messages API. Point the official @anthropic-ai/sdk at the gateway and all requests are proxied with automatic memory.

Before you begin​

Complete Anthropic's Get started with Claude guide first. It covers SDK installation, API keys, and the base Messages API setup.

Configure the client​

Create an Anthropic client with your gateway API key and base URL. The Anthropic SDK sends the key via x-api-key, which the gateway accepts natively.

TypeScriptsrc/gateway.ts
import Anthropic from "@anthropic-ai/sdk";

export const client = new Anthropic({
  apiKey: "YOUR_API_KEY",
  baseURL: "https://gateway-api.mastra.ai",
});

All subsequent examples import this client instance from ./gateway.

Messages​

Send a standard messages request. The gateway routes it to Anthropic and returns the response.

TypeScriptsrc/messages.ts
import { client } from "./gateway";

const message = await client.messages.create({
  model: "anthropic/claude-sonnet-4-6",
  max_tokens: 20,
  messages: [
    { role: "user", content: "What is 2+2? Reply with just the number." },
  ],
});

if (message.content[0].type === "text") {
  console.log(message.content[0].text);
}

// Returns "4"

System messages​

Set the model's behavior with the top-level system parameter.

const message = await client.messages.create({
  model: "anthropic/claude-sonnet-4-6",
  max_tokens: 100,
  system: "You are a calculator. Only respond with numbers, no words.",
  messages: [
    { role: "user", content: "What is 10 * 5?" },
  ],
});

if (message.content[0].type === "text") {
  console.log(message.content[0].text);
}

// Returns "50"

Multi-turn conversations​

Pass the full conversation history in the messages array so the model retains context across turns.

const message = await client.messages.create({
  model: "anthropic/claude-sonnet-4-6",
  max_tokens: 100,
  messages: [
    { role: "user", content: "Remember this word: banana" },
    { role: "assistant", content: "Got it, I will remember the word banana." },
    { role: "user", content: "What word did I ask you to remember? Reply with just the word." },
  ],
});

if (message.content[0].type === "text") {
  console.log(message.content[0].text);
}

// Returns "banana"

Streaming​

Use client.messages.stream() to receive deltas incrementally.

TypeScriptsrc/stream.ts
import { client } from "./gateway";

const stream = client.messages.stream({
  model: "anthropic/claude-sonnet-4-6",
  max_tokens: 50,
  messages: [
    { role: "user", content: "Count from 1 to 5, separated by commas." },
  ],
});

for await (const event of stream) {
  if (event.type === "content_block_delta" && event.delta.type === "text_delta") {
    process.stdout.write(event.delta.text);
  }
}

// Returns "1, 2, 3, 4, 5"

Memory with thread and resource IDs​

Pass x-thread-id and x-resource-id as extra headers. The gateway stores observations per thread and injects them as context on subsequent requests.

TypeScriptsrc/memory.ts
import { client } from "./gateway";

// First request: introduce yourself
await client.messages.create({
  model: "anthropic/claude-sonnet-4-6",
  max_tokens: 256,
  messages: [
    { role: "user", content: "My name is Alex and I prefer concise answers." },
  ],
  // @ts-expect-error - extra headers passed through to the gateway
  headers: {
    "x-thread-id": "my-thread-1",
    "x-resource-id": "user-42",
  },
});

// Second request: the gateway remembers
const response = await client.messages.create({
  model: "anthropic/claude-sonnet-4-6",
  max_tokens: 256,
  messages: [
    { role: "user", content: "What is my name?" },
  ],
  // @ts-expect-error - extra headers passed through to the gateway
  headers: {
    "x-thread-id": "my-thread-1",
    "x-resource-id": "user-42",
  },
});

if (response.content[0].type === "text") {
  console.log(response.content[0].text);
}

// Returns "Alex"

Tool calling​

Define tools using the Anthropic tool format with input_schema.

TypeScriptsrc/tools.ts
import Anthropic from "@anthropic-ai/sdk";
import { client } from "./gateway";

export const helloWorldTool: Anthropic.Tool = {
  name: "helloWorld",
  description: "Returns a greeting for the given name",
  input_schema: {
    type: "object",
    properties: {
      name: { type: "string", description: "The name to greet" },
    },
    required: ["name"],
  },
};

// Step 1: Send the request with tools
const first = await client.messages.create({
  model: "anthropic/claude-sonnet-4-6",
  max_tokens: 200,
  messages: [
    { role: "user", content: "Use the helloWorld tool to greet Alice." },
  ],
  tools: [helloWorldTool],
});

const toolUseBlock = first.content.find((b) => b.type === "tool_use");
if (toolUseBlock?.type !== "tool_use") throw new Error("Expected tool_use block");

const args = toolUseBlock.input as { name: string };

// Execute the tool locally
const result = { greeting: `Hello, ${args.name}!` };

// Step 2: Send the tool result back
const second = await client.messages.create({
  model: "anthropic/claude-sonnet-4-6",
  max_tokens: 200,
  messages: [
    { role: "user", content: "Use the helloWorld tool to greet Alice." },
    { role: "assistant", content: first.content },
    {
      role: "user",
      content: [
        {
          type: "tool_result",
          tool_use_id: toolUseBlock.id,
          content: JSON.stringify(result),
        },
      ],
    },
  ],
  tools: [helloWorldTool],
});

const textBlock = second.content.find((b) => b.type === "text");
if (textBlock?.type === "text") {
  console.log(textBlock.text);
  // Returns "Hello, Alice!"
}

Streaming tool calls​

Stream a tool-calling request to receive input_json_delta events as the model generates tool arguments.

import Anthropic from "@anthropic-ai/sdk";
import { client } from "./gateway";
import { helloWorldTool } from "./tools";

const stream = client.messages.stream({
  model: "anthropic/claude-sonnet-4-6",
  max_tokens: 200,
  messages: [
    { role: "user", content: "Use the helloWorld tool to greet Bob." },
  ],
  tools: [helloWorldTool],
});

const events: Anthropic.MessageStreamEvent[] = [];
for await (const event of stream) {
  events.push(event);
}

// Find the tool_use block
const toolUseStart = events.find(
  (e) => e.type === "content_block_start" && e.content_block.type === "tool_use",
);

// Accumulate the JSON deltas
const jsonDeltas = events
  .filter((e) => e.type === "content_block_delta" && e.delta.type === "input_json_delta")
  .map((e) => {
    if (e.type === "content_block_delta" && e.delta.type === "input_json_delta") {
      return e.delta.partial_json;
    }
    return "";
  });

const fullArgs = JSON.parse(jsonDeltas.join(""));
console.log(fullArgs.name); // Returns "Bob"
  • Features: Observational memory, streaming, BYOK, and gateway tools
  • Models: Supported providers and model routing
  • API reference: Complete endpoint documentation