How it works
- Paste a curl command: from the API's docs, your terminal, or your browser's dev tools (or convert one with the cURL converter).
- The generator turns path IDs, query parameters and JSON or form body fields into tool parameters, with types inferred from your example values.
- Rename the tool and improve the descriptions: that's what the model reads when deciding what to call.
- Copy the format you need: Claude, OpenAI, an MCP server, or just the handler.
Keep API keys away from the model
A model should never see your credentials: anything in its context can end up in its output. The generator spots Authorization and API-key headers, -u credentials and key-like query parameters (access_key, apikey, appid, token…), removes them from the schema and reads them from environment variables in the handler instead.
Use it with Claude
Pass the definition in tools. When Claude stops with stop_reason: "tool_use", run the handler for each tool_use block and send the results back as tool_result blocks, all in one message:
import Anthropic from "@anthropic-ai/sdk";
import { getForecast } from "./handler.js"; // the generated handler
const client = new Anthropic(); // reads ANTHROPIC_API_KEY
// Paste the "Claude (Anthropic)" definition from the generator here.
const tools: Anthropic.Beta.BetaTool[] = [/* … */];
const messages: Anthropic.Beta.BetaMessageParam[] = [
{ role: "user", content: "Do I need an umbrella in Lagos today?" },
];
while (true) {
const response = await client.beta.messages.create({
model: "claude-opus-5-5",
max_tokens: 16000,
tools,
messages,
// If a request is declined, retry it on a fallback model automatically.
betas: ["server-side-fallback-2026-07-01"],
fallbacks: "default",
});
messages.push({ role: "assistant", content: response.content });
if (response.stop_reason !== "tool_use") {
for (const block of response.content) if (block.type === "text") console.log(block.text);
break;
}
// Run every tool call, then send all results back in one message.
const results: Anthropic.Beta.BetaToolResultBlockParam[] = [];
for (const block of response.content) {
if (block.type !== "tool_use") continue;
try {
results.push({ type: "tool_result", tool_use_id: block.id, content: await getForecast(block.input) });
} catch (error) {
results.push({ type: "tool_result", tool_use_id: block.id, content: String(error), is_error: true });
}
}
messages.push({ role: "user", content: results });
}Use it with OpenAI
Pass the definition in the tools array. With the Responses API, each tool call arrives as a function_call item: run the handler with JSON.parse(item.arguments) and send back a function_call_output item with the same call_id. With Chat Completions, use the nested { type: "function", function: {...} } format and reply with a tool message.
Use it as an MCP server
Save the MCP server code as server.ts, install @modelcontextprotocol/sdk and zod, and add it to your MCP client. For Claude Desktop, add it to claude_desktop_config.json:
{
"mcpServers": {
"get-forecast": {
"command": "npx",
"args": ["tsx", "/absolute/path/to/server.ts"],
"env": { "OPEN_METEO_API_KEY": "only-if-the-api-needs-one" }
}
}
}In Claude Code: claude mcp add get-forecast -- npx tsx /absolute/path/to/server.ts. Browse existing MCP servers in the directory too.
Free APIs that make great AI tools
- Open-Meteo: weather forecasts, no key.
- REST Countries: country facts, currencies and languages.
- Nager.Date: public holidays for 100+ countries.
- Frankfurter: currency exchange rates.
- ipstack: IP geolocation, so an agent can localise answers (free plan with a key).
Find more in the APIs with no key list, and generate schemas for structured outputs with the JSON Schema generator.