← ClaudeAtlas

mcp-tool-authoringlisted

How to add or change an MCP tool in this repository. Use when adding a tool to server.py, changing a tool's parameters or return text, or debugging FastMCP registration.
anrysys/tg-ai · ★ 0 · AI & Automation · score 72
Install: claude install-skill anrysys/tg-ai
# Authoring an MCP tool Authority: [docs/10-product/srs.md](../../../docs/10-product/srs.md) and [docs/30-api/mcp-tools.md](../../../docs/30-api/mcp-tools.md). ## The shape ```python @mcp.tool() @guarded_tool async def tg_do_thing(target: str, limit: int = 10) -> str: """One line saying what this does for the user. When to use it rather than a neighbouring tool, and any consequence the agent must know about before calling. Args: target: What forms are accepted. limit: What range; note that it is clamped, not rejected. Returns: What the text contains, and what a failure looks like. """ ``` Decorator order matters: `@mcp.tool()` outermost, `@guarded_tool` directly on the function. ## Hard requirements | Rule | Why | | --- | --- | | Return `str` under all conditions; never raise | An escaping exception can kill the stdio server mid-session (`SPEC-SND-004`) | | No `from __future__ import annotations` in `server.py` | FastMCP inspects signatures at import time and cannot resolve string annotations. It fails with `issubclass() arg 1 must be a class` | | Clamp `limit`, never reject it | `max(1, min(int(limit), N))`. An agent guessing 10000 should get an answer, not a round trip (`SPEC-RCV-004`) | | `raise ToolError(...)` for expected failures | Produces `ERROR: <message>` without stack-trace noise | | Never `print()` | stdout is the protocol channel. Use `log.*` (stderr) | | Acquire the client via `await telegram()`, the pool