MCP Tool Server
A Model Context Protocol server that turns an existing REST backend into tools, resources and prompts an AI agent can call, with configurable outbound messaging and a hardened HTTP surface.
Request path in production
- AI clientthe model lives here
- MCP transportstdio, SSE or streamable HTTP
- tool handlerflag, validation, rate limit
- lifespan contextshared clients and services
- backend clientshort-lived service JWT
- REST backend / channelsemail and SMS
What the server exposes
Tools
8
Backend operations wrapped as typed, LLM-callable functions, each one switchable by configuration.
Resources
2
Read-only context for the agent: the server’s capabilities and enabled tools, and an aggregated summary from the backend.
Prompts
3
Parameterised prompt templates that chain the tools into multi-step workflows.
Transports
stdio · SSE · HTTP
One codebase serves local agents over stdio and remote ones over SSE or streamable HTTP, chosen by configuration.
Architecture decisions
- Shared resources, created once
- An async lifespan builds the backend client, the messaging services and the transformers at startup; every tool reads them from the request context instead of opening its own.
- The backend stays behind one client
- Tools never talk HTTP themselves. A single client owns timeouts, authentication and the response envelope.
- Self-refreshing service tokens
- Outbound calls carry a short-lived signed JWT that is re-minted shortly before it expires, falling back to a user token or an API key.
- Channels behind interfaces
- Email goes through an interface with a webhook implementation and an SMTP fallback, picked at startup; SMS goes through a provider abstraction.
- Features as configuration
- Each tool checks its own flag and answers with a clear "disabled" result; a resource tells the agent what is switched on.
- Output shaped for the caller
- Backend results are transformed into several JSON-configured formats, under a timeout.
- Moving to explicit layers
- Domain, application and infrastructure layers with repository interfaces and a dependency-injection container are being introduced around the running server.
Hardening the surface
- Refuses to run unprotected
- An HTTP transport will not start without an API key, and weak keys are flagged at startup.
- Rate limits
- A thread-safe sliding-window limiter, applied globally and per recipient per hour.
- Strict inputs
- Phone numbers validated to E.164 with blocklists for special numbers, message length checks and sanitisation.
- SSRF protection
- Media URLs must be HTTPS and cannot point to private or loopback addresses.
- Privacy in logs
- Phone numbers are masked before anything is logged.
- Container
- A slim image running as a non-root user, with a health-check command.