Skip to content
Merged
Show file tree
Hide file tree
Changes from 7 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
15 changes: 15 additions & 0 deletions .dockerignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
.azure
.venv
.logfire
.devcontainer
infra

# Common Python and development files to exclude
__pycache__
*.pyc
*.pyo
*.egg-info
.pytest_cache
.ruff_cache
.env
.git
261 changes: 206 additions & 55 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,59 +1,130 @@
# Python MCP Demo

A demonstration project showcasing Model Context Protocol (MCP) implementations using FastMCP, with examples of stdio, HTTP transports, and integration with LangChain and Agent Framework.
A demonstration project showcasing Model Context Protocol (MCP) implementations using FastMCP, with examples of stdio and HTTP transports, integration with LangChain and Agent Framework, and deployment to Azure Container Apps.

## Table of Contents

- [Prerequisites](#prerequisites)
- [Setup](#setup)
- [Python Scripts](#python-scripts)
- [MCP Server Configuration](#mcp-server-configuration)
- [Debugging](#debugging)
- [Getting started](#getting-started)
- [GitHub Codespaces](#github-codespaces)
- [VS Code Dev Containers](#vs-code-dev-containers)
- [Local environment](#local-environment)
- [Run local MCP servers](#run-local-mcp-servers)
- [Use with GitHub Copilot](#use-with-github-copilot)
- [Debug with VS Code](#debug-with-vs-code)
- [Inspect with MCP inspector](#inspect-with-mcp-inspector)
- [Run local Agents <-> MCP](#run-local-agents---mcp)
- [Deploy to Azure](#deploy-to-azure)
- [Azure account setup](#azure-account-setup)
- [Deploying with azd](#deploying-with-azd)
- [Costs](#costs)
- [Deploy to Azure with private networking](#deploy-to-azure-with-private-networking)

## Prerequisites
## Getting started

- Python 3.13 or higher
- [uv](https://docs.astral.sh/uv/)
- API access to one of the following:
- GitHub Models (GitHub token)
- Azure OpenAI (Azure credentials)
- Ollama (local installation)
- OpenAI API (API key)
You have a few options for setting up this project. The quickest way to get started is GitHub Codespaces, since it will setup all the tools for you, but you can also set it up locally.

## Setup
### GitHub Codespaces

1. Install dependencies using `uv`:
You can run this project virtually by using GitHub Codespaces. Click the button to open a web-based VS Code instance in your browser:

[![Open in GitHub Codespaces](https://github.com/codespaces/badge.svg)](https://codespaces.new/pamelafox/python-mcp-demo)

Once the Codespace is open, open a terminal window and continue with the deployment steps.

### VS Code Dev Containers

A related option is VS Code Dev Containers, which will open the project in your local VS Code using the [Dev Containers extension](https://marketplace.visualstudio.com/items?itemName=ms-vscode-remote.remote-containers):

1. Start Docker Desktop (install it if not already installed)
2. Open the project: [![Open in Dev Containers](https://img.shields.io/static/v1?style=for-the-badge&label=Dev%20Containers&message=Open&color=blue&logo=visualstudiocode)](https://vscode.dev/redirect?url=vscode://ms-vscode-remote.remote-containers/cloneInVolume?url=https://github.com/pamelafox/python-mcp-demo)
3. In the VS Code window that opens, once the project files show up (this may take several minutes), open a terminal window.
4. Continue with the deployment steps.

### Local environment

If you're not using one of the above options, then you'll need to:

1. Make sure the following tools are installed:
- [Azure Developer CLI (azd)](https://aka.ms/install-azd)
- [Python 3.13+](https://www.python.org/downloads/)
- [Docker Desktop](https://www.docker.com/products/docker-desktop/)
- [Git](https://git-scm.com/downloads)

2. Clone the repository and open the project folder.

3. Create a [Python virtual environment](https://docs.python.org/3/tutorial/venv.html#creating-virtual-environments) and activate it.

4. Install the dependencies:

```bash
uv sync
```

2. Copy `.env-sample` to `.env` and configure your environment variables:
5. Copy `.env-sample` to `.env` and configure your environment variables:

```bash
cp .env-sample .env
```

3. Edit `.env` with your API credentials. Choose one of the following providers by setting `API_HOST`:
6. Edit `.env` with your API credentials. Choose one of the following providers by setting `API_HOST`:
- `github` - GitHub Models (requires `GITHUB_TOKEN`)
- `azure` - Azure OpenAI (requires Azure credentials)
- `ollama` - Local Ollama instance
- `openai` - OpenAI API (requires `OPENAI_API_KEY`)

## Python Scripts
## Run local MCP servers

This project includes two MCP servers in the [`servers/`](servers/) directory:

Run any script with: `uv run <script_path>`
| File | Description |
|------|-------------|
| [servers/basic_mcp_stdio.py](servers/basic_mcp_stdio.py) | MCP server with stdio transport for VS Code integration |
| [servers/basic_mcp_http.py](servers/basic_mcp_http.py) | MCP server with HTTP transport on port 8000 |

- **servers/basic_mcp_http.py** - MCP server with HTTP transport on port 8000
- **servers/basic_mcp_stdio.py** - MCP server with stdio transport for VS Code integration
- **agents/langchainv1_http.py** - LangChain agent with MCP integration
- **agents/langchainv1_github.py** - LangChain tool filtering demo with GitHub MCP (requires `GITHUB_TOKEN`)
- **agents/agentframework_learn.py** - Microsoft Agent Framework integration with MCP
- **agents/agentframework_http.py** - Microsoft Agent Framework integration with local Expenses MCP server
Both servers implement an "Expenses Tracker" with a tool to add expenses to a CSV file.

## MCP Server Configuration
### Use with GitHub Copilot

### Using with MCP Inspector
The `.vscode/mcp.json` file configures MCP servers for GitHub Copilot integration:

**Available Servers:**

- **expenses-mcp**: stdio transport server for production use
- **expenses-mcp-debug**: stdio server with debugpy on port 5678
- **expenses-mcp-http**: HTTP transport server at `http://localhost:8000/mcp`. You must start this server manually with `uv run servers/basic_mcp_http.py` before using it.

**Switching Servers:**

Configure which server GitHub Copilot uses by opening the Chat panel, selecting the tools icon, and choosing the desired MCP server from the list.

![Servers selection dialog](readme_serverselect.png)

**Example input:**

Use a query like this to test the expenses MCP server:

```text
Log expense for 50 bucks of pizza on my amex today
```

![Example GitHub Copilot Chat Input](readme_samplequery.png)

### Debug with VS Code

The `.vscode/launch.json` provides a debug configuration to attach to an MCP server.

**To debug an MCP server with GitHub Copilot Chat:**

1. Set breakpoints in the MCP server code in `servers/basic_mcp_stdio.py`
2. Start the debug server via `mcp.json` configuration by selecting `expenses-mcp-debug`
3. Press `Cmd+Shift+D` to open Run and Debug
4. Select "Attach to MCP Server (stdio)" configuration
5. Press `F5` or the play button to start the debugger
6. Select the expenses-mcp-debug server in GitHub Copilot Chat tools
7. Use GitHub Copilot Chat to trigger the MCP tools
8. Debugger pauses at breakpoints

### Inspect with MCP inspector

The [MCP Inspector](https://github.com/modelcontextprotocol/inspector) is a developer tool for testing and debugging MCP servers.

Expand Down Expand Up @@ -86,45 +157,125 @@ The inspector provides a web interface to:
- Inspect server responses and errors
- Debug server communication

### Using with GitHub Copilot
---

The `.vscode/mcp.json` file configures MCP servers for GitHub Copilot integration:
## Run local Agents <-> MCP

**Available Servers:**
This project includes example agents in the [`agents/`](agents/) directory that demonstrate how to connect AI agents to MCP servers:

- **expenses-mcp**: stdio transport server for production use
- **expenses-mcp-debug**: stdio server with debugpy on port 5678
- **expenses-mcp-http**: HTTP transport server at `http://localhost:8000/mcp`. You must start this server manually with `uv run servers/basic_mcp_http.py` before using it.
| File | Description |
|------|-------------|
| [agents/agentframework_learn.py](agents/agentframework_learn.py) | Microsoft Agent Framework integration with MCP |
| [agents/agentframework_http.py](agents/agentframework_http.py) | Microsoft Agent Framework integration with local Expenses MCP server |
| [agents/langchainv1_http.py](agents/langchainv1_http.py) | LangChain agent with MCP integration |
| [agents/langchainv1_github.py](agents/langchainv1_github.py) | LangChain tool filtering demo with GitHub MCP (requires `GITHUB_TOKEN`) |

**Switching Servers:**
**To run an agent:**

Configure which server GitHub Copilot uses by opening the Chat panel, selecting the tools icon, and choosing the desired MCP server from the list.
1. First start the HTTP MCP server:

![Servers selection dialog](readme_serverselect.png)
```bash
uv run servers/basic_mcp_http.py
```

**Example input**
2. In another terminal, run an agent:

Use a query like this to test the expenses MCP server:
```bash
uv run agents/agentframework_http.py
```

```
Log expense for 50 bucks of pizza on my amex today
```
The agents will connect to the MCP server and allow you to interact with the expense tracking tools through a chat interface.

![Example GitHub Copilot Chat Input](readme_samplequery.png)
---

## Debugging
## Deploy to Azure

The `.vscode/launch.json` provides one debug configuration:
This project can be deployed to Azure Container Apps using the Azure Developer CLI (azd). The deployment provisions:

**Attach to MCP Server (stdio)**: Attaches to server started via `expenses-mcp-debug` in `mcp.json`
- **Azure Container Apps** - Hosts both the MCP server and agent
- **Azure OpenAI** - Provides the LLM for the agent
- **Azure Cosmos DB** - Stores expenses data
- **Azure Container Registry** - Stores container images
- **Log Analytics** - Monitoring and diagnostics

To debug an MCP server with GitHub Copilot Chat:
### Azure account setup

1. Set breakpoints in the MCP server code in `servers/basic_mcp_stdio.py`
1. Start the debug server via `mcp.json` configuration by selecting `expenses-mcp-debug`
1. Press `Cmd+Shift+D` to open Run and Debug
1. Select "Attach to MCP Server (stdio)" configuration
1. Press `F5` or the play button to start the debugger
1. Select the expenses-mcp-debug server in GitHub Copilot Chat tools
1. Use GitHub Copilot Chat to trigger the MCP tools
1. Debugger pauses at breakpoints
1. Sign up for a [free Azure account](https://azure.microsoft.com/free/) and create an Azure Subscription.
2. Check that you have the necessary permissions:
- Your Azure account must have `Microsoft.Authorization/roleAssignments/write` permissions, such as [Role Based Access Control Administrator](https://learn.microsoft.com/azure/role-based-access-control/built-in-roles#role-based-access-control-administrator-preview), [User Access Administrator](https://learn.microsoft.com/azure/role-based-access-control/built-in-roles#user-access-administrator), or [Owner](https://learn.microsoft.com/azure/role-based-access-control/built-in-roles#owner).
- Your Azure account also needs `Microsoft.Resources/deployments/write` permissions on the subscription level.

### Deploying with azd

1. Login to Azure:

```bash
azd auth login
```

For GitHub Codespaces users, if the previous command fails, try:

```bash
azd auth login --use-device-code
```

2. Create a new azd environment:

```bash
azd env new
```

This will create a folder inside `.azure` with the name of your environment.

3. Provision and deploy the resources:

```bash
azd up
```

It will prompt you to select a subscription and location. This will take several minutes to complete.

4. Once deployment is complete, a `.env` file will be created with the necessary environment variables to run the agents locally against the deployed resources.

### Costs

Pricing varies per region and usage, so it isn't possible to predict exact costs for your usage.

You can try the [Azure pricing calculator](https://azure.com/e/3987c81282c84410b491d28094030c9a) for the resources:

- **Azure OpenAI Service**: S0 tier, GPT-4o-mini model. Pricing is based on token count. [Pricing](https://azure.microsoft.com/pricing/details/cognitive-services/openai-service/)
- **Azure Container Apps**: Consumption tier. [Pricing](https://azure.microsoft.com/pricing/details/container-apps/)
- **Azure Container Registry**: Standard tier. [Pricing](https://azure.microsoft.com/pricing/details/container-registry/)
- **Azure Cosmos DB**: Serverless tier. [Pricing](https://azure.microsoft.com/pricing/details/cosmos-db/)
- **Log Analytics** (Optional): Pay-as-you-go tier. Costs based on data ingested. [Pricing](https://azure.microsoft.com/pricing/details/monitor/)

⚠️ To avoid unnecessary costs, remember to take down your app if it's no longer in use, either by deleting the resource group in the Portal or running `azd down`.

---

### Deploy to Azure with private networking

To demonstrate enhanced security for production deployments, this project supports deploying with a virtual network (VNet) configuration that restricts public access to Azure resources.

1. Set these azd environment variables to set up a virtual network and private endpoints for the Container App, Cosmos DB, and OpenAI resources:

```bash
azd env set USE_VNET true
azd env set USE_PRIVATE_INGRESS true
```

The Log Analytics and ACR resources will still have public access enabled, so that you can deploy and monitor the app without needing a VPN. In production, you would typically restrict these as well.

2. Provision and deploy:

```bash
azd up
```

### Additional costs for private networking
Copy link

Copilot AI Dec 4, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The heading level is inconsistent. This section "Deploy to Azure with private networking" is using h3 (###) but should be h2 (##) to match the same level as "Deploy to Azure" (line 191). Similarly, "Additional costs for private networking" should also be h3 (###) to match "Costs" (line 240).

Copilot uses AI. Check for mistakes.

When using VNet configuration, additional Azure resources are provisioned:

- **Virtual Network**: Pay-as-you-go tier. Costs based on data processed. [Pricing](https://azure.microsoft.com/pricing/details/virtual-network/)
- **Azure Private DNS Resolver**: Pricing per month, endpoints, and zones. [Pricing](https://azure.microsoft.com/pricing/details/dns/)
- **Azure Private Endpoints**: Pricing per hour per endpoint. [Pricing](https://azure.microsoft.com/pricing/details/private-link/)
38 changes: 38 additions & 0 deletions agents/Dockerfile
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
# ------------------- Stage 1: Build Stage ------------------------------
# We use Alpine for smaller image size (~329MB vs ~431MB for Debian slim).
# Trade-off: We must install build tools to compile native extensions (cryptography, etc.)
# since pre-built musl wheels aren't available. Debian -slim would skip compilation
# but produces a larger final image due to glibc wheel sizes.
FROM python:3.13-alpine AS build

# Install build dependencies for packages with native extensions (cryptography, etc.)
# https://cryptography.io/en/latest/installation/#building-cryptography-on-linux
RUN apk add --no-cache gcc g++ musl-dev python3-dev libffi-dev openssl-dev cargo pkgconfig

COPY --from=ghcr.io/astral-sh/uv:0.9.14 /uv /uvx /bin/

WORKDIR /code

# Copy dependency files and install dependencies (for layer caching)
# Note: We can't use --mount=type=cache since Azure Container Apps remote build doesn't support BuildKit:
# https://github.com/Azure/acr/issues/721
COPY uv.lock pyproject.toml ./
RUN uv sync --locked --no-install-project

# Copy the project and sync
COPY . .
RUN uv sync --locked

# ------------------- Stage 2: Final Stage ------------------------------
FROM python:3.13-alpine AS final

RUN addgroup -S app && adduser -S app -G app

COPY --from=build --chown=app:app /code /code

WORKDIR /code/agents
USER app

ENV PATH="/code/.venv/bin:$PATH"

ENTRYPOINT ["python", "agentframework_http.py"]
Loading