Query Feyenoord Football Data with Natural Language
Feyod MCP Server answers natural language questions about Feyenoord matches, players, and opponents via a public, LangChain-powered endpoint.
1.0.0Add to Favorites
Why it matters
Leverage natural language to query a comprehensive Feyenoord football match database. This asset translates your questions into SQL, retrieves match information, player statistics, and opponent data, and validates queries for accuracy.
Outcomes
What it gets done
Convert natural language questions into executable SQL queries.
Retrieve detailed Feyenoord match, player, and opponent data.
Validate and attempt to correct generated SQL queries using LLMs.
Access data via a public HTTP endpoint or local Docker deployment.
Source
Get it from source
Spark does not host a copy of it.
Open sourceReports
Agent outcome reports
No reports yet
Capabilities
Tools your agent gets
Answers questions about Feyenoord football match data using natural language queries converted to SQL.
Overview
Feyod MCP Server
Feyod MCP Server answers natural language questions about Feyenoord matches, players, and opponents by translating them into SQL over the Feyod database via LangChain. Use it to query Feyenoord match, player, and opponent data conversationally, either through the public endpoint or a self-hosted instance.
What it does
Feyod MCP Server is an MCP server for querying Feyenoord football match data using natural language. It provides a natural language interface to Feyod (Feyenoord Open Data), letting users ask questions about matches, players, opponents, and related events. Under the hood it uses LangChain to convert a natural language question into a SQL query, optionally using few-shot examples for accuracy, validate the generated SQL, attempt to fix invalid SQL with an LLM, execute the valid SQL against a SQLite database, and return the raw results. LLM and embedding providers, such as OpenAI or Google, are loaded dynamically through a provider factory, so the underlying model is swappable via configuration.
When to use - and when NOT to
Use it when you want to ask natural language questions about Feyenoord: match lineups, results, goals, cards, players, and opponents, either by connecting to the public endpoint or by running your own instance against the Feyod database. It is scoped specifically to Feyenoord data pulled from the jeroenvdmeer/feyod repository; it is not a general football-data or sports-analytics tool, and you cannot query other clubs or competitions through it.
Capabilities
- A single natural-language tool, answer_feyenoord_question, discoverable via the MCP protocol's tools/list, which answers questions in natural language about matches (lineups, results, goals, cards, and more), players, and opponents
- Natural-language-to-SQL translation via LangChain, including SQL validation and LLM-assisted repair of invalid queries before execution against SQLite
- Configurable LLM and embedding provider selection, for example OpenAI or Google, through a provider factory, without changing server code
Because the public endpoint lets an LLM generate and run SQL against a shared database, the project documents specific safeguards: the system prompt instructs the model to only ever generate SELECT statements, the application independently verifies each generated query starts with SELECT before running it, the publicly hosted database file is mounted read-only, and every query is capped at 5 results and pre-checked with an EXPLAIN statement before execution, with a second LLM call attempting a fix if that check fails.
How to install
The simplest path is the public endpoint, already running at https://mcp.feyod.nl/mcp - point any MCP-compatible client, such as Claude Desktop, at that URL.
To self-host with Docker:
docker pull jeroenvdmeer/feyod-mcp
docker run -p 8000:8000 \
-e LLM_PROVIDER="your_llm_provider" \
-e LLM_API_KEY="your_api_key" \
jeroenvdmeer/feyod-mcp
You can also mount a local feyod.db file instead of using the one baked into the image, by adding a volume mount pointing at the absolute path of your database file. To run from source instead: clone both jeroenvdmeer/feyod-mcp and jeroenvdmeer/feyod, create and activate a virtual environment with uv, build the SQLite database from the Feyod SQL file with sqlite3 feyod.db < feyod.sql, install dependencies with uv add "mcp[cli]" langchain langchain-openai langchain-google-genai python-dotenv aiosqlite (or pip install -r requirements.txt), and configure a .env file in the mcp directory with DATABASE_PATH, HOST, LOG_LEVEL, and your chosen LLM provider and API key.
Who it's for
Feyenoord fans, developers, and Feyenoord Open Data (Feyod) contributors who want to query match history, player, and opponent data conversationally instead of writing SQL against the Feyod database by hand.
Source README
Feyod MCP Server
Model Context Protocol (MCP) server for querying Feyenoord football match data using natural language.
The Streamable HTTP server is publicly available at https://mcp.feyod.nl/mcp. A Docker container is available on Docker Hub.
Key features
This MCP server provides a natural language interface to query Feyod: Feyenoord Open Data. This allows users to get answers to their questions related to Feyenoord matches, players, opponents and related events.
The underlying Feyod database is maintained in the jeroenvdmeer/feyod GitHub repository. You will need to obtain the latest SQL file from that repository to set up the required database.
The server uses LangChain to:
- Convert natural language questions into SQL queries (optionally leveraging few-shot examples for better accuracy).
- Validate the generated SQL.
- Attempt to fix invalid SQL using an LLM.
- Execute the valid SQL against a SQLite database.
- Return the raw query results.
LLM and embedding models are dynamically loaded based on configuration using a provider factory (llm_factory.py), allowing easy switching between providers like OpenAI, Google, etc.
Consumption
Using the Public Endpoint
The Feyod MCP server is publicly available at https://mcp.feyod.nl/mcp. You can connect to this endpoint from any MCP-compatible client, such as Claude Desktop.
Using the Docker Container
A Docker image of the Feyod MCP server is available on Docker Hub. You can pull and run it using the following commands:
Pull the Docker image:
docker pull jeroenvdmeer/feyod-mcpRun the Docker container:
You will need to provide the necessary environment variables for the LLM provider and API key. You can also mount thefeyod.dbfile if you want to use a local database instead of the one included in the image.docker run -p 8000:8000 \ -e LLM_PROVIDER="your_llm_provider" \ -e LLM_API_KEY="your_api_key" \ jeroenvdmeer/feyod-mcpReplace
your_llm_providerandyour_api_keywith your actual LLM configuration.To mount a local database file:
docker run -p 8000:8000 \ -e LLM_PROVIDER="your_llm_provider" \ -e LLM_API_KEY="your_api_key" \ -v <absolute_path_to_feyod_db>:/app/feyod/feyod.db \ jeroenvdmeer/feyod-mcpReplace
<absolute_path_to_feyod_db>with the absolute path to yourfeyod.dbfile on your host machine.
Tools
This server exposes MCP tools for querying the Feyenoord database. Tools are discoverable via the MCP protocol (tools/list).
- answer_feyenoord_question: Answers questions about Feyenoord. Questions can be asked in natural language, text, and can be about matches (lineups, results, goals, cards, etc.), players, and opponents.
Setup
Clone repositories:
# Clone this repo for the MCP server git clone https://github.com/jeroenvdmeer/feyod-mcp.git # Clone the Feyod database git clone https://github.com/jeroenvdmeer/feyod.git # Change directory into the MCP server cd feyod-mcpCreate and activate a virtual environment (recommended: uv):
Refer to https://docs.astral.sh/uv/ for the installation instructions of
uv.uv venv .venv\Scripts\activate # Windows # or source .venv/bin/activate # macOS/LinuxInstall dependencies:
# Using uv (recommended) uv add "mcp[cli]" langchain langchain-openai langchain-google-genai python-dotenv aiosqlite # Or using pip pip install -r requirements.txtSet up the database:
# Change directory to the feyod directory with the SQL file cd ../feyod # Build the SQLite database using the SQL statements sqlite3 feyod.db < feyod.sql
Configuration
Create a .env file in the mcp directory with the following variables:
# Path to the SQLite database file (relative to mcp folder or absolute)
DATABASE_PATH="../feyod/feyod.db"
# Server host binding (defaults to localhost/127.0.0.1)
HOST="127.0.0.1"
# Logging level (e.g., DEBUG, INFO, WARNING, ERROR)
LOG_LEVEL=INFO
# --- LLM Configuration ---
LLM_PROVIDER="google" # or "openai", etc.
LLM_API_KEY="YOUR_API_KEY_HERE"
LLM_MODEL="gemini-2.5-flash"
# --- Example Loading Configuration (Optional) ---
EXAMPLE_SOURCE="local" # or "mongodb"
EXAMPLE_DB_CONNECTION_STRING=""
EXAMPLE_DB_NAME="feyenoord_data"
EXAMPLE_DB_COLLECTION="examples"
Notes:
- Replace placeholder API key with your actual key.
- The
HOSTsetting defaults to "127.0.0.1" for local development. When running in Docker, it's automatically set to "0.0.0.0" to allow external connections. - Ensure the
LLM_PROVIDERmatches one defined inllm_factory.py. - Install the necessary LangChain integration package for your chosen provider (e.g.,
langchain-google-genai). - If using
EXAMPLE_SOURCE="mongodb", configure MongoDB settings as above.
Running the Server
You can run the server in several ways:
- Development mode (with hot reload and Inspector support):
mcp dev main.py - Standard execution:
python main.py # or mcp run main.py
The server will start and listen for MCP connections (stdio by default, or HTTP/SSE if configured).
Running with Docker
You can containerize the MCP server using the provided Dockerfile.
Build the Docker image:
Navigate to themcpdirectory in your terminal and run the following command:docker build -t feyod-mcp:latest .This will build an image tagged
feyod-mcp:latest.Run the Docker container:
You can run the container, mapping the internal port 8000 to an external port (e.g., 8000) on your host machine. You will also need to mount the database file as a volume so the container can access it.docker run -p 8000:8000 -v <absolute_path_to_feyod_db>:/app/../feyod/feyod.db feyod-mcp:latestReplace
<absolute_path_to_feyod_db>with the absolute path to yourfeyod.dbfile on your host machine.Alternatively, you can pass environment variables directly:
docker run -p 8000:8000 -e DATABASE_PATH="/app/../feyod/feyod.db" -e LLM_PROVIDER="google" -e LLM_API_KEY="YOUR_API_KEY_HERE" -e LLM_MODEL="gemini-2.5-flash" -v <absolute_path_to_feyod_db>:/app/../feyod/feyod.db feyod-mcp:latestRemember to replace the placeholder values with your actual configuration.
The server inside the container will start and listen on 0.0.0.0:8000.
Adding New LLM Providers
To add support for a new provider:
- Install Package: Install the required LangChain integration package (e.g.,
pip install langchain-anthropic). - Update Factory: Edit
llm_factory.pyto add the provider. - Update
.env/ README: Add the necessary API key to your.envfile.
Dependencies
- Python 3.10+
- See
requirements.txtfor specific package dependencies. - Provider-specific packages (e.g.,
langchain-openai,langchain-google-genai).
Debugging and Troubleshooting
- Use
mcp dev main.pyand the MCP Inspector for local testing. - Logs are written to stderr and can be viewed in Claude Desktop logs or your terminal.
- For environment/config issues, check
.envand Claude Desktop config. - See MCP Debugging Guide for more tips.
Security
This section provides an overview of the key security measures implemented in the MCP server. These measures are selected based on a risk assessment and the security considerations provided in the MCP documentation.
Risk assessment
The key assets of the MCP server are:
- The information in the Feyod database
- The publicly exposed Streamable HTTP server that can be consumed by end-users
Both assets serve the key objective of the MCP server to provide correct answers to questions from the end-user.
Risks related to the information in the Feyod database
As a basis for the risk assessment you can find the analysis of the information security criteria in the following overview.
| Criterium | Impact | Description |
|---|---|---|
| Confidentiality | None | As the Feyod database is publicly available, exposure of the data will have no impact. |
| Integrity | High | The key features of the MCP server resolves around providing accurate answers to questions. When the data is no longer complete and/or correct, the MCP server can no longer live up to this promise. |
| Availability | High | The key features of the MCP server resolves around providing accurate answers to questions. When the data is no longer available, the MCP server can no longer live up to this promise. |
Given the importance of the integrity and availability of the data, interactions with the database which delete and/or alter the Feyod database are considered the key risks that impact the security of the information in the Feyod database. Such interactions can be performed by:
- Misusing the MCP server to generate malicious SQL queries (e.g.
DELETEandUPDATEqueries) - Unauthorised access to the database in hosting platform of the MCP server
Risks related to the publicly exposed Streamable HTTP server
Given the objective to provide correct answers to questions from the end-user to the following key risks are considered:
- Incorrect SQL queries and/or output messages generated by the LLM leading to incorrect answers
- Excessive requests are made to the MCP server leading to unavailability of the service and high costs
- Malicious requests are made to the MCP service which trigger a high number of costly LLM calls and lead to high costs
Key security controls
Based on the key risks identified related to the information in the Feyod database and the publicly exposed Streamable HTTP server, the following key security controls are implemented.
Key controls related to the information in the Feyod database
| Risk | Control | Implementation Details |
|---|---|---|
Misusing the MCP server to generate malicious SQL queries (e.g. DELETE and UPDATE queries) |
Prompt Engineering & Query Validation | Prompt-Level Enforcement: The system prompt sent to the LLM in query_processor.py contains the explicit instruction: "DO NOT make any DML statements (INSERT, UPDATE, DELETE, DROP etc.) to the database. Only SELECT statements are allowed."Application-Level Guardrail: After generation, the application code validates that the returned SQL string begins with SELECT (case-insensitive). This serves as a deterministic check to prevent the execution of other statement types.Read-Only Access: For the publicly hosted service, the database file is mounted as read-only. This provides a strong, infrastructure-level guarantee that no write or delete operations can be performed, regardless of the generated SQL. |
| Unauthorised access to the database in hosting platform of the MCP server | Filesystem and Network Isolation | Local File Access: Per standard configuration the SQLite database is a local file (feyod.db) and is not exposed over a network port. The application, as seen in database.py, accesses it directly from the filesystem, minimizing the network attack surface.Principle of Least Privilege: In the production hosting environment, standard filesystem permissions are used to ensure that only the service account running the MCP server process has read access to the database file. |
Key controls related to the publicly exposed Streamable HTTP server
| Risk | Control | Implementation Details |
|---|---|---|
| Incorrect SQL queries and/or output messages generated by the LLM leading to incorrect answers | Multi-Stage Validation Workflow | Context-Rich Generation: To improve accuracy, the LLM is provided with the full database schema (from database.get_schema_description) and, when available, few-shot examples of valid question-query pairs (from examples.py).Pre-Execution Syntax Check: In query_processor.py, every generated SQL query is first checked using an EXPLAIN statement (check_sql_syntax function). This validates the query's syntax against the database schema without actually executing it, catching most errors.Automated Fixing Loop: If the syntax check fails, the workflow ( attempt_fix_sql function) triggers a second LLM call, providing it with the invalid query and the specific database error it produced. This allows the model to attempt a correction, which is then re-validated before execution. |
| Excessive requests are made to the MCP server leading to unavailability of the service and high costs | Resource & Infrastructure Limiting | Query Result Capping: The SQL generation prompt instructs the LLM to "always limit your query to at most 5 results", which prevents queries from returning excessively large datasets that could strain the server or client.Containerization: The use of Docker allows for applying resource limits (CPU, memory) on the container, preventing a single runaway process from impacting the entire host machine. |
| Malicious requests are made to the MCP service which trigger a high number of costly LLM calls and lead to high costs | Efficient Workflow & External Monitoring | Optimized LLM Usage: The query processing workflow is designed to be efficient. For a valid user question, it typically requires only a single LLM call. The more expensive "fixer" call is only triggered upon failure of the initial generated query. |
Security audits
References
MCP resources:
Securing generative AI and LLM applications:
FAQ
Common questions
Discussion
Questions & comments · 0
Sign In Sign in to leave a comment.
