mcp-server-template
mcp-server-template
Ein produktionsreifer Ausgangspunkt für einen MCP-Server.
Der Schnellstart in der MCP-Dokumentation liefert dir in zehn Zeilen ein funktionierendes Tool. Das ist das, was du in den folgenden drei Wochen hinzufügst, sobald dieses Tool von etwas aufgerufen wird, das du nicht kontrollierst.
@mcp.tool()
def add(a: int, b: int) -> int:
return a + b # fine on a laptopWas dort fehlt, sind keine Funktionen. Es ist das, was passiert, wenn das Tool hängt, eine Exception auslöst, einen Roman zurückgibt oder vierzig Mal gleichzeitig aufgerufen wird – und was das Modell in diesen Fällen sehen darf.
Das Problem, das dieses Template löst
Der Aufrufer eines MCP-Tools ist ein Sprachmodell, und das verändert die Technik.
Ein Modell kann keinen Stacktrace lesen, aber es gibt freudig einen an deine Benutzer weiter. Ein ausgeleckter Stacktrace ist also sowohl nutzlos als auch eine Offenlegung.
Ein Modell hat eine eigene Deadline. Ein Tool, das hängt, erzeugt keine langsame Antwort; es erzeugt eine tote Konversation.
Ein Modell kann ein abgeschnittenes Ergebnis nicht von einem vollständigen unterscheiden. Wenn sein Kontext stillschweigend überläuft, wird kein Fehler ausgelöst – es verschlechtert die Antwort, und du erfährst es von einem Kunden.
Ein Modell wird wiederholen, wenn du es lässt. „Nicht gefunden" und „Upstream ist down" müssen also unterschiedliche Antworten sein, sonst hämmert es einen Dienst für einen Datensatz, der nie existiert hat.
Jeder dieser Fälle wird nur einmal behandelt, und zwar an einer zentralen Stelle, sodass ein Tool, das am Freitagnachmittag hinzugefügt wird, denselben Schutz erbt wie das, das am ersten Tag sorgfältig geschrieben wurde.
Related MCP server: mcp-starter-kit
Was du bekommst
Timeout pro Tool | Wirklicher Abbruch, nicht nur eine Warnung im Nachhinein. Gibt einen |
Parallelitäts-Obergrenze | Begrenzte parallele Ausführung, sodass eine Burst nicht das überrennt, was deine Tools aufrufen |
Fehlergrenze | Deklarierte Fehler erreichen den Aufrufer; unerwartete werden zu |
Geheimnis-Schwärzung | Wird auf Logs und ausgehende Nachrichten angewendet, weil Schlüssel häufiger über interpolierte Exception-Strings nach außen gelangen als über Code |
Sichtbare Kürzung | Zu große Ergebnisse werden sichtbar abgeschnitten, niemals still |
Korrelations-IDs | Eine ID pro Aufruf, im Log und im Fehler – die der Benutzer dir nennen kann |
Strukturierte Logs auf stderr | stdout gehört zum Protokoll – ein falsches |
Fail-fast-Konfiguration | Falsche Einstellungen stoppen Server beim Boot, spät nicht bei der ersten Anfrage |
Offline-Tests | Die Suite läuft im Zug. Keine Live-Schlüssel, kein Netzwerk |
Schnellstart
git clone https://github.com/muhammadwaqasmbd/mcp-server-template
cd mcp-server-template
make install
make test
make run # stdio, ready for a desktop MCP clientStattdessen über das meinene Firefox anbieten:
TRANSPORT=streamable-http PORT=8000 python -m mcp_server_templateEinen Desktop-Client darauf gespeichert
{
"mcpServers": {
"template": {
"command": "python",
"args": ["-m", "mcp_server_template"],
"cwd": "/absolute/path/to/mcp-server-template"
}
}
}Ein eigenes Tool hinzufügen
Schreibe die Funktion. Sonst nichts.
# src/mcp_server_template/tools/orders.py
from ..errors import InvalidInput, UpstreamUnavailable
async def cancel_order(order_id: str) -> dict:
"""Cancel an order. Returns the order's new state."""
if not order_id.strip():
raise InvalidInput("order_id must not be empty") # model can fix this
...
raise UpstreamUnavailable("order service timed out") # model may retryRegistriere es hinter der Die „schütz“:
mcp.tool(name="cancel_order", description="Cancel an order by id.")(
guard.wrap(orders.cancel_order)
)Es hat jetzt den Timeout, die Obergrenze, die Fehlergrenze, die Kürzung und es Logging. Du hast davon nichts geschrieben.
Wirf InvalidInput, wenn das Modell es korrigieren kann. Wirf UpstreamUnavailable, wenn ein weiterer Versuch helfen könnte. Gib für schlicht negative Ergebnisse einfach normal zurück – ein fehlender Datensatz ist eine Antwort, kein Fehler.
Stylish
server.py the ONLY module that imports the MCP SDK
│
├── guard.py timeout · concurrency · error boundary · truncation · timing
├── errors.py what a model is allowed to see, and secret redaction
├── observability.py JSON logs on stderr, correlation ids
├── config.py validated once at boot, immutable thereafter
└── tools/ plain functions. No protocol knowledge. No decoratorsDer Beunruhigt Diepteilt zeigt in eine Richtung: Tools wissen nichts über das Programm, und die Schutzschicht weiß nichts über Tools. Deshalb laufen die Tests in Millisekunden ohne einen Server, und deshalb betrifft eine SD-Kerne genau eine Datei.
Was dieses Bewusst nicht tut
Die „Ränder“ ehrlich darüber zu sagen ist gerade Funktionen mehr.
Keine Authentifizierung. Über stdio der System des Betriebssystems ist die Sicherheitsgrenze. Wenn du in HTTP machst, Getreide ein echter Schulschutz davor – die SDK unterstützt das, es hier zu verdrahten in einem Gefahrenmodell implizieren.
Keine Retry-Logik in den Tools. Die
STUFFgibt mit, ob ein Fehler wieder anfällig ist; sagt euch nicht ob, der Aufrufer hat die Kontext und das Budget.Keine Beschleunigungsbegrenzung pro Anfrage. Die Obergrenze begrenzt die Gesamtarbeit, nicht die Fairness zwischen Identitäten. Wenn du das brauchst, brauchst du zuerst eine Identität.
Keine anhaltende, Warteschlange oder Scheduler. Der Tool-Erf ist zu einem „Job Runner“ ohne Schritt wurde und wurde dies, ist ein verteiltes System, das niemanden absichtlich entwaren – eine Wendung.
Keine Streaming-Ergebnisse. Sinnvoll einge, wenn langlaufende Tools, kannst du es an; die Fehlergrenze macht es schwieriger – die meisten Tools brauchen es nicht.
Testen
make testZuversicht, die Suite schlägt fehl: Es gibt keinen Fehler, einangehaltenes Tool wird abgebrochen, eine unerwartete Exception kann die Nachricht nicht warten, Überdimensionierte Ausgabe wird sichtbar gekürzt, die Obergrenze keine unter zehn Aufrufen liegt, und es wird kein nicht blockierender Sync-Tool kann jedoch den Event-Loop nicht wirklich – ale.
Lizenz
MIT – Siehe LICENSE.
Gebaut von Muhammad Waqas, der den größten Teil seiner Zeit im Agentensystemen verbraucht in regulierten Regionen, wo eine sichere falsche Antwort ein meldepflichtiger Unfall ist.
Available Tools
3 toolsfetch_recordA
Look up a record by key. Returns found=false when absent; that is not an error.
| Name | Required | Description | Default |
|---|---|---|---|
| key | Yes | ||
| simulate_outage | No |
Output Schema
| Name | Required | Description |
|---|---|---|
No output parameters | ||
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
With no annotations, the description carries the full burden of behavioral disclosure. It does add one valuable behavioral detail: a missing record is reported via 'found=false' and is not treated as an error. This is useful context. However, it does not state that the operation is read-only, nor does it explain the simulate_outage parameter's behavior. The description provides some behavioral clarity but leaves notable gaps.
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?
The description is two sentences, direct, and front-loaded with the primary action. It avoids verbosity and includes only the most essential information. The key behavioral note about 'found=false' is presented efficiently. No wasted words.
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 simple fetch tool, the description covers the main action and the most important edge case (absent record). However, it omits any explanation of the 'simulate_outage' parameter, which is part of the tool's interface. While an output schema exists and relieves the description of detailing return values, the parameter gap remains. The description is adequate for basic usage but incomplete for full correct invocation.
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?
Schema description coverage is 0%, so the description must compensate. It implicitly clarifies that 'key' is the lookup identifier, but it offers no additional detail about the parameter's format or acceptable values. The 'simulate_outage' parameter is entirely unexplained—an agent cannot infer its purpose or effect from the description. Given the low coverage, this is a significant shortfall.
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 clearly states the primary action: 'Look up a record by key.' This is a specific verb (look up) with a clear resource (record) and method (by key). It is immediately distinct from sibling tools like summarise_lengths and slow_operation, as those suggest different operations. No ambiguity.
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 when to use the tool (when you need to retrieve a record by its key) but provides no explicit guidance on alternatives or exclusion conditions. It does not mention any context where this tool should be avoided or mention sibling tools. This qualifies as implied usage, which meets the minimum viable threshold.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
slow_operationA
Sleeps, to demonstrate the server's timeout behaviour.
| Name | Required | Description | Default |
|---|---|---|---|
| seconds | No |
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 full burden of behavioral disclosure. It states the core behavior (sleeping) and the intended effect (timeout demonstration), but does not mention the adjustable 'seconds' parameter, what happens after the sleep (return value or error), or any side effects. This is partially transparent but incomplete for a tool with no annotation coverage.
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?
The description is a single, short sentence that front-loads the core action ('Sleeps') and purpose. There is no wasted wording, making it highly efficient and easy to parse.
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 simple tool with one optional parameter and an output schema, the description is fairly complete. It conveys the tool's purpose and behavior, and the output schema covers return values. However, it could explicitly mention that the sleep duration is configurable via the 'seconds' parameter, which is currently only in the schema. Overall, it is adequate for a demo tool.
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 schema has one parameter 'seconds' with default 60 and 0% description coverage. The description does not mention this parameter at all, so it fails to connect the sleep duration to the parameter. The parameter name is somewhat self-explanatory, but the description provides no added meaning, leaving the agent to guess how the parameter influences the operation.
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 clearly states the verb 'Sleeps' and the resource 'server's timeout behaviour', making the tool's purpose unmistakable. It distinguishes itself from siblings 'summarise_lengths' and 'fetch_record' which clearly serve different functions.
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 usage for demonstrating timeout behaviour, which gives context, but it does not explicitly mention when to use this tool versus alternatives. No exclusions or conditions are provided, leaving the agent to infer that it is for testing timeouts only.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
summarise_lengthsA
Return per-item character counts and a total for a list of strings.
| Name | Required | Description | Default |
|---|---|---|---|
| items | Yes |
Output Schema
| Name | Required | Description |
|---|---|---|
No output parameters | ||
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
No annotations are provided, so the description carries the full burden. It states the behavior accurately but does not discuss edge cases (e.g., empty list, null elements) or any side effects. For a pure computation tool, this is adequate but minimal disclosure.
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, front-loaded sentence with no wasted words. The core functionality is stated immediately, making it quick for an agent to parse.
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?
The tool is simple, and an output schema exists, so the description does not need to explain return values. Combined with the clear single parameter and the presence of the output schema, the description is complete for an agent to invoke the tool correctly.
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?
Schema description coverage is 0%, so the description must compensate for the undocumented 'items' parameter. It clarifies that the parameter is a list of strings, which aligns with the schema. However, it does not add details about constraints (e.g., whether null is allowed) or the order of results. The description adds minimal value beyond the schema's type declaration.
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 clearly states the tool returns per-item character counts and a total for a list of strings, specifying a concrete verb and resource. It does not explicitly differentiate from siblings, but the siblings (fetch_record, slow_operation) are obviously distinct in purpose, so the lack of explicit differentiation isn't a major gap.
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 purpose implies when to use it (whenever you need length summaries), but no explicit guidance is given about when not to use it or which alternatives to prefer. Since the alternatives are clearly unrelated, the implied usage is sufficient, though not explicit.
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.
3 tool updates
v0.1.0- First observed
fetch_record - First observed
slow_operation - First observed
summarise_lengths
TDQS
Scored across 3 tools
Each tool addresses a separate concern: one computes string lengths, one looks up records, and one simulates a timeout. There is no overlap or realistic chance of choosing the wrong tool.
Two tools follow a clear snake_case verb_noun pattern (summarise_lengths, fetch_record), but slow_operation reads as adjective_noun. The naming is still readable and predictable overall.
Three tools is a reasonable size for a template server. Each tool exists to demonstrate a distinct capability, so none feel redundant or excessive.
As a template, the set covers the demonstrated scenarios: a utility operation, a record lookup with a defined absent-case, and a timeout example. There are no obvious dead ends or missing pieces for that purpose.
Maintenance
Related MCP Connectors
MCP server for your apps' tools and custom tools, plus hosted AI agents and approval-gated workflows
Security & DLP proxy for MCP: tool-poisoning scans, PII redaction on tool args/results. Beta.
MCP server for progressive tool usage at any scale (see https://klavis.ai)
AgentGuard — 20-tool AI safety MCP: policy preflight, risk scoring, audit logging, rate limits.
Related MCP Servers
- AlicenseNot gradedqualityDmaintenanceA production-grade MCP server designed for multi-tenant, authenticated, and observable AI agent systems, enabling secure tool execution across heterogeneous data sources.67MIT
- AlicenseAqualityCmaintenanceA production-ready foundation for building secure, observable MCP servers with built-in authentication, rate limiting, and reference tools like database-query and semantic-search.1533 npmMIT
- FlicenseNot gradedqualityDmaintenanceA production-ready, security-first starting point for building Model Context Protocol servers, enforcing safe defaults like dry-run and tenant isolation.-
- AlicenseNot gradedqualityDmaintenanceAn enterprise MCP server scaffold that provides secure, governed access to internal tools through RBAC, audit logging, rate limiting, and prompt-injection boundaries, with a FastAPI control plane and OpenTelemetry observability.MIT