Model Context Protocol
Connect GreyhoundAPI to Claude or ChatGPT and ask in plain English. Twenty-three tools over real GB and Australian racing — cards, results, form, sectionals, prices and trainer records. Your key, your data, no code.
Connect it
The server is hosted — nothing to install and nothing to run. Six fields, and one of them catches people out, so it is called out below.
gapi_test_ and reaches 7 of the tools straight away.
Greyhound API is fine. The URL is
https://greyhoundapi.com/mcp
x-api-key
with your key as the value. This is what identifies you; it is stored securely by
Claude and never shown again.
https://greyhoundapi.com/mcpx-api-keygapi_test_… or gapi_live_…Other MCP clients work the same way: the address above, and your key in an
x-api-key header. Authorization: Bearer is accepted too, for
clients that only offer that.
Then ask it something. No prompt engineering — the tools describe themselves, so the assistant picks the right one: “What won the 19:28 at Monmore on Tuesday?” · “Show me A Bad Winter’s last six runs.”
The tools
Curated on purpose. A model given every endpoint chooses badly; these map to the questions people actually ask. The full REST API is still there for anything else.
todays_racecardsFree keyEvery race card scheduled today across Great Britain and Australia, with runners, trap draws and scheduled off times.
arguments region, track_id, grade, distance_m, summary
required none
upcoming_racesFree keyRaces due off shortly, nearest first. Use this for "what is running next".
arguments hours, region, track_id, grade, limit
required none
latest_resultsFree keyThe most recently settled races, newest first, with finishing order and times.
arguments since, region, limit
required none
find_racesFree keySearch the race archive by date range, region, track, grade, distance or status. The general-purpose way to locate races.
arguments ids, date_from, date_to, region, track_id
required none
get_raceFree keyOne race in full: conditions, going, distance, grade and its runners.
arguments race_id
required race_id
get_race_resultLiveThe finishing order for one race, with times, sectionals and starting prices where published. Requires a Live key.
arguments race_id
required race_id
dog_layoffLive PlusHow a greyhound has run after different lengths of time off, beside how greyhounds generally run after the same break. Rates are suppressed where the dog has too few runs; counts are always shown. Requires a Live Plus key.
arguments dog_id
required dog_id
dog_trendLive PlusWhether a greyhound is running quicker or slower lately, each run measured against par for that track and distance, with the change shown beside the dog's own run-to-run variation so noise is not mistaken for a trend. Requires a Live Plus key.
arguments dog_id, track_id, distance_m, window
required dog_id
meeting_analysisLive PlusA whole card as one unit: how fast the track actually ran against par for each distance, and whether the published going agreed. Trap wins are counts only — a single card cannot show bias. Requires a Live Plus key.
arguments meeting_id
required meeting_id
race_precedentsLive PlusRaces from the archive that ran under matching conditions at this track and distance, with what happened in them. Each row says what it matched on and where it differs. History, never a forecast. Requires a Live Plus key.
arguments race_id, limit
required race_id
race_fieldLive PlusEvery runner in one race with its record at this track and trip, its grade record, days since it last ran and how it has run off that break, beside the strike rate of the trap it has drawn. Replaces a call per runner per measure. Measurements only, never a forecast; runners short of history are named, not omitted. Requires a Live Plus key.
arguments race_id
required race_id
race_analysisLive PlusConditions and early pace for one race in a single call, joined per runner — trap record, winning times, field experience and each runner's early split with its sample size. Measurements only, never a forecast. Requires a Live Plus key.
arguments race_id
required race_id
race_paceLive PlusEach runner's measured early split from past runs at this track and distance, with the run count behind every figure. Runners with too little data are named, not omitted. Measurements only, never a forecast. Requires a Live Plus key.
arguments race_id
required race_id
race_conditionsLive PlusThe context one race runs in: trap strike rates at this track and distance, typical winning time, and how experienced the field is. Every figure carries its sample size. Historical context, never a forecast. Requires a Live Plus key.
arguments race_id
required race_id
get_race_marketLiveMarket data for one race: each runner's starting price and the best Betfair back and lay prices taken seconds before the off. Factual prices only, never a prediction. Requires a Live key.
arguments race_id
required race_id
find_dogLiveFind a greyhound by name. Use this first when someone names a dog, to get its dog_id. Requires a Live key.
arguments ids, name, sire, dam, sex
required none
get_dog_formLiveA greyhound's recent runs — the form line: date, track, distance, grade, finishing position, time and price. Requires a Live key.
arguments dog_id, limit
required dog_id
compare_dogsLiveEvery time two greyhounds have met, with how each finished. Needs both dog ids. Requires a Live key.
arguments dog_id, rival_id
required dog_id, rival_id
dog_statisticsLive PlusA greyhound's record split by distance, track, trap, grade and going — what tends to happen rather than what happened once. Requires a Live Plus key.
arguments dog_id, track_id, distance_m
required dog_id
find_trainerLiveFind a trainer by name to get their trainer_id. Requires a Live key.
arguments name, limit
required name
trainer_statisticsLive PlusA trainer's strike rate split by track, distance, trap and grade over a rolling window. Requires a Live Plus key.
arguments trainer_id, months, track_id
required trainer_id
list_tracksFree keyEvery track covered, with region and the distances raced there.
arguments ids, region
required none
track_statisticsFree keyTrap bias and winning-time distribution for a track, by distance.
arguments track_id
required track_id
In practice
You do not name the tool. You ask the question, and the assistant works out which of the 23 to call and how to fill it in. These are real questions and the tools they trigger.
What won the 19:28 at Monmore on Tuesday?
find_races → get_race_result
Resolves the meeting and time to a race, then reads the finishing order, times and SPs.
Show me A Bad Winter’s last six runs.
find_dog → get_dog_form
Looks the name up to get an id first, then pulls the form line. You never see the two-step.
Which trap wins most over 575m at Romford?
list_tracks → track_statistics
Trap bias by distance, straight from the archive rather than a rule of thumb.
Have these two dogs ever met?
find_dog ×2 → compare_dogs
Two lookups then the head-to-head record, with how each finished every time.
Who is running tonight at Sheffield?
todays_racecards
Tonight’s card with runners, trap draws and scheduled off times.
How has this trainer done over the last three months?
find_trainer → trainer_statistics
Strike rate split by track, distance, trap and grade over a rolling window.
The chaining is the point. Nearly every useful question needs a name turned into an id first. Writing that yourself is two API calls and some error handling; here the assistant does it because the tool descriptions tell it to.
How it works
The Model Context Protocol is JSON-RPC 2.0 over HTTP. Worth understanding if you are going to build on it, and reassuring if you are wondering what your assistant is sending us.
initializeOn connecting, the client asks what protocol we speak and what we are. We answer with a short brief telling the model this is factual race data, that names must be resolved to ids first, and that dates are the track’s own calendar date.
tools/listThe client asks what it can do. It gets 23 tools, each with a JSON Schema for its arguments — types, which are required, and an example value. This is generated from the same registry that builds our documentation, so it cannot drift.
tools/callWhen your question needs data, the model picks a tool and fills in the arguments. We forward that to the REST API with your key, and hand back the JSON plus a line of context — how fresh it is, what was truncated, or why a list came back empty.
# see it yourself — no key needed to list the tools curl -X POST https://greyhoundapi.com/mcp \ -H "Content-Type: application/json" \ -d '{"jsonrpc":"2.0","id":1,"method":"tools/list"}' # and a real call, with your key curl -X POST https://greyhoundapi.com/mcp \ -H "Content-Type: application/json" \ -H "X-API-Key: $GAPI_KEY" \ -d '{"jsonrpc":"2.0","id":2,"method":"tools/call", "params":{"name":"list_tracks","arguments":{"region":"GB"}}}'
From your own code
A chat window is the quickest way in, not the only one. Any model runtime that speaks MCP can use this, and what you build on top is yours.
Pass the server in tools with type: "mcp". OpenAI fetches the
tool list itself, then calls whatever the model chooses. Your key travels in
headers on every request.
from openai import OpenAI client = OpenAI() resp = client.responses.create( model="gpt-4.1", tools=[{ "type": "mcp", "server_label": "greyhoundapi", "server_url": "https://greyhoundapi.com/mcp", "headers": {"x-api-key": os.environ["GAPI_KEY"]}, "require_approval": "never", }], input="Which trap wins most over 575m at Romford?", ) print(resp.output_text)
Narrow what the model sees with allowed_tools if you only want
a few. Note that OpenAI does not retain your headers between requests, so the key goes on
every call.
There is no SDK to install. It is one HTTP endpoint and three methods, so a client is about fifteen lines in any language.
import requests, os URL = "https://greyhoundapi.com/mcp" H = {"X-API-Key": os.environ["GAPI_KEY"]} def rpc(method, params=None, _id=[0]): _id[0] += 1 r = requests.post(URL, headers=H, json={ "jsonrpc": "2.0", "id": _id[0], "method": method, "params": params or {}, }) return r.json() tools = rpc("tools/list")["result"]["tools"] out = rpc("tools/call", { "name": "get_dog_form", "arguments": {"dog_id": 655044}, }) print(out["result"]["content"][0]["text"])
Hand tools to whichever model you like as its function
definitions — the schemas are already in the right shape.
Claude, in the app. No code at all — add it
as a custom connector with the four fields above. Anthropic’s API
also accepts remote MCP servers through its mcp_servers parameter if you are
building rather than chatting; their documentation has the current shape.
Make it yours
Most clients let you restrict which tools a model can see. A form-analysis assistant might
only need find_dog, get_dog_form and dog_statistics;
a results bot needs latest_results and nothing else. Fewer tools means better
choices and fewer wasted calls.
Nothing stops you running your own MCP server that calls this one, adds your own tools, and presents a single surface to your team — your database alongside our racing data. The REST API is there for anything the 23 tools do not cover.
The reason this is worth doing at all: somebody who would never write a script can ask a question and get an answer out of the archive. No spreadsheet exports, no asking a developer, no waiting.
Working out whether the data suits you takes minutes in a chat window instead of an afternoon of throwaway code. The response shapes are identical to the REST API, so nothing you learn is wasted when you do build properly.
What it is and is not
Every tool call goes through the same API as any other client, with your key. The same rate limits, the same quota, the same tier scope. Nothing is bypassed, and MCP usage appears in your dashboard alongside everything else.
This returns factual race data — results, times, form and published prices. It contains no predictions, ratings or selections, and the server tells the assistant so. If a model offers you a tip from this, that is the model, not us.