mcp-tool-server
Click on "Install 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., "@mcp-tool-serverCheck the response time and headers for https://example.com"
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.
mcp-tool-server
A production-shaped MCP tool server built with FastMCP 3, FastAPI, and Pydantic v2 — three example tools, a REST health endpoint on the same port, 100% test coverage, and a multi-stage Docker build.
Built in six incremental phases (each independently reviewable in the commit history this structure implies); see Roadmap.
Why this exists
This is a reference/portfolio implementation, not a business application — the three tools exist to demonstrate patterns (sync vs. async execution, external I/O, structured validation, error translation, tool metadata) rather than to solve one specific problem. The interesting parts are the architectural decisions, documented inline as comments where they're non-obvious rather than collected in one wall of text here:
Tools are decoupled from the MCP server instance. Each tool in
app/tools/builds a standaloneToolviaFunctionTool.from_function(...)instead of decorating an existingmcpobject.create_server()wires them in at construction time (FastMCP(tools=ALL_TOOLS)). This avoids a circular import betweenapp.serverandapp.tools, and makes every tool callable and unit-testable without any MCP machinery involved.Business logic doesn't know MCP exists.
app/services/has zero FastMCP imports and raises plainValueError. Translation toToolErrorhappens once, at theapp/tools/boundary — the one place that's actually MCP-specific.Dependencies were added when first used, not upfront. FastAPI wasn't added until Phase 3, when the health endpoint actually needed it;
httpxanduvicornlikewise. The result is a lockfile with nothing unused in it.Two ASGI apps, one port.
mcp.http_app()returns a Starlette app for the MCP protocol; it's mounted inside a FastAPI app that also serves/health. The one genuine gotcha here — FastMCP's session manager needs the sub-app'slifespanexplicitly passed to the parent app, or tool calls fail with a task-group error despite/healthworking fine — is documented where it's handled, inapp/asgi.py.
Related MCP server: simple-mcp-server
Tools
Tool | Style | Tags | Description |
| sync |
| Word/character/sentence counts and an estimated reading time. |
| async |
| Status code, headers, and response time for an http/https URL. Only transport failures raise — a 404 is valid data. |
| sync |
| Convert between celsius, fahrenheit, and kelvin; rejects values below absolute zero. |
Each carries MCP tool annotations (readOnlyHint, idempotentHint /
openWorldHint) so clients can reason about side effects before calling them.
Architecture
app/
├── server.py # create_server(): builds the FastMCP instance + tool registry
├── asgi.py # create_asgi_app(): mounts FastMCP into FastAPI for the http transport
├── config/ # Environment-driven settings (Pydantic v2 / pydantic-settings)
├── utils/ # Logging and other cross-cutting helpers
├── api/ # Plain REST routes (currently just /health)
├── tools/ # MCP tool adapters: schema, metadata, ValueError -> ToolError translation
├── services/ # Pure business logic. No FastMCP import, anywhere.
└── models/ # Pydantic schemas shared by tools/services/api
tests/ # 32 tests, 100% line coverage (unit + integration, no real network calls)Dependency direction is one-way: server/asgi → tools/api → services → models.
Nothing in services/ or models/ imports anything above it.
Quick Start
uv sync
cp .env.example .env
uv run python -m app.serverThis starts the http transport on http://0.0.0.0:8000, serving both
/health and the MCP endpoint at /mcp. Set MCP_TRANSPORT=stdio in .env
instead if a client (e.g. Claude Desktop) will spawn this process directly.
Docker
cp .env.example .env
docker compose up --buildThe image is a multi-stage build (python:3.12-slim + pinned uv): dependencies
are synced in a builder stage from the lockfile before any application code is
copied in, so rebuilds only reinstall packages when uv.lock actually changes.
The runtime stage carries only the built virtual environment and app/ — no
uv, no lockfile, no tests, no dev dependencies — and runs as a non-root user
with a HEALTHCHECK against /health.
# without compose
docker build -t mcp-tool-server .
docker run --rm -p 8000:8000 --env-file .env -e MCP_HOST=0.0.0.0 mcp-tool-serverNote: the Dockerfile follows the standard multi-stage
uvpattern and was reviewed carefully, but this environment had no Docker daemon available to actually rundocker buildagainst — unlike the rest of this project, it wasn't executed end-to-end. Worth a first build-and-run before you rely on it.
Configuration
All variables are optional and prefixed MCP_; see .env.example for the
full, commented list. The ones worth knowing about:
Variable | Default | Notes |
|
|
|
|
| Only used for the |
|
|
|
|
| Standard library log level name |
|
| FastMCP pings PyPI on startup by default; set |
Example usage
Health check:
curl http://localhost:8000/health
# {"status":"ok","name":"mcp-tool-server","version":"0.1.0","environment":"development"}Calling a tool — the MCP endpoint is a stateful, session-based protocol
(not plain REST), so the practical way to call it is fastmcp's own client
rather than raw curl:
import asyncio
from fastmcp import Client
async def main():
async with Client("http://localhost:8000/mcp") as client:
result = await client.call_tool(
"convert_temperature",
{"value": 100, "from_unit": "celsius", "to_unit": "fahrenheit"},
)
print(result.data) # output_value=212.0 ...
asyncio.run(main())Or in-memory, against the server object directly (no network at all — this is exactly what the test suite does):
from fastmcp import Client
from app.server import mcp
async with Client(mcp) as client:
tools = await client.list_tools()Testing
uv run pytest # 32 tests, coverage report on by default (see pyproject.toml)
uv run ruff check .
uv run mypy appCoverage is 100% across all 217 statements in app/. That number is a
byproduct of testing real behavior (every tool's error path, the settings
validation, the main() transport dispatch, the FastAPI lifespan wiring),
not a target chased for its own sake — the last few percentage points came
directly from pytest --cov-report=term-missing pointing at genuine gaps,
including one real bug it caught: create_asgi_app(settings) accepted a
settings argument that the health route was silently ignoring in favor of
the global cached singleton, fixed via a FastAPI dependency override in
app/asgi.py.
Network-dependent tests (test_web_service.py) use httpx.MockTransport —
no real HTTP calls, no flakiness, no dependency on network access in
whatever environment runs the suite.
Roadmap
Phase 1 — Architecture & project initialization
Phase 2 — Example tools + tool metadata
Phase 3 — FastAPI mounting + health endpoint
Phase 4 — Full unit test suite
Phase 5 — Docker + docker-compose
Phase 6 — Full documentation pass
License
MIT — see LICENSE.
This server cannot be installed
Maintenance
Resources
Unclaimed servers have limited discoverability.
Looking for Admin?
If you are the server author, to access and configure the admin panel.
Related MCP Servers
- FlicenseAqualityDmaintenanceA lightweight MCP server providing utility tools for math, text processing, data conversion, and URL fetching. It supports both STDIO and SSE communication modes for seamless integration with Claude Desktop and remote AI agents.51
- Alicense-qualityDmaintenanceA simple MCP server offering three utility tools: UUID generation, temperature conversion, and text statistics.10MIT
- Flicense-qualityCmaintenanceA lightweight MCP server providing tools for adding integers, getting current time, and fetching weather forecasts via wttr.in.
- Flicense-qualityDmaintenanceA simple MCP server that provides basic utility tools for text manipulation, file operations, and calculations, intended to be connected to Claude AI desktop app.
Related MCP Connectors
Remote MCP server: 10 developer utilities (base64, JWT, DNS, UUID, URL, JSON, UA, IP lookup).
MCP server for URL shortening and management
MCP server for generating rough-draft project plans from natural-language prompts.
Latest Blog Posts
- Who's Calling? MCP Hosts Are an Identity Blind Spot (And the Spec Knows It)By Om-Shree-0709 on .mcpAgent IdentityOAuth 2.1
- Your AI Chatbot Just Exposed Your CEO's Salary to an InternBy Om-Shree-0709 on .Agent IdentityMCP SecurityOAuth Delegation
- Why MCP Servers Need Execution Sandboxing (And Why Your Current Stack Isn't Enough)By Om-Shree-0709 on .Agentic AiPrompt InjectionWebAssembly
MCP directory API
We provide all the information about MCP servers via our MCP API.
curl -X GET 'https://glama.ai/api/mcp/v1/servers/Kartik281204/MCP-Tool-Server'
If you have feedback or need assistance with the MCP directory API, please join our Discord server