Exposing Tools: Declarative Tool Definitions
~12 min read
Tools are the main way an MCP server exposes functionality — in mcp-use, each tool is a small, declarative definition with a name, input parameters, and a callback returning content.
With a scaffolded server in place (previous subtopic), the first capability worth exposing is usually a Tool. Earlier in this curriculum, the 6 core MCP primitives were covered — this subtopic zooms into how ONE of those primitives, Tools, specifically works when built using mcp-use.
Tools represent actions the agent can perform. They are the main way an MCP server exposes functionality — anything from API calls to calculations to workflow steps. In mcp-use, tools are registered on the server using a simple declarative definition. Each tool includes a name, input parameters, and a callback that returns content to the client.
This course's minimal example defines a complete MCP server with a single tool: get_weather, which returns a basic weather response. Any MCP-compatible client can automatically discover and invoke this tool during capability negotiation — meaning once you've declared the tool this way, you don't need any separate registration step for clients to find it; the discovery mechanism is built into the protocol itself, and any client connecting to your server (whether it's a raw MCP client or an mcp-use-powered agent, as covered in the agents/clients topic) will see this tool listed automatically.
This declarative-definition pattern is deliberately minimal by design — you specify WHAT the tool is called, WHAT inputs it needs, and WHAT it does when called, and the framework handles the protocol-level plumbing of advertising that tool's schema to connecting clients and routing incoming tool-call requests to your callback function. This is exactly what makes tool definitions portable and reusable: the same declared tool works identically whether it's called by a Claude-based agent, a custom mcp-use agent, or any other MCP-compliant client, since none of them need tool-specific integration code — they all just speak MCP.
💻 Code example
# Book's mcp-use example is TypeScript; here's the equivalent
# declarative shape (name, input parameters, callback) in Python
# via the official MCP SDK, following the same minimal-tool pattern.
from mcp.server.fastmcp import FastMCP
mcp = FastMCP("weather-server")
@mcp.tool()
def get_weather(location: str) -> dict:
"""A minimal tool example, matching the book's own
get_weather demonstration -- name, input parameter, and a
callback that returns content to the client."""
# In a real server this would call a weather API;
# simplified here to focus on the declarative registration shape
return {"location": location, "forecast": "Sunny", "temp_c": 22}
if __name__ == "__main__":
mcp.run()
# Any MCP-compatible client -- raw MCP client or an mcp-use agent --
# can now automatically discover and invoke get_weather during
# capability negotiation, with zero tool-specific integration code
💬 Deep Dive with AI
Key points
- •Tools are the main way an MCP server exposes functionality — actions the agent can perform, from API calls to calculations
- •In mcp-use, each tool is a small declarative definition: a name, input parameters, and a callback that returns content
- •The book's minimal example: a get_weather tool returning a basic weather response
- •Any MCP-compatible client automatically discovers and invokes registered tools during capability negotiation — no manual client-side registration needed
- •This makes tool definitions portable: the same tool works identically across any MCP-compliant client without tool-specific integration code