FastAPI + MCP Greeting Template
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., "@FastAPI + MCP Greeting TemplateCreate a greeting for Anar and list the latest 5 greetings"
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.
FastAPI + MCP Greeting Template
A Docker-only development template: greeting REST endpoints (FastAPI), an MCP
server (official mcp Python SDK v2, Streamable HTTP), and PostgreSQL, with an
isolated test database, MCP Inspector support, and automatic reload of mounted
source. All application commands run in Docker; the host only needs Docker with
Compose and a shell for the bin/ wrappers. Graphify is optional local
developer tooling and additionally requires uv
on the host.
Prerequisites
Docker Engine with the
docker composeplugin andcompose up --waitsupport (Compose 2.17 or newer). Verify with:
docker compose versionThe wrappers deliberately do not fall back to legacy docker-compose v1.
Related MCP server: Hello World MCP Server
Copy and rename this template
This repository is a copy-and-rename starter. Before first initialization in a copied project, rename these coordinated surfaces together:
Repository directory.
[project].nameinpyproject.toml.Import package directory
src/app/and all imports ofapp.Compose project name (
COMPOSE_PROJECT_NAME) and image names incompose.yaml.Database names (
DEV_DB_NAME,TEST_DB_NAME,APP_DB_NAME).Default sample login names in both
secrets/.env.samplefiles.README title/examples and Python module references in Compose/Uvicorn commands.
Rename the checked-in examples and samples before bin/init. No
provisioning rule requires the original template_fastapi_mcp or template_
strings after those coordinated edits.
First run
bin/init
# Edit etc/dev/secrets/.env and etc/test/secrets/.env, replacing every placeholder.
bin/check-secrets all
bin/build
bin/compose up -d --wait postgres
bin/migrate
bin/start
bin/test -q
bin/inspectorbin/init copies each missing etc/dev/.env / etc/test/.env from its
.env.example, and each missing secrets/.env from that environment's
secrets/.env.sample (mode 0600), without overwriting existing values.
Both secret files use POSTGRES_USER and POSTGRES_PASSWORD, but you must
replace the placeholders with different development and test values before
running bin/start, bin/migrate, or bin/test. Changing development
credentials does not reinitialize a persisted PostgreSQL volume; guarded
provisioning updates only the configured test role's password without touching
development roles or data.
The committed uv.lock makes bin/lock unnecessary for ordinary checkout
setup; use it after dependency edits, then bin/build and recreate affected
containers.
Optional: Graphify codebase navigation
Graphify is local-only tooling: its generated graphify-out/ directory and
Git hook configuration are intentionally not committed. To install the pinned
tool and local hooks, run:
bin/graphify-setup
bin/graphify update .Use bin/graphify query "<question>" for codebase investigations. Graphify
refreshes automatically after commits and branch switches; run
bin/graphify update . after uncommitted changes when you need an up-to-date
graph before committing or querying. Set GRAPHIFY_SKIP_HOOK=1 for a single
commit or checkout when an automatic rebuild is not wanted.
Commands
Command | Purpose |
| Copy missing configs/secrets, never overwrite |
| Run the pinned local Graphify tool through |
| Install the pinned tool and local Graphify Git hooks |
| Validate secret files without printing values |
| Raw Compose access (dev config by default) |
| Build the development image |
| Regenerate |
| Apply Alembic migrations to the dev database |
| Start the app (waits until healthy) |
| Stop services, preserving data |
| Follow |
| Provision test DB, migrate, run pytest |
| Start the MCP Inspector web UI |
All wrappers resolve paths relative to their own location, so they work when invoked from outside the project directory.
Use the web API
After bin/start, the development server is available at http://localhost:8000
(the default APP_PORT in etc/dev/.env). Open the interactive API page at
http://localhost:8000/docs. The machine-readable
OpenAPI JSON document is at
http://localhost:8000/openapi.json.
The REST endpoints are:
GET http://localhost:8000/health→{"status":"ok"}(independent of PostgreSQL).POST http://localhost:8000/greetingsaccepts JSON{"name":"Anar"}and returns HTTP 201:
{"id":"…","name":"Anar","created_at":"2026-10-04T12:00:00Z"}GET http://localhost:8000/greetings?limit=20returns a JSON array, newest first (created_at DESC, id DESC). Limit: 1–100, default 20.
For example, create and list a greeting with curl:
curl -X POST http://localhost:8000/greetings \
-H 'Content-Type: application/json' \
-d '{"name":"Anar"}'
curl 'http://localhost:8000/greetings?limit=20'Use the MCP server
The MCP server uses Streamable HTTP at
http://localhost:8000/mcp. Configure an MCP
client with that URL and the Streamable HTTP transport. It exposes these tools:
create_greetingwith{"name":"Anar"}returns a greeting object (id,name,created_at).list_greetingswith{"limit":20}returns{"greetings":[…]};limitdefaults to 20 and must be 1–100.
The Python SDK client can call the tools like this (run from an environment with this project's dependencies installed):
import asyncio
from mcp import Client
async def main():
async with Client("http://localhost:8000/mcp") as client:
created = await client.call_tool("create_greeting", {"name": "Anar"})
print(created.structured_content)
listed = await client.call_tool("list_greetings", {"limit": 20})
print(listed.structured_content)
asyncio.run(main())Names are trimmed; empty/whitespace-only or >100 characters are rejected. Duplicate names are allowed. REST input errors are HTTP 422; storage failures are sanitized HTTP 503. MCP failures are protocol tool errors without SQL, credentials, or connection strings.
Inspector
Run bin/inspector after bin/start. It starts the Inspector container and
prints the browser URL http://localhost:6274 (the
default CLIENT_PORT). In Inspector, choose Import from registry config,
select docs/inspector-registry-config.json,
and import the listed server. Then connect and use create_greeting with
{"name":"Anar"} or list_greetings with {"limit":20} to try the tools.
The config uses http://app:8000/mcp, which resolves from the Inspector
container over the Compose network. If you run Inspector directly on the host,
change the imported server URL to http://localhost:8000/mcp instead.
Inspector UI authentication stays enabled; its token is injected into the served page, and Inspector logs are disabled so the token banner is not recorded.
Development workflow
Source hot reload: the project is bind-mounted at
/workspacewith dependencies at/opt/venvand the app installed editable against/workspace/src. Editing host Python files reloads via Uvicorn without a rebuild (polling enabled for bind mounts). Verify imports resolve under/workspace/src/.Dependency/Dockerfile changes:
bin/lock(ifpyproject.tomlchanged), thenbin/buildand recreate affected containers. A staleuv.lockfails the image build by design (uv sync --locked).Environment changes: recreate affected containers.
Schema changes: edit migrations, then run the explicit
bin/migrate(dev) — startup never migrates implicitly. Tests migrate the test database viabin/test.bin/stoppreserves the PostgreSQL volume; there is no automatic reset.
Troubleshooting (sanitized)
Unhealthy PostgreSQL:
bin/compose ps,bin/logs postgres; confirm the dev secret file passesbin/check-secrets dev(mode0600, no placeholders).Missing migrations (
relation "greetings" does not exist): runbin/migratefor dev,bin/testfor the test database.MCP connection errors mentioning Host/Origin: use
http://app:8000/mcpfrom inside Compose (Inspector) andhttp://localhost:8000/mcpfrom the host; check that requests carry an allowed Host.Stale lockfile build failure: run
bin/lock, thenbin/build.Missing/placeholder credentials:
bin/check-secrets allfails without printing values; replace every placeholder with distinct dev/test values.Never print resolved Compose config or container environments containing credentials; use
bin/compose config --quietfor validation.
This server cannot be deployed
Maintenance
Related MCP Connectors
Remote MCP server exposing SMI Aware tools, resources, and skills over Streamable HTTP.
Query, browse, and automate OmegaAI workspaces from any MCP client. Streamable HTTP with OAuth 2.0.
- TypeshipOAuthdev.typeship
Generate a typed SDK, CLI, and MCP server from any OpenAPI or GraphQL spec, and keep them current.
Public Streamable HTTP MCP gateway for XGRChain, XDaLa sessions, Explorer data and XGR standards.
Related MCP Servers
- FlicenseNot gradedqualityDmaintenanceA simple MCP server implementation that demonstrates streaming capabilities with tools for greetings and notifications, accessible through an interactive command-line client.1-
- FlicenseNot gradedqualityNot gradedmaintenanceA simple demonstration server for the Model Context Protocol that provides tools for creating and managing greetings with support for multiple transport methods (stdio, HTTP, SSE).-
- AlicenseCqualityDmaintenanceA simple MCP server that provides a basic greeting tool for saying hello with customizable names. Serves as a boilerplate template for developers to quickly create and deploy new MCP servers.16 npmMIT
- FlicenseNot gradedqualityDmaintenanceA demonstration MCP server that runs over HTTP with streamable transport, providing a simple greeting tool for testing MCP client-server communication. Built with FastMCP framework for educational purposes in learning MCP server development.-