A modular, extensible AI assistant that combines AutoGen (ag2) agent orchestration with the Model Context Protocol (MCP) for structured tool exposure, all wrapped in a clean Streamlit chat interface. The agent leverages NVIDIA NIM-hosted LLMs and provides out-of-the-box capabilities for file operations, web search, weather lookups, and location-based place discovery.
- Overview
- Features
- Architecture
- How MCP Works in This Project
- Tool Calling Flow
- Installation
- Configuration Reference
- Available Tools
- Session & Memory Management
- Database Schema
- Development
- License
Autogen-MCP-Agent demonstrates a production-oriented pattern for building LLM-powered agents: instead of hardcoding tool logic inside the agent, tools are served through a separate MCP server process. The AutoGen agent discovers and invokes these tools over the stdio transport using the StdioMcpToolAdapter, keeping concerns cleanly separated and making it straightforward to add, remove, or modify tools independently of the agent itself.
The user interacts with the system through a browser-based Streamlit UI that manages chat sessions, renders rich responses (including inline maps and place cards), and persists conversation history to a local SQLite database.
- MCP-Based Tool Architecture — Tools are registered on a standalone MCP server and consumed by the AutoGen agent via the
StdioMcpToolAdapter, following the official Model Context Protocol specification. - Six Built-in Tools — File creation, editing, and deletion; web search via Google Serper; real-time weather via WeatherAPI; and location/place discovery via Google Maps & Places API.
- Dual AutoGen Backends — Supports the newer
autogen-agentchat+autogen-extstack (preferred, with native MCP integration) and falls back to legacyautogenif the extensions are unavailable. - Graceful Fallback — When neither AutoGen backend is present, the agent falls back to direct tool execution with keyword-based intent detection, so the system remains partially functional even without an LLM.
- Persistent Chat History — All conversations are stored in a local SQLite database with per-session isolation, enabling session switching and history replay.
- Streamlit Chat UI — A responsive, light-themed chat interface with sidebar session management, special rendering for location results (map images + place cards), and weather emoji display.
- NVIDIA NIM LLM Backend — Uses the NVIDIA Integrate API endpoint (
integrate.api.nvidia.com/v1) as an OpenAI-compatible endpoint, configured viapydantic-settings. - Configuration via
.env— All API keys and settings are managed through a.envfile, loaded automatically bypydantic-settings.
| Layer | Technology |
|---|---|
| LLM Backend | NVIDIA NIM (OpenAI-compatible API) — default model: deepseek-ai/deepseek-v4-pro |
| Agent Framework | autogen-agentchat + autogen-ext (primary) / autogen (legacy fallback) |
| Tool Protocol | Model Context Protocol (mcp) via stdio transport |
| UI | Streamlit |
| Database | SQLite (via Python sqlite3) |
| Configuration | pydantic-settings + .env file |
| HTTP Clients | requests (for external APIs) |
| Geocoding | Google Maps Geocoding API + Google Places API |
| Web Search | Google Serper API |
| Weather | WeatherAPI.com |
| Python Version | >= 3.12 |
The system is organized into five distinct layers, each with a clear responsibility. Data flows downward from the user's browser through the Streamlit UI into the MasterAgent, which communicates with the MCP server over stdio to invoke tools. The NVIDIA NIM LLM sits alongside the agent as an external service. All conversation data is persisted to a local SQLite database, and configuration is centralized in config/settings.py using pydantic-settings.
Autogen-MCP-Agent/
├── main.py # Entry point — launches Streamlit app
├── run.py # Alternative entry point with explicit server args
├── pyproject.toml # Project metadata and dependencies (uv/pip compatible)
├── env-style.txt # Template listing all required environment variables
├── README.md # This file
├── architecture.png # Architecture diagram
│
├── config/
│ ├── __init__.py # Exports `settings` singleton
│ └── settings.py # Pydantic Settings class — all config in one place
│
└── src/
├── agents/
│ ├── __init__.py
│ └── master_agent.py # Core agent: orchestrates LLM, MCP tools, sessions
│
├── mcp/
│ ├── __init__.py
│ ├── mcp_server.py # MCPServerWrapper — FastMCP convenience wrapper (fallback use)
│ └── http_server.py # *** THE ACTUAL MCP SERVER *** — mcp.server.Server via stdio
│
├── tools/
│ ├── __init__.py
│ ├── file_tools.py # File CRUD operations (create, edit, delete)
│ ├── web_search_tools.py # Google Serper web search
│ ├── weather_tools.py # WeatherAPI.com current weather
│ └── location_tools.py # Google Geocoding + Places API
│
├── database/
│ ├── __init__.py
│ └── db_manager.py # SQLite manager — sessions, messages, history
│
├── memory/
│ ├── __init__.py
│ └── session_manager.py # In-memory session cache backed by DB
│
└── ui/
├── __init__.py
└── streamlit_app.py # Full Streamlit chat UI with sidebar + rich output
Central configuration using pydantic-settings. Reads from environment variables and .env file. Holds all API keys, the LLM model name, the NVIDIA API base URL, MCP server host/port, and the database URL. A module-level settings singleton is imported throughout the codebase.
The brain of the application. The MasterAgent class:
- Creates an
OpenAIChatCompletionClientpointed at the NVIDIA NIM endpoint. - Spawns a child Python process running
src.mcp.http_serveras an MCP server. - Loads each of the six tools individually via
StdioMcpToolAdapter.from_server_params(). - Creates an
AssistantAgentwith the loaded tools and a system prompt. - On each user query, prepends conversation history as context, sends the task to the agent, and saves the exchange to the database.
If the new AutoGen extensions are not installed, it falls back to legacy autogen.AssistantAgent + UserProxyAgent. If neither is available, it uses a keyword-matching fallback that calls tools directly.
This is the real MCP server used at runtime. It inherits from mcp.server.Server and communicates over stdio transport. This is the process that the AutoGen agent connects to via StdioMcpToolAdapter. It defines the full JSON Schema for each tool's input parameters and dispatches calls to the appropriate tool class through handle_list_tools() and handle_call_tool() handlers. This file must be running (either manually or as an auto-spawned child process) before the agent can use any tools.
A higher-level wrapper using FastMCP (the convenience API from the mcp package). It registers the same six tools using the @server.tool() decorator. This wrapper also provides a execute_tool() method for direct (non-MCP) tool invocation, used by the fallback path when AutoGen is not available. This is NOT the server used at runtime — it exists as a utility for direct tool execution and testing.
Four tool classes, each encapsulating a specific capability:
- FileTools (
file_tools.py) — Local filesystem operations withpathlib.Path. Creates, edits, and deletes files with automatic parent directory creation. - WebSearchTools (
web_search_tools.py) — POST requests togoogle.serper.dev/search, returning top 5 organic results with titles, links, and snippets. - WeatherTools (
weather_tools.py) — GET requests toapi.weatherapi.com/v1/current.json, returning temperature, conditions, humidity, wind, and "feels like" data with emoji mapping. - LocationTools (
location_tools.py) — Two-step process: geocode a location string via Google Geocoding API to get lat/lng, then search for nearby places via Google Places API. Also generates a Google Static Maps URL with numbered markers.
A lightweight SQLite wrapper using Python's built-in sqlite3. Creates the chat_history table on first run, provides methods for saving messages, retrieving session history, and listing all sessions with message counts.
An optional in-memory cache layer on top of DatabaseManager. Provides create_session(), get_session(), add_message(), and get_session_history() with a configurable limit.
The Streamlit frontend. Features include:
- A sidebar showing all past chat sessions (clickable to switch).
- A "New Chat" button that creates a fresh session.
- Custom CSS for a polished, light-themed chat experience.
- Special rendering for location results: inline Google Static Maps images and place cards with ratings, addresses, and "View Details" buttons.
- Async bridge: creates a new event loop to call the agent's
async process_query()from Streamlit's synchronous context.
The Model Context Protocol (MCP) is an open standard that defines how LLM applications expose and consume tools. In this project, MCP serves as the bridge between the tool implementations and the AutoGen agent.
The file src/mcp/http_server.py is the actual MCP server that runs at runtime. Despite its name suggesting HTTP, it uses stdio transport — communication happens over the operating system's standard input and output pipes. This file contains the MCPHttpServer class which inherits from mcp.server.Server and registers two core handlers:
-
handle_list_tools()— Returns a list oftypes.Toolobjects, each with aname,description, andinputSchema(JSON Schema describing the expected parameters). The agent calls this during initialization to discover what tools are available. -
handle_call_tool(name, arguments)— Dispatches a tool call to the matching tool class method and returns the result astypes.TextContent. The agent calls this whenever the LLM decides to invoke a tool.
Important: The other file in the
src/mcp/directory —mcp_server.py— is a convenience wrapper built onFastMCP. It is not the server used at runtime. It exists to provide aexecute_tool()method for the fallback path (when AutoGen is not installed) and for testing tools directly without going through the MCP protocol.
Every tool is registered with an explicit JSON Schema that tells the LLM exactly what parameters to pass. For example, the create_file tool is registered as:
types.Tool(
name="create_file",
description="Create a file with specific extension in a specific path",
inputSchema={
"type": "object",
"properties": {
"path": {"type": "string", "description": "Directory path"},
"filename": {"type": "string", "description": "Name of the file"},
"extension": {"type": "string", "description": "File extension"},
"content": {"type": "string", "description": "File content", "default": ""}
},
"required": ["path", "filename", "extension"]
}
)This schema is sent to the LLM during tool discovery, enabling the model to generate properly structured function calls with the correct parameter names and types.
The MCP server (http_server.py) communicates with the AutoGen agent over stdio (standard input/output), not HTTP. This is a deliberate choice with several advantages:
- No network overhead — communication happens over OS pipes, making it fast and secure with no exposed ports.
- Process isolation — the MCP server runs as a separate child process, so a tool crash doesn't bring down the agent.
- Simplicity — no need to manage ports, CORS, or network configuration.
The server is started via StdioServerParams in the MasterAgent:
server_params = StdioServerParams(
command=sys.executable, # Python interpreter
args=["-m", "src.mcp.http_server"], # Run http_server.py as a module
env=None, # Inherit parent environment
)You can also run the MCP server manually in a separate terminal for debugging:
python -m src.mcp.http_serverAutoGen's autogen-ext package provides StdioMcpToolAdapter, which handles the entire lifecycle:
- Launches the MCP server (
src/mcp/http_server.py) as a subprocess. - Sends a
tools/listrequest to discover available tools. - Wraps each tool as a callable that AutoGen's
AssistantAgentcan invoke. - On each invocation, sends a
tools/callrequest to the MCP server and returns the result.
Tools are loaded individually by name to give the agent fine-grained control over which tools are available:
for tool_name in ["create_file", "edit_file", "delete_file",
"find_locations", "web_search", "get_weather"]:
adapter = await StdioMcpToolAdapter.from_server_params(
server_params,
tool_name=tool_name
)
self.tools.append(adapter)User types message in Streamlit UI
|
v
MasterAgent.process_query(query, session_id)
|
+-- Load last 10 messages from DB (conversation context)
+-- Prepend context to the user query
|
v
AssistantAgent.run(task=context + query)
|
v
LLM (NVIDIA NIM / deepseek-v4-pro) decides to call a tool
|
v
StdioMcpToolAdapter sends tools/call to MCP server (via stdio)
|
v
MCP Server (http_server.py) dispatches to the appropriate Tool class
|
v
Tool class executes (e.g., WeatherTools.get_weather("Tokyo"))
|
v
Result flows back: Tool --> MCP Server --> Adapter --> Agent --> LLM
|
v
LLM generates a natural language response using the tool result
|
v
Response saved to SQLite and displayed in Streamlit
When AutoGen is not available, the agent uses keyword-based intent detection to match user queries to tools:
if "create file" in query_lower:
params = self._extract_file_params(query)
return mcp_wrapper.execute_tool("create_file", **params)
elif "weather" in query_lower:
params = self._extract_weather_params(query)
return mcp_wrapper.execute_tool("get_weather", **params)
# ... etcThe MCPServerWrapper.execute_tool() method (from mcp_server.py) bypasses MCP entirely and calls the tool classes directly. This ensures the system remains partially functional even without an LLM backend, though tool parameter extraction is less sophisticated (regex-based vs. LLM-driven).
- Python 3.12 or later — the project requires Python >= 3.12 as specified in
pyproject.toml. - NVIDIA API Key — obtain one from NVIDIA NIM (free tier available).
- API keys for external tools (optional, based on which tools you want to use):
- Google Serper API key — serper.dev
- WeatherAPI key — weatherapi.com
- Google Maps API key (with Places API enabled) — Google Cloud Console
git clone https://github.com/armanjscript/Autogen-MCP-Agent.git
cd Autogen-MCP-Agentuv is a fast Python package and project manager written in Rust. It replaces pip, virtualenv, and pip-tools with a single, significantly faster tool.
macOS / Linux:
curl -LsSf https://astral.sh/uv/install.sh | shWindows (PowerShell):
powershell -ExecutionPolicy ByPass -c "irm https://astral.sh/uv/install.ps1 | iex"Via pip (any platform):
pip install uvVia Homebrew (macOS):
brew install uvVerify the installation:
uv --versionFrom the project root directory, run:
uv venvThis creates a .venv/ directory containing an isolated Python environment. If you want to specify a Python version explicitly:
uv venv --python 3.12macOS / Linux:
source .venv/bin/activateWindows (Command Prompt):
.venv\Scripts\activate.batWindows (PowerShell):
.venv\Scripts\Activate.ps1You should see (.venv) prefixed to your terminal prompt, indicating the virtual environment is active.
With the virtual environment activated, install all project dependencies from pyproject.toml:
uv pip install -e .Or, alternatively, using uv sync (which also creates a lockfile):
uv syncThis installs all required packages including:
ag2[openai]andautogen-agentchat— AutoGen agent frameworkautogen-ext[mcp]— AutoGen MCP extensions (includesStdioMcpToolAdapter)mcp[cli]— Model Context Protocol SDKstreamlit— Web UI frameworkpydantic-settingsandpython-dotenv— Configuration managementrequests— HTTP client for external APIsgeopy— Geocoding utilitiessqlalchemy— Database toolkit (available but not actively used; the project uses rawsqlite3)
Copy the environment template and fill in your API keys:
cp env-style.txt .envEdit the .env file with your actual keys:
NVIDIA_API_KEY=nvapi-xxxxxxxxxxxxxxxxxxxxxxxx
GOOGLE_SERPER_API_KEY=xxxxxxxxxxxxxxxxxxxxxxxx
WEATHER_API_KEY=xxxxxxxxxxxxxxxxxxxxxxxx
DATABASE_URL=sqlite:///./chat_history.db
GOOGLE_MAPS_API_KEY=xxxxxxxxxxxxxxxxxxxxxxxx| Variable | Required | Description |
|---|---|---|
NVIDIA_API_KEY |
Yes | API key for NVIDIA NIM (LLM backend) |
GOOGLE_SERPER_API_KEY |
No | API key for Google Serper web search |
WEATHER_API_KEY |
No | API key for WeatherAPI.com |
GOOGLE_MAPS_API_KEY |
No | API key for Google Maps & Places API |
DATABASE_URL |
No | SQLite connection string (defaults to sqlite:///./chat_history.db) |
Note: The
NVIDIA_API_KEYis the only strictly required key for the LLM to function. The other keys are needed only if you want to use the corresponding tools. The system will return an informative error message if a tool is called without its required API key.
Before running the main application, the MCP server (src/mcp/http_server.py) must be running. This is the process that exposes all six tools (file operations, web search, weather, location) to the agent via the Model Context Protocol over stdio.
Open a separate terminal, navigate to the project root, ensure your virtual environment is activated, and run:
python -m src.mcp.http_serverThis starts the MCP server in stdio mode, listening for tools/list and tools/call requests. Leave this terminal open — the server will stay running and wait for input.
How it works at runtime: When the MasterAgent initializes, its
StdioMcpToolAdapterautomatically spawnspython -m src.mcp.http_serveras a child process behind the scenes. However, running it manually first is recommended so you can see the server's output and debug any tool registration issues. If you skip this step, the adapter will attempt to spawn it automatically — but if there are import errors or configuration issues, they will be silently swallowed.
With the MCP server running (Step 7), open a new terminal (or use the same one after stopping the manual server), activate the virtual environment, and launch the Streamlit app:
Option A — Using the main entry point:
python main.pyOption B — Using the run script (explicit server args):
python run.pyOption C — Running Streamlit directly:
streamlit run src/ui/streamlit_app.py --server.port=8501 --server.address=localhostThe application will be available at http://localhost:8501 in your browser.
Summary of the two-terminal workflow:
Terminal 1 (MCP Server) Terminal 2 (Application) python -m src.mcp.http_serverpython run.py(keeps running, waits for stdio) (launches Streamlit at :8501)
All configuration is managed in config/settings.py via the Settings class (powered by pydantic-settings). Values are resolved in this order: environment variables > .env file > defaults.
| Setting | Default | Description |
|---|---|---|
NVIDIA_API_KEY |
"" |
NVIDIA NIM API key |
NVIDIA_API_BASE |
https://integrate.api.nvidia.com/v1 |
NVIDIA API base URL (OpenAI-compatible) |
LLM_MODEL |
deepseek-ai/deepseek-v4-pro |
LLM model identifier |
DATABASE_URL |
sqlite:///./chat_history.db |
Database connection string |
GOOGLE_SERPER_API_KEY |
"" |
Google Serper API key |
GOOGLE_MAPS_API_KEY |
"" |
Google Maps API key |
WEATHER_API_KEY |
"" |
WeatherAPI.com key |
MCP_SERVER_HOST |
localhost |
MCP server host (reserved for future use) |
MCP_SERVER_PORT |
8022 |
MCP server port (reserved for future use) |
To change the LLM model, either set the LLM_MODEL environment variable or edit config/settings.py. Any OpenAI-compatible model served by NVIDIA NIM can be used.
| Tool | Parameters | Description |
|---|---|---|
create_file |
path, filename, extension, content |
Creates a new file at the specified path. Parent directories are created automatically if they don't exist. |
edit_file |
path, filename, content, extension |
Writes content to an existing file, or creates it if extension is provided and the file doesn't exist. If no extension is given, it searches for a file matching filename.* in the given path. |
delete_file |
path, filename |
Deletes a file at path/filename. Returns an error if the file doesn't exist. |
| Tool | Parameters | Description |
|---|---|---|
web_search |
query |
Searches the web using the Google Serper API. Returns the top 5 organic results with title, link, snippet, and position. |
| Tool | Parameters | Description |
|---|---|---|
get_weather |
city |
Fetches the current weather for a city from WeatherAPI.com. Returns temperature (C and F), condition text with emoji, humidity, wind speed, and "feels like" temperature. |
| Tool | Parameters | Description |
|---|---|---|
find_locations |
query, location |
Two-step process: (1) geocodes the location string via Google Geocoding API to get lat/lng, (2) searches for nearby places matching query via Google Places API. Returns place names, addresses, ratings, coordinates, types, and a Google Static Maps URL with numbered markers. |
The application maintains a persistent record of all conversations using SQLite. Key behaviors:
- Session Isolation — Each chat session is identified by a unique UUID. Messages from different sessions are stored separately and never mixed.
- Context Window — The agent loads the last 10 messages from the current session to build context for each new query. This gives the LLM conversational awareness without overwhelming the context window.
- Session Switching — The Streamlit sidebar lists all past sessions with their creation time and message count. Clicking a session loads its full history into the UI.
- New Chat — The "New Chat" button creates a fresh session UUID and clears the in-memory message list. The previous session's history remains in the database.
- In-Memory Cache — The
SessionManagerclass optionally caches session data in a Python dictionary for faster access, falling back to the database for uncached sessions.
The project uses a single SQLite table:
CREATE TABLE IF NOT EXISTS chat_history (
id INTEGER PRIMARY KEY AUTOINCREMENT,
session_id TEXT NOT NULL,
human_message TEXT,
ai_message TEXT,
timestamp DATETIME DEFAULT CURRENT_TIMESTAMP
);
CREATE INDEX IF NOT EXISTS idx_session_id ON chat_history(session_id);session_id— UUID identifying the conversation session.human_message— The user's input (NULL if the row represents a system/agent-initiated message).ai_message— The agent's response (NULL if the row represents a user-only turn).timestamp— Auto-set to the insertion time.
The database file (chat_history.db) is created automatically in the project root on first run.
To extend the system with a new tool:
- Create the tool class in
src/tools/my_tool.py:
from typing import Dict, Any
class MyTool:
def do_something(self, param: str) -> Dict[str, Any]:
# Your logic here
return {"success": True, "result": "..."}-
Register it in the MCP server — Add a new entry in
src/mcp/http_server.py(low-leveltypes.Toolregistration inhandle_list_tools()) and add the dispatch case inhandle_call_tool(). Also add it tosrc/mcp/mcp_server.py(FastMCP@server.tool()decorator). -
Add it to the tool loading list in
src/agents/master_agent.py:
tool_names = [
# ... existing tools ...
"do_something"
]-
Update the tool map in
MCPServerWrapper.execute_tool()insrc/mcp/mcp_server.py. -
Export from
src/tools/__init__.py.
This project is provided as-is. Please refer to the original repository for license information.
