Handle
Connecting…
Back to Workshop
Module 07 ~20 min

Add a Custom Tool

Add a random facts tool to the MCP server. The agent discovers it automatically — no agent code changes needed.

What You'll Build

Random Facts Tool

A new MCP tool that returns fun facts

Auto-Discovery

Agent finds the new tool with zero changes

MCP Pattern

Register, route, implement — that's it

Step by Step

Step 7a

Register the Tool in tools/list

First, add the new tool definition to the tools/list handler. This tells the agent (and the LLM) what the tool does and what parameters it accepts. The random facts tool takes an optional category parameter.

services/mcp-server/app.py Python
# Add to the tools list in handle_tools_list()
{
    "name": "get_random_fact",
    "description": "Get a random fun fact. Optionally specify a category.",
    "inputSchema": {
        "type": "object",
        "properties": {
            "category": {
                "type": "string",
                "description": "Category: science, history, animals, technology, space",
                "enum": ["science", "history", "animals", "technology", "space"]
            }
        },
        "required": []
    }
}
Step 7b

Implement the Tool Function

Write the function that generates random facts. For this workshop we use a hardcoded list, but you could easily connect to an external API later.

services/mcp-server/app.py Python
import random

FACTS = {
    "science": [
        "Honey never spoils. Archaeologists have found 3000-year-old honey in Egyptian tombs that was still edible.",
        "A teaspoon of a neutron star would weigh about 6 billion tons.",
        "Octopuses have three hearts and blue blood.",
    ],
    "history": [
        "Cleopatra lived closer in time to the Moon landing than to the construction of the Great Pyramid.",
        "The Oxford University is older than the Aztec Empire.",
        "Ancient Romans used crushed mouse brains as toothpaste.",
    ],
    "animals": [
        "A group of flamingos is called a 'flamboyance'.",
        "Cows have best friends and get stressed when separated.",
        "Sea otters hold hands while sleeping so they don't drift apart.",
    ],
    "technology": [
        "The first computer bug was an actual moth found in a Harvard Mark II computer in 1947.",
        "The entire Apollo 11 computer had less processing power than a modern calculator.",
        "The first domain name ever registered was symbolics.com on March 15, 1985.",
    ],
    "space": [
        "There are more stars in the universe than grains of sand on all of Earth's beaches.",
        "A day on Venus is longer than a year on Venus.",
        "Neutron stars can spin at a rate of 600 rotations per second.",
    ],
}

def get_random_fact(category: str = None) -> str:
    if category and category in FACTS:
        return random.choice(FACTS[category])
    all_facts = [f for facts in FACTS.values() for f in facts]
    return random.choice(all_facts)
Step 7c

Route the Tool Call

Add routing in the tools/call handler so when the agent requests get_random_fact, the server calls your new function.

services/mcp-server/app.py Python
# In handle_tools_call(), add a new elif branch:
elif tool_name == "get_random_fact":
    category = arguments.get("category")
    fact = get_random_fact(category)
    return {
        "content": [{"type": "text", "text": fact}],
        "isError": False
    }

Pattern: Adding a tool to the MCP server always follows the same three steps: (1) register in tools/list, (2) implement the function, (3) route in tools/call. The agent never needs to change.

Step 7d

Rebuild and Test

Rebuild just the MCP server and restart. The agent will re-discover tools on startup and automatically find get_random_fact.

Terminal Bash
# Rebuild the MCP server only
docker compose build mcp-server

# Restart all services (agent re-discovers tools on startup)
docker compose up -d

# Verify the new tool appears in tools/list
curl -X POST http://localhost:8000/message \
  -H "Content-Type: application/json" \
  -H "MCP-Protocol-Version: 2026-07-28" \
  -H "Mcp-Method: tools/list" \
  -d '{"jsonrpc":"2.0","id":1,"method":"tools/list","params":{"_meta":{"io.modelcontextprotocol/protocolVersion":"2026-07-28","io.modelcontextprotocol/clientCapabilities":{}}}}'

You should see get_random_fact in the tools list alongside get_weather.

Step 7e

Test the Tool Directly

Call the tool directly via JSON-RPC to verify it works before testing through the agent.

Terminal Bash
# Call without a category (random from all)
curl -X POST http://localhost:8000/message \
  -H "Content-Type: application/json" \
  -H "MCP-Protocol-Version: 2026-07-28" \
  -H "Mcp-Method: tools/call" \
  -H "Mcp-Name: get_random_fact" \
  -d '{"jsonrpc":"2.0","id":1,"method":"tools/call","params":{"name":"get_random_fact","arguments":{},"_meta":{"io.modelcontextprotocol/protocolVersion":"2026-07-28","io.modelcontextprotocol/clientCapabilities":{}}}}'

# Call with a specific category
curl -X POST http://localhost:8000/message \
  -H "Content-Type: application/json" \
  -H "MCP-Protocol-Version: 2026-07-28" \
  -H "Mcp-Method: tools/call" \
  -H "Mcp-Name: get_random_fact" \
  -d '{"jsonrpc":"2.0","id":1,"method":"tools/call","params":{"name":"get_random_fact","arguments":{"category":"space"},"_meta":{"io.modelcontextprotocol/protocolVersion":"2026-07-28","io.modelcontextprotocol/clientCapabilities":{}}}}'
Step 7f

Test Through the Agent

Now ask the agent for a fact. The LLM will decide to use the new tool — no agent code changes were needed.

Terminal Bash
# Ask for a random fact
curl -X POST http://localhost:8001/query \
  -H "Content-Type: application/json" \
  -d '{"query": "Tell me a fun fact about space"}'

# Try combining tools in a single query
curl -X POST http://localhost:8001/query \
  -H "Content-Type: application/json" \
  -d '{"query": "What is the weather in Oslo and tell me a random science fact"}'

This is the power of MCP: You added a tool to the server, and the agent automatically discovered and used it. The LLM decides when to call which tool based on the user's query. Try the combined query — the LLM will call both tools in one go.

What You've Built

A new get_random_fact tool with category support
Registered, implemented, and routed in the MCP server
Agent auto-discovered the tool with zero code changes
LLM can combine multiple tools in a single query

How was this module?

Your feedback helps us improve the workshop.

Submitting as anonymous

Your handle is sent with this feedback; leave it blank in the header and the submission stays anonymous. Please keep personal data out of the comment too — no name, e-mail address or employer, yours or anyone else's.

Wire It Together Real APIs