Skip to main content
Glama

FoodOps MCP

Seeded food-order, delivery, refund, and invoice operations exposed through Model Context Protocol. Node.js 22, strict TypeScript, pnpm, SQLite, Zod, and the pinned MCP SDK. The applications are the MCP backend, dashboard REST API and React 18/Vite web foundation.

From the workspace root, with Node 22 and pnpm 10 active:

pnpm install
cp .env.example .env
pnpm migrate
pnpm seed
pnpm build
pnpm --silent dev:mcp

Copy .env.example only when creating your local .env; preserve existing settings. Stdio waits for an MCP host on stdin and writes only JSON-RPC to stdout. Use Ctrl+C to stop it. Start HTTP with MCP_AUTH_TOKEN set using pnpm start:http.

See the MCP server guide for environment variables, the tool catalog, authenticated HTTP, complete Inspector/Claude Desktop verification, and troubleshooting. The project documentation is the source of truth.

Validation:

pnpm typecheck
pnpm build
pnpm test
pnpm lint

Transport tests start temporary loopback listeners and child processes. They use seeded temporary databases and do not change data/foodops.sqlite.

MCP environment

Process values override the workspace .env.

Variable

Default

Meaning

DB_PATH

./data/foodops.sqlite

Initialized SQLite file; relative to workspace root.

MCP_HOST

127.0.0.1

HTTP bind address; non-loopback access also needs an explicit allowlist.

PORT

3001

HTTP port, integer 1–65535.

MCP_PORT

unset

Legacy port fallback when PORT is absent.

ALLOWED_HOSTS

loopback at PORT

Comma-separated host:port authorities for request Host and Origin. Defaults: 127.0.0.1, localhost, [::1] with the listener port. No URLs or wildcards.

MCP_AUTH_TOKEN

unset

Required for HTTP: at least 32 characters without whitespace. Stdio is trusted locally.

MCP_CONFIRM_SECRET

random per process

Optional shared HMAC secret, at least 32 characters without surrounding whitespace; sharing supports multiple processes, rotation invalidates tokens.

LOG_LEVEL

info

fatal, error, warn, info, debug, trace, or silent.

Choose stdio or HTTP through its entrypoint. Preview write tools without a token, show the preview to the user, then execute with its five-minute confirmation_token after approval. The host enforces human approval. See the server guide for retry behavior and the isolated stdio verification command.

Related MCP server: Food Order Bot MCP Server

Dashboard API foundation

Set a separate ADMIN_TOKEN in .env (32+ characters, no whitespace), then run pnpm dev:api, or pnpm build followed by pnpm start:api. Public probes: GET /api/health for liveness and GET /api/ready for a core DB read. Domain routes require bearer authentication; operator writes require explicit confirmation and an idempotency key. See the REST endpoint reference. See the API guide for security, error contracts, and lifecycle ownership.

Variable

Default

Meaning

DB_PATH

./data/foodops.sqlite

Existing initialized SQLite file; relative to workspace root.

API_HOST

127.0.0.1

Listener host; trustProxy is false.

API_PORT

3002

Integer 1–65535.

ADMIN_TOKEN

required

32+ characters without whitespace; bearer auth.

API_CONFIRM_SECRET

unset

Optional 32+ characters without whitespace; random per-process when unset/empty.

WEB_ORIGIN

http://localhost:5173

Comma-separated exact HTTP(S) origins; credentials disabled.

LOG_LEVEL

info

fatal, error, warn, info, debug, trace, silent.

RATE_LIMIT_PER_MIN

1200

Positive safe integer; overall per-IP requests/minute.

RATE_LIMIT_WRITE_PER_MIN

60

Positive safe integer; independent write/preview/simulator bucket.

RATE_LIMIT_TICKET_PER_MIN

60

Positive safe integer; independent ticket issuance bucket.

SIMULATOR

off

off or on; explicitly authorized synthetic traffic.

SIMULATOR_INTERVAL_MS

5000

