Skip to main content
Glama
README.md
# MCP + LangChain Demo

A beginner-friendly project that demonstrates how to build **MCP (Model Context Protocol) servers** and connect them to an **LLM agent** using LangChain and LangGraph.

---

## What is MCP?

**MCP (Model Context Protocol)** is an open protocol that lets you expose custom tools (functions) to LLMs in a standardized way. Think of it as a universal plugin system for AI models.

**Key concepts:**

| Term | Definition |
|------|-----------|
| **MCP Server** | A process that exposes tools (functions) over a transport (stdio or HTTP). The LLM can call these tools. |
| **MCP Client** | A process that connects to one or more MCP servers, discovers their tools, and forwards them to an LLM. |
| **Tool** | A Python function decorated with `@mcp.tool()` that the LLM can invoke. |
| **Transport** | The communication method between client and server. `stdio` = same machine via stdin/stdout. `streamable-http` = over HTTP. |
| **FastMCP** | A high-level Python class from the `mcp` library that makes it easy to create MCP servers. |

---

## Project Structure

```
MCPLEARNING/
├── mathserver.py      # MCP Server 1 - Math tools (stdio transport)
├── weather.py         # MCP Server 2 - Weather tool (HTTP transport)
├── client.py          # LangChain agent that connects to both servers
├── .env               # API keys (NOT pushed to GitHub)
├── .gitignore
├── requirements.txt
└── pyproject.toml
```

---

## How It Works (Step by Step)

### Step 1: MCP Server — `mathserver.py`

This file creates an MCP server named **"Math"** that exposes two tools:

- `add(a, b)` — Returns the sum of two integers.
- `multiply(a, b)` — Returns the product of two integers.

It runs on **stdio transport**, meaning the client spawns it as a subprocess and communicates through stdin/stdout. No port needed.

```python
from mcp.server.fastmcp import FastMCP

mcp = FastMCP("Math")

@mcp.tool()
def add(a: int, b: int) -> int:
    """Addition of two numbers"""
    return a + b

@mcp.tool()
def multiply(a: int, b: int) -> int:
    """Multiplication of two numbers"""
    return a * b

if __name__ == "__main__":
    mcp.run(transport="stdio")
```

### Step 2: MCP Server — `weather.py`

This file creates an MCP server named **"Weather"** that exposes one tool:

- `get_weather(location)` — Returns weather info for a given location.

It runs on **streamable-http transport**, meaning it starts a web server on `http://127.0.0.1:8000/mcp`. The client connects to it over HTTP.

```python
from mcp.server.fastmcp import FastMCP

mcp = FastMCP("Weather")

@mcp.tool()
async def get_weather(location: str) -> str:
    """Get the weather"""
    return "It's always raining in California"

if __name__ == "__main__":
    mcp.run(transport="streamable-http")
```

### Step 3: Client Agent — `client.py`

This is the brain of the project. It:

1. **Connects to both MCP servers** using `MultiServerMCPClient`.
2. **Discovers all tools** from both servers (`add`, `multiply`, `get_weather`).
3. **Creates a Groq LLM** (hosted open-source model) and binds the tools to it.
4. **Builds a LangGraph agent** — a state machine where:
   - The LLM decides whether to call a tool or respond directly.
   - If a tool is called, the result is fed back to the LLM for a final answer.
5. **Tests two queries**:
   - "What is 3 + 5?" → Uses the `add` tool.
   - "What is the weather in California?" → Uses the `get_weather` tool.

---

## Prerequisites

- Python 3.13+
- [uv](https://docs.astral.sh/uv/) package manager (recommended) or pip
- A **Groq API key** — Get one free at [console.groq.com](https://console.groq.com)

---

## Setup

### 1. Clone the repository

```bash
git clone https://github.com/<YOUR_USERNAME>/MCPLEARNING.git
cd MCPLEARNING
```

### 2. Create and activate virtual environment

```bash
# Using uv (recommended)
uv venv
uv pip install -r requirements.txt

# Or using pip
python -m venv .venv
.venv\Scripts\activate        # Windows
source .venv/bin/activate     # Mac/Linux
pip install -r requirements.txt
```

### 3. Set up your API key

Create a `.env` file in the project root:

```
GROQ_API_KEY=your_groq_api_key_here
```

> **IMPORTANT:** Never commit your `.env` file. It is excluded via `.gitignore`.

---

## Running the Project

You need **two terminals** open:

### Terminal 1 — Start the Weather MCP Server

```bash
python weather.py
```

You should see:

```
INFO: Uvicorn running on http://127.0.0.1:8000
```

> **Note:** Only `weather.py` needs to be started manually. The `mathserver.py` is spawned automatically by the client (stdio transport).

### Terminal 2 — Run the Client

```bash
python client.py
```

### Expected Output

```
Available MCP tools:
- add
- multiply
- get_weather

==============================
Testing Math MCP
==============================

Math Response: 3 + 5 = 8.

==============================
Testing Weather MCP
==============================

Weather Response: It's always raining in California.
```

---

## How to Create Your Own MCP Server

1. **Install the MCP library:**

```bash
pip install mcp
```

2. **Create a new Python file** (e.g., `myserver.py`):

```python
from mcp.server.fastmcp import FastMCP

mcp = FastMCP("MyServer")

@mcp.tool()
def my_tool(param: str) -> str:
    """Description of what this tool does."""
    return f"Result: {param}"

if __name__ == "__main__":
    mcp.run(transport="stdio")        # For stdio transport
    # mcp.run(transport="streamable-http")  # For HTTP transport
```

3. **Connect it in your client** by adding it to the `MultiServerMCPClient` config:

```python
client = MultiServerMCPClient({
    "myserver": {
        "command": "python",
        "args": ["myserver.py"],
        "transport": "stdio",
    },
})
```

---

## Transport Comparison

| Transport | How it Works | When to Use |
|-----------|-------------|-------------|
| **stdio** | Client spawns the server as a subprocess. Communicates via stdin/stdout. | Local tools, simple setup, no network needed. |
| **streamable-http** | Server runs as a web server. Client connects via HTTP. | Remote tools, multiple clients, cross-machine access. |

---

## Key Libraries Used

| Library | Purpose |
|---------|---------|
| `mcp` | Build MCP servers with `FastMCP`. |
| `langchain-mcp-adapters` | Bridge between MCP servers and LangChain tools. |
| `langchain-groq` | LangChain integration for Groq-hosted LLMs. |
| `langgraph` | Build agent workflows as a graph (agent ↔ tools loop). |
| `python-dotenv` | Load API keys from `.env` file. |

---

## Important Things to Take Care Of

1. **Weather server must be running before the client** — Since it uses HTTP transport, the server process must be started first. The math server (stdio) is auto-spawned by the client.

2. **Groq API key is required** — Without it, the LLM calls will fail. Get a free key at [console.groq.com](https://console.groq.com).

3. **Never commit `.env`** — Always add `.env` to `.gitignore` before pushing code.

4. **Port conflicts** — The weather server runs on port 8000 by default. If another process uses that port, the server will fail to start.

5. **Windows encoding issue** — On Windows, the console may not support UTF-8 characters returned by the LLM. The `client.py` handles this with `sys.stdout.reconfigure(encoding="utf-8")`.

6. **Model availability** — The Groq model name (`openai/gpt-oss-120b`) must be valid and available on the Groq platform. Check [Groq's model list](https://console.groq.com/docs/models) for current options.