LeoWalker's picture
feat(auth): add FastAPI token proxy for MCP HTTP, dual-server mode in main.py; add tests; docs and env example
aee78d5
# FoodWise MCP Server
## Overview
The FoodWise MCP (Model Context Protocol) server provides AI agents with comprehensive inventory management capabilities. It exposes food inventory data and operations through a standardized protocol that enables intelligent assistance with meal planning, expiration management, and kitchen organization.
## Architecture
The MCP server is built using [FastMCP](https://github.com/jlowin/fastmcp) and organized into three focused modules:
```
src/foodwise/mcp_server/
β”œβ”€β”€ main.py # Entry point & primitive registration
β”œβ”€β”€ fastmcp_tools.py # πŸ”§ CRUD operations (12 tools)
β”œβ”€β”€ fastmcp_resources.py # πŸ“‚ Live data sources (4 resources)
β”œβ”€β”€ fastmcp_prompts.py # πŸ“ Workflow templates (5 prompts)
└── README.md # This documentation
```
### Design Principles
- **Separation of Concerns**: Each module handles one type of MCP primitive
- **Live Data**: Resources always fetch fresh data from Notion (no caching)
- **Defensive Programming**: Graceful handling of missing/invalid Notion data
- **Type Safety**: Full type annotations for better maintainability
## MCP Primitives
### πŸ”§ Tools (Actions)
*Defined in `fastmcp_tools.py`*
**Inventory Tools (5):**
| Tool | Purpose | Key Parameters |
|------|---------|----------------|
| `get_inventory` | Retrieve inventory items with filtering | `filter_type`, `category`, `storage_type`, `expiring_days` |
| `add_inventory_item` | Add new food items | `name`, `category`, `storage_type`, `quantity`, `unit` + optional fields |
| `search_inventory_items` | Find items by name/category | `search_term`, `search_type` |
| `update_inventory_item` | Modify existing items | `page_id`, `updated_data` |
| `remove_inventory_item` | Archive items | `page_id` |
**Shopping Tools (7):**
| Tool | Purpose | Key Parameters |
|------|---------|----------------|
| `get_shopping_list` | Retrieve shopping items with filtering | `store`, `priority`, `status` |
| `add_shopping_item` | Add new shopping items | `item_name`, `quantity`, `unit`, `store`, `priority` + optional fields |
| `update_shopping_item` | Modify shopping items | `page_id` + update fields |
| `remove_shopping_item` | Archive shopping items | `page_id` |
| `create_shopping_from_recipe` | Generate shopping list from recipe | `recipe_ingredients`, `servings`, `preferred_store` |
| `optimize_shopping_by_store` | Organize shopping by store | Returns store-grouped lists with tips |
| `move_purchased_to_inventory` | Move purchased items to inventory | `purchased_item_ids` |
### πŸ“‚ Resources (Live Data)
*Defined in `fastmcp_resources.py`*
**Inventory Resources (2):**
| Resource URI | Purpose | Data Provided |
|--------------|---------|---------------|
| `inventory://items` | Complete inventory state | All items with metadata |
| `inventory://expiring-items` | Expiration alerts | Items expiring in next 7 days (urgent/moderate/upcoming) |
**Shopping Resources (2):**
| Resource URI | Purpose | Data Provided |
|--------------|---------|---------------|
| `shopping://list` | Current shopping list | All shopping items organized by status |
| `shopping://by-store` | Shopping organized by store | Items grouped by preferred store with totals |
### πŸ“ Prompts (Workflow Templates)
*Defined in `fastmcp_prompts.py`*
| Prompt | Purpose | Key Features |
|--------|---------|-------------|
| `add_item_helper` | Guide item entry | Required/optional fields, validation, organization tips |
| `meal_planning_assistant` | Plan meals using available inventory | Prioritize expiring items, provide recipes, shopping lists |
| `expiration_manager` | Handle items expiring soon | Safety assessment, usage strategies, preservation methods |
| `shopping_list_optimizer` | Create smart shopping lists | Avoid duplicates, consider storage capacity |
| `smart_shopping_assistant` | General shopping guidance | Budget management, store optimization, duplicate prevention |
## Integration
### Claude Desktop Configuration
#### Local MCP Server
Add to your `claude_desktop_config.json`:
```json
{
"mcpServers": {
"foodwise": {
"command": "uv",
"args": ["run", "python", "-m", "foodwise.mcp_server"],
"cwd": "/path/to/FoodWise",
"env": {
"MCP_LOG_LEVEL": "INFO"
}
}
}
}
```
For development with debug logging:
```json
{
"mcpServers": {
"foodwise-dev": {
"command": "uv",
"args": ["run", "fastmcp", "dev", "src/foodwise/mcp_server/main.py"],
"cwd": "/path/to/FoodWise",
"env": {
"MCP_LOG_LEVEL": "DEBUG"
}
}
}
}
```
#### Remote MCP Server βœ… NEW!
For remote access without local setup:
```json
{
"mcpServers": {
"foodwise-remote": {
"command": "npx",
"args": ["supergateway", "--streamableHttp", "https://leowalker-foodwise-remote-mcp.hf.space/mcp/"]
}
}
}
```
### Remote MCP Server with Token (Recommended)
Enable a lightweight token gate compatible with Desktop + `supergateway`.
```json
{
"mcpServers": {
"foodwise-remote": {
"command": "npx",
"args": [
"supergateway",
"--streamableHttp",
"https://<your-space>.hf.space/mcp/?key=$MCP_AUTH_TOKEN"
]
}
}
}
```
Notes:
- Prefer the `Authorization: Bearer` header in general; `?key=` is provided for bridge compatibility.
- When `MCP_AUTH_TOKEN` is set, `main.py` runs MCP upstream on `127.0.0.1:7870` and the proxy on public `PORT` (7860).
- Health check (no auth): `GET /health` β†’ `{ "status": "ok" }`.
**🌐 Remote Deployment**: The MCP server is deployed on HuggingFace Spaces using Docker with:
- FastMCP HTTP transport
- Python 3.12 + uv package management
- Automatic OAuth-free access for MCP clients
- Environment secrets managed in HuggingFace Space settings
**Requirements for Remote Access**:
- `npx` installed (comes with Node.js)
- `supergateway` package (automatically installed via npx)
- Internet connection
### Usage Examples
**Get expiring items:**
```
Use the inventory://expiring-items resource to see what needs attention
```
**Plan meals:**
```
Use the meal_planning_assistant prompt with current inventory data
```
**Add new item:**
```
Use add_inventory_item tool with: milk, Dairy, Refrigerator, 1, gallon
```
## Data Backend
The MCP server connects to a **Notion database** that stores all inventory data. The `FoodWiseNotionClient` handles:
- βœ… CRUD operations on inventory items
- βœ… Filtering and search functionality
- βœ… Expiration date calculations
- βœ… Defensive handling of flexible Notion schema
### Database Schema
Key Notion properties:
- **Name** (title): Item identifier
- **Category** (select): Food category (Dairy, Raw Meat, etc.)
- **Storage Type** (select): Pantry/Refrigerator/Freezer
- **Quantity** (number): Amount available
- **Unit** (text): Measurement unit
- **Best By Date** (date): Expiration date
- **Location/Shelf** (text): Specific storage location
- **Tags** (multi-select): Organization labels
## Error Handling
The server implements comprehensive error handling:
- **Notion API errors**: Graceful degradation with error messages
- **Missing data**: Defensive programming with sensible defaults
- **Type mismatches**: Safe conversion with fallbacks
- **Network issues**: Timeout handling and retry logic
## Development
### Running the Server
```bash
# Basic usage (stdio transport)
uv run python -m foodwise.mcp_server
# With debug logging
MCP_LOG_LEVEL=DEBUG uv run python -m foodwise.mcp_server
# Using FastMCP CLI with HTTP transport
uv run fastmcp run src/foodwise/mcp_server/main.py --transport http --port 8080
# Custom server name
MCP_SERVER_NAME="MyFoodWise" uv run python -m foodwise.mcp_server
```
#### Remote Deployment (HTTP Mode)
For HuggingFace Spaces or similar cloud deployment:
```bash
# Using the main.py entry point (for Docker/cloud deployment)
uv run python main.py
# With custom environment
HOST=0.0.0.0 PORT=7860 ENVIRONMENT=production uv run python main.py
# Local HTTP testing (before deployment)
HOST=127.0.0.1 PORT=7860 uv run python main.py
```
**Remote Server Features**:
- HTTP transport for web accessibility
- Environment-based configuration
- Docker containerization ready
- OAuth-free MCP client access
### Testing Integration
```bash
# Test with manual MCP client
uv run python scripts/manual_test.py
# Test with FastMCP dev server (includes MCP Inspector)
uv run fastmcp dev src/foodwise/mcp_server/main.py
```
#### Remote Server Testing
```bash
# Test remote MCP server with MCP Inspector
npx @modelcontextprotocol/inspector "https://leowalker-foodwise-remote-mcp.hf.space/mcp/"
# Test supergateway bridge locally
npx supergateway --streamableHttp "https://leowalker-foodwise-remote-mcp.hf.space/mcp/" --logLevel debug
# Verify remote server health
curl -I "https://leowalker-foodwise-remote-mcp.hf.space/mcp/"
```
**Remote Testing Notes**:
- MCP Inspector provides interactive testing interface
- `supergateway` bridges HTTP MCP to stdio for Claude Desktop
- Remote server responds on `/mcp/` endpoint with Streamable-HTTP protocol
### Adding New Primitives
1. **Tools**: Add to `fastmcp_tools.py` and register in `register_inventory_tools()`
2. **Resources**: Add to `fastmcp_resources.py` and register in `register_resources()`
3. **Prompts**: Add template constant and function to `fastmcp_prompts.py`
## Configuration
The server follows FastMCP best practices for minimal configuration:
- **Environment Variables**:
- `MCP_SERVER_NAME` - Override server name (default: "FoodWise")
- `MCP_LOG_LEVEL` - Set logging level (DEBUG, INFO, WARNING, ERROR)
- **CLI Arguments**: Use `fastmcp run` with transport and port options
- **Zero Config**: Works out of the box with sensible defaults
## Future Enhancements
- [ ] External recipe API integration
- [ ] Configurable meal suggestion algorithms
- [ ] Batch operations for bulk inventory updates
- [ ] Advanced filtering and sorting options
- [ ] Integration with grocery delivery APIs
- [ ] Nutritional information tracking
---
*For more information about the broader FoodWise project, see the main [README.md](../../../README.md).*