Skip to main content
Glama
LaysonDilson

mcp-ops-server

by LaysonDilson

mcp-ops-server

A reference implementation of an MCP server that gives an LLM agent real, safe write access to a business database — orders arriving from sales channels, production state per item, and FIFO material stock.

It is deliberately small (about 1,000 lines including tests) and deliberately opinionated. Every design decision below came from running a system shaped like this one in a real operation, where a wrong tool call costs money rather than a red test.

pip install -r requirements.txt
python -m ops          # runnable demo, no MCP client needed
pytest                 # 29 tests

What this demonstrates

Most "AI integration" projects wire a chatbot on top of a REST API and stop. The hard part is not calling the model — it is designing a tool surface that an autonomous agent cannot corrupt, over data that stays correct when the same file gets imported for the fourth time.

Four rules carry most of that weight:

1. State is derived, never assigned

An order's status is computed from its items every time an item moves:

Derived

meaning

open

every item still todo

in_progress

some item started

ready

every item done

Only genuine human decisions — packing, shipped, cancelled — are written directly, and derivation refuses to overwrite them. There is no code path where an agent sets ready on an order whose items are untouched, because there is no code path where anything sets ready at all.

2. Re-importing a file must never destroy work

Channel exports overlap: today's file contains yesterday's orders. Ingestion upserts on (channel, external_id), and item rows are replaced wholesale — the export is the source of truth for what was ordered. But production state is snapshotted per SKU first and re-applied afterwards.

Without that snapshot, the 6am import silently resets everything finished the day before. When quantity drops between exports, the most advanced units are the ones kept: throwing away finished work is worse than throwing away pending work.

def test_reimport_preserves_production_state(conn):
    ...  # tests/test_ops.py

3. Header data is not row data

Marketplace exports repeat the order total and the fee on every item line. Summing them multiplies revenue by the item count — the most common and most expensive bug in this category of importer. Fees are read once per order group, and there is a test that fails if that ever regresses.

An actual fee, once known, never regresses to an estimate.

4. Balances are sums, not counters

Stock has no stored balance. Receipts create FIFO lots; consumption walks them oldest-first and returns what the material really cost. The balance is SUM(in) - SUM(out) over an append-only movement log, so it cannot drift from its own history. Insufficient stock raises rather than going negative or consuming partially.


Related MCP server: scopedb-mcp

The tool surface

Eleven tools. The interesting part is not the count — it is that the docstrings are longer than the functions.

Tool

Purpose

board_list

open orders with items, most urgent deadline first

item_set_state

move one item todo → doing → done, optionally drawing material

order_advance

apply a manual status, refusing transitions that skip production

ingest_csv

idempotent import of a channel export

stock_status / stock_receive / stock_consume

derived balance, FIFO lots, real cost

material_upsert / sku_upsert

catalogue

pending_recipes

SKUs seen in orders with no recipe yet, most-sold first

audit_tail

who changed what, when

Why the docstrings are long

A tool's docstring is not a comment. It is the entire interface contract the model sees at call time. The model cannot read the source, cannot inspect the schema, and cannot ask a clarifying question before choosing arguments. Every ambiguity left in a docstring becomes a wrong tool call in production.

What actually works:

  • say what the tool is for, not only what it does;

  • name the units and the exact allowed values;

  • state what it refuses and why;

  • point at the tool to call instead when this one is the wrong choice.

Compare a typical generated docstring with the one in mcp_server.py:

# Typical — technically accurate, operationally useless
def stock_receive(material_code: str, qty: float, unit_cost: float) -> dict:
    """Receive stock for a material."""

# What the model actually needs
def stock_receive(material_code: str, qty: float, unit_cost: float) -> dict:
    """Register a purchase as a new FIFO lot.

    Args:
        material_code: must already exist — create it with `material_upsert`.
        qty: amount received, in the material's own unit (g, ml, unit).
        unit_cost: price per that same unit, not per package. If you bought a
            1kg spool for 90.00 and the unit is grams, unit_cost is 0.09.
    """

The second version is why an agent stops recording a 1kg spool as costing 90.00 per gram.

Safety rails

  • Destructive and terminal transitions are validated, not trusted: ready → packing → shipped is the only path to shipped.

  • Every mutation is written to audit_log with its actor (agent, human, ingest), so agent actions can always be separated from human ones after the fact.

  • A missing recipe never blocks production; it only leaves costing incomplete and puts the SKU at the top of pending_recipes. Catalogue maintenance is a queue you drain by frequency, not a hundred forms you fill before starting.


Architecture

ops/
├── db.py           schema + forward-only idempotent migrations
├── ingest.py       CSV parsing: dirty money, tabs, locale dates, grouping
├── services.py     derived state, idempotent upsert, FIFO, audit
├── mcp_server.py   the tool surface (docstrings are the contract)
└── __main__.py     runnable demo
tests/test_ops.py   29 tests, one per way this goes wrong

Dependencies: mcp and pytest. Storage is SQLite through the standard library — no ORM, because at this size the schema is the documentation.

migrate() runs on every connection and is safe to call repeatedly: a fresh database and one from three versions ago converge to the same shape. Table reshaping happens in a _pre_migrate hook that runs before the schema script, because creating an index on a column that does not exist yet is the classic way to brick a startup on real data.

Registering it with an MCP client

claude mcp add ops -- python -m ops.mcp_server

Built against mcp >= 2.0, where the server class is MCPServer. On mcp 1.x the equivalent import is from mcp.server.fastmcp import FastMCP.


What is deliberately absent

  • No web UI. The tools are the product; a UI would be the least interesting 400 lines here.

  • No auth or multi-tenancy. Single operator by design. Adding tenancy would mean a tenant filter on every query — a real concern, but a different demonstration.

  • No LLM calls anywhere in this codebase. Arithmetic is deterministic and belongs in code. The model's job is to decide what to do and to explain the result — not to add up a stock balance.


Provenance

Extracted from the design of a private system I built and run daily for my own manufacturing operation — a 35-tool MCP server that ingests marketplace order exports, schedules production against shipping deadlines, and tracks material consumption. This repository reimplements that architecture on a neutral domain with synthetic data; it shares no code, data or business logic with the original.

Built by Layson Santos — 13 years of Java and distributed systems, now building systems where the LLM is part of the architecture rather than a chatbot bolted on top.

MIT licensed.

A
license - permissive license
-
quality - not tested
C
maintenance

Maintenance

Maintainers
Response time
Release cycle
Releases (12mo)
Commit activity

Resources

Unclaimed servers have limited discoverability.

Looking for Admin?

If you are the server author, to access and configure the admin panel.

Related MCP Servers

View all related MCP servers

Related MCP Connectors

  • MCP server for AI agents to plan, verify, and deploy Cloudflare-native apps.

  • Control plane for autonomous software labor. Agents claim objectives over MCP with audit trail.

  • MCP server for generating rough-draft project plans from natural-language prompts.

View all MCP Connectors

Latest Blog Posts

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/LaysonDilson/mcp-ops-server'

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