Skip to content

Code examples

Working snippets for the three most common runtimes. All of them talk to the same hosted server (https://mcp.crank.ing/mcp) and get the same structured envelopes. Tool schemas are exported from one source — see the integration guide.

Install the SDK for your runtime first. These examples assume environment variables for any model-provider key; Crank itself needs no key to connect.

Claude

Claude speaks MCP natively. Point its remote MCP connector at the Crank server and it can discover and call every tool.

import anthropic

client = anthropic.Anthropic()  # ANTHROPIC_API_KEY in env

resp = client.beta.messages.create(
    model="claude-opus-4-8",
    max_tokens=1024,
    messages=[{
        "role": "user",
        "content": "What is the USDC quote for swapping 1 SOL? Use wallet <PUBKEY>.",
    }],
    mcp_servers=[{
        "type": "url",
        "url": "https://mcp.crank.ing/mcp",
        "name": "crank",
    }],
    betas=["mcp-client-2025-04-04"],
)
print(resp.content)

For a local agent, register the stdio transport instead (Claude Desktop / Claude Code mcpServers config):

{
  "mcpServers": {
    "crank": { "command": "python", "args": ["-m", "crank_mcp.server"] }
  }
}

The Claude Agent SDK can load the same server programmatically. When a tool returns an unsigned transaction, sign it in your process — never send a private key to the model or to Crank.

GPT (OpenAI function calling)

Feed the exported OpenAI tool definitions to the chat/responses API, then dispatch any tool call back to the Crank MCP server.

import json, httpx
from openai import OpenAI

oai = OpenAI()  # OPENAI_API_KEY in env

# 1. Tool defs exported from the Crank registry (scripts/export-tool-schemas.py
#    -> build/tool-schemas/openai.json), or fetch the hosted copy.
tools = json.load(open("build/tool-schemas/openai.json"))

resp = oai.chat.completions.create(
    model="gpt-4.1",
    messages=[{"role": "user", "content": "Get the SOL balance of <PUBKEY>."}],
    tools=tools,
)

# 2. Dispatch each tool call to the MCP server.
async def call_crank(name, args):
    from fastmcp import Client
    async with Client("https://mcp.crank.ing/mcp") as c:
        return await c.call_tool(name, {**args, "caller_id": "my-gpt-agent"})

for tc in resp.choices[0].message.tool_calls or []:
    out = await call_crank(tc.function.name, json.loads(tc.function.arguments))
    # feed `out` back as a tool result message, then continue the loop

A no-MCP alternative is to expose Crank as a GPT Action using the OpenAPI document (reference/openapi.json). Full REST route and the hosted dispatch endpoints: docs/integrations/openai.md.

Gemini

Gemini uses functionDeclarations. Use the exported Gemini block (it strips the schema keys Gemini rejects and expresses optional params as nullable).

import json
import google.generativeai as genai

genai.configure()  # GOOGLE_API_KEY in env

decls = json.load(open("build/tool-schemas/gemini.json"))  # {"functionDeclarations": [...]}
model = genai.GenerativeModel("gemini-2.5-pro", tools=[decls])

chat = model.start_chat()
resp = chat.send_message("Show open perp positions for <PUBKEY>.")

for part in resp.parts:
    fc = getattr(part, "function_call", None)
    if fc:
        out = await call_crank(fc.name, dict(fc.args))   # same dispatch as GPT
        # return the function response to the chat, then continue

Detailed REST route and hosted dispatch endpoints: docs/integrations/gemini.md.

LangChain / CrewAI

Both have native MCP tool loaders — point them at https://mcp.crank.ing/mcp and every tool is available as a structured tool. If you prefer not to use the MCP loader, the exported langchain.json gives you serializable StructuredTool definitions (name, description, args_schema) with no LangChain runtime dependency.

Crank SDKs

For a batteries-included path, use the dependency-free Crank SDKs (crank-sdk for Python, @crank/sdk for TypeScript) or scaffold a starter with create-crank-agent. See docs/integrations/sdk.md.

The signing rule (every runtime)

Value-bearing tools return an unsigned transaction. Whatever the runtime:

  1. Read the unsigned transaction from the ok envelope.
  2. Sign it locally with the agent's key.
  3. Broadcast it (or pass it back via the tool's signed_transaction argument).

The model never sees a private key, and Crank never holds one. See Authentication & x402.