Providers
Claude Agents SDK
Use NIN Connect tools with the Anthropic Claude API — tool_use, manual agent loop, and input_schema mapping.
Installation
npm install @nin.in/core @anthropic-ai/sdkEnvironment Variables
NIN_API_KEY=nk_live_xxxxxxxxx
ANTHROPIC_API_KEY=sk-ant-xxxxxxxxxFull Example
import { Nin } from "@nin.in/core";
import Anthropic from "@anthropic-ai/sdk";
const nin = new Nin({ apiKey: process.env.NIN_API_KEY! });
const session = nin.session("user_123");
const anthropic = new Anthropic();
// fetch tool definitions from the Slack plugin
const toolDefs = await session.getTools({ plugins: ["slack"] });
// map to Anthropic tool format
// inputSchema maps directly to input_schema, so Claude sees every
// parameter name, type, and description
const tools = toolDefs.map((t) => ({
name: t.slug,
description: t.description,
input_schema: t.inputSchema ?? {
type: "object" as const,
properties: {},
},
}));
// run an agentic loop
let messages: Anthropic.MessageParam[] = [
{ role: "user", content: "Send 'hello team' to #general on Slack" },
];
let response = await anthropic.messages.create({
model: "claude-sonnet-4-20250514",
max_tokens: 1024,
tools,
messages,
});
// handle tool calls in a loop
while (response.stop_reason === "tool_use") {
const toolUse = response.content.find((b) => b.type === "tool_use");
if (!toolUse || toolUse.type !== "tool_use") break;
// execute via NIN — auth is injected automatically
const result = await session.execute(
toolUse.name,
toolUse.input as Record<string, unknown>
);
messages = [
...messages,
{ role: "assistant", content: response.content },
{
role: "user",
content: [
{
type: "tool_result",
tool_use_id: toolUse.id,
content: JSON.stringify(result),
},
],
},
];
response = await anthropic.messages.create({
model: "claude-sonnet-4-20250514",
max_tokens: 1024,
tools,
messages,
});
}
console.log(response.content);How It Works
session.getTools()returns tool definitions withinputSchema(JSON Schema)- Tools are mapped to Anthropic's format:
{ name, description, input_schema } - The first
messages.create()call sends the prompt and tools to Claude - When Claude returns
stop_reason: "tool_use", extract the tool call session.execute()runs the tool through NIN with auth injected- The tool result is appended as a
tool_resultmessage - Loop until Claude produces a final text response
Agent Loop Helper
For cleaner code, extract the loop into a reusable function:
const runAgent = async (
prompt: string,
session: ReturnType<Nin["session"]>,
pluginSlugs: string[]
) => {
const toolDefs = await session.getTools({ plugins: pluginSlugs });
const tools = toolDefs.map((t) => ({
name: t.slug,
description: t.description,
input_schema: t.inputSchema ?? {
type: "object" as const,
properties: {},
},
}));
let messages: Anthropic.MessageParam[] = [
{ role: "user", content: prompt },
];
while (true) {
const response = await anthropic.messages.create({
model: "claude-sonnet-4-20250514",
max_tokens: 1024,
tools,
messages,
});
if (response.stop_reason !== "tool_use") {
return response.content;
}
const toolUse = response.content.find((b) => b.type === "tool_use");
if (!toolUse || toolUse.type !== "tool_use") return response.content;
const result = await session.execute(
toolUse.name,
toolUse.input as Record<string, unknown>
);
messages = [
...messages,
{ role: "assistant", content: response.content },
{
role: "user",
content: [
{
type: "tool_result",
tool_use_id: toolUse.id,
content: JSON.stringify(result),
},
],
},
];
}
};
// usage
const output = await runAgent(
"Send 'hello team' to #general on Slack",
session,
["slack"]
);