Skip to main content
Glama
mgnlia

Shelf Life MCP

by mgnlia

Shelf Life MCP

CI License: MIT

A self-hosted Model Context Protocol (MCP) server that tracks household shelf life — what is in the fridge, what is about to expire, and what to cook first. Built as an Alexa+ Agent Skill entry, it speaks the open MCP spec (2025-11-25+) over Streamable HTTP and persists everything in a local SQLite file. No cloud dependency, no partner-only SDK.

License: MIT — see LICENSE at the top of the repo.


Why this exists

Alexa+ "Agent Skills" are MCP servers. This project implements that contract against the open specification so it can be demoed with the MCP Inspector or any generic MCP client, rather than depending on Amazon's partner-only Category SDK / MCP Toolkit.

Related MCP server: household-agent

Language choice

Python 3.10+ with uv. Rationale:

  • The official mcp Python SDK (v2) ships a first-class MCPServer class and a Client that can connect in memory, which makes a passing test per tool trivial and hermetic — no subprocess, no port, no flaky network.

  • uv gives reproducible, fast dependency resolution and a lockfile.

  • SQLite is in the standard library, so persistence adds zero runtime deps.

Features

Tool

Purpose

add_item

Record a food item with an expiry date.

list_items

List items, filtered by all / expiring / expired / consumed.

expiring_soon

Items expiring within N days (default 7), soonest first.

consume_item

Reduce quantity; auto-marks consumed at zero.

suggest_recipe

Deterministic "use it up" suggestion; urgency or FIFO ranking.

Architecture

mcp.json ──► config.load_config() ──► MCPServer (server.py)
                                          │
                                          ├── add_item        ┐
                                          ├── list_items      │
                                          ├── expiring_soon   ├─► Store (store.py) ──► SQLite
                                          ├── consume_item    │
                                          └── suggest_recipe  ┘
                                          │
                                   mcp.run(transport="streamable-http", ...)
  • mcp.json is a real MCP config document. It is loaded in code at import time (server.pyload_config()), and it drives the transport host, port, path, protocol version, and database location. It is not decorative.

  • config.py validates the config with Pydantic and resolves paths.

  • store.py owns all SQLite access (schema, queries, the recipe heuristic).

  • server.py registers the five tools and derives mcp.run() kwargs from the loaded config.

Setup

Requires Python 3.10+ and uv.

git clone https://github.com/mgnlia/shelf-life-mcp.git
cd shelf-life-mcp
uv sync --dev

Run

Streamable HTTP (the transport declared in mcp.json):

uv run shelf-life-mcp
# or:
uv run python -m shelf_life_mcp

The server listens on http://127.0.0.1:8000/mcp (host/port/path come from mcp.json). Override the config or database without editing files:

SHELF_LIFE_CONFIG=/path/to/mcp.json SHELF_LIFE_DB=/tmp/demo.db uv run shelf-life-mcp

Try it with the MCP Inspector

npx @modelcontextprotocol/inspector
# Transport: Streamable HTTP
# URL:       http://127.0.0.1:8000/mcp

MCP client configuration

Drop this into your MCP client's config (Claude Desktop, Cursor, VS Code, etc.). The same document lives in mcp.json in this repo.

{
  "mcpServers": {
    "shelf-life": {
      "type": "streamable-http",
      "url": "http://127.0.0.1:8000/mcp",
      "transport": { "host": "127.0.0.1", "port": 8000, "path": "/mcp" },
      "database": "./shelf_life.db",
      "protocolVersion": "2025-11-25"
    }
  }
}

Tool schemas

Generated from the Python type hints; output_schema is derived from each return annotation.

add_item

{
  "name": "add_item",
  "input_schema": {
    "type": "object",
    "properties": {
      "name": { "type": "string", "title": "Name" },
      "expires_on": { "type": "string", "title": "Expires On" },
      "qty": { "type": "number", "default": 1, "title": "Qty" },
      "unit": { "type": "string", "default": "item", "title": "Unit" }
    },
    "required": ["name", "expires_on"]
  }
}

list_items

{
  "name": "list_items",
  "input_schema": {
    "type": "object",
    "properties": {
      "filter": { "type": "string", "default": "all", "title": "Filter" }
    },
    "required": []
  }
}

filterall | expiring | expired | consumed.

expiring_soon

{
  "name": "expiring_soon",
  "input_schema": {
    "type": "object",
    "properties": { "days": { "type": "integer", "default": 7, "title": "Days" } },
    "required": []
  }
}

consume_item

{
  "name": "consume_item",
  "input_schema": {
    "type": "object",
    "properties": {
      "id": { "type": "integer", "title": "Id" },
      "qty": { "type": "number", "default": 1, "title": "Qty" }
    },
    "required": ["id"]
  }
}

suggest_recipe

{
  "name": "suggest_recipe",
  "input_schema": {
    "type": "object",
    "properties": {
      "use_first": { "type": "boolean", "default": true, "title": "Use First" }
    },
    "required": []
  }
}

use_first changes how the suggested ingredients are ranked:

  • use_first: true (default) — rank by urgency: already-expired items first, then the soonest expiry, then name. The dish is named after the most urgent ingredient.

  • use_first: false — ignore urgency and rank by stock age (FIFO): items added earliest come first, so the oldest stock is cleared before it spoils. The dish is named after the longest-held ingredient.

Both modes consider only unconsumed items expiring within 7 days and cap the suggestion at three ingredients. When nothing is close to expiring, the tool returns an empty use_first list and a "shop fresh" rationale.

Tests

One passing test per tool, run through the in-memory MCP client against the real registered tools:

uv run pytest

Covered: add_item, list_items, expiring_soon, consume_item, suggest_recipe (both use_first modes), plus tool-registration and config/edge-case tests.

Project layout

shelf-life-mcp/
├── mcp.json                 # MCP config, loaded in code
├── pyproject.toml
├── src/shelf_life_mcp/
│   ├── config.py            # MCP config loading + validation
│   ├── store.py             # SQLite persistence + recipe heuristic
│   ├── server.py            # MCPServer, tools, transport
│   └── __main__.py
└── tests/
    ├── conftest.py
    ├── test_tools.py        # one test per tool
    └── test_config.py

License

MIT © 2026 Shelf Life MCP contributors.

Related MCP Connectors

Related MCP Servers

  • A
    license
    Not graded
    quality
    C
    maintenance
    Household-aware kitchen brain for AI agents: manage pantry inventory with freshness tracking, shopping lists, recipe collections with cook notes and per-diner ratings, dietary profiles with allergen safety, and kitchen equipment — all through 27 tools with OAuth 2.1 authentication. Includes a free tool for ingredient-based recipe generation without an account (accounts are free!).
    MIT
  • F
    license
    A
    quality
    B
    maintenance
    Enables users to manage their fridge inventory by listing, adding, removing, checking items, and identifying expiring items, as well as getting dinner ideas from available ingredients.
    5
    -
  • F
    license
    Not graded
    quality
    C
    maintenance
    Your digital kitchen, powered by AI. Track what you have, discover what you can cook, and get guided through every recipe — step by step, timer by timer.
    -