# German Football MCP Server (`mrbridge/german-football-mcp`) Actor

German football MCP server for Claude, ChatGPT and Cursor. League tables, fixtures, results, top scorers and goal-by-goal records from the Bundesliga down to the Regionalliga, plus women's football and the cup, with head-to-head history and seasons back to the early 2000s. Data: OpenLigaDB, ODbL.

- **URL**: https://apify.com/mrbridge/german-football-mcp.md
- **Developed by:** [MrBridge](https://apify.com/mrbridge) (community)
- **Categories:** MCP servers, AI, Sports
- **Stats:** 1 total users, 0 monthly users, 0.0% runs succeeded, 0 bookmarks
- **User rating**: No ratings yet

## Pricing

from $3.00 / 1,000 read operations

This Actor is paid per event and usage. You are charged both the fixed price for specific events and for Apify platform usage.
Since this Actor supports Apify Store discounts, the price gets lower the higher subscription plan you have.

Learn more: https://docs.apify.com/actors/running/actors-in-store.md#pay-per-event

## What's an Apify Actor?

An Actor is a serverless cloud program that runs on the Apify platform. It has two run modes.
In Batch mode, an Actor accepts a well-defined JSON input, performs an action which can take anything from a few seconds to a few hours,
and optionally produces a well-defined JSON output, datasets with results, or files in key-value store.
In Standby mode, an Actor provides a web server which can be used as a website, API, or an MCP server.

Apify vocabulary and the platform model are defined once, in the agent quickstart at https://apify.com/agents.md.

## How to integrate an Actor?

If asked about integration, you help developers integrate Actors into their projects.
You adapt to their stack and deliver integrations that are safe, well-documented, and production-ready.

Do not guess an integration path. Every one of them is in the agent quickstart at https://apify.com/agents.md: the Apify MCP server, Agent Skills with the Apify CLI, the JavaScript and Python clients, the REST API, and the account-free path for an agent with no human to sign in. It also carries the rule on stating cost before the first paid run.

For examples already wired to this Actor's own input schema, see the [API](#api) section below.

Each client library has reference documentation the quickstart does not restate: [JavaScript/TypeScript](https://docs.apify.com/api/client/js/docs.md) (`npm install apify-client`) and [Python](https://docs.apify.com/api/client/python/docs.md) (`pip install apify-client`).

# README

## ⚽ German Football MCP Server

Give Claude, ChatGPT, Cursor, VS Code or any MCP client the league tables and fixtures of German football, with results and scorers, from the Bundesliga down to the Regionalliga. This MCP server reads OpenLigaDB, a community-run results database under an open licence, through 10 read-only tools. Women's football, the cup, national teams and European cups are in too.

Ask "how did Hamburg do in their last five matches, and who scored?" and your assistant calls `sport_get_team_matches`, then `sport_get_match`. You get each result with its half-time score, the scorers and their minutes, plus the next fixture. Data from OpenLigaDB (www.openligadb.de), licensed under ODbL 1.0.

### Quick start

1. Copy your Apify API token from [Apify Console > Settings > API & Integrations](https://console.apify.com/settings/integrations).
2. Point your MCP client at `https://mrbridge--german-football-mcp.apify.actor/mcp` with that token, as a Bearer header or as `?token=` in claude.ai and ChatGPT ([Connect](#connect) has every recipe).
3. Ask in plain language.

### What this server exposes

This server reads fixtures, results, league tables, top scorers and goal records from OpenLigaDB, a community-run sports results database, through its public JSON API. It has 10 read-only tools: a competition finder, the clubs of a competition, the league table, the top scorers, one matchday, the rounds of a season, the matches of a season with filters, a club's recent and upcoming matches across competitions, one match in full (goals, scorers, minutes, half-time score, venue, attendance) and the head-to-head record of two clubs. Coverage follows what the OpenLigaDB community maintains: German football from the Bundesliga down to the Regionalliga, the Frauen-Bundesliga, the DFB-Pokal, the national teams, European cups, DEL ice hockey, PDC darts and many smaller leagues, for the current season and earlier ones. It needs no API key and no account. Every answer carries the OpenLigaDB credit and the ODbL licence.

### Tools

| Tool | What it answers | Billed event |
|---|---|---|
| `sport_list_leagues` | Find competitions and their shortcuts | `tool-read` |
| `sport_list_teams` | List the teams of a competition | `tool-read` |
| `sport_get_standings` | Get the league table | `tool-read` |
| `sport_get_top_scorers` | Get the top scorers of a competition | `tool-read` |
| `sport_get_matchday` | Get the matches of a matchday | `tool-read` |
| `sport_list_matchdays` | List the rounds of a season | `tool-read` |
| `sport_get_season_matches` | Get the matches of a season | `tool-read` |
| `sport_get_team_matches` | Get a club's recent and upcoming matches | `tool-read` |
| `sport_get_match` | Get one match in full | `tool-action` |
| `sport_get_head_to_head` | Get the head-to-head record of two clubs | `tool-action` |

#### `sport_list_leagues`: Find competitions and their shortcuts

Use this when you need the shortcut of a competition before asking for its table, matches, teams or scorers, or want to know which competitions OpenLigaDB covers in a season: German football from the Bundesliga down to the Regionalliga, the Frauen-Bundesliga, the DFB-Pokal, European cups, national teams, DEL ice hockey, PDC darts and many community leagues. The main competitions are flagged `featured` and listed first, because many community and test leagues reuse their names. Do not use for teams, tables or results (use sport_list_teams, sport_get_standings, sport_get_matchday). Parameters: `query` (words to find in the name or shortcut, e.g. "Pokal"), `sport` (sport name, English or German, or sport id, e.g. "football", "Eishockey"), `season` (year the season starts, e.g. 2026, default the current season), `limit` (1-100, default 25), `offset`, `response_format` ("concise" default, "detailed" adds each league's sport and the sports facet). Sport names are German and chosen by the community (darts tournaments are filed under "Test").

| Parameter | Type | Required | Example |
|---|---|---|---|
| `query` | string | no | `"Pokal"` |
| `sport` | string | no | `"football"` |
| `season` | integer | no | `2026` |
| `limit` | integer | no | `25` |
| `offset` | integer | no | `0` |
| `response_format` | "concise" or "detailed" | no | `"concise"` |

Returns `{ season, season_defaulted, leagues[], sports[], pagination, attribution }`. Upstream: OpenLigaDB. Cache: daily (1 day). Read-only.

#### `sport_list_teams`: List the teams of a competition

Use this when you need the clubs taking part in a competition in one season, or the numeric team_id of a club for sport_get_team_matches or sport_get_head_to_head. Team ids are stable across seasons and competitions. Do not use for the table (use sport_get_standings) or for finding a competition shortcut (use sport_list_leagues). Parameters: `league` (shortcut, e.g. "bl1"), `season` (year the season starts, e.g. 2026, default the current season), `query` (words to find in the club name, e.g. "Borussia"), `limit` (1-100, default 50), `offset`, `response_format` ("concise" default with id and name, "detailed" adds short name and group).

| Parameter | Type | Required | Example |
|---|---|---|---|
| `league` | string | yes | `"bl1"` |
| `season` | integer | no | `2026` |
| `query` | string | no | `"Borussia"` |
| `limit` | integer | no | `50` |
| `offset` | integer | no | `0` |
| `response_format` | "concise" or "detailed" | no | `"concise"` |

Returns `{ league, season, season_defaulted, teams[], pagination, attribution }`. Upstream: OpenLigaDB. Cache: intraday (5 minutes). Read-only.

#### `sport_get_standings`: Get the league table

Use this when you need the table of a league in a season: position, played, won, drawn and lost matches, goals for and against, goal difference and points, for example the current Bundesliga, 3. Liga or DEL table, or the final table of an earlier season. Positions follow OpenLigaDB's order, which applies the league's tie-breakers. If that list is not ordered by points, this server sorts it on points, goal difference and goals scored. Do not use for knockout cups (use sport_get_matchday), for top scorers (use sport_get_top_scorers) or for live scores. Parameters: `league` (shortcut, e.g. "bl1"), `season` (year the season starts, e.g. 2026, default the current season), `limit` (1-100, default 50), `offset`, `response_format` ("concise" default, "detailed" adds short names, goals for and goals against).

| Parameter | Type | Required | Example |
|---|---|---|---|
| `league` | string | yes | `"bl1"` |
| `season` | integer | no | `2026` |
| `limit` | integer | no | `50` |
| `offset` | integer | no | `0` |
| `response_format` | "concise" or "detailed" | no | `"concise"` |

Returns `{ league, season, season_defaulted, standings[], pagination, attribution }`. Upstream: OpenLigaDB. Cache: intraday (5 minutes). Read-only.

#### `sport_get_top_scorers`: Get the top scorers of a competition

Use this when you need the goal scorers ranking of a competition in a season, for example the Bundesliga or 3. Liga top scorers, or who scored the most goals in an earlier season. Players with no goal are left out. Rank is computed by this server (players level on goals share a rank). OpenLigaDB does not publish the scorer's club here, and community entry can list one player under several ids. Do not use for the goals of one match (use sport_get_match) or for the league table (use sport_get_standings). Parameters: `league` (shortcut, e.g. "bl1"), `season` (year the season starts, e.g. 2026, default the current season), `limit` (1-100, default 20), `offset`, `response_format` ("concise" default, "detailed" adds cache information).

| Parameter | Type | Required | Example |
|---|---|---|---|
| `league` | string | yes | `"bl1"` |
| `season` | integer | no | `2026` |
| `limit` | integer | no | `20` |
| `offset` | integer | no | `0` |
| `response_format` | "concise" or "detailed" | no | `"concise"` |

Returns `{ league, season, season_defaulted, scorers[], pagination, attribution }`. Upstream: OpenLigaDB. Cache: intraday (5 minutes). Read-only.

#### `sport_get_matchday`: Get the matches of a matchday

Use this when you need the fixtures and results of one matchday or round of a competition: kickoff times, home and away teams, status, score and half-time score, for example "this weekend's Bundesliga results" or "matchday 12 of the 3. Liga 2025". Without `matchday`, the current round of the league is used (current season or later only). "detailed" adds goals with minute and scorer, every published result type, and venue and attendance when published. Do not use for a whole season (use sport_get_season_matches), for one club across competitions (use sport_get_team_matches) or for live minute-by-minute scores (data can be 5 minutes old). Parameters: `league` (shortcut, e.g. "bl1"), `season` (year the season starts, e.g. 2026, default the current season), `matchday` (round number from sport_list_matchdays, e.g. 5), `limit` (1-100, default 50, detailed pages hold at most 20), `offset`, `response_format` ("concise" default or "detailed").

| Parameter | Type | Required | Example |
|---|---|---|---|
| `league` | string | yes | `"bl1"` |
| `season` | integer | no | `2026` |
| `matchday` | integer | no | `5` |
| `limit` | integer | no | `50` |
| `offset` | integer | no | `0` |
| `response_format` | "concise" or "detailed" | no | `"concise"` |

Returns `{ league, season, season_defaulted, matchday, summary, matches[], pagination, attribution }`. Upstream: OpenLigaDB. Cache: intraday (5 minutes). Read-only.

#### `sport_list_matchdays`: List the rounds of a season

Use this when you need the matchdays or rounds of a competition in a season (for example "1. Spieltag" to "34. Spieltag", or cup rounds such as "Achtelfinale"), their numbers for sport_get_matchday, and which round is current. The current round is given for the current season or later only. Do not use for the matches themselves (use sport_get_matchday) or for finding a competition (use sport_list_leagues). Parameters: `league` (shortcut, e.g. "dfb"), `season` (year the season starts, e.g. 2026, default the current season), `limit` (1-200, default 100), `offset`, `response_format` ("concise" default, "detailed" adds the OpenLigaDB group id and cache information).

| Parameter | Type | Required | Example |
|---|---|---|---|
| `league` | string | yes | `"bl1"` |
| `season` | integer | no | `2026` |
| `limit` | integer | no | `100` |
| `offset` | integer | no | `0` |
| `response_format` | "concise" or "detailed" | no | `"concise"` |

Returns `{ league, season, season_defaulted, current, matchdays[], pagination, attribution }`. Upstream: OpenLigaDB. Cache: intraday (5 minutes). Read-only.

#### `sport_get_season_matches`: Get the matches of a season

Use this when you need many matches of one competition season at once, filtered by club, status or a range of matchdays: every result of a club this season, its remaining fixtures, the home record, or matchdays 10 to 17. Matches are sorted by kickoff. "detailed" adds goals with minute and scorer, and venue and attendance when published. Do not use for one round (use sport_get_matchday), for a club across all competitions (use sport_get_team_matches) or for one match (use sport_get_match). Parameters: `league` (shortcut, e.g. "bl1"), `season` (year the season starts, e.g. 2026, default the current season), `team_id` (e.g. 40) or `team_name` (part of the club name, e.g. "Dortmund"), `status` ("all" default, "finished", "upcoming"), `from_matchday` and `to_matchday` (e.g. 10 and 17), `limit` (1-100, default 50, detailed pages hold at most 20), `offset`, `response_format` ("concise" default or "detailed").

| Parameter | Type | Required | Example |
|---|---|---|---|
| `league` | string | yes | `"bl1"` |
| `season` | integer | no | `2026` |
| `team_id` | integer | no | `40` |
| `team_name` | string | no | `"Dortmund"` |
| `status` | "all" or "finished" or "upcoming" | no | `"all"` |
| `from_matchday` | integer | no | `10` |
| `to_matchday` | integer | no | `17` |
| `limit` | integer | no | `50` |
| `offset` | integer | no | `0` |
| `response_format` | "concise" or "detailed" | no | `"concise"` |

Returns `{ league, season, season_defaulted, summary, matches[], pagination, attribution }`. Upstream: OpenLigaDB. Cache: intraday (5 minutes). Read-only.

#### `sport_get_team_matches`: Get a club's recent and upcoming matches

Use this when you need what a club played recently and plays next, across every competition OpenLigaDB holds (league, cup, European cups): its last result, its next match, or all its matches a few weeks around today. `last_result` and `next_match` are picked by this server from the window. Entries of community test leagues, past community entries without a result and copies of the same match are left out. Do not use for a whole season of one competition (use sport_get_season_matches) or for the record between two clubs (use sport_get_head_to_head). Parameters: `team_id` (numeric id from sport_list_teams, e.g. 40) or `team_name` (part of the club name, e.g. "Dortmund"), exactly one, `weeks_past` (0-26, default 4), `weeks_future` (0-26, default 4), `status` ("all" default, "finished", "upcoming"), `limit` (1-100, default 50, detailed pages hold at most 20), `offset`, `response_format` ("concise" default or "detailed"). A name can match several clubs (first team, women, reserves): `matched_teams` lists up to 25 of them, then use team_id.

| Parameter | Type | Required | Example |
|---|---|---|---|
| `team_id` | integer | no | `40` |
| `team_name` | string | no | `"Dortmund"` |
| `weeks_past` | integer | no | `4` |
| `weeks_future` | integer | no | `4` |
| `status` | "all" or "finished" or "upcoming" | no | `"all"` |
| `limit` | integer | no | `50` |
| `offset` | integer | no | `0` |
| `response_format` | "concise" or "detailed" | no | `"concise"` |

Returns `{ team_id, team_name, matched_teams[], matched_teams_total, window, last_result, next_match, summary, matches[], pagination, attribution }`. Upstream: OpenLigaDB. Cache: intraday (5 minutes). Read-only.

#### `sport_get_match`: Get one match in full

Use this when you need everything about one match: who scored and in which minute, the running score after each goal, penalties and own goals, the half-time score, extra time or penalties, venue and attendance when published (rare for recent seasons), and the time of the last update. Take the match_id from sport_get_matchday, sport_get_season_matches, sport_get_team_matches or sport_get_head_to_head. Do not use for several matches (use those tools with response_format "detailed") or for live minute-by-minute tracking (data can be 5 minutes old). Parameter: `match_id` (integer, e.g. 72375).

| Parameter | Type | Required | Example |
|---|---|---|---|
| `match_id` | integer | yes | `72375` |

Returns `{ match, attribution }`. Upstream: OpenLigaDB. Cache: intraday (5 minutes). Read-only.

#### `sport_get_head_to_head`: Get the head-to-head record of two clubs

Use this when you need the record between two clubs: how often they met, wins for each, draws, goals for each, the first and last meeting, and the meetings themselves, most recent first, across every season and competition OpenLigaDB holds. Totals are computed by this server over finished meetings: a penalty shootout winner counts as a win, shootout goals are left out. Entries of community test leagues, past community entries without a result and copies of the same match are left out. Do not use for one club's recent form (use sport_get_team_matches) or for a league table (use sport_get_standings). Parameters: `team_id_1` and `team_id_2` (numeric ids from sport_list_teams, e.g. 40 and 7), `limit` (1-100, default 20, detailed pages hold at most 20), `offset`, `response_format` ("concise" default or "detailed").

| Parameter | Type | Required | Example |
|---|---|---|---|
| `team_id_1` | integer | yes | `40` |
| `team_id_2` | integer | yes | `7` |
| `limit` | integer | no | `20` |
| `offset` | integer | no | `0` |
| `response_format` | "concise" or "detailed" | no | `"concise"` |

Returns `{ team_1, team_2, summary, matches[], pagination, attribution }`. Upstream: OpenLigaDB. Cache: hourly (1 hour). Read-only.

### Connect

Endpoint (Streamable HTTP): `https://mrbridge--german-football-mcp.apify.actor/mcp`

Every client authenticates with your Apify API token, found in [Apify Console > Settings > API & Integrations](https://console.apify.com/settings/integrations). Clients that support custom headers send it as `Authorization: Bearer <token>`. The others use the `?token=` URL variant, which must be treated as a secret: keep it out of commits, screenshots and shared logs.

#### Claude Code

```bash
claude mcp add --transport http german-football "https://mrbridge--german-football-mcp.apify.actor/mcp" --header "Authorization: Bearer ${APIFY_TOKEN}"
```

#### Cursor, VS Code and other JSON configurations

```json
{
  "mcpServers": {
    "german-football": {
      "type": "http",
      "url": "https://mrbridge--german-football-mcp.apify.actor/mcp",
      "headers": {
        "Authorization": "Bearer ${APIFY_TOKEN}"
      }
    }
  }
}
```

#### claude.ai and Claude Desktop

Add a custom connector with the URL `https://mrbridge--german-football-mcp.apify.actor/mcp?token=YOUR_APIFY_TOKEN` and no authentication. Prefilled link (replace the token placeholder before saving): [add German Football MCP Server to Claude](https://claude.ai/customize/connectors?modal=add-custom-connector\&connectorName=German%20Football%20MCP%20Server\&connectorUrl=https%3A%2F%2Fmrbridge--german-football-mcp.apify.actor%2Fmcp%3Ftoken%3DYOUR_APIFY_TOKEN).

#### ChatGPT (developer mode)

Settings > Apps > Create, URL `https://mrbridge--german-football-mcp.apify.actor/mcp?token=YOUR_APIFY_TOKEN`, authentication "No authentication". ChatGPT snapshots the tool list: after a server update, an admin has to click Refresh on the app.

#### OpenAI Responses API

```json
{
  "type": "mcp",
  "server_label": "german_football",
  "server_url": "https://mrbridge--german-football-mcp.apify.actor/mcp",
  "headers": {
    "Authorization": "Bearer YOUR_APIFY_TOKEN"
  },
  "require_approval": "never"
}
```

Add `allowed_tools` to restrict the tool list. Tool calls must finish within about 60 seconds on this API, and every tool of this server answers in under 50 seconds.

#### Anthropic Messages API

```json
{
  "mcp_servers": [
    {
      "type": "url",
      "url": "https://mrbridge--german-football-mcp.apify.actor/mcp",
      "name": "german-football",
      "authorization_token": "YOUR_APIFY_TOKEN"
    }
  ],
  "tools": [
    {
      "type": "mcp_toolset",
      "mcp_server_name": "german-football"
    }
  ]
}
```

Send the beta header `anthropic-beta: mcp-client-2025-11-20`.

#### One-click OAuth alternative

`https://mcp.apify.com/?tools=mrbridge/german-football-mcp` connects through Apify OAuth without a token. It exposes the Actor as a single tool rather than the granular tools listed above.

#### Cost control

Each Standby run has a spending limit (`maxTotalChargeUsd`). When a call uses the last of it, the result is still returned, and later calls in that run answer `CHARGE_LIMIT_REACHED` until the limit is raised.

### Why use this server

- **Depth below the top flight.** The 2. Bundesliga, the 3. Liga, the Regionalliga and Oberliga divisions, the Frauen-Bundesliga, the DFB-Pokal and the national teams, as far as the OpenLigaDB community maintains them.
- **Goals with scorer and minute.** Matches of recent seasons list their goals with scorer and minute, the running score after each one, and whether it was a penalty or an own goal, plus half-time, extra-time and shootout results. Older archive matches carry the final score only.
- **Head-to-head in one call.** How often two clubs met, who won more often, the goals on each side and the first and last meeting, across seasons and competitions.
- **A club's week at a glance.** Last result and next match in any competition (league, cup, European), without knowing which one to ask about.
- **Archive seasons.** Past seasons back to the early 2000s, cached longer because they no longer change.
- **Open licence.** The data is under the ODbL and every answer carries the credit, so whatever you build with it can be published.

### Pricing (Pay-per-Event)

| Event | Charged when | Price |
|---|---|---|
| `apify-actor-start` | run start (platform default) | see the Store page |
| `tool-read` (primary event) | each successful read tool call | see the Store page |
| `tool-action` | each successful call of a detailed or computed tool | see the Store page |

Never charged: initialize, tools/list, pings, readiness probes, and any call that ends in an error (invalid input, not found, upstream failure, timeout, spending limit).

Platform usage comes on top of these events. This server runs in Apify Standby mode, and you also pay the platform usage of your own Standby run, billed to your Apify account like any other run: the memory set for the Standby run, for as long as the server is up, idle time included, until the run stops at its idle timeout.
The [Apify pay-per-event documentation](https://docs.apify.com/actors/publishing/monetize/pay-per-event#platform-usage-costs) says so: "For runs in Standby mode, users always pay the platform usage costs in addition to the event charges."

### Limits, caveats and attribution

- **Not a live score service.** Current-season data is cached for 5 minutes, because OpenLigaDB asks clients to fetch each league at most once every 30 to 60 seconds during matches and to keep their own copy. Volunteers also enter results by hand, so a goal can show up a few minutes late.
- **Community data.** OpenLigaDB users type the results, scorers and kickoff times, and no editor checks them. Errors and gaps happen, more often during live matches and in smaller leagues. Do not rely on the data where a wrong value can cause harm, betting included.
- **Which competitions.** OpenLigaDB holds whatever its community maintains. `sport_list_leagues` lists the main competitions first and flags them as `featured`. Other leagues with similar names can be test or private leagues. A few competitions change their shortcut from one season to the next (the Europa League, for example), so look the shortcut up for each season.
- **Seasons.** A season is named by the year it starts: 2026 means 2026/2027. Without a season, the tools use the current European football season (this year from July, last year until June). Calendar-year competitions such as darts or national teams need their year. The previous season is cached for a day and older seasons for 30 days, because OpenLigaDB says finished seasons no longer change.
- **Computed fields.** Match statuses (finished, started, scheduled), scorer ranks and head-to-head totals are computed by this server from the published data, and each answer says so. Table positions follow OpenLigaDB's order, which applies the league's own tie-breakers. A penalty shootout winner counts as a win in head-to-head totals, and shootout goals are left out of the goal totals.
- **No logos or crests.** OpenLigaDB links club crests hosted elsewhere and grants no rights on them, and club names and crests are not covered by its licence. This server drops every crest URL before it stores or returns anything.
- **Rate limits.** OpenLigaDB allows 60 requests per minute per IP address and may throttle or block clients that strain its server. This server keeps to 30 per minute per instance, retries a 429 once and a server error twice with growing waits, and serves its stored copy when OpenLigaDB is down (the answer then shows `cache.stale`). A busy period can answer `UPSTREAM_RATE_LIMITED`: retry a minute later. Errors are never charged.
- **Availability.** OpenLigaDB is a privately run project on a rented server, with no availability promise. The operator may require registration, keys or quotas for heavy use in the future, with four weeks of notice.
- **Attribution.** Every answer carries an `attribution` block: the credit "Daten von OpenLigaDB (www.openligadb.de), lizenziert unter ODbL 1.0", the licence link, the licence and terms pages, and the notices. Keep the credit when you show or publish the data.
- **Affiliation.** This server is not affiliated with OpenLigaDB or with any league, club or federation.

### Data terms

The data comes from [OpenLigaDB](https://www.openligadb.de) under the [Open Database License 1.0](https://opendatacommons.org/licenses/odbl/1-0/) (ODbL). OpenLigaDB allows anyone to use, copy, change and pass on the data, commercially too, on three conditions set out on its [licence page](https://www.openligadb.de/lizenz). By using this server you agree to meet them for the data it returns:

- **Credit OpenLigaDB wherever you use the data publicly.** The line OpenLigaDB suggests is "Daten von OpenLigaDB (www.openligadb.de), lizenziert unter ODbL 1.0". On a website, put it where readers will find it, such as the footer or a sources page.
- **Share alike if you build a database.** If you publish a changed version of the database (results you stored, corrected and extended, for example), it has to be under the ODbL too. A table, a chart or an app screen made from the data only needs the credit.
- **No technical lock-in.** If you pass the database on, do not protect it in a way that stops the people who receive it from using their ODbL rights.
- **Club names, crests and logos** are not under the ODbL and belong to their owners.

The fee for this server pays for the service (hosting, caching and the answers it computes), not for a licence on the data, which OpenLigaDB gives to everyone for free.

### Use cases

- **Fan assistants.** Ask for this weekend's results, the current table or a club's next fixture in plain language, lower leagues included.
- **Match previews.** Writers and podcasters pull the head-to-head record, recent form and top scorers before a game.
- **Stats side projects.** Season archives and goal-by-goal records feed charts and small analyses, with the source credited when published.
- **Club and league newsletters.** An agent drafts a weekly roundup of a Regionalliga division or of the Frauen-Bundesliga.
- **Teaching.** Openly licensed football numbers for data-analysis classes.

### More sports data tools

- [live scores MCP server](https://apify.com/mrbridge/espn-mcp-server): live scores, standings, box scores and odds for the major leagues, inside Claude or ChatGPT.
- [bulk ESPN sports data](https://apify.com/mrbridge/espn-sports-data-scraper): whole seasons of scores, boxscores, odds and player gamelogs as a flat dataset.

### FAQ

#### Are the scores live?

No. Current-season data is cached for 5 minutes and volunteers type results by hand, so a goal can show up late. Think reference and archive, not live ticker, and never betting.

#### Which competitions are covered?

Whatever the OpenLigaDB community maintains: German football above all, plus European cups and a few other sports such as ice hockey or darts. `sport_list_leagues` lists the main competitions first. Coverage outside Germany is uneven.

#### How are seasons named?

By the year they start: 2026 means 2026/2027. Without a season, the tools use the current European one.

#### Do I get club crests or logos?

No. Crests and league marks belong to their owners and are never returned.

#### What does a call cost?

Each successful tool call is one event, at the price shown on the [Pricing tab](https://apify.com/mrbridge/german-football-mcp/pricing) for your Apify plan: `tool-action` for `sport_get_match` and `sport_get_head_to_head`, `tool-read` for every other tool. Paid Apify plans get lower prices. On the free plan, a read costs $0.005 and an action $0.01, so 100 reads come to $0.50 in events. On top of that, your Apify account pays the platform usage of your own Standby run while the server is up, idle minutes included. Errors are never charged, and `maxTotalChargeUsd` caps what one run can spend.

#### Why is the first call slower?

The first call after a quiet period starts a new Standby run on your Apify account, which takes a few seconds. Then it answers quickly, and it shuts down after about 5 idle minutes.

#### Is this server affiliated with OpenLigaDB or the leagues?

No. It reads that database's public API and credits it in every answer, with no tie to its operator or to any league, club or federation.

#### Need live scoreboards?

The [ESPN MCP Server](https://apify.com/mrbridge/espn-mcp-server) from the same account covers live scoreboards, news and rosters for major leagues.

#### Your feedback

Found a bug or a competition that reads wrong? Tell us on the [Issues tab](https://apify.com/mrbridge/german-football-mcp/issues). Wrong results can also be fixed at the source, where volunteers edit them.

More MCP servers, scrapers and data studies from the same team: [mr-bridge.com](https://mr-bridge.com).

### Changelog

- 0.1.4: Output, dataset and key-value store schemas, as Apify asks for publication: the Output tab of a run started from the Console shows the connection details and one row per tool.
- 0.1.3: the Input tab shows the endpoint and how to connect an AI client, and a run started from the Console outputs the connection details and the tool list
- 0.1.2: pricing events tool-read and tool-action
- 0.1.1: fixes from the first live capture: head-to-head records and club windows count each real match once, without community test leagues, unplayed community entries or copies, cup matches whose final result comes first are read correctly (extra time and penalties included), blank and repeated goal entries are left out, the goal overtime flag is documented as an added-time flag OpenLigaDB sets inconsistently, and venue and attendance are described as present only when published
- 0.1.0: initial build (private, unpublished). 10 tools on OpenLigaDB.

# Actor input Schema

## `mcpEndpoint` (type: `string`):

Paste this URL into your MCP client (Streamable HTTP). It is shown here for copying only: the server ignores this form, and every parameter goes in your questions.

## Actor input object example

```json
{
  "mcpEndpoint": "https://mrbridge--german-football-mcp.apify.actor/mcp"
}
```

# Actor output Schema

## `connection` (type: `string`):

The item written by a run started from the Console: endpoint, token options, client recipes and the list of tools with the event each one bills.

# API

You can run this Actor programmatically using our API. Below are code examples in JavaScript, Python, and CLI, as well as the OpenAPI specification and MCP server setup.

## JavaScript example

```javascript
import { ApifyClient } from 'apify-client';

// Initialize the ApifyClient with your Apify API token
// Replace the '<YOUR_API_TOKEN>' with your token
const client = new ApifyClient({
    token: '<YOUR_API_TOKEN>',
});

// Prepare Actor input
const input = {
    "mcpEndpoint": "https://mrbridge--german-football-mcp.apify.actor/mcp"
};

// Run the Actor and wait for it to finish
const run = await client.actor("mrbridge/german-football-mcp").call(input);

// Fetch and print Actor results from the run's dataset (if any)
console.log('Results from dataset');
console.log(`💾 Check your data here: https://console.apify.com/storage/datasets/${run.defaultDatasetId}`);
const { items } = await client.dataset(run.defaultDatasetId).listItems();
items.forEach((item) => {
    console.dir(item);
});

// 📚 Want to learn more 📖? Go to → https://docs.apify.com/api/client/js/docs

```

## Python example

```python
from apify_client import ApifyClient

# Initialize the ApifyClient with your Apify API token
# Replace '<YOUR_API_TOKEN>' with your token.
client = ApifyClient("<YOUR_API_TOKEN>")

# Prepare the Actor input
run_input = { "mcpEndpoint": "https://mrbridge--german-football-mcp.apify.actor/mcp" }

# Run the Actor and wait for it to finish
run = client.actor("mrbridge/german-football-mcp").call(run_input=run_input)

# Fetch and print Actor results from the run's dataset (if there are any)
print(f"💾 Check your data here: https://console.apify.com/storage/datasets/{run.default_dataset_id}")
for item in client.dataset(run.default_dataset_id).iterate_items():
    print(item)

# 📚 Want to learn more 📖? Go to → https://docs.apify.com/api/client/python/docs/quick-start

```

## CLI example

```bash
echo '{
  "mcpEndpoint": "https://mrbridge--german-football-mcp.apify.actor/mcp"
}' |
apify call mrbridge/german-football-mcp --silent --output-dataset

```

## MCP server setup

```json
{
    "mcpServers": {
        "apify": {
            "type": "http",
            "url": "https://mcp.apify.com/?tools=fetch-actor-details,mrbridge/german-football-mcp"
        }
    }
}
```

The hosted server signs you in with OAuth on first connect, so no API token belongs in this config. Clients without OAuth support can send an `Authorization: Bearer <APIFY_API_TOKEN>` header instead, using a token from API & Integrations in Apify Console (https://console.apify.com/settings/integrations).

## OpenAPI specification

Download the OpenAPI definition: https://api.apify.com/v2/actors/RObg4sGpL1JMqVEgc/builds/L4TQZccVP2jTaOGN1/openapi.json
