MCP servers with the exchange
Use any model on the exchange with the tools of an MCP server. An MCP client lists the tools of a server, lets a model choose a tool, and runs it. The exchange accepts OpenAI tool definitions, so the client converts each MCP tool to that format and sends it with the request.
To give an agent the tools of the exchange itself, see the Liquid MCP server.
Before you start
-
A workspace with a balance and a
spendkey. See API keys. -
The key exported in your shell:
export LIQUID_API_KEY=sk-liquid-...
1. Install the packages
# Python 3.10 or later, and Node.js for the example server
pip install mcp openai
The example server needs Node.js.
2. Run the tool loop
This client starts a local file server, sends its tools with each request, and runs every tool call that the model returns. It stops when the model answers without a tool call.
import asyncio
import json
import os
from mcp import ClientSession, StdioServerParameters
from mcp.client.stdio import stdio_client
from openai import AsyncOpenAI
client = AsyncOpenAI(
base_url="https://router.inference.ai.exchange/v1",
api_key=os.environ["LIQUID_API_KEY"],
default_headers={"X-Title": "MCP", "x-liquid-cap-usd": "0.05"},
)
server = StdioServerParameters(
command="npx",
args=["-y", "@modelcontextprotocol/[email protected]", os.getcwd()],
)
def to_openai_tool(tool):
return {
"type": "function",
"function": {
"name": tool.name,
"description": tool.description or "",
"parameters": tool.input_schema,
},
}
async def main(question):
async with stdio_client(server) as (read, write):
async with ClientSession(read, write) as session:
await session.initialize()
tools = [to_openai_tool(t) for t in (await session.list_tools()).tools]
messages = [{"role": "user", "content": question}]
for _ in range(8):
response = await client.chat.completions.create(
model="liquid.auto", messages=messages, tools=tools
)
reply = response.choices[0].message
messages.append(reply.model_dump(exclude_none=True))
if not reply.tool_calls:
print(reply.content)
return
for call in reply.tool_calls:
result = await session.call_tool(
call.function.name, json.loads(call.function.arguments)
)
text = "\n".join(p.text for p in result.content if p.type == "text")
messages.append({"role": "tool", "tool_call_id": call.id, "content": text})
asyncio.run(main("List the files in this directory."))
What it costs
Each request is a separate auction, and each has its own charge. The x-liquid-cap-usd header limits the charge of one request. See Purchasing rules.
The loop sends the whole conversation with each request. The exchange charges for every input token. Keep tool results short.
Change the model
Choose another model, router model or preset from GET /v1/models. The model must support tools. See Market data.
Notes
- A remote MCP server needs
streamable_http_clientfrommcp.client.streamable_httpin place ofstdio_client. The rest of the loop does not change. - MCP 2.0 renamed
inputSchematoinput_schemaon a tool. Code for MCP 1.x that readsinputSchemafails on 2.x.