f1-mcp-server
# Formula 1 MCP Server
A Model Context Protocol (MCP) server that empowers AI assistants (such as Claude Desktop, Cursor, or custom agents) to inspect, explore, and query Formula 1 data hosted on AWS.
Built using [FastMCP](https://github.com/jlowin/fastmcp), this server integrates natively with **AWS Glue Data Catalog** (schema metadata) and **Amazon Athena** (serverless SQL execution over S3 Parquet tables).
---
## Relationship to Upstream Data Pipeline
This repository is designed as a **downstream AI consumption layer** built directly on top of the [Formula 1 Enterprise Data Pipeline (`aws-f1-pipeline`)](https://github.com/GovIndLok/aws-f1-pipeline).
### How It Fits into the End-to-End Architecture
```
UPSTREAM DATA PIPELINE
(GovIndLok/aws-f1-pipeline)
┌─────────────────────────────────────────────────────┐
│ Amazon S3 Data Lake (dbt-athena) │
│ Bronze ➔ Silver ➔ Gold │
└──────────────────────────┬──────────────────────────┘
│ (Table & Schema Metadata)
▼
┌───────────────────────┐
│ AWS Glue Data Catalog │
│ (Gold Database) │
└───────────┬───────────┘
│
═══════════════════════════════════════╪═══════════════════════════════════════
DOWNSTREAM AI INTERFACE
(This Repository)
│
▼
┌───────────────────────────┐
│ f1-mcp-server │
│ - FastMCP (Python) │
│ - Boto3 (Glue & Athena) │
└─────────────┬─────────────┘
│ (stdio / SSE JSON-RPC)
▼
┌───────────────────────────┐
│ AI Clients │
│ (Claude Desktop / Cursor) │
└───────────────────────────┘
```
1. **Upstream Pipeline (`aws-f1-pipeline`)**:
- Transforms Formula 1 race and telemetry data using `dbt-athena` across Medallion layers (**Bronze** $\rightarrow$ **Silver** $\rightarrow$ **Gold**), materializing optimized Apache Parquet tables in Amazon S3.
- Registers dimensional models, facts, and analytical marts into the **AWS Glue Data Catalog**.
2. **Downstream Application (`f1-mcp-server`)**:
- Connects directly to the curated **Gold** schema in AWS Glue.
- Translates high-level agent intents into validated Athena queries.
- Exposes structured tools that allow LLMs to explore schemas, sample records, and perform multi-table joins without writing SQL by hand or needing direct AWS console access.
---
## Gold Data Schema
The server queries the `gold` database generated by the upstream pipeline, organized into a Star schema:
| Layer | Tables | Description |
|---|---|---|
| **Dimensions (`dim_*`)** | `dim_drivers`<br>`dim_constructors`<br>`dim_circuits`<br>`dim_races` | Reference data containing driver details, teams, circuits, track coordinates, and race calendars. |
| **Facts (`fct_*`)** | `fct_results`<br>`fct_lap_times`<br>`fct_pit_stops`<br>`fct_qualifyings` | Granular race events, grid positions, finishing results, lap timing, and pit stop durations. |
| **Marts (`mart_*`)** | `mart_drivers_season_stats`<br>`mart_constructors_season_stats` | Pre-aggregated standings and championship points for fast retrieval. |
---
## MCP Tools
The server registers 4 tools under the FastMCP framework:
### 1. `list_tables`
Discovers tables available in the Gold schema, automatically grouped by marts, facts, and dimensions.
- **Argument:** `table_type` (*optional*): Filter by `"marts"`, `"facts"`, or `"dims"`.
- **Returns:** Dictionary listing tables and their descriptions.
### 2. `tables_schema`
Fetches column names and data types for one or more tables from the Glue Data Catalog.
- **Argument:** `table_s`: List of table names, e.g. `["dim_drivers", "fct_results"]`.
- **Returns:** Dictionary mapping table names to their column definitions.
### 3. `get_sample_data`
Previews the top 10 rows of a table with schema-validated column filters.
- **Arguments:**
- `table_name`: Name of the table to sample.
- `filters` (*optional*): List of filter rules: `[{"column": "nationality", "operator": "=", "value": "British"}]`. Supported operators include `=`, `!=`, `>`, `<`, `>=`, `<=`, `IN`, `BETWEEN`, `LIKE`.
- `join_logic` (*optional*): Combine multiple filters using `"AND"` (default) or `"OR"`.
- **Returns:** JSON object containing sample rows.
### 4. `run_a_query`
Executes custom analytical queries joining fact and dimension tables on Athena.
- **Arguments:**
- `main_table`: Primary table to query (e.g. `"fct_results"`).
- `columns`: Dictionary mapping tables to requested column names, e.g. `{"fct_results": ["position", "points"], "dim_drivers": ["forename", "surname"]}`.
- `join` (*optional*): List of joins: `[{"table": "dim_drivers", "join_column": "driver_id", "on_column": "driver_id"}]`.
- `filters` (*optional*): Filter criteria with automatic type and operator formatting.
- `filter_logic` (*optional*): `"AND"` (default) or `"OR"`.
- `limit` (*optional*): Maximum rows to return (default: 20, max: 500).
- **Validation:**
- Ensures every table referenced in `columns` is either the `main_table` or explicitly joined.
- Formats strings with single quotes, tuples for `IN`, and numeric bounds for `BETWEEN`.
---
## Environment Configuration
Copy `.env.example` to `.env` and provide your AWS and Athena details:
```bash
cp .env.example .env
```
Configuration reference:
```dotenv
# AWS Configuration
AWS_PROFILE=your-aws-profile
AWS_REGION=your-aws-region
# Athena & Glue Settings
GLUE_DATABASE=gold
S3_RESULTS_BUCKET=s3://<your-athena-query-results-bucket>/staging/query-results/
QUERY_TIMEOUT_SECONDS=15
# MCP Server Settings
MCP_SERVER_HOST=127.0.0.1
MCP_SERVER_PORT=8000
```
---
## Getting Started
### 1. Prerequisites
- Python 3.12+
- [uv](https://github.com/astral-sh/uv) (recommended) or standard `pip`
- Valid AWS credentials with permissions for Athena (`StartQueryExecution`, `GetQueryExecution`, `GetQueryResults`), Glue (`GetTables`, `GetTable`), and S3 (read/write access to query results bucket).
### 2. Installation
```bash
# Clone the repository
git clone https://github.com/GovIndLok/f1_mcp_server.git
cd f1_mcp_server
# Install dependencies using uv
uv sync
# Activate the virtual environment
source .venv/bin/activate
```
### 3. Running the Server
#### Standard Input/Output (`stdio`) — Default for local AI clients:
```bash
source .venv/bin/activate
python -m src.server.mcp_server --transport stdio
```
#### Server-Sent Events (`sse`) — For network or containerized setups:
```bash
source .venv/bin/activate
python -m src.server.mcp_server --transport sse --port 8080
```
---
## Client Integration
### Claude Desktop
Add the server definition to your `claude_desktop_config.json`:
```json
{
"mcpServers": {
"f1-mcp-server": {
"command": "/path/to/f1_mcp_server/.venv/bin/python",
"args": ["-m", "src.server.mcp_server", "--transport", "stdio"],
"cwd": "/path/to/f1_mcp_server",
"env": {
"AWS_PROFILE": "your-aws-profile",
"AWS_REGION": "your-aws-region",
"GLUE_DATABASE": "gold",
"S3_RESULTS_BUCKET": "s3://<your-athena-query-results-bucket>/staging/query-results/"
}
}
}
}
```
### Cursor
In Cursor Settings $\rightarrow$ Features $\rightarrow$ MCP Servers, add:
- **Name:** `f1-data`
- **Type:** `command`
- **Command:** `python -m src.server.mcp_server --transport stdio`
---
## Deployment
For containerized or remote deployments, run the server using the SSE transport (`--transport sse --port 8080`). It can be deployed as an AWS ECS Fargate container behind an Application Load Balancer (ALB) or API reverse proxy, with an IAM Task Role configured for least-privilege access to Athena, Glue, and S3.
TDQS
Scored across 4 tools
list_tables and tables_schema are clearly distinct, but get_sample_data and run_a_query overlap significantly—both can query a single table with filters, and run_a_query can reproduce sample-style queries with limit. The descriptions hint at different use cases (quick sample vs. custom joins), but the boundary is not sharply defined.
Names are snake_case and somewhat readable, but styles are mixed: list_tables and get_sample_data use a verb+noun pattern, run_a_query adds an article, and tables_schema uses a noun phrase with no verb. Overall it is still predictable enough to navigate, but not a clean consistent convention.
Four tools is small but appropriate for a read-only F1 data exploration server. Each tool covers a meaningful step: discover tables, inspect schemas, sample data, and run custom queries. It does not feel padded or trivially thin.
The set covers the core read-only workflow well: list available tables, understand their schema, preview data, and execute arbitrary queries. Minor gaps include no pagination/offset support and no explicit relationship metadata, but agents can work around these via run_a_query and tables_schema.