SmartPark Reservation MCP Server
Provides a secure MCP tool to append confirmed parking reservations to durable storage with validation, audit logging, and concurrency safety.
README
SmartPark Reservation MCP Server — Stage 3
A real MCP (Model Context Protocol) server, built with the official
mcp Python SDK, that writes confirmed parking reservations to durable
storage once a human administrator has approved them (Stage 2).
This is a separate repository/service from Stages 1 and 2 — Agent 2 calls this server's single tool over the network, the same way any MCP-compliant client would.
What it does
Exposes exactly one MCP tool: write_confirmed_reservation. Once
the administrator (Agent 2) approves a reservation, Agent 2 calls this
tool, which:
-
Validates every field (rejects the
|delimiter, newlines, null bytes, and overly long values — these would corrupt the file format or let a caller inject a fake extra record). -
Appends one line to
data/confirmed_reservations.txtin the exact required format:Name | Car Number | Reservation Period | Approval Time -
Does this atomically and safely under concurrent calls (cross-platform file locking), and logs the attempt (success or rejection) to an audit log.
Architecture
Agent 2 (Stage 2 Admin Agent) Agent 3 (this repo)
┌──────────────────────────┐ MCP/HTTP ┌────────────────────────────┐
│ apply_decision(confirmed) │ ────────────▶ │ POST /mcp │
│ │ Bearer token │ BearerAuthMiddleware │
│ integration/ │ required │ RateLimitMiddleware │
│ admin_agent_client.py │ │ MCPServer │
│ -> record_confirmed_ │ │ └─ write_confirmed_ │
│ reservation() │ │ reservation tool │
└──────────────────────────┘ │ └─ validate ─┐ │
│ ▼ │
│ data/confirmed_ │
│ reservations.txt │
│ (file-locked append) │
│ + data/audit.log │
└────────────────────────────┘
Why the official MCP SDK (not just a REST endpoint)
Stage 3 asks for a real MCP server, or a FastAPI stand-in if that's not
feasible. The official mcp Python SDK (MCPServer, formerly known as
FastMCP) turned out to be fully usable here: it builds a standard
streamable-HTTP ASGI app (so it composes with normal Starlette middleware
for auth/rate-limiting) and ships with production security features out
of the box — DNS-rebinding protection, host/origin allowlisting, and
request-body size limits — which is exactly what "secure and resistant to
unauthorized access" calls for. Building a hand-rolled JSON-RPC-over-FastAPI
server would have meant re-implementing a worse version of these same
protections.
Security measures
| Concern | Mitigation |
|---|---|
| Unauthorized callers | BearerAuthMiddleware — every request needs Authorization: Bearer <MCP_API_KEY>, compared with hmac.compare_digest (no timing side-channel). No key configured → the server generates and prints a random one-time key rather than silently allowing unauthenticated access. |
| Abuse / DoS | RateLimitMiddleware — fixed-window limit per client IP (default 30 req/min, configurable). |
| DNS rebinding / host spoofing | The MCP SDK's built-in TransportSecuritySettings (enabled by default), with configurable ALLOWED_HOSTS/ALLOWED_ORIGINS for production. |
| Path traversal | Structurally impossible — the output file path is fixed by server config and is never accepted as a tool argument. |
| Record/format injection | Every field is validated to reject the ` |
| Concurrent-write corruption | Cross-platform atomic file locking (filelock) around every append — tested with 20 simultaneous threads writing with zero interleaved/corrupted lines. |
| Oversized/malformed requests | max_request_body_size capped at 64KB (reservation payloads are tiny; anything bigger is rejected outright). |
| Traceability without leaking secrets | Every write attempt (success or rejection) is appended to data/audit.log, with only a masked token prefix — the real API key is never logged. |
| Reliability | A stuck lock surfaces as a clear, catchable TimeoutError after 5s rather than hanging the server; invalid input raises a specific InvalidReservationField the MCP layer turns into a normal tool-error result rather than crashing the process. |
Project structure
parking_mcp_server/
├── app/
│ ├── config.py # .env-driven configuration
│ ├── reservation_writer.py # field validation + atomic file append
│ ├── audit_log.py # append-only audit trail
│ ├── security.py # BearerAuthMiddleware, RateLimitMiddleware
│ └── server.py # MCPServer + tool + ASGI wiring
├── integration/
│ ├── admin_agent_client.py # what Stage 2 imports to call this server
│ └── db_patch_example.py # exact diff for Stage 2's decision endpoint
├── tests/ # 22 pytest tests across 4 modules
├── demo.py # end-to-end demo (live server + real MCP client)
├── view_reservations.py # quick CLI viewer for the output file/audit log
├── run_server.sh / run_server.ps1
├── requirements.txt
├── .env.example
└── .github/workflows/ci.yml # runs tests on both ubuntu-latest and windows-latest
Setup
Works identically on Windows, macOS, and Linux — pure Python (the
official mcp SDK, Starlette/uvicorn, and the cross-platform filelock
package; no OS-specific binaries).
python -m venv .venv && source .venv/bin/activate # Windows: .venv\Scripts\activate
pip install -r requirements.txt
cp .env.example .env
# Set MCP_API_KEY in .env for a stable key -- otherwise a random one-time
# key is generated and printed at startup.
Windows-specific notes
- Use
run_server.ps1instead ofrun_server.sh. filelockusesmsvcrtunder the hood on Windows automatically — no extra configuration needed for the concurrency-safety guarantees.- CI runs the full test suite on
windows-latestas well asubuntu-latest(see.github/workflows/ci.yml).
Usage
Run the demo (starts its own server, no setup needed):
PYTHONPATH=. python demo.py
Run the real server:
./run_server.sh # Linux/macOS
.\run_server.ps1 # Windows
It prints a generated MCP_API_KEY on first run if you haven't set one —
copy it into your client's Authorization: Bearer <key> header (or into
Stage 2's .env as MCP_API_KEY, see Integration below).
View what's been written:
PYTHONPATH=. python view_reservations.py
Run tests:
PYTHONPATH=. python -m pytest tests/ -v
Integration with Agent 2 (Stage 2)
integration/admin_agent_client.py— the client Stage 2 imports (record_confirmed_reservation(name, car_number, reservation_period, approval_time)), which opens a real MCP client session, authenticates, and calls the tool.integration/db_patch_example.py— the exact before/after diff for Stage 2'sPOST /requests/{id}/decisionendpoint: once a reservation is marked"confirmed", it now also callsrecord_confirmed_reservation(...)so the approval is durably recorded here, not just in Stage 2's own request-tracking table.- Stage 2's
.envneeds:MCP_SERVER_URL=http://127.0.0.1:8002/mcpandMCP_API_KEY=<the same key configured on this server>.
Notes / limitations (Stage 3 scope)
- Rate limiting and the audit log are in-memory/local-file, appropriate for a single-process deployment; a multi-instance deployment would move the rate limiter to a shared store (e.g. Redis) and the audit log to a centralized logging system.
MCP_API_KEYis a single shared secret rather than per-client credentials — sufficient for a single trusted caller (Agent 2), but a multi-tenant deployment would want per-client tokens or the MCP SDK's full OAuth 2.1 support (auth_server_provider/AuthSettings, not used here since it requires standing up a separate OAuth issuer).- The reservations file is a flat text file, as specified; a higher-volume production deployment would likely write to a database instead, behind the same tool interface.
Recommended Servers
playwright-mcp
A Model Context Protocol server that enables LLMs to interact with web pages through structured accessibility snapshots without requiring vision models or screenshots.
Magic Component Platform (MCP)
An AI-powered tool that generates modern UI components from natural language descriptions, integrating with popular IDEs to streamline UI development workflow.
Audiense Insights MCP Server
Enables interaction with Audiense Insights accounts via the Model Context Protocol, facilitating the extraction and analysis of marketing insights and audience data including demographics, behavior, and influencer engagement.
VeyraX MCP
Single MCP tool to connect all your favorite tools: Gmail, Calendar and 40 more.
graphlit-mcp-server
The Model Context Protocol (MCP) Server enables integration between MCP clients and the Graphlit service. Ingest anything from Slack to Gmail to podcast feeds, in addition to web crawling, into a Graphlit project - and then retrieve relevant contents from the MCP client.
Kagi MCP Server
An MCP server that integrates Kagi search capabilities with Claude AI, enabling Claude to perform real-time web searches when answering questions that require up-to-date information.
E2B
Using MCP to run code via e2b.
Neon Database
MCP server for interacting with Neon Management API and databases
Exa Search
A Model Context Protocol (MCP) server lets AI assistants like Claude use the Exa AI Search API for web searches. This setup allows AI models to get real-time web information in a safe and controlled way.
Qdrant Server
This repository is an example of how to create a MCP server for Qdrant, a vector search engine.