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