GoodNews MCP Example¶
This notebook demonstrates how to connect an LLMAgent to a locally running
stdio MCP server using the stdio transport introduced in Chapter 5. The MCP
server used here is mcp-goodnews,
developed by the author, which fetches and surfaces positive news articles via
the NewsAPI.
Requirements¶
- A NewsAPI API key stored in the environment variable
NEWS_API_KEY - A Cohere API key stored in the environment variable
COHERE_API_KEY - The
mcp-goodnewsserver cloned and available locally
Setup Instructions¶
To ensure you have the required dependencies to run this notebook, you'll need to have our llm-agents-from-scratch framework installed on the running Jupyter kernel. To do this, you can launch this notebook with the following command while within the project's root directory:
# we need the notebook-utils and openai extras for this notebook
uv sync --extra notebook-utils --extra openai
# to launch the notebook
uv run --with jupyter jupyter lab
Alternatively, if you just want to use the published version of llm-agents-from-scratch without local development, you can install it from PyPI by uncommenting the cell below.
# Uncomment the line below to install `llm-agents-from-scratch` from PyPI
# !pip install 'llm-agents-from-scratch[notebook-utils,openai]'
Running an Ollama service¶
To execute the code provided in this notebook, you’ll need to have Ollama installed on your local machine and have its LLM hosting service running. To download Ollama, follow the instructions found on this page: https://ollama.com/download. After downloading and installing Ollama, you can start a service by opening a terminal and running the command ollama serve.
If running on Runpod using the Runpod templates for this Capstone project, then an Ollama service will already be running for you.
import logging
from llm_agents_from_scratch.logger import enable_console_logging
enable_console_logging(logging.INFO)
Creating an MCPToolProvider for GoodNews MCP Server¶
Unlike the HTTP-based MCP servers, mcp-goodnews runs locally as a subprocess
and is connected to via the stdio transport. We connect to it using the
stdio_params parameter on MCPToolProvider.
Before running the cells below, you'll need to clone the mcp-goodnews repo
to your local machine:
mkdir -p ~/mcp-servers
cd ~/mcp-servers
git clone https://github.com/VectorInstitute/mcp-goodnews
import getpass
import os
os.environ["COHERE_API_KEY"] = getpass.getpass("Cohere API Key: ")
os.environ["NEWS_API_KEY"] = getpass.getpass("News API Key: ")
from pathlib import Path
from mcp import StdioServerParameters
from llm_agents_from_scratch.tools.mcp import MCPToolProvider
server_path = Path.home() / "mcp-servers/mcp-goodnews/src/mcp_goodnews"
server_params = StdioServerParameters(
command="uv",
args=["run", "--with", "mcp", "mcp", "run", "server.py"],
cwd=server_path,
env={
"NEWS_API_KEY": os.environ["NEWS_API_KEY"],
"COHERE_API_KEY": os.environ["COHERE_API_KEY"],
},
)
goodnews_mcp_provider = MCPToolProvider(
name="goodnews_mcp",
stdio_params=server_params,
)
Create our LLM agent¶
We'll now use the LLMAgentBuilder class to create an LLM agent equipped with
the tools from the GoodNews MCP server. Recall from Chapter 5 that the builder
takes care of tool discovery for each of its attached MCP tool providers.
from llm_agents_from_scratch import LLMAgentBuilder
from llm_agents_from_scratch.llms import OllamaLLM
llm = OllamaLLM(
model="qwen3:14b",
)
agent = (
await LLMAgentBuilder()
.with_llm(llm)
.with_mcp_provider(goodnews_mcp_provider)
.build()
)
# Print all tools
for tool in agent.tools:
desc = (tool.description or "")[:100]
print(f"{tool.name}:\n\t{desc}...")
mcp__goodnews_mcp__fetch_list_of_goodnews: Fetch a list of headlines and return only top-ranked news based on positivity....
agent.tools_registry[
"mcp__goodnews_mcp__fetch_list_of_goodnews"
].parameters_json_schema
{'properties': {'category': {'default': 'all',
'enum': ['all', 'science', 'health', 'technology'],
'title': 'Category',
'type': 'string'}},
'title': 'fetch_list_of_goodnewsArguments',
'type': 'object'}
A simple task for our agent¶
Now that we have our agent, let's give it a simple task to perform. The GoodNews
MCP server exposes a single tool, fetch_list_of_goodnews, which accepts an
optional category parameter. The supported categories are all, science,
health, and technology. We'll ask our agent to fetch some good news in the
health category.
# task
from llm_agents_from_scratch.data_structures import Task
instruction = (
"Show me some good news articles in the science category. "
"Your final answer must contain ONLY the article titles and URLs from the "
"tool results. Do not summarize or describe what you did."
)
task = Task(
instruction=instruction,
)
handler = agent.run(task, max_steps=10)
INFO (llm_agents_fs.LLMAgent) : 🚀 Starting task: Show me some good news articles in the science category. Your final answer must contain ONLY the article titles and URLs from the too...[TRUNCATED] INFO (llm_agents_fs.TaskHandler) : ⚙️ Processing Step: Show me some good news articles in the science category. Your final answer must contain ONLY the article titles and URLs from the ...[TRUNCATED]
INFO (llm_agents_fs.TaskHandler) : 🛠️ Executing Tool Call: mcp__goodnews_mcp__fetch_list_of_goodnews
INFO (llm_agents_fs.TaskHandler) : ✅ Successful Tool Call: [{'type': 'text', 'text': '{"articles": [\n {\n "title": "Scientists may have found the holy grail of quantum comput...[TRUNCATED]
INFO (llm_agents_fs.TaskHandler) : ✅ Step Result: 1. Scientists may have found the holy grail of quantum computing - ScienceDaily (https://www.sciencedaily.com/releases/2026/02/26022100...[TRUNCATED]
INFO (llm_agents_fs.TaskHandler) : No new step required.
INFO (llm_agents_fs.LLMAgent) : 🏁 Task completed: 1. Scientists may have found the holy grail of quantum computing - ScienceDaily (https://www.sciencedaily.com/releases/2026/02/26022...[TRUNCATED]
result = handler.exception() or handler.result()
print(result)
1. Scientists may have found the holy grail of quantum computing - ScienceDaily (https://www.sciencedaily.com/releases/2026/02/260221000252.htm) 2. Amazing study finds that mice perform first aid when their friends are in distress - Earth.com (https://www.earth.com/news/mice-perform-first-aid-cpr-to-unconscious-companions-distress-to-revive-them/) 3. Photographer Stumbles Upon One of the Largest Dinosaur Trackways Ever Recorded - Indian Defence Review (https://indiandefencereview.com/photographer-largest-dinosaur-trackways/)