# Function calling

> The Chord agent tools as an OpenAI-style JSON Schema manifest, always current, for any framework that takes a tool list.

Source: https://getchord.xyz/docs/agents/function-calling/

`https://api.getchord.xyz/v1/mcp/tools.json` is the tool set as JSON Schema: a `tools` array in the OpenAI function format, the `base_url`, the MCP endpoint and the `auth` header. It is public, needs no install, and is printed from the same list the [hosted MCP server](/docs/agents/mcp/) serves, so it never lags behind it. A copy also lives at `https://getchord.xyz/agent/tools.json`.

```bash
curl -s https://api.getchord.xyz/v1/mcp/tools.json | jq '{base_url, mcp, auth, tools: [.tools[].function.name]}'
```

```json
{
  "base_url": "https://api.getchord.xyz",
  "mcp": "https://api.getchord.xyz/v1/mcp",
  "auth": { "header": "X-API-Key", "required": false },
  "tools": ["chord_chains", "chord_status", "chord_overview", "chord_tokens", "chord_search", "chord_token", "chord_trades", "chord_candles", "chord_wallet", "chord_wallet_trades", "chord_smart_money", "chord_holders", "chord_lp_pools", "chord_lp_positions", "chord_quote", "chord_swap_tx", "chord_ask"]
}
```

## A minimal loop

Hand `tools` to the model. When it returns a tool call, send that call to the MCP endpoint as one JSON-RPC message and give the text back to the model. No MCP library is needed: it is one POST.

```ts
const manifest = await fetch("https://api.getchord.xyz/v1/mcp/tools.json").then((r) => r.json());
const tools = manifest.tools; // OpenAI format: { type: "function", function: { name, description, parameters } }

async function runChordTool(name: string, args: object) {
  const res = await fetch(manifest.mcp, {
    method: "POST",
    headers: { "content-type": "application/json", ...(process.env.CHORD_API_KEY ? { "X-API-Key": process.env.CHORD_API_KEY } : {}) },
    body: JSON.stringify({ jsonrpc: "2.0", id: 1, method: "tools/call", params: { name, arguments: args } }),
  }).then((r) => r.json());
  return res.result.content[0].text; // JSON text: { chain, route, data }; res.result.isError marks a tool-level error
}

// 1. ask the model with the tools attached
// 2. for each tool_call the model returns:
for (const call of message.tool_calls) {
  const result = await runChordTool(call.function.name, JSON.parse(call.function.arguments));
  messages.push({ role: "tool", tool_call_id: call.id, content: result });
}
// 3. ask the model again with the tool results
```

Every data tool takes a `chain` (`monad`, `robinhood`, `arc`, `avalanche`, `base`, `bnb`, `arbitrum`, `ethereum`, `solana`). To default one, POST to `https://api.getchord.xyz/v1/mcp?chain=arc` instead. Tools take addresses and integer amounts in the token's smallest unit; `chord_search` turns a symbol into an address, and the token's `decimals` come back with it.

Each answer names the REST `route` that produced it. If you would rather call REST yourself, [`GET /v1/chains`](/docs/api-reference/) lists the route of every capability on every chain.

## The trading pair

`chord_quote` returns the route, the expected output and a `quoteId`; `chord_swap_tx` returns the unsigned transaction for that `quoteId` and a taker, with the approval it needs and a simulation. Both work on the eight EVM chains; Solana swaps are REST only (`/v1/sol/trade/*`). The model proposes; your code signs, or shows the user what would be signed. Never let a model hold a key.

## Direct REST as tools

For a framework that generates tools from an OpenAPI document (LangChain's OpenAPI toolkit, an OpenAI Actions schema, a Gemini extension), point it at [openapi.json](/docs/openapi.json). Every operation has an `operationId`, a summary a model can read, and examples.
