Inventory MCP Server
by SebastianUVG
README.md
# Inventory MCP Server
## Overview
Inventory MCP Server is a standalone Model Context Protocol server for querying
and administering a small business inventory. It exposes deterministic inventory
facts and controlled write operations backed by SQLite, so an MCP host does not
need to invent stock information.
The MCP lifecycle and JSON-RPC 2.0 handling are implemented directly with the
Python standard library. This project does not use FastMCP, an MCP SDK, an LLM,
OpenAI, or a Web framework.
## Features
- MCP protocol version `2025-06-18` over newline-delimited stdio.
- Manual `initialize`, `notifications/initialized`, `ping`, `tools/list`, and
`tools/call` handling.
- Exactly 12 inventory tools: seven read operations and five write operations.
- Repository abstraction separating business rules from SQLite.
- Atomic stock updates and movement creation.
- Reproducible schema and deterministic demonstration seed.
- Idempotent bootstrap that never duplicates seed records.
- Structured MCP results and redacted protocol logging to stderr.
- No runtime dependencies outside Python's standard library.
## Architecture
```text
MCP Host
-> MCP Client
-> newline-delimited JSON-RPC 2.0 over stdio
-> Inventory MCP Server
-> Inventory Tool Dispatcher
-> InventoryService
-> InventoryRepository
-> SQLiteInventoryRepository
-> SQLite
```
The host owns the LLM, conversation, user interface, and write-confirmation
policy. This repository contains only the Inventory MCP Server.
## Requirements
- Python 3.11 or newer.
- Git only when cloning the future public repository.
- Docker is optional.
## Installation
Clone the repository and enter it:
```bash
git clone <public-repository-url>
cd inventory-mcp-server
```
Create a virtual environment:
```bash
python -m venv .venv
```
Activate it on Windows PowerShell:
```powershell
.\.venv\Scripts\Activate.ps1
```
Or activate it on macOS/Linux:
```bash
source .venv/bin/activate
```
Install the package in editable mode:
```bash
python -m pip install -e .
```
No API key or Internet connection is required after installation.
## Database Setup
Create the SQLite schema and deterministic demonstration data:
```bash
python -m inventory_mcp.inventory.bootstrap --seed
```
The default database is `data/inventory.db`. The command creates parent
directories and the database when absent. Running it again is safe: products are
identified by SKU and demonstration movements by unique reference, so the second
run adds zero records.
For an explicit path:
```powershell
$env:INVENTORY_DB_PATH = "data/my-inventory.db"
python -m inventory_mcp.inventory.bootstrap --seed
```
The optional `--reset` flag deletes and rebuilds the selected database. Use it
only intentionally for disposable demonstration data:
```bash
python -m inventory_mcp.inventory.bootstrap --reset --seed
```
## Running the Server
Start the primary stdio transport:
```bash
python -m inventory_mcp.mcp.stdio
```
After editable installation, the equivalent console command is:
```bash
inventory-mcp
```
An stdio MCP server waits for JSON-RPC messages on stdin, so an empty terminal
appears idle. Normally an MCP host starts and communicates with this process.
Protocol frames use stdout exclusively; diagnostic logs use stderr.
## MCP Integration
A generic MCP host can launch the server with an absolute Python executable and
an absolute database path. Adapt the host's configuration format as needed:
```json
{
"mcpServers": {
"inventory": {
"command": "/absolute/path/to/.venv/bin/python",
"args": ["-m", "inventory_mcp.mcp.stdio"],
"env": {
"INVENTORY_DB_PATH": "/absolute/path/to/data/inventory.db"
}
}
}
}
```
On Windows, the executable normally ends in `.venv\\Scripts\\python.exe`.
This example is conceptual because host configuration formats differ. Use a host
that supports MCP `2025-06-18` and newline-delimited stdio.
### JSON-RPC lifecycle examples
Each message below is one complete line. Initialize first:
```json
{"jsonrpc":"2.0","id":1,"method":"initialize","params":{"protocolVersion":"2025-06-18","capabilities":{},"clientInfo":{"name":"example-host","version":"1.0"}}}
```
Complete initialization with a notification:
```json
{"jsonrpc":"2.0","method":"notifications/initialized"}
```
Discover the server-owned tool catalog:
```json
{"jsonrpc":"2.0","id":2,"method":"tools/list"}
```
Call a read tool:
```json
{"jsonrpc":"2.0","id":3,"method":"tools/call","params":{"name":"get_low_stock_products","arguments":{"include_out_of_stock":true,"limit":5}}}
```
Call a write tool:
```json
{"jsonrpc":"2.0","id":4,"method":"tools/call","params":{"name":"record_inventory_entry","arguments":{"sku":"ELEC-002","quantity":5,"reason":"Supplier delivery","reference":"EXAMPLE-IN-001"}}}
```
Successful tool execution returns MCP `content`, `structuredContent`, and
`isError: false`. Expected business failures return a successful JSON-RPC response
with `isError: true`; malformed parameters remain JSON-RPC errors.
## Available Tools
The server exposes exactly these tools:
| Type | Tool |
| --- | --- |
| Read | `get_product_stock` |
| Read | `get_low_stock_products` |
| Read | `get_restock_recommendations` |
| Read | `get_product_movements` |
| Read | `get_inactive_products` |
| Read | `get_product_movement_ranking` |
| Read | `list_products` |
| Write | `add_product` |
| Write | `record_inventory_entry` |
| Write | `record_inventory_exit` |
| Write | `update_product` |
| Write | `adjust_inventory` |
See [docs/tools.md](docs/tools.md) for every tool's purpose, parameters, result,
errors, and example arguments. `tools/list` remains the authoritative
machine-readable definition.
## Example Scenarios
- Find products requiring attention with `get_low_stock_products`.
- Calculate purchase quantities with `get_restock_recommendations`.
- Audit one product with `get_product_movements`.
- Browse products by category, price, stock, or search text with `list_products`.
- Create a SKU with `add_product`.
- Record deliveries and sales with `record_inventory_entry` and
`record_inventory_exit`.
- Change administrative thresholds or price with `update_product`.
- Reconcile a physical count with `adjust_inventory`.
## Configuration
The standalone server has one environment variable:
| Variable | Default | Meaning |
| --- | --- | --- |
| `INVENTORY_DB_PATH` | `data/inventory.db` | SQLite file used by bootstrap and the server. |
Copy `.env.example` only as a reference. The server intentionally has no
LLM provider credentials, remote token, or deployment-platform configuration.
## Logging
The server writes one compact JSON record per protocol request and response to
stderr. Stdout contains only JSON-RPC protocol frames. Sensitive keys such as
`authorization`, `api_key`, `password`, `secret`, and `token` are recursively
replaced with `[REDACTED]` if they occur in a message.
Do not redirect diagnostic stderr into stdout because that would corrupt the
stdio protocol stream.
## Testing
Run the complete standalone suite without API keys or network access:
```bash
python -m unittest discover -s tests -v
```
The tests cover domain rules, repository behavior, SQLite bootstrap and seed,
atomicity and rollback, JSON-RPC validation, MCP initialization, exactly 12 tool
schemas, read/write calls, business errors, and a real stdio subprocess.
## Project Structure
```text
inventory-mcp-server/
|-- README.md
|-- docs/tools.md
|-- pyproject.toml
|-- Dockerfile
|-- .dockerignore
|-- .env.example
|-- .gitignore
|-- src/inventory_mcp/
| |-- config.py
| |-- inventory/
| | |-- models.py
| | |-- repository.py
| | |-- service.py
| | |-- bootstrap.py
| | `-- sqlite/
| `-- mcp/
| |-- jsonrpc.py
| |-- logging.py
| |-- protocol.py
| |-- tools.py
| |-- server.py
| `-- stdio.py
`-- tests/
```
## Optional Docker Usage
Python and stdio do not require Docker. To use an isolated container instead:
```bash
docker build -t inventory-mcp-server:local .
docker volume create inventory-mcp-data
docker run --rm --entrypoint python -v inventory-mcp-data:/data inventory-mcp-server:local -m inventory_mcp.inventory.bootstrap --seed
docker run --rm -i -v inventory-mcp-data:/data inventory-mcp-server:local
```
The final command requires `-i` because MCP reads JSON-RPC messages from stdin.
The named volume preserves SQLite between container executions.
## Security and Limitations
- The included records are fictitious demonstration data.
- SQLite is appropriate for local use and this academic server, not every
high-concurrency production deployment.
- Stdio access is controlled by the local operating system and the MCP host.
- Five tools modify data. A host should show the exact pending operation and ask
the user for confirmation before invoking a write tool.
- The server validates arguments and uses parameterized SQL, but it does not
implement user accounts, roles, or an approval interface.
- Database files, `.env`, logs, caches, and virtual environments are ignored by Git.
## License
No license has been selected yet. Choose and add a license before publishing if
you want to grant reuse rights explicitly.
This server cannot be deployed
Maintenance
ActivityMaintained
ResponsivenessNo issues