ClinicFlow AI
Click on "Deploy Server".
Wait a few minutes for the server to deploy. Once ready, it will show a "Started" state.
In the chat, type
@followed by the MCP server name and your instructions, e.g., "@ClinicFlow AICheck available appointment slots for next Tuesday afternoon and suggest one."
That's it! The server will respond to your query, and you can continue using it as needed.
Here is a step-by-step guide with screenshots.
ClinicFlow AI
Appointment booking with transactional slots and confirmed agent actions.
Role focus: Applied AI / Python Backend / Healthtech. Status: working local portfolio implementation, with synthetic data.
Demo

Excerpt from the recorded local UI demonstration, played faster. Full recording. Screenshot. Rebuild with ./scripts/render_gif.sh (FFmpeg required).
Related MCP server: clinic-engine
The engineering decision
A suggested appointment is not a booking. A conditional database update claims the slot; the booking and idempotency key commit in the same transaction. Cancellation releases only the slot still owned by that booking.
flowchart LR
UI request --> Proposal; MCP --> Availability; Proposal --> Human_confirmation; Human_confirmation --> Transaction; Transaction --> Slots_and_bookingsRun locally
Requirements: Python 3.12, uv and Make.
git clone https://github.com/danielpdev/clinicflow-ai.git
cd clinicflow-ai
make setup
make demo
make test
make evalmake demo uses an isolated temporary database where relevant, so it is safe to repeat. make eval writes a timestamped report to reports/evaluation-fixture.json. Fixture mode is deterministic and does not represent model inference. There is no recurring hosting or API subscription cost.
For the React interface (Node 22+ and pnpm 11.25.0):
make web-setup web-build
make serveOpen http://127.0.0.1:8101. The same server exposes /docs.
Real local model mode
Install Ollama, then in a separate terminal run:
OLLAMA_HOST=127.0.0.1:11435 OLLAMA_NO_CLOUD=1 ollama serveOLLAMA_HOST=127.0.0.1:11435 ollama pull qwen3:4b
make eval-localThe router also uses qwen3:1.7b as fallback; download it explicitly when running that project. No paid API key is required. First-time model/package downloads require internet and disk space. Inference runs locally. A missing model or dependency is an explicit error, never a silent fixture fallback.
PostgreSQL
The zero-service quickstart uses SQLite. The same SQLAlchemy domain layer also runs on PostgreSQL:
docker compose up -d postgres
DATABASE_URL=postgresql+psycopg://portfolio:local-demo-only@127.0.0.1:55440/demo make servetests/test_postgres.py uses POSTGRES_TEST_URL and drops its test tables during cleanup. Point it only at a dedicated disposable test database. CI provisions one independently. Local demonstration credentials are deliberately non-secret and must never be reused for production.
MCP transport
uv run --frozen python -m app.serverThis starts the official Python SDK 2.3.0 stdio server. Configure your MCP client to launch that command from this repository directory. The exposed availability/proposal tools cannot create bookings. The separate UI/API requires confirmation.
Watch the recorded demo · Reproduce the walkthrough
Verification and evidence
16 competing attempts for one slot, replayed requests, payload conflicts, cancellation after rebooking, restart persistence and PostgreSQL transactions.
Evaluation report — measured during an actual run; inspect the mode and dataset size.
CI uses standard GitHub-hosted runners and deterministic tests without downloading LLM weights. The lockfiles record exact package versions. Local-model results, when present, live in reports/evaluation-local.json; hardware/model identities are in reports/environment.json.
Limits and next iteration
The local model requested clarification in the recorded run despite an explicit date; the transaction benchmark is a system-correctness test, not a model-quality score. The demo has no identity provider or medical functionality.
Next: Add timezone-aware slot generation and a real patient identity boundary.
The local demonstration does not include production authentication, secret management or operational service guarantees. Bind it to localhost and use synthetic data. These projects demonstrate engineering decisions; they do not claim real customers, paid production deployments or guaranteed interviews.
Explore the complete 20-project portfolio
Project ownership
Implemented with Codex assistance for Daniel Popa. The owner should review the code, run it, make an independent change and rehearse the tradeoffs before presenting it at interview. That human understanding check is pending and cannot be verified automatically. See development notes.
MIT for original source; dependencies/models retain their own licenses. See third-party notices.
Reproduce browser acceptance
make web-setup web-build
uv run --frozen --group browser playwright install chromium
uv run --frozen --group browser python scripts/ui_smoke.pyThe script starts and stops its own local API using a temporary database. It checks a meaningful UI action and mobile overflow.
Available Tools
2 toolsavailable_appointmentsA
List synthetic clinic appointments; never book from model output alone.
| Name | Required | Description | Default |
|---|---|---|---|
No parameters | |||
Output Schema
| Name | Required | Description |
|---|---|---|
| result | Yes |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
With no annotations, the description must carry the safety profile itself; it discloses that the data is synthetic and adds a guardrail against booking off model output, which is real behavioral value. It stops short of stating that the operation is read-only, whether results are paginated or cached, or how fresh the availability data is.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
A single compact sentence with the resource first and the safety directive second — nothing is padded. It is arguably under-sized for a tool that gates a downstream booking sibling, but no sentence is wasted.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
An output schema exists and the tool has no parameters, so the description need not cover return values or inputs. Given that low complexity and the presence of the key booking safeguard, what remains is only minor: no explicit direction on how this pairs with propose_appointment.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
The tool takes zero parameters and the schema is empty and fully described, so there is nothing for the description to clarify. Baseline 4 applies; no parameter gaps exist.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
The description pairs a concrete verb ("List") with a concrete resource ("clinic appointments") and qualifies the dataset as "synthetic," so an agent knows this is a read-only enumeration over mock data. It also implicitly separates itself from the sibling propose_appointment by deprecating booking behavior, though it never names the sibling.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
"Never book from model output alone" gives one explicit usage constraint and hints that booking happens elsewhere, which is meaningful. However, it does not say when to call this versus propose_appointment, whether to call it before proposing, or what preconditions exist, leaving the routing mostly inferred.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
propose_appointmentB
Validate an available slot and return a proposal needing human confirmation.
| Name | Required | Description | Default |
|---|---|---|---|
| slot_id | Yes |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
With no annotations, the description carries the full burden. It usefully discloses that the result is a proposal requiring human confirmation rather than a final booking, but it omits side effects (e.g., whether the slot is reserved), permissions, validation criteria, and response details.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
One front-loaded sentence with no wasted words. The key action and the human-confirmation outcome are stated immediately.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
For a tool with no annotations and no output schema, the description is too thin. It leaves unresolved whether validation holds the slot, what the proposal contains, and how slot_id should be sourced or formatted.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
The single slot_id parameter has 0% schema description coverage, so the description must compensate. It only loosely connects slot_id to 'an available slot' by implication, without explaining format, source, or expected values.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
States a specific verb ('Validate') and resource ('available slot') and says it returns a proposal needing confirmation. This implies a distinction from the sibling available_appointments, but does not explicitly name or compare against it.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
The description implies a proposal step but gives no explicit guidance on when to use this tool versus available_appointments, no prerequisites, and no alternatives. The agent must infer that this is called after selecting a slot.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
Tool Schema Changelog
Recent tool additions, removals, and schema changes observed during successful MCP inspections.
2 tool updates
v0.1.0- First observed
available_appointments - First observed
propose_appointment
TDQS
Scored across 2 tools
The two tools are clearly separable: one is a read-only listing of slots, the other a validation/proposal action that produces a human-confirmation artifact. There is mild overlap since both operate on appointment slots, but a caller can reliably pick the right one.
Naming styles are mixed: 'available_appointments' is an adjective+noun phrase while 'propose_appointment' follows a verb_noun pattern. Both remain readable and snake_case is consistent, but there is no single predictable convention.
Two tools is thin even accounting for the deliberate human-in-the-loop safety constraint. The pair covers discovery and proposal, but the surface feels minimal for a clinic booking domain.
Only listing and proposing exist; there is no way to confirm a proposal, cancel, reschedule, or fetch details of a specific appointment. Some of this is intentionally offloaded to a human, but an agent will hit dead ends for common follow-up operations.
Maintenance
Related MCP Connectors
Hosted MCP server for Cliniko — patients, appointments, availability, and invoices for AI agents.
Read appointments, types, calendars and availability; create, cancel or reschedule bookings.
Find open slots on any appty link and book solo providers. Providers manage bookings by API key.
Remote MCP for TehProf Booking: browse resources & availability, create & cancel reservations.
Related MCP Servers
- AlicenseAqualityDmaintenanceProvides tools to check appointment availability and format call summaries via stdio MCP transport.2MIT
- AlicenseNot gradedqualityBmaintenanceProvides MCP tools to list valid appointment slots, schedule, reschedule, and cancel appointments under a clinic's business policy (hours, buffers, minimum notice, practitioner availability).1MIT

Daykeeper MCPofficial
AlicenseAqualityAmaintenanceA local stdio MCP adapter for the Daykeeper management API. It uses separately issued scoped credentials and exposes read-only tools by default; planning and mutations require explicit opt-in.826 npmApache 2.0- AlicenseNot gradedqualityCmaintenanceEnables an AI assistant to read bookings, check availability and session conditions, and prepare unsaved booking, cancellation or waitlist previews for a TheirCare / FullyBooked account through a local stdio MCP connection. Final saving and terms acceptance are deliberately left to the user, who confirms them personally in the bundled local companion web interface.MIT