Football connector (Kickmesh)
This guide is for kickmesh-mcp 0.1.0, the server behind the Kickmesh Football Data + News MCP. It speaks the Model Context Protocol with the official TypeScript SDK, over stdio or Streamable HTTP, and calls API-Football v3. 14 data tools and 3 news tools. Sources: BBC Sport, Sky Sports, ESPN, The Guardian, The Independent, and CBS Sports.
Requirements
- Node.js on the host that runs
node dist/index.js. The Docker image uses Node 20 Alpine. - An API-Football key from the dashboard. The free plan is 100 requests a day.
- An MCP client that can launch a stdio server or connect to Streamable HTTP.
Install and build
From the kickmesh-mcp project directory:
npm install && npm run build
export API_FOOTBALL_KEY=your_key # free key: https://dashboard.api-football.com
npm start # stdio
npm run start:http # Streamable HTTP at http://localhost:3000/mcp
npm test # mocked tests, no key needednpm start runs stdio. npm run start:http passes --http. npm test runs mocked tests and does not need a key.
API key
Export API_FOOTBALL_KEY in the environment of the server process. The client sends it as the x-apisports-key header to https://v3.football.api-sports.io. A cache hit returns before the key is checked. A cold process has an empty cache, so the first real call needs the key. Bot Essentials does not issue keys and does not see yours.
stdio
With no --http flag and without MCP_TRANSPORT=http, the process connects a stdio transport and waits for a client. This is the right mode for a desktop app that starts the server itself.
Streamable HTTP
npm run start:http or MCP_TRANSPORT=http listens on PORT (default 3000). One API-Football client is shared for the life of the process, so cache and budget are process-wide. Each HTTP request builds its own MCP server object and a stateless Streamable HTTP transport (no session id).
/mcpaccepts MCP requests./healthresponds with the bodyok.- Any other path returns 404.
curl -s http://localhost:3000/healthTwo replicas do not share a counter. Each process would apply its own daily budget, which can outrun the real API-Football quota. Run one process unless you have a higher quota and a shared limit in front.
Client config
stdio clients that read an mcpServers map, including Claude Desktop, use a block like this. Replace the path with the absolute path to dist/index.js on that machine, and replace the key.
{
"mcpServers": {
"kickmesh-mcp": {
"command": "node",
"args": ["/absolute/path/to/kickmesh-mcp/dist/index.js"],
"env": { "API_FOOTBALL_KEY": "your_key" }
}
}
}For Streamable HTTP, point the client’s remote MCP setting at http://localhost:3000/mcp.
Docker
The Dockerfile is a multi-stage Node 20 Alpine build. It installs dependencies, compiles, prunes dev packages, then runs with NODE_ENV=production, MCP_TRANSPORT=http, and PORT=3000.
docker build -t kickmesh-mcp . && docker run -p 3000:3000 -e API_FOOTBALL_KEY=your_key kickmesh-mcpData tools
14 tools are registered today. Parameters are checked before a request. Search text is reduced to letters, numbers, and spaces, and it must leave at least 3 characters. API-Football mishandles search combined with other filters, so team and league search send the search alone and apply country or season on the client.
| Tool | API path | Parameters | Returns |
|---|---|---|---|
live_scores | fixtures | leagues (optional). League ids joined with '-', for example 39-140. The server sends this as the API live parameter, or live=all when leagues is omitted. | Live fixtures in progress, with an optional league filter. |
fixtures | fixtures | date (YYYY-MM-DD), league, team, season, from, to, next, last, status, timezone. The schema marks each one optional. Pass at least one filter. | Fixtures by date, league, team, or season. |
standings | standings | league (required), season (required, four-digit year such as 2024). | League table for a season. |
team_stats | teams/statistics | league, season, and team. All three are required. | Team statistics for one league season. |
player_stats | players | season (required). Optional: id, team, league, search, page. | Player statistics by id, team, or league, with an optional name search. |
lineups | fixtures/lineups | fixture (required). | Lineups for a fixture. |
events | fixtures/events | fixture (required). | Goals, cards, and substitutions in a fixture. |
transfers | transfers | player and team. Both are optional. | Transfers for a player or a team. |
injuries | injuries | league, season, team, fixture, and date. All are optional. | Injuries by league and season, team, fixture, or date. |
odds | odds | fixture, league, season, date, bookmaker, and bet. All are optional. | Pre-match odds. |
predictions | predictions | fixture (required). | API-Football predictions for a fixture. |
search_teams | teams | query (required, at least 3 letters or digits). country (optional). Country is matched locally after the search, case-insensitive, on the team country name. | Find teams by name. The API search is sent on its own. |
search_leagues | leagues | query (optional, at least 3 letters or digits when set), country, season. With a query, country and season are filtered locally. Without a query, country and season are sent to the API. | Find leagues and cups by name, or list them by country and season. |
api_budget | none | No parameters. This tool does not call API-Football. | Local daily and per-minute budget: day, used, remaining, dailyLimit, perMinuteLimit. |
News layer
latest_news, news_search, list_sources are shipped. They read RSS from BBC Sport, Sky Sports, ESPN, The Guardian, The Independent, and CBS Sports. Each item is a headline plus a short summary (2 sentences max), with source attribution and the original link. The tools never return full articles. News uses no API-Football requests.
latest_news— Latest items: a headline, a short summary (2 sentences max), source attribution, and the original link. Never a full article.news_search— Search headlines and short summaries. Each hit keeps source attribution and the original link, and is never a full article.list_sources— List the six RSS sources this connector reads, with each homepage.
Caching
The cache is an in-memory map keyed by the endpoint and a sorted query string. A hit skips the network and the budget. api_budget is not cached. The cache clears when the process exits.
| Cache key | TTL | Tool |
|---|---|---|
fixtures:live | 30 seconds | live_scores |
fixtures/events | 60 seconds | events |
fixtures | 5 minutes | fixtures |
fixtures/lineups | 10 minutes | lineups |
odds | 30 minutes | odds |
standings | 1 hour | standings |
teams/statistics | 1 hour | team_stats |
players | 1 hour | player_stats |
injuries | 1 hour | injuries |
predictions | 1 hour | predictions |
teams | 24 hours | search_teams |
leagues | 24 hours | search_leagues |
transfers | 24 hours | transfers |
Rate limits
The free plan is 100 requests a day. The local daily budget defaults to that number and the per-minute limit defaults to 10. The UTC date rolls the local day counter back to zero at 00:00 UTC.
- The per-minute check runs before a request is counted. It returns a
[budget]error. - The daily counter increments when a request is sent. A failed HTTP call still counts locally.
- After a response,
x-ratelimit-requests-remainingcan raise the local used count so it catches up with API-Football. - When the daily budget is exhausted, cached rows are still served.
Environment
- API_FOOTBALL_KEY
- Default: unset. Your API-Football key. Required when a call misses the cache. The server sends it as the x-apisports-key header.
- API_FOOTBALL_DAILY_LIMIT
- Default: 100. Local daily request budget. The default matches the free plan.
- API_FOOTBALL_PER_MINUTE_LIMIT
- Default: 10. Local cap on requests started in a rolling 60 seconds.
- API_FOOTBALL_BASE_URL
- Default: https://v3.football.api-sports.io. API root. Change it only if API-Football gives you another host.
- MCP_TRANSPORT
- Default: unset, which means stdio. Set to http to serve Streamable HTTP. The Docker image sets this for you.
- PORT
- Default: 3000. Port for Streamable HTTP. /mcp is the MCP path and /health returns ok.
Errors
Tool failures return isError: true and a text message. Budget failures are prefixed with [budget]. Other failures include a missing key, an HTTP status from API-Football, or an error payload from the API.
Tests
npm test in the connector project runs the mocked suite. It does not need API_FOOTBALL_KEY and it does not call API-Football.
Questions, bug reports and ideas for a template go to the contact page.
