Use this when you're building a custom agent with the Anthropic SDK and want to pass Vlozi tools to Claude's tool_use. If you just want Vlozi inside Claude Desktop or Claude Code, see the MCP clients page instead — those clients speak MCP natively.
The pattern
Every turn:
- Fetch the tool list from
GET /tools - Pass it to Claude as
tools - When Claude returns a
tool_useblock, callPOST /tools/<name>and feed the result back astool_result
Example (TypeScript)
import Anthropic from "@anthropic-ai/sdk";
const VLOZI_KEY = process.env.VLOZI_API_KEY!;
const MCP = "https://mcp.vlozi.app";
const anthropic = new Anthropic();
async function listVloziTools() {
const r = await fetch(`${MCP}/tools`, {
headers: { Authorization: `Bearer ${VLOZI_KEY}` },
});
const { data } = await r.json();
// Claude doesn't allow "." in tool names — map blog.list_posts ↔ blog_list_posts
return data.tools.map((t: any) => ({
name: t.name.replace(".", "_"),
description: t.description,
input_schema: t.inputSchema,
}));
}
async function callVloziTool(name: string, input: Record<string, unknown>) {
const r = await fetch(`${MCP}/tools/${name.replace("_", ".")}`, {
method: "POST",
headers: {
Authorization: `Bearer ${VLOZI_KEY}`,
"content-type": "application/json",
"x-agent-id": "my-custom-agent",
},
body: JSON.stringify(input),
});
return r.json();
}
async function runAgent(prompt: string) {
const tools = await listVloziTools();
const messages: Anthropic.MessageParam[] = [{ role: "user", content: prompt }];
while (true) {
const res = await anthropic.messages.create({
model: "claude-sonnet-4-6",
max_tokens: 4096,
tools,
messages,
});
if (res.stop_reason !== "tool_use") return res.content;
const toolResults: Anthropic.ToolResultBlockParam[] = [];
for (const block of res.content) {
if (block.type === "tool_use") {
const result = await callVloziTool(block.name, block.input as any);
toolResults.push({
type: "tool_result",
tool_use_id: block.id,
content: JSON.stringify(result),
});
}
}
messages.push({ role: "assistant", content: res.content });
messages.push({ role: "user", content: toolResults });
}
}
await runAgent("Show my last 3 published posts and write a LinkedIn summary.");The Python pattern is identical — replace SDK imports with anthropic.Anthropic(); the structures map 1-to-1.
Tips
- Tool name dots: Claude's
tool_usedoesn't allow.in names. Mapblog.list_posts↔blog_list_posts. - Filter tools per turn: Don't pass all 14 every call — Claude picks better with 3–6 relevant tools.
- Set
x-agent-id: A stable per-agent string ("ops-bot", "content-bot") shows up in your audit log. - Cache the tool list: Stable for the lifetime of an API key's scopes. Cache for an hour.