Skip to main content
Glama

ANSES Ciqual MCP Server

by zzgael
README.md9.57 kB
# ANSES Ciqual MCP Server <div align="center"> [![Tests](https://github.com/zzgael/ciqual-mcp/actions/workflows/tests.yml/badge.svg)](https://github.com/zzgael/ciqual-mcp/actions/workflows/tests.yml) [![PyPI version](https://badge.fury.io/py/ciqual-mcp.svg)](https://badge.fury.io/py/ciqual-mcp) [![Python 3.10+](https://img.shields.io/badge/python-3.10+-blue.svg)](https://www.python.org/downloads/) [![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg)](https://opensource.org/licenses/MIT) [![MCP Protocol](https://img.shields.io/badge/MCP-1.0-green.svg)](https://modelcontextprotocol.io/) An MCP (Model Context Protocol) server providing SQL access to the ANSES Ciqual French food composition database. Query nutritional data for over 3,000 foods with full-text search support. ![ANSES Ciqual Database](assets/ciqual-banner.jpg) </div> ## Features - 🍎 **Comprehensive Database**: Access nutritional data for 3,185+ French foods - 🔍 **SQL Interface**: Query using standard SQL with full flexibility - 🌍 **Bilingual Support**: French and English food names - 🔤 **Fuzzy Search**: Built-in full-text search with typo tolerance - 📊 **60+ Nutrients**: Detailed composition including vitamins, minerals, macros, and more - 🔄 **Auto-Updates**: Automatically refreshes data yearly from ANSES (checks on startup) - 🔒 **Read-Only**: Safe queries with no risk of data modification - 💾 **Lightweight**: ~10MB SQLite database with efficient indexing ## Installation ### Via pip ```bash pip install ciqual-mcp ``` ### Via uvx (recommended) ```bash uvx ciqual-mcp ``` ### From source ```bash git clone https://github.com/zzgael/ciqual-mcp.git cd ciqual-mcp pip install -e . ``` ## MCP Client Configuration ### Claude Desktop Add to your Claude Desktop configuration: **macOS**: `~/Library/Application Support/Claude/claude_desktop_config.json` **Windows**: `%APPDATA%/Claude/claude_desktop_config.json` **Linux**: `~/.config/Claude/claude_desktop_config.json` ```json { "mcpServers": { "ciqual": { "command": "uvx", "args": ["ciqual-mcp"] } } } ``` ### Gemini CLI Add to your Gemini CLI configuration file `~/.gemini/settings.json`: ```json { "mcpServers": { "ciqual": { "command": "uvx", "args": ["ciqual-mcp"] } } } ``` ### Codex CLI Add to your Codex CLI configuration file `~/.codex/config.toml`: ```toml [mcp_servers.ciqual] command = "uvx" args = ["ciqual-mcp"] ``` ## Usage ### As an MCP Server The server implements the Model Context Protocol and exposes a single `query` function: ```bash # Start the server standalone (for testing) ciqual-mcp ``` ### Direct Python Usage ```python from ciqual_mcp.data_loader import initialize_database # Initialize/update the database initialize_database() # Then use SQLite directly import sqlite3 conn = sqlite3.connect("~/.ciqual/ciqual.db") cursor = conn.execute("SELECT * FROM foods WHERE alim_nom_eng LIKE '%apple%'") ``` ## API Documentation ### MCP Function: `query` The server exposes a single MCP function for executing SQL queries on the Ciqual database. #### Function Signature ```python async def query(sql: str) -> list[dict] ``` #### Parameters - **`sql`** (string, required): The SQL query to execute on the database - Must be a SELECT or WITH query (read-only access) - Supports all standard SQLite SQL syntax - Can use JOIN, GROUP BY, ORDER BY, etc. - Supports full-text search via the `foods_fts` table #### Returns - **`list[dict]`**: Array of result rows, where each row is a dictionary with column names as keys - Empty list if no results match the query - Error dictionary with `"error"` key if query fails #### Error Handling The function returns an error dictionary in these cases: - Database not initialized: `{"error": "Database not initialized..."}` - Non-SELECT query attempted: `{"error": "Only SELECT queries are allowed for safety."}` - SQL syntax error: `{"error": "SQL error: [details]"}` - Table not found: `{"error": "Table not found. Available tables: foods, nutrients, composition, foods_fts, food_groups"}` #### Example Usage in MCP Context ```json { "method": "query", "params": { "sql": "SELECT f.alim_nom_eng, n.const_nom_eng, c.teneur, n.unit FROM foods f JOIN composition c ON f.alim_code = c.alim_code JOIN nutrients n ON c.const_code = n.const_code WHERE f.alim_nom_eng LIKE '%apple%' AND n.const_code IN (328, 25000, 31000)" } } ``` #### Response Example ```json [ { "alim_nom_eng": "Apple, raw", "const_nom_eng": "Energy", "teneur": 52.0, "unit": "kcal/100g" }, { "alim_nom_eng": "Apple, raw", "const_nom_eng": "Protein", "teneur": 0.3, "unit": "g/100g" } ] ``` ## Database Schema ### Tables #### `foods` - Food items - `alim_code` (INTEGER, PK): Unique food identifier - `alim_nom_fr` (TEXT): French name - `alim_nom_eng` (TEXT): English name - `alim_grp_code` (TEXT): Food group code #### `nutrients` - Nutrient definitions - `const_code` (INTEGER, PK): Unique nutrient identifier - `const_nom_fr` (TEXT): French name - `const_nom_eng` (TEXT): English name - `unit` (TEXT): Measurement unit (g/100g, mg/100g, etc.) #### `composition` - Nutritional values - `alim_code` (INTEGER): Food identifier - `const_code` (INTEGER): Nutrient identifier - `teneur` (REAL): Value per 100g - `code_confiance` (TEXT): Confidence level (A/B/C/D) #### `foods_fts` - Full-text search Virtual table for fuzzy matching with French/English names ### Common Nutrient Codes | Category | Code | Nutrient | Unit | |----------|------|----------|------| | **Energy** | 327 | Energy | kJ/100g | | | 328 | Energy | kcal/100g | | **Macros** | 25000 | Protein | g/100g | | | 31000 | Carbohydrates | g/100g | | | 40000 | Fat | g/100g | | | 34100 | Fiber | g/100g | | | 32000 | Sugars | g/100g | | **Minerals** | 10110 | Sodium | mg/100g | | | 10200 | Calcium | mg/100g | | | 10260 | Iron | mg/100g | | | 10190 | Potassium | mg/100g | | **Vitamins** | 55400 | Vitamin C | mg/100g | | | 56400 | Vitamin D | µg/100g | | | 51330 | Vitamin B12 | µg/100g | ## Example Queries ### Basic Search ```sql -- Find foods by name SELECT * FROM foods WHERE alim_nom_eng LIKE '%orange%'; -- Fuzzy search (handles typos) SELECT * FROM foods_fts WHERE foods_fts MATCH 'orang*'; ``` ### Nutritional Queries ```sql -- Get vitamin C content for oranges SELECT f.alim_nom_eng, c.teneur as vitamin_c_mg FROM foods f JOIN composition c ON f.alim_code = c.alim_code WHERE f.alim_nom_eng LIKE '%orange%' AND c.const_code = 55400; -- Find foods highest in protein SELECT f.alim_nom_eng, c.teneur as protein_g FROM foods f JOIN composition c ON f.alim_code = c.alim_code WHERE c.const_code = 25000 ORDER BY c.teneur DESC LIMIT 10; -- Compare macros for different foods SELECT f.alim_nom_eng as food, MAX(CASE WHEN c.const_code = 25000 THEN c.teneur END) as protein_g, MAX(CASE WHEN c.const_code = 31000 THEN c.teneur END) as carbs_g, MAX(CASE WHEN c.const_code = 40000 THEN c.teneur END) as fat_g, MAX(CASE WHEN c.const_code = 328 THEN c.teneur END) as calories_kcal FROM foods f JOIN composition c ON f.alim_code = c.alim_code WHERE f.alim_nom_eng IN ('Apple, raw', 'Banana, raw', 'Orange, raw') AND c.const_code IN (25000, 31000, 40000, 328) GROUP BY f.alim_code, f.alim_nom_eng; ``` ### Dietary Restrictions ```sql -- Find low-sodium foods (<100mg/100g) SELECT f.alim_nom_eng, c.teneur as sodium_mg FROM foods f JOIN composition c ON f.alim_code = c.alim_code WHERE c.const_code = 10110 AND c.teneur < 100 ORDER BY c.teneur ASC; -- High-fiber foods (>5g/100g) SELECT f.alim_nom_eng, c.teneur as fiber_g FROM foods f JOIN composition c ON f.alim_code = c.alim_code WHERE c.const_code = 34100 AND c.teneur > 5 ORDER BY c.teneur DESC; ``` ## Data Source Data is sourced from the official ANSES Ciqual database: - Website: https://ciqual.anses.fr/ - Data portal: https://www.data.gouv.fr/fr/datasets/table-de-composition-nutritionnelle-des-aliments-ciqual/ The database is automatically updated yearly when the server starts (data hasn't changed since 2020, so yearly updates are sufficient). ## Requirements - Python 3.9 or higher - 50MB free disk space (for database) - Internet connection (for initial data download) ## License MIT License - See LICENSE file for details ## Contributing Contributions are welcome! Please feel free to submit a Pull Request. ## Development ### Running Tests ```bash # Install development dependencies pip install -e . pip install pytest pytest-asyncio # Run unit tests python -m pytest tests/test_server.py -v # Run functional tests (requires database) python -m pytest tests/test_functional.py -v ``` ## Troubleshooting ### Database not initializing - Check internet connection - Ensure write permissions to `~/.ciqual/` directory - Try manual initialization: `python -m ciqual_mcp.data_loader` ### XML parsing errors - The tool handles malformed XML automatically with recovery mode - If issues persist, delete `~/.ciqual/ciqual.db` and restart ## Credits Developed by **Gael Debost** as part of GPT Workbench, a multi-LLM interface for medical research developed by [Ideagency](https://ideagency.fr). Data provided by ANSES (Agence nationale de sécurité sanitaire de l'alimentation, de l'environnement et du travail). ## Citation If you use this tool in your research, please cite: ```bibtex @software{ciqual_mcp, title = {ANSES Ciqual MCP Server}, author = {Gael Debost}, year = {2025}, url = {https://github.com/zzgael/ciqual-mcp} } ```

MCP directory API

We provide all the information about MCP servers via our MCP API.

curl -X GET 'https://glama.ai/api/mcp/v1/servers/zzgael/ciqual-mcp'

If you have feedback or need assistance with the MCP directory API, please join our Discord server