1000–60000 ms; jitter ±10%, clamped to bounds.

SIMULATOR_SEED

42

Unsigned 32-bit deterministic action RNG seed.

SIMULATOR_MAX_ACTIVE

60

Positive safe integer; simulator placement admission cap.

CHANGE_FEED_POLL_MS

500

100–60000 ms; single non-overlapping poller.

SSE_MAX_STREAMS

50

1–1000 concurrent streams.

SSE_REPLAY_LIMIT

1000

1–10000 durable change events per reconnect.

CALL_LOG_RETENTION_DAYS

30

1–1000000 days; audit history pruned hourly, together with 24-hour change history.

Live updates and simulator

Use POST /api/stream/ticket with bearer auth, then GET /api/stream?ticket=... within 30 seconds. Tickets are single-use; reconnect with a fresh ticket and Last-Event-ID for retained database changes. Never put the admin token in a URL. See the API reference for event/replay and simulator control contracts.

Variable

Default

Bounds/purpose

CHANGE_FEED_POLL_MS

500

100–60000 ms

SSE_MAX_STREAMS

50

1–1000 concurrent streams

SSE_REPLAY_LIMIT

1000

1–10000 durable replay events

SIMULATOR_INTERVAL_MS

5000

1000–60000 ms, ±10% jitter clamped to bounds

SIMULATOR_SEED

42

Unsigned 32-bit action seed

SIMULATOR=off is the default. With on, synthetic actions use core services as system. GET/POST /api/simulator reports statistics and changes runtime settings; restart restores environment defaults. Run pnpm smoke:api after building to exercise SSE and REST cancellation on an isolated temporary seed.

REST operations now require preview → explicit operator approval → execute with confirmation_token and Idempotency-Key. Previews add a token and five-minute expiry; the old confirm field is rejected. REST/MCP tokens are channel-separated. API_CONFIRM_SECRET is optional (32+ characters, no whitespace); unset uses a random process-local key. A stored semantic replay is returned before token verification, after auth and strict validation.

Rate limits are independent per IP: overall RATE_LIMIT_PER_MIN=1200 (including auth failures and unknown routes), write/preview/simulator RATE_LIMIT_WRITE_PER_MIN=60, and ticket issuance RATE_LIMIT_TICKET_PER_MIN=60. All must be positive integers. Tickets consume overall + ticket, not write quota. CORS exposes Retry-After, X-RateLimit-Limit, X-RateLimit-Remaining, X-RateLimit-Reset, Idempotency-Replayed and X-Request-Id on ordinary, 429 and SSE responses. Allowed request headers include Authorization, Content-Type, Idempotency-Key, Last-Event-ID, X-Request-Id, and existing X-Run-Id.

Simulator backlog: SIMULATOR_MAX_ACTIVE=60 (positive safe integer) prevents simulator placement when all active orders, including failed payments, reach the cap. External writers are not capped. Progression samples oldest untouched candidates per status (updated_at ASC, id ASC), excluding failed payments. Status adds ticks_waiting_for_partner, counting once per tick where any pickup candidate waits for a partner; other actions may still progress.

Audit history retention is controlled by CALL_LOG_RETENTION_DAYS (default 30). Its feed cursor is monotonic across pruning. Runtime.shutdown() stops and awaits background work, closes streams/tickets, and then closes DB handles; close() returns the same shutdown promise and must be awaited. Close Fastify before disposing an embedded runtime so HTTP handlers can drain.

Web foundation

See the web guide. Run pnpm dev:web at http://127.0.0.1:5173; the /api proxy targets port 3002. Existing .env files need WEB_ORIGIN to include that exact origin. Never put credentials in VITE_ variables or browser persistence.

pnpm build compiles shared, core, MCP and API first, then independently typechecks/bundles web. pnpm build:web builds shared and web only. Recursive typecheck/test and root lint include web. Shared package exports require built output; web commands build shared automatically. Dashboard features are deferred to Phase 5a.

Related MCP Connectors

Related MCP Servers