Skip to main content
Glama
bobbylite

service-template

by bobbylite

service-template

A minimal, reusable Python backend template: one FastAPI app exposing the same business logic through two front doors — a REST endpoint and an MCP tool.

Clone it, rename it, and build on the seams it leaves you.

The pattern

Service-layer architecture with a light ports-and-adapters seam. The HTTP route and the MCP tool are thin adapters; neither owns logic, and neither knows about the other.

HTTP request  ──▶ api/health.py  ──┐
                                   ├──▶ services/health_service.py  (single source of truth)
MCP tool call ──▶ mcp/tools.py  ───┘

Adding auth, identity, or persistence later touches the service and identity layers — not the adapters.

Related MCP server: http-mcp-server

Layout

src/app/
├── main.py                # app factory, lifespan, mounts the MCP sub-app
├── api/health.py          # adapter #1 — HTTP
├── mcp/tools.py           # adapter #2 — MCP
├── services/
│   └── health_service.py  # shared business logic
├── core/
│   ├── config.py          # pydantic-settings
│   └── logging.py         # structured JSON logging
└── identity/provider.py   # extension seam — SPIFFE/SPIRE goes here later

Quickstart

uv sync                                  # create .venv and install everything
uv run uvicorn app.main:app --reload     # serve on http://127.0.0.1:8000

Surface

Address

Health endpoint

GET http://127.0.0.1:8000/health

OpenAPI docs

http://127.0.0.1:8000/docs

MCP endpoint

http://127.0.0.1:8000/mcp/ (streamable HTTP)

curl http://127.0.0.1:8000/health
# {"status":"ok","uptime_seconds":3.14,"version":"0.1.0"}

Development

uv run pytest            # tests
uv run ruff check .      # lint
uv run ruff format .     # format
uv run mypy              # type check (strict)

Configuration

Settings live in src/app/core/config.py and are read from the environment or a .env file using the APP_ prefix. Copy .env.example to .env to start.

Setting

Env var

Default

app_name

APP_APP_NAME

service-template

version

APP_VERSION

0.1.0

log_level

APP_LOG_LEVEL

INFO

Extending it

A new MCP tool — add a function to src/app/mcp/tools.py (or a new module under src/app/mcp/ registered on the same mcp instance). Put the logic in services/, and call it from the tool.

A new HTTP route — add a router under src/app/api/ and include it in create_app(). Same rule: the logic belongs in services/.

Workload identity (SPIFFE/SPIRE)src/app/identity/provider.py is a no-op stub today. Replace NullIdentityProvider with an implementation backed by the spiffe package and have callers depend on get_identity_provider(). Nothing in api/ or services/ should need to change.

Renaming for a new project — rename the src/app/ package, update name in pyproject.toml, the packages entry under [tool.hatch.build.targets.wheel], and the app_name default in core/config.py. Nothing in the logic references this template by name.

Related MCP Connectors

Related MCP Servers

  • A
    license
    Not graded
    quality
    D
    maintenance
    Mock HTTP server implementing MCP (Model Context Protocol) with streamable HTTP transport, health endpoint, and example tools like echo and time.
    261 npm
    MIT
  • F
    license
    Not graded
    quality
    B
    maintenance
    A simple cloud-hosted MCP server for verifying upstream MCP connectivity via Streamable HTTP, exposing a single tool that returns a fixed success message.
    -
  • A
    license
    Not graded
    quality
    C
    maintenance
    Enables MCP clients to call a hello tool and access observability features, including metrics and request traces, through a Streamable HTTP transport with SQLite-backed storage.
    261 npm
    MIT