cookbook

Real examples.

Four self-contained code examples for calling OpenScores: raw cURL against the MCP HTTP endpoint, the Anthropic Python SDK, the Anthropic TypeScript SDK, and an end-to-end ~50-line match- report agent. Copy any block, replace osk_live_YOUR_KEY_HERE with the key you minted on /account, and run.

Last updated: 12 Jun 2026

cURL — raw MCP HTTP

The MCP server speaks JSON-RPC 2.0 over Streamable HTTP. This is the lowest-level path — no SDK, no library. Useful when you're debugging a client integration or want to confirm a key is live.

bash
# Call list_leagues over raw MCP HTTP.
# Replace osk_live_YOUR_KEY_HERE with the key you minted on /account.

curl https://api.openscores.ai/mcp/ \
  -H "Authorization: Bearer osk_live_YOUR_KEY_HERE" \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "id": 1,
    "method": "tools/call",
    "params": {
      "name": "list_leagues",
      "arguments": {}
    }
  }'

Returns a JSON list of every league in the database. To list tools instead, replace tools/call with tools/list and drop the params field.

Python · Anthropic SDK

Most agent workflows live here. The Anthropic Python SDK connects to MCP servers directly — no separate MCP-client package needed. Claude decides which tool to call from the user prompt.

python
# Ask Claude a football question. The SDK handles MCP discovery,
# tool selection, and the back-and-forth automatically.

from anthropic import Anthropic

client = Anthropic()

response = client.beta.messages.create(
    model="claude-sonnet-4-5",
    max_tokens=1024,
    mcp_servers=[
        {
            "type": "url",
            "url": "https://api.openscores.ai/mcp/",
            "name": "openscores",
            "authorization_token": "osk_live_YOUR_KEY_HERE",
        }
    ],
    messages=[
        {
            "role": "user",
            "content": "Which World Cup teams haven't lost a match yet?",
        }
    ],
)

for block in response.content:
    if block.type == "text":
        print(block.text)

Requires pip install anthropic. Set ANTHROPIC_API_KEY in your env.

TypeScript · Anthropic SDK

Same flow as Python, JS ecosystem. Drop into a Next.js API route or a long-running Node server.

typescript
// Same flow in TypeScript. Drop into a Next.js Route Handler or a
// standalone Node script.

import Anthropic from "@anthropic-ai/sdk";

const client = new Anthropic();

const response = await client.beta.messages.create({
  model: "claude-sonnet-4-5",
  max_tokens: 1024,
  mcp_servers: [
    {
      type: "url",
      url: "https://api.openscores.ai/mcp/",
      name: "openscores",
      authorization_token: "osk_live_YOUR_KEY_HERE",
    },
  ],
  messages: [
    {
      role: "user",
      content: "Top scorer in La Liga this season?",
    },
  ],
});

for (const block of response.content) {
  if (block.type === "text") {
    console.log(block.text);
  }
}

Requires npm i @anthropic-ai/sdk.

End-to-end: match-report agent

A complete script that picks the most recent finished fixture in the World Cup, pulls lineups + events + stats with get_fixture, then asks Claude to write a 200-word match report. Reproducible end to end.

python
# Match-report agent — picks the most recent finished WC fixture
# and writes a 200-word recap. ~50 lines, end to end.

from anthropic import Anthropic

client = Anthropic()

MCP_SERVER = {
    "type": "url",
    "url": "https://api.openscores.ai/mcp/",
    "name": "openscores",
    "authorization_token": "osk_live_YOUR_KEY_HERE",
}

response = client.beta.messages.create(
    model="claude-sonnet-4-5",
    max_tokens=2048,
    mcp_servers=[MCP_SERVER],
    messages=[
        {
            "role": "user",
            "content": (
                "Find the most recent finished fixture in the 2026 World Cup. "
                "Use get_fixture to pull lineups, the event timeline, and "
                "statistics. Write a 200-word match report in the voice of a "
                "BBC Sport correspondent: lead with the scoreline, mention "
                "the goalscorers in chronological order, name the key VAR "
                "moments if any, end with the standout performer."
            ),
        }
    ],
)

# The SDK already executed the tool calls; the final assistant message
# carries the rendered report.
report = "".join(
    block.text for block in response.content if block.type == "text"
)
print(report)

The script makes one tool call to find the fixture, one to fetch its detail, and one Claude completion to write the report. ~50 lines, runs in <5 seconds end to end.

Got a different stack? Share what you build.