A powerful research assistant built with the Model Context Protocol (MCP) and Pydantic AI. This project demonstrates how to integrate multiple MCP servers with an AI agent to create an intelligent research tool that can search academic papers, access file systems, and fetch web content.
┌─────────────────────────────────────────────────────────────┐
│ Pydantic AI Agent │
│ (with OpenAI/LLM) │
└──────────────────────┬──────────────────────────────────────┘
│
│ Tools, Prompts, Resources
│
┌──────────────────────┴──────────────────────────────────────┐
│ MCP Client │
│ (manages multiple MCP servers and provides unified access) │
└───────┬──────────────────┬─────────────────┬────────────────┘
│ │ │
│ │ │
┌───────┴────────┐ ┌───────┴────────┐ ┌──────┴─────────┐
│ Research │ │ Filesystem │ │ Fetch │
│ Server │ │ Server │ │ Server │
│ (Custom) │ │ (MCP npm) │ │ (MCP pip) │
└────────────────┘ └────────────────┘ └────────────────┘
- MCP Client (
src/clients/client.py): Manages connections to multiple MCP servers and provides a unified interface for tools, prompts, and resources - Pydantic AI Agent (
src/clients/agent.py): Interactive chat agent that uses MCP tools to perform research and other tasks - Research Server (
src/servers/research.py): Custom MCP server for searching and managing academic papers from arXiv
- Python 3.13+
- uv (Python package manager)
- Node.js and npm (for filesystem server)
- Clone the repository:
git clone https://github.com/phungpx/MCP_exploration.git
cd MCP_exploration- Install dependencies using uv:
uv sync- Create a
.envfile with your LLM configuration:
LLM_MODEL=gemini-2.5-flash
LLM_API_KEY=
LLM_BASE_URL=https://generativelanguage.googleapis.com/v1beta/openai/
LANGFUSE_SECRET_KEY=
LANGFUSE_PUBLIC_KEY=
LANGFUSE_BASE_URL=Edit server_config.json to configure your MCP servers:
{
"mcpServers": {
"filesystem": {
"command": "npx",
"args": [
"-y",
"@modelcontextprotocol/server-filesystem",
"."
]
},
"research": {
"command": "uv",
"args": [
"run",
"python",
"-m",
"src.servers.research"
],
"cwd": "."
},
"fetch": {
"command": "uvx",
"args": [
"mcp-server-fetch"
]
},
"git": {
"command": "uvx",
"args": [
"mcp-server-git",
"--repository",
".git"
]
},
"time": {
"command": "uvx",
"args": [
"mcp-server-time"
]
},
"sequential-thinking": {
"command": "npx",
"args": [
"-y",
"@modelcontextprotocol/server-sequential-thinking"
]
}
}
}- research servers
npx @modelcontextprotocol/inspector python -m src.servers.researchnpx @modelcontextprotocol/inspector uvx mcp-server-fetchnpx @modelcontextprotocol/inspector npx -y @modelcontextprotocol/server-filesystem <directory-path>npx @modelcontextprotocol/inspector uvx mcp-server-git --repository .gitnpx @modelcontextprotocol/inspector uvx mcp-server-timenpx @modelcontextprotocol/inspector npx -y @modelcontextprotocol/server-sequential-thinkingApplication settings are managed through src/settings.py using Pydantic Settings:
- LLM Settings: Model name, API key, base URL, temperature, max tokens
- Research Directory: Where to store downloaded papers
MCP_exploration/
├── main.py # CLI entry point
├── pyproject.toml # Project dependencies
├── server_config.json # MCP servers configuration
├── .env # Environment variables (not in repo)
├── README.md # This file
├── docs/
└── src/
├── client.py # MCP client implementation
└── agent.py # Pydantic AI agent with CLI
├── servers/
│ └── research.py # Custom research MCP server
├── papers/ # Research papers storage
└── settings.py # Application settings
Run the interactive research agent:
uv run main.py
# or
uv run python main.py
# or directly
uv run src/clients/agent.pyOnce the agent starts, you'll see available prompts and resources. Use these commands:
exit,quit,bye,goodbye- Exit the chat
/prompts- List all available prompts with descriptions/resources- List all available resources with descriptions/use-prompt <key>- Display a specific prompt/read-resource <key>- Read and display a specific resource
=== MCP Client Started ===
📝 Available Prompts: 1
- research/generate_search_prompt
📚 Available Resources: 2
- research/papers://folders
- research/papers://{topic}
💡 Commands:
/prompts - List all available prompts
/resources - List all available resources
/use-prompt <key> - Use a specific prompt
/read-resource <key> - Read a specific resource
exit/quit - Exit the chat
==================================================
[You] Search for recent papers on quantum computing
[Assistant] I'll search for recent papers on quantum computing...
[Agent uses search_papers tool and provides results]
[You] /read-resource research/papers://folders
📚 Resource 'research/papers://folders':
# Available Topics
- quantum_computing
- machine_learning
Use @quantum_computing to access papers in that topic.
Located at src/servers/research.py - A custom MCP server for academic research.
search_papers(topic, max_results): Search arXiv for papers on a topicextract_info(paper_id): Get detailed information about a specific paper
papers://folders: List all available research topic folderspapers://{topic}: Get all papers for a specific topic with full details
generate_search_prompt(topic, num_papers): Generate a comprehensive research prompt for Claude
Provides file system access capabilities.
read_file(path): Read file contentswrite_file(path, content): Write content to a filelist_directory(path): List directory contents- And more...
Fetches content from the web.
fetch(url): Fetch content from a URL- And more...
You can create custom MCP servers using FastMCP:
from mcp.server.fastmcp import FastMCP
mcp = FastMCP("my_server")
@mcp.tool()
def my_tool(param: str) -> str:
"""Tool description"""
return f"Result: {param}"
@mcp.resource("myresource://{id}")
def my_resource(id: str) -> str:
"""Resource description"""
return f"Resource content for {id}"
@mcp.prompt()
def my_prompt(param: str) -> str:
"""Prompt description"""
return f"Generated prompt with {param}"
if __name__ == "__main__":
mcp.run(transport="stdio")- Add server configuration to
server_config.json - The client will automatically discover tools, prompts, and resources
- Restart the agent to load the new server