|
| 1 | +# FunctionsMcpTool - MCP Server Sample |
| 2 | + |
| 3 | +This Azure Functions app implements an MCP server that demonstrates various tool patterns. It includes sample tools for connectivity testing, code snippet management with Azure Blob Storage, and more. Additional tools will be added over time to showcase different MCP capabilities. |
| 4 | + |
| 5 | +## Features |
| 6 | + |
| 7 | +This MCP server currently provides the following tools: |
| 8 | + |
| 9 | +- **hello_mcp**: A simple hello world tool for testing connectivity |
| 10 | +- **get_snippet**: Retrieve a saved code snippet by name from Azure Blob Storage |
| 11 | +- **save_snippet**: Save a code snippet with a name to Azure Blob Storage |
| 12 | + |
| 13 | +More tools will be added to demonstrate additional MCP patterns and Azure Functions bindings. |
| 14 | + |
| 15 | +## Prerequisites |
| 16 | + |
| 17 | +- [Python](https://www.python.org/downloads/) version 3.13 or higher |
| 18 | +- [Azure Functions Core Tools](https://learn.microsoft.com/azure/azure-functions/functions-run-local?pivots=programming-language-python#install-the-azure-functions-core-tools) >= `4.8.0` |
| 19 | +- Azure Storage Emulator (Azurite) for local development |
| 20 | + |
| 21 | +## Local Development |
| 22 | + |
| 23 | +### 1. Start Azurite |
| 24 | + |
| 25 | +An Azure Storage Emulator is needed to store snippets locally: |
| 26 | + |
| 27 | +```shell |
| 28 | +docker run -p 10000:10000 -p 10001:10001 -p 10002:10002 \ |
| 29 | + mcr.microsoft.com/azure-storage/azurite |
| 30 | +``` |
| 31 | + |
| 32 | +> **Note**: If using the Azurite VS Code extension, run `Azurite: Start` from the command palette. |
| 33 | +
|
| 34 | +### 2. Install Dependencies |
| 35 | + |
| 36 | +From the `src/FunctionsMcpTool` directory, create and activate a virtual environment, then install dependencies: |
| 37 | + |
| 38 | +```shell |
| 39 | +python3 -m venv .venv |
| 40 | + |
| 41 | +# macOS/Linux |
| 42 | +source .venv/bin/activate |
| 43 | + |
| 44 | +# Windows |
| 45 | +.venv\Scripts\activate |
| 46 | + |
| 47 | +pip install -r requirements.txt |
| 48 | +``` |
| 49 | + |
| 50 | +### 3. Run the Function App |
| 51 | + |
| 52 | +```shell |
| 53 | +func start |
| 54 | +``` |
| 55 | + |
| 56 | +## Using the MCP Server |
| 57 | + |
| 58 | +### Connect from VS Code - GitHub Copilot |
| 59 | + |
| 60 | +1. Open [.vscode/mcp.json](../../.vscode/mcp.json) |
| 61 | +2. Find the server called `local-mcp-function` and click **Start**. The server uses the endpoint: `http://localhost:7071/runtime/webhooks/mcp` |
| 62 | +3. In Copilot chat agent mode, try these prompts: |
| 63 | + - "Say Hello" |
| 64 | + - "Save this snippet as snippet1" (with code selected) |
| 65 | + - "Retrieve snippet1 and apply to newFile.py" |
| 66 | + |
| 67 | +### Connect from MCP Inspector |
| 68 | + |
| 69 | +1. Install and run MCP Inspector: |
| 70 | + ```shell |
| 71 | + npx @modelcontextprotocol/inspector |
| 72 | + ``` |
| 73 | +2. Open the URL displayed (e.g., http://0.0.0.0:5173/#resources) |
| 74 | +3. Set transport type to `Streamable HTTP` |
| 75 | +4. Set URL to `http://0.0.0.0:7071/runtime/webhooks/mcp` and **Connect** |
| 76 | +5. **List Tools**, select a tool, and **Run Tool** |
| 77 | + |
| 78 | +## Verify Local Storage |
| 79 | + |
| 80 | +After saving snippets, verify they're stored in Azurite: |
| 81 | + |
| 82 | +### Using Azure Storage Explorer |
| 83 | + |
| 84 | +1. Open Azure Storage Explorer |
| 85 | +2. Navigate to **Emulator & Attached** → **Storage Accounts** → **(Emulator - Default Ports) (Key)** |
| 86 | +3. Go to **Blob Containers** → **snippets** |
| 87 | +4. View your saved snippet blobs |
| 88 | + |
| 89 | +### Using Azure CLI |
| 90 | + |
| 91 | +```shell |
| 92 | +# List blobs in the snippets container |
| 93 | +az storage blob list --container-name snippets --connection-string "DefaultEndpointsProtocol=http;AccountName=devstoreaccount1;AccountKey=Eby8vdM02xNOcqFlqUwJPLlmEtlCDXJ1OUzFT50uSRZ6IFsuFq2UVErCz4I6tq/K1SZFPTOtr/KBHBeksoGMGw==;BlobEndpoint=http://127.0.0.1:10000/devstoreaccount1;" |
| 94 | +``` |
| 95 | + |
| 96 | +## How It Works |
| 97 | + |
| 98 | +The function uses Azure Functions' first-class MCP decorators to expose tools: |
| 99 | + |
| 100 | +```python |
| 101 | +@app.mcp_tool() |
| 102 | +def hello_mcp() -> str: |
| 103 | + """Hello world.""" |
| 104 | + return "Hello I am MCPTool!" |
| 105 | + |
| 106 | +@app.mcp_tool() |
| 107 | +@app.mcp_tool_property(arg_name="snippetname", description="The name of the snippet.") |
| 108 | +@app.blob_input(arg_name="file", connection="AzureWebJobsStorage", path=_BLOB_PATH) |
| 109 | +def get_snippet(file: func.InputStream, snippetname: str) -> str: |
| 110 | + """Retrieve a snippet by name from Azure Blob Storage.""" |
| 111 | + # ... implementation |
| 112 | + |
| 113 | +@app.mcp_tool() |
| 114 | +@app.mcp_tool_property(arg_name="snippetname", description="The name of the snippet.") |
| 115 | +@app.mcp_tool_property(arg_name="snippet", description="The content of the snippet.") |
| 116 | +@app.blob_output(arg_name="file", connection="AzureWebJobsStorage", path=_BLOB_PATH) |
| 117 | +def save_snippet(file: func.Out[str], snippetname: str, snippet: str) -> str: |
| 118 | + """Save a snippet with a name to Azure Blob Storage.""" |
| 119 | + # ... implementation |
| 120 | +``` |
| 121 | + |
| 122 | +The MCP decorators automatically: |
| 123 | +- Infer tool properties from function signatures and type hints |
| 124 | +- Handle JSON serialization |
| 125 | +- Expose the functions as MCP tools without manual configuration |
| 126 | + |
| 127 | +## Deployment to Azure |
| 128 | + |
| 129 | +See [Deploy to Azure for Remote MCP](../../README.md#deploy-to-azure-for-remote-mcp) for deployment instructions. |
| 130 | + |
| 131 | +## Troubleshooting |
| 132 | + |
| 133 | +## Troubleshooting |
| 134 | + |
| 135 | +| Error | Solution | |
| 136 | +|---|---| |
| 137 | +| `AttributeError: 'FunctionApp' object has no attribute 'mcp_resource_trigger'` | Python 3.13 is required. Verify with `python3 --version`. Install via `brew install python@3.13` (macOS) or from [python.org](https://www.python.org/downloads/). Recreate your virtual environment with Python 3.13 after installing. | |
| 138 | +| Connection refused | Ensure Azurite is running (`docker run -p 10000:10000 -p 10001:10001 -p 10002:10002 mcr.microsoft.com/azure-storage/azurite`) | |
| 139 | +| API version not supported by Azurite | Pull the latest Azurite image (`docker pull mcr.microsoft.com/azure-storage/azurite`) then restart Azurite and the app | |
| 140 | +| Blob not found | Verify the snippet was saved successfully and the name matches exactly | |
0 commit comments