Skip to content

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 serves, so it never lags behind it. A copy also lives at https://getchord.xyz/agent/tools.json.

Terminal window
curl -s https://api.getchord.xyz/v1/mcp/tools.json | jq '{base_url, mcp, auth, tools: [.tools[].function.name]}'
{
"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"]
}

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.

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 lists the route of every capability on every chain.

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.

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. Every operation has an operationId, a summary a model can read, and examples.