Skip to content

AI Tool & MCP Server Generator

Paste a curl command for any API and get a tool your AI agent can call: a function-calling definition for OpenAI or Claude, a complete MCP server, and the handler that makes the real request. Credentials stay out of the model's view.

Tool details · good descriptions matter more than anything else

ParameterTypeSent inRequiredDescription for the model
latitudenumberquery
longitudenumberquery
currentstringquery
timezonestringquery
{
  "name": "get_forecast",
  "description": "Forecast via GET api.open-meteo.com/v1/forecast. Edit this to say what the tool does and when to use it.",
  "input_schema": {
    "type": "object",
    "properties": {
      "latitude": {
        "type": "number",
        "description": "Latitude. Example: 6.45"
      },
      "longitude": {
        "type": "number",
        "description": "Longitude. Example: 3.39"
      },
      "current": {
        "type": "string",
        "description": "Current (comma-separated). Example: temperature_2m,precipitation"
      },
      "timezone": {
        "type": "string",
        "description": "Timezone. Example: Africa/Lagos"
      }
    },
    "required": [
      "latitude",
      "longitude",
      "current",
      "timezone"
    ]
  }
}

Converted in your browser. Nothing you paste (including API keys) is sent anywhere or saved.

How it works

  1. Paste a curl command: from the API's docs, your terminal, or your browser's dev tools (or convert one with the cURL converter).
  2. The generator turns path IDs, query parameters and JSON or form body fields into tool parameters, with types inferred from your example values.
  3. Rename the tool and improve the descriptions: that's what the model reads when deciding what to call.
  4. 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:

TypeScript
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:

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

Find more in the APIs with no key list, and generate schemas for structured outputs with the JSON Schema generator.

Frequently asked questions

What is function calling (tool use)?

It's how AI models use external APIs. You describe a function (its name, what it does, and its parameters as a JSON Schema). When the model decides it needs it, it replies with the arguments; your code makes the real API call and sends the result back, and the model uses it in its answer.

What is an MCP server?

The Model Context Protocol is an open standard for giving AI apps tools. An MCP server exposes tools once, and any MCP client (Claude Desktop, Claude Code, Cursor, VS Code and many others) can use them without provider-specific code. The generator writes a complete TypeScript MCP server for your API.

Do OpenAI and Claude need different tool definitions?

Only the wrapper differs. Both use JSON Schema for parameters: Claude calls it input_schema, OpenAI calls it parameters, and OpenAI's Chat Completions API nests everything under a function key. The generator writes each format from the same request.

Is my API key safe?

The conversion runs in your browser and nothing is sent anywhere. In the generated code, credentials (Authorization headers, -u, and key-like query parameters such as access_key or apikey) are read from environment variables and left out of the schema, so the model never sees them and can't leak or invent them.

Why does the tool description matter so much?

The model chooses which tool to call, and with which arguments, almost entirely from the names and descriptions. Say what the tool does, when to use it, and what each parameter means and accepts (units, formats, allowed values). It's the single biggest factor in how reliably the tool is used.

More free developer tools