Handle
Connecting…
Back to Workshop
Module 08 ~20 min

Connect to Real APIs

Add a news tool that fetches real headlines from Google News RSS. Move from hardcoded data to live data sources.

What You'll Build

News Tool

Fetch real headlines from Google News RSS

Parsing a Real Response

Turn upstream XML into MCP content

Multi-Tool Agent

Weather + facts + news in one agent

Step by Step

Step 8a

Look at the Feed

The news source is Google News RSS. No sign-up, no key, no rate-limit dashboard — just a URL that returns XML. Query it in your browser or with curl before you write any code, so you know what shape the data arrives in.

Terminal Bash
# Search the feed for a topic
curl -s "https://news.google.com/rss/search?q=artificial+intelligence&hl=en-US&gl=US&ceid=US:en" | head -40

# Or the plain top-stories feed, no query
curl -s "https://news.google.com/rss?hl=en-US&gl=US&ceid=US:en" | head -40

Three query parameters carry the locale: hl is the language, gl the country, and ceid pairs the two — US:en for English, NO:no for Norwegian. Each <item> in the response has a title, link and source. That is all this tool needs.

Nothing to add to .env: this tool takes no secret. The one key the workshop needs is OPENAI_API_KEY for the agent, and you set that back in module 2.

Step 8b

Register the News Tool

Add the news tool definition to tools/list. It takes a required topic and an optional count parameter.

services/mcp-server/app.py Python
# Add to the tools list in handle_tools_list()
{
    "name": "get_news",
    "description": "Get latest news headlines for a topic.",
    "inputSchema": {
        "type": "object",
        "properties": {
            "topic": {
                "type": "string",
                "description": "The news topic to search for"
            },
            "count": {
                "type": "integer",
                "description": "Number of headlines to return (default 5, max 10)",
                "default": 5
            }
        },
        "required": ["topic"]
    }
}
Step 8c

Implement the News Function

This function calls Google News RSS to fetch real headlines. Unlike the facts tool, this one makes an actual HTTP request to an external service — and parses XML rather than JSON.

services/mcp-server/app.py Python
import httpx
from xml.etree import ElementTree

GOOGLE_NEWS_RSS = "https://news.google.com/rss/search"

async def get_news(topic: str, count: int = 5) -> str:
    """Fetch latest news headlines for a given topic. No API key needed."""
    count = min(count, 10)  # Cap at 10

    async with httpx.AsyncClient() as http:
        resp = await http.get(
            GOOGLE_NEWS_RSS,
            params={"q": topic, "hl": "en-US", "gl": "US", "ceid": "US:en"},
            timeout=10.0,
        )
        resp.raise_for_status()

    # Google News RSS is plain XML: channel > item > title / link / source.
    items = ElementTree.fromstring(resp.text).findall(".//item")[:count]
    if not items:
        return f"No news found for topic: {topic}"

    lines = [f"Top {len(items)} headlines for '{topic}':\n"]
    for i, item in enumerate(items, 1):
        title = item.findtext("title", "No title")
        source = item.findtext("source", "Unknown")
        lines.append(f"{i}. {title} ({source})")

    return "\n".join(lines)
Step 8d

Route the Tool Call

Add the routing for get_news in the tools/call handler.

services/mcp-server/app.py Python
# In handle_tools_call(), add a new elif branch:
elif tool_name == "get_news":
    topic = arguments.get("topic", "technology")
    count = arguments.get("count", 5)
    result = await get_news(topic, count)
    return {
        "content": [{"type": "text", "text": result}],
        "isError": False
    }
Step 8e

Rebuild and Test

Rebuild the MCP server, restart, and test the new tool.

Terminal Bash
# Rebuild and restart
docker compose build mcp-server
docker compose up -d

# Test the news tool directly
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_news" \
  -d '{"jsonrpc":"2.0","id":1,"method":"tools/call","params":{"name":"get_news","arguments":{"topic":"artificial intelligence","count":3},"_meta":{"io.modelcontextprotocol/protocolVersion":"2026-07-28","io.modelcontextprotocol/clientCapabilities":{}}}}'

You should see real news headlines about AI, straight from the Google News feed.

Step 8f

Test the Full Pipeline

Ask the agent questions that trigger the news tool. Try combining it with other tools to see the LLM orchestrate multiple calls.

Terminal Bash
# Ask for news
curl -X POST http://localhost:8001/query \
  -H "Content-Type: application/json" \
  -d '{"query": "What are the latest news about AI?"}'

# Combine all three tools in one query
curl -X POST http://localhost:8001/query \
  -H "Content-Type: application/json" \
  -d '{"query": "Give me the weather in London, a fun science fact, and top 3 AI news headlines"}'

Multi-tool orchestration: The combined query demonstrates the real power of the agentic loop. The LLM sees all three tools, decides it needs all of them, calls each one through the MCP server, and then synthesizes the results into a single coherent response.

Step 8g

Verify All Tools

List all tools to confirm your MCP server now exposes three tools — all automatically available to the agent.

Terminal Bash
# List all tools — you should see all three
curl -s -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":{}}}}' | python3 -m json.tool

Expected: get_weather, get_random_fact, and get_news all listed with their schemas.

What you've proven: The MCP pattern scales cleanly. Each new tool is self-contained in the server. The agent discovers everything dynamically. The LLM decides which tools to call. You could add ten more tools without touching the agent code.

What You've Built

A get_news tool that fetches real headlines from Google News RSS
An upstream XML response parsed down into MCP text content
Three-tool agent: weather, facts, and news — all auto-discovered
Multi-tool orchestration: LLM calls 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.

Custom Tool Local LLMs