fix readme
Browse files- README.md +78 -32
- STEP_BY_STEP_GUIDE.md +93 -273
README.md
CHANGED
|
@@ -10,63 +10,109 @@ pinned: false
|
|
| 10 |
short_description: A minimal Gradio MCP server that provides timezone-aware dat
|
| 11 |
---
|
| 12 |
|
| 13 |
-
# Berlin Time MCP
|
| 14 |
|
| 15 |
-
|
| 16 |
|
| 17 |
-
##
|
| 18 |
|
| 19 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
| 20 |
|
| 21 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 22 |
|
| 23 |
1. Install dependencies:
|
| 24 |
```bash
|
| 25 |
pip install -r requirements.txt
|
| 26 |
```
|
| 27 |
|
| 28 |
-
2. Run the server:
|
|
|
|
|
|
|
| 29 |
```bash
|
| 30 |
python app_time_mcp_server.py
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 31 |
```
|
| 32 |
|
| 33 |
-
3. Open your browser to
|
|
|
|
|
|
|
| 34 |
|
| 35 |
-
## Deploying to HuggingFace Spaces
|
| 36 |
|
| 37 |
1. Create a new Space at [huggingface.co/spaces](https://huggingface.co/spaces)
|
| 38 |
-
2. Choose
|
| 39 |
-
3. Upload
|
| 40 |
-
- `app_time_mcp_server.py` (rename to `app.py` for HF Spaces)
|
| 41 |
-
- `requirements.txt`
|
| 42 |
-
4. Your Space will automatically deploy!
|
| 43 |
|
| 44 |
-
|
| 45 |
|
| 46 |
-
|
|
|
|
| 47 |
|
| 48 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 49 |
|
| 50 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 51 |
|
| 52 |
-
|
| 53 |
|
| 54 |
-
|
| 55 |
|
| 56 |
-
|
| 57 |
-
|
| 58 |
-
|
| 59 |
-
|
| 60 |
-
"timezone": "Europe/Berlin",
|
| 61 |
-
"timestamp": "2025-12-04T17:00:57+01:00",
|
| 62 |
-
"utc_offset": "+0100",
|
| 63 |
-
"day_of_week": "Wednesday",
|
| 64 |
-
"is_dst": false
|
| 65 |
}
|
| 66 |
```
|
| 67 |
|
| 68 |
-
|
|
|
|
|
|
|
| 69 |
|
| 70 |
-
-
|
| 71 |
-
-
|
| 72 |
-
- Add timezone difference calculator
|
|
|
|
| 10 |
short_description: A minimal Gradio MCP server that provides timezone-aware dat
|
| 11 |
---
|
| 12 |
|
| 13 |
+
# Berlin Time & World Time MCP Servers
|
| 14 |
|
| 15 |
+
This directory contains two example MCP (Model Context Protocol) servers built with Gradio.
|
| 16 |
|
| 17 |
+
## π Available Servers
|
| 18 |
|
| 19 |
+
### 1. Simple Berlin Time (`app_time_mcp_server.py`)
|
| 20 |
+
- **Function:** Returns current time in Berlin.
|
| 21 |
+
- **Complexity:** Simple, no parameters.
|
| 22 |
+
- **Port:** 7860
|
| 23 |
+
- **Best for:** Learning the basics of MCP.
|
| 24 |
|
| 25 |
+
### 2. World Time (`app_world_time_mcp_server.py`)
|
| 26 |
+
- **Function:** Returns current time for 25+ major cities.
|
| 27 |
+
- **Complexity:** Takes a `city` parameter (e.g., "Tokyo", "New York").
|
| 28 |
+
- **Port:** 7860 (when deployed) / 7861 (local dev).
|
| 29 |
+
- **Best for:** Demonstrating tool arguments and dynamic responses.
|
| 30 |
+
|
| 31 |
+
---
|
| 32 |
+
|
| 33 |
+
## π Local Testing
|
| 34 |
|
| 35 |
1. Install dependencies:
|
| 36 |
```bash
|
| 37 |
pip install -r requirements.txt
|
| 38 |
```
|
| 39 |
|
| 40 |
+
2. Run the server of your choice:
|
| 41 |
+
|
| 42 |
+
**Option A: Berlin Time**
|
| 43 |
```bash
|
| 44 |
python app_time_mcp_server.py
|
| 45 |
+
# Runs on http://localhost:7860
|
| 46 |
+
```
|
| 47 |
+
|
| 48 |
+
**Option B: World Time**
|
| 49 |
+
```bash
|
| 50 |
+
python app_world_time_mcp_server.py
|
| 51 |
+
# Runs on http://localhost:7861 (to avoid conflict)
|
| 52 |
```
|
| 53 |
|
| 54 |
+
3. Open the URL in your browser to test the UI manually.
|
| 55 |
+
|
| 56 |
+
---
|
| 57 |
|
| 58 |
+
## βοΈ Deploying to HuggingFace Spaces
|
| 59 |
|
| 60 |
1. Create a new Space at [huggingface.co/spaces](https://huggingface.co/spaces)
|
| 61 |
+
2. Choose **Gradio** as the SDK.
|
| 62 |
+
3. Upload your files.
|
|
|
|
|
|
|
|
|
|
| 63 |
|
| 64 |
+
### β οΈ IMPORTANT: Deployment Checklist
|
| 65 |
|
| 66 |
+
#### 1. Configure the Entry File (The "Pro" Way)
|
| 67 |
+
Instead of renaming your file to `app.py`, you can tell HuggingFace which file to run by editing the **YAML Header** at the very top of your `README.md` in the Space.
|
| 68 |
|
| 69 |
+
**For Berlin Time:**
|
| 70 |
+
```yaml
|
| 71 |
+
---
|
| 72 |
+
title: Berlin Time MCP
|
| 73 |
+
emoji: π
|
| 74 |
+
colorFrom: blue
|
| 75 |
+
colorTo: indigo
|
| 76 |
+
sdk: gradio
|
| 77 |
+
sdk_version: 5.0.0
|
| 78 |
+
app_file: app_time_mcp_server.py <-- CHANGE THIS
|
| 79 |
+
pinned: false
|
| 80 |
+
---
|
| 81 |
+
```
|
| 82 |
|
| 83 |
+
**For World Time:**
|
| 84 |
+
```yaml
|
| 85 |
+
---
|
| 86 |
+
title: World Time MCP
|
| 87 |
+
emoji: π
|
| 88 |
+
colorFrom: green
|
| 89 |
+
colorTo: blue
|
| 90 |
+
sdk: gradio
|
| 91 |
+
sdk_version: 5.0.0
|
| 92 |
+
app_file: app_world_time_mcp_server.py <-- CHANGE THIS
|
| 93 |
+
pinned: false
|
| 94 |
+
---
|
| 95 |
+
```
|
| 96 |
+
|
| 97 |
+
#### 2. Check the Port
|
| 98 |
+
HuggingFace Spaces **REQUIRES** the app to run on port **7860**.
|
| 99 |
+
- If you use `app_world_time_mcp_server.py`, **change `server_port=7861` to `server_port=7860`** in the code before deploying.
|
| 100 |
+
- If you don't do this, you will get an `OSError: Cannot find empty port`.
|
| 101 |
|
| 102 |
+
### Configuration for Your Agent
|
| 103 |
|
| 104 |
+
Once deployed, update your `src/config/settings.py`:
|
| 105 |
|
| 106 |
+
```python
|
| 107 |
+
servers["berlin_time"] = {
|
| 108 |
+
"url": "https://huggingface.co/spaces/YOUR_USERNAME/YOUR_SPACE_NAME/gradio_api/mcp/",
|
| 109 |
+
"transport": "sse"
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 110 |
}
|
| 111 |
```
|
| 112 |
|
| 113 |
+
---
|
| 114 |
+
|
| 115 |
+
## π Documentation
|
| 116 |
|
| 117 |
+
- [Step-by-Step Guide](STEP_BY_STEP_GUIDE.md): Detailed teaching guide.
|
| 118 |
+
- [MCP Connection Flow](../.gemini/antigravity/brain/26cb67ea-9995-44cc-8251-52a912873dc8/mcp_connection_flow.md): Visual diagram of how it works.
|
|
|
STEP_BY_STEP_GUIDE.md
CHANGED
|
@@ -1,339 +1,159 @@
|
|
| 1 |
-
# Step-by-Step Guide:
|
| 2 |
|
| 3 |
## β
What We've Built
|
| 4 |
|
| 5 |
-
You now have
|
| 6 |
-
- `app_time_mcp_server.py` - The main server application
|
| 7 |
-
- `requirements.txt` - Dependencies (gradio, pytz)
|
| 8 |
-
- `README.md` - Documentation
|
| 9 |
-
- `.gitignore` - Git configuration
|
| 10 |
|
| 11 |
-
|
|
|
|
|
|
|
|
|
|
| 12 |
|
| 13 |
-
|
| 14 |
-
|
| 15 |
-
|
| 16 |
-
|
| 17 |
-
2. β
Exposing an MCP endpoint at: `http://localhost:7860/gradio_api/mcp/`
|
| 18 |
-
3. β
Ready to be called by AI agents
|
| 19 |
|
| 20 |
---
|
| 21 |
|
| 22 |
-
## π Understanding
|
| 23 |
|
| 24 |
-
### 1. The Core Function
|
| 25 |
|
|
|
|
| 26 |
```python
|
| 27 |
def get_berlin_time():
|
| 28 |
-
|
| 29 |
-
|
| 30 |
-
# ... returns structured data
|
| 31 |
```
|
| 32 |
|
| 33 |
-
**
|
| 34 |
-
|
| 35 |
-
|
| 36 |
-
|
| 37 |
-
|
| 38 |
-
|
| 39 |
-
|
| 40 |
-
- Includes both human-readable and machine-readable formats
|
| 41 |
-
- Provides extra context (day of week, DST status)
|
| 42 |
|
| 43 |
### 2. The Gradio Interface
|
| 44 |
|
| 45 |
```python
|
| 46 |
demo = gr.Interface(
|
| 47 |
-
fn=
|
| 48 |
-
inputs=
|
| 49 |
-
outputs=gr.JSON(
|
| 50 |
-
|
| 51 |
)
|
| 52 |
```
|
| 53 |
|
| 54 |
-
|
| 55 |
-
- `fn=get_berlin_time` - The function to expose
|
| 56 |
-
- `inputs=None` - No parameters needed (simple tool)
|
| 57 |
-
- `outputs=gr.JSON()` - Returns JSON data
|
| 58 |
-
- Creates both a UI and an API endpoint
|
| 59 |
-
|
| 60 |
-
### 3. The MCP Magic: `mcp_server=True`
|
| 61 |
|
| 62 |
```python
|
| 63 |
demo.launch(mcp_server=True)
|
| 64 |
```
|
| 65 |
-
|
| 66 |
-
**This single parameter:**
|
| 67 |
-
- Starts the normal Gradio UI (for testing)
|
| 68 |
-
- **ALSO** starts an MCP protocol server
|
| 69 |
-
- Automatically creates MCP tool definitions
|
| 70 |
-
- Handles all MCP communication
|
| 71 |
-
|
| 72 |
-
**What happens behind the scenes:**
|
| 73 |
-
1. Gradio analyzes your function signature
|
| 74 |
-
2. Creates an MCP tool definition with:
|
| 75 |
-
- Tool name: `get_berlin_time`
|
| 76 |
-
- Input schema: (none in this case)
|
| 77 |
-
- Output schema: (JSON object)
|
| 78 |
-
3. Exposes an MCP endpoint that AI agents can connect to
|
| 79 |
-
|
| 80 |
-
---
|
| 81 |
-
|
| 82 |
-
## π§ͺ Testing Locally
|
| 83 |
-
|
| 84 |
-
### Method 1: Web UI (Manual Testing)
|
| 85 |
-
|
| 86 |
-
1. **Server is already running** at http://localhost:7860
|
| 87 |
-
2. Open your browser to that URL
|
| 88 |
-
3. Click the "Submit" button
|
| 89 |
-
4. You'll see JSON output like:
|
| 90 |
-
```json
|
| 91 |
-
{
|
| 92 |
-
"time": "2025-12-04 17:00:57 CET",
|
| 93 |
-
"timezone": "Europe/Berlin",
|
| 94 |
-
"timestamp": "2025-12-04T17:00:57+01:00",
|
| 95 |
-
"utc_offset": "+0100",
|
| 96 |
-
"day_of_week": "Wednesday",
|
| 97 |
-
"is_dst": false
|
| 98 |
-
}
|
| 99 |
-
```
|
| 100 |
-
|
| 101 |
-
### Method 2: MCP Protocol (AI Agent Testing)
|
| 102 |
-
|
| 103 |
-
The MCP endpoint is at: `http://localhost:7860/gradio_api/mcp/`
|
| 104 |
-
|
| 105 |
-
AI agents can connect to this endpoint and:
|
| 106 |
-
1. Discover available tools
|
| 107 |
-
2. Call `get_berlin_time`
|
| 108 |
-
3. Receive the structured response
|
| 109 |
|
| 110 |
---
|
| 111 |
|
| 112 |
-
## π Deploying to HuggingFace Spaces
|
| 113 |
|
| 114 |
-
|
| 115 |
|
| 116 |
-
|
| 117 |
|
| 118 |
-
|
| 119 |
-
# In the external_mcp_servers directory
|
| 120 |
-
cp app_time_mcp_server.py app.py
|
| 121 |
-
```
|
| 122 |
-
|
| 123 |
-
### Step 2: Create a HuggingFace Space
|
| 124 |
-
|
| 125 |
-
1. Go to https://huggingface.co/spaces
|
| 126 |
-
2. Click "Create new Space"
|
| 127 |
-
3. Fill in:
|
| 128 |
-
- **Name:** `berlin-time-mcp` (or your choice)
|
| 129 |
-
- **License:** Choose one (e.g., MIT)
|
| 130 |
-
- **SDK:** Select **Gradio**
|
| 131 |
-
- **Visibility:** Public or Private
|
| 132 |
-
|
| 133 |
-
### Step 3: Upload Files
|
| 134 |
|
| 135 |
-
|
|
|
|
|
|
|
|
|
|
| 136 |
|
| 137 |
-
**
|
| 138 |
-
```
|
| 139 |
-
|
| 140 |
-
git init
|
| 141 |
-
git add app.py requirements.txt README.md
|
| 142 |
-
git commit -m "Initial MCP server"
|
| 143 |
-
git remote add hf https://huggingface.co/spaces/YOUR_USERNAME/berlin-time-mcp
|
| 144 |
-
git push hf main
|
| 145 |
```
|
| 146 |
|
| 147 |
-
**
|
| 148 |
-
|
| 149 |
-
|
| 150 |
-
- `app.py` (renamed from app_time_mcp_server.py)
|
| 151 |
-
- `requirements.txt`
|
| 152 |
-
- `README.md` (optional)
|
| 153 |
-
|
| 154 |
-
### Step 4: Automatic Deployment
|
| 155 |
-
|
| 156 |
-
HuggingFace will:
|
| 157 |
-
1. Detect it's a Gradio app (from `requirements.txt`)
|
| 158 |
-
2. Install dependencies
|
| 159 |
-
3. Run `app.py`
|
| 160 |
-
4. Provide a public URL: `https://huggingface.co/spaces/YOUR_USERNAME/berlin-time-mcp`
|
| 161 |
-
|
| 162 |
-
### Step 5: Verify Deployment
|
| 163 |
-
|
| 164 |
-
Once deployed, you'll see:
|
| 165 |
-
- The Gradio UI at the Space URL
|
| 166 |
-
- MCP endpoint at: `https://huggingface.co/spaces/YOUR_USERNAME/berlin-time-mcp/gradio_api/mcp/`
|
| 167 |
-
|
| 168 |
-
---
|
| 169 |
-
|
| 170 |
-
## π Integrating with Your LangGraph Agent
|
| 171 |
-
|
| 172 |
-
### Prerequisites
|
| 173 |
-
|
| 174 |
-
```bash
|
| 175 |
-
pip install mcp langchain-mcp
|
| 176 |
```
|
| 177 |
|
| 178 |
-
|
| 179 |
|
| 180 |
-
|
| 181 |
|
| 182 |
-
|
| 183 |
-
from mcp import ClientSession, StdioServerParameters
|
| 184 |
-
from mcp.client.stdio import stdio_client
|
| 185 |
-
from langchain.tools import Tool
|
| 186 |
-
import asyncio
|
| 187 |
|
| 188 |
-
|
| 189 |
-
"""Connect to the Berlin Time MCP server"""
|
| 190 |
-
|
| 191 |
-
# For local testing
|
| 192 |
-
server_params = StdioServerParameters(
|
| 193 |
-
command="python",
|
| 194 |
-
args=["external_mcp_servers/app_time_mcp_server.py"]
|
| 195 |
-
)
|
| 196 |
-
|
| 197 |
-
# Or for deployed version:
|
| 198 |
-
# server_params = HttpServerParameters(
|
| 199 |
-
# url="https://huggingface.co/spaces/YOUR_USERNAME/berlin-time-mcp/gradio_api/mcp/"
|
| 200 |
-
# )
|
| 201 |
-
|
| 202 |
-
async with stdio_client(server_params) as (read, write):
|
| 203 |
-
async with ClientSession(read, write) as session:
|
| 204 |
-
await session.initialize()
|
| 205 |
-
tools = await session.list_tools()
|
| 206 |
-
return session, tools
|
| 207 |
-
|
| 208 |
-
def create_berlin_time_tool():
|
| 209 |
-
"""Create a LangChain tool from the MCP server"""
|
| 210 |
-
|
| 211 |
-
async def get_time():
|
| 212 |
-
session, _ = await connect_to_berlin_time_mcp()
|
| 213 |
-
result = await session.call_tool("get_berlin_time", {})
|
| 214 |
-
return result
|
| 215 |
-
|
| 216 |
-
return Tool(
|
| 217 |
-
name="get_berlin_time",
|
| 218 |
-
func=lambda: asyncio.run(get_time()),
|
| 219 |
-
description="Get the current date and time in Berlin, Germany. "
|
| 220 |
-
"Returns time in multiple formats including ISO 8601."
|
| 221 |
-
)
|
| 222 |
-
```
|
| 223 |
|
| 224 |
-
|
|
|
|
| 225 |
|
| 226 |
-
|
| 227 |
|
| 228 |
```python
|
| 229 |
-
|
| 230 |
-
|
| 231 |
-
# Add to your existing tools
|
| 232 |
-
berlin_time_tool = create_berlin_time_tool()
|
| 233 |
|
| 234 |
-
#
|
| 235 |
-
|
| 236 |
-
# ... your existing tools ...
|
| 237 |
-
berlin_time_tool
|
| 238 |
-
]
|
| 239 |
```
|
| 240 |
|
| 241 |
-
|
| 242 |
|
| 243 |
-
|
| 244 |
-
- "What time is it in Berlin?"
|
| 245 |
-
- "What's the current date and time in Berlin?"
|
| 246 |
-
- "Is it daytime in Berlin right now?"
|
| 247 |
|
| 248 |
-
|
| 249 |
-
|
| 250 |
-
|
| 251 |
-
|
| 252 |
-
|
| 253 |
|
| 254 |
---
|
| 255 |
|
| 256 |
-
##
|
| 257 |
-
|
| 258 |
-
### Key Points to Emphasize:
|
| 259 |
|
| 260 |
-
|
| 261 |
-
- It's a standard way for AI to talk to tools
|
| 262 |
-
- Like HTTP for web, MCP for AI tools
|
| 263 |
|
| 264 |
-
|
| 265 |
-
- One parameter: `mcp_server=True`
|
| 266 |
-
- Handles all the protocol complexity
|
| 267 |
-
- Provides both UI and API
|
| 268 |
|
| 269 |
-
|
| 270 |
-
|
| 271 |
-
|
| 272 |
-
|
| 273 |
-
|
| 274 |
-
|
| 275 |
-
|
| 276 |
-
|
| 277 |
-
|
|
|
|
| 278 |
|
| 279 |
-
###
|
| 280 |
|
| 281 |
-
1. **
|
| 282 |
-
2. **
|
| 283 |
-
3. **
|
| 284 |
-
4. **
|
| 285 |
-
5. **
|
|
|
|
| 286 |
|
| 287 |
---
|
| 288 |
|
| 289 |
-
##
|
| 290 |
-
|
| 291 |
-
### Immediate Next Steps:
|
| 292 |
-
1. β
Test the local server (currently running)
|
| 293 |
-
2. βοΈ Deploy to HuggingFace Spaces
|
| 294 |
-
3. βοΈ Integrate with your LangGraph agent
|
| 295 |
-
4. βοΈ Test end-to-end with your agent
|
| 296 |
|
| 297 |
-
|
| 298 |
|
| 299 |
-
|
| 300 |
-
|
| 301 |
-
|
| 302 |
-
|
| 303 |
-
```
|
| 304 |
|
| 305 |
-
|
| 306 |
-
|
| 307 |
-
|
| 308 |
-
# Convert between timezones
|
| 309 |
-
```
|
| 310 |
|
| 311 |
-
|
| 312 |
-
|
| 313 |
-
def is_business_hours(timezone: str = "Europe/Berlin"):
|
| 314 |
-
# Check if it's business hours (9-5)
|
| 315 |
-
```
|
| 316 |
-
|
| 317 |
-
**4. Multiple Tools in One Server**
|
| 318 |
-
```python
|
| 319 |
-
# Create multiple gr.Interface instances
|
| 320 |
-
# Combine them with gr.TabbedInterface
|
| 321 |
-
```
|
| 322 |
-
|
| 323 |
-
---
|
| 324 |
|
| 325 |
-
|
| 326 |
-
|
| 327 |
-
You now have:
|
| 328 |
-
- β
A working MCP server with Berlin time tool
|
| 329 |
-
- β
Complete understanding of how MCP works
|
| 330 |
-
- β
Local testing capability
|
| 331 |
-
- β
Deployment instructions for HF Spaces
|
| 332 |
-
- β
Integration guide for LangGraph
|
| 333 |
-
- β
Teaching materials for colleagues
|
| 334 |
-
|
| 335 |
-
**The beauty of this approach:**
|
| 336 |
-
- Simple Python function β Gradio interface β MCP server
|
| 337 |
-
- One line (`mcp_server=True`) enables AI integration
|
| 338 |
-
- Deploy anywhere Gradio runs
|
| 339 |
-
- Use with any MCP-compatible AI system
|
|
|
|
| 1 |
+
# Step-by-Step Guide: Building & Deploying MCP Servers
|
| 2 |
|
| 3 |
## β
What We've Built
|
| 4 |
|
| 5 |
+
You now have **two** working MCP server examples in `external_mcp_servers/`:
|
|
|
|
|
|
|
|
|
|
|
|
|
| 6 |
|
| 7 |
+
1. **`app_time_mcp_server.py`** (Original)
|
| 8 |
+
- Simple, parameter-less tool.
|
| 9 |
+
- Returns Berlin time only.
|
| 10 |
+
- Great for first-time understanding.
|
| 11 |
|
| 12 |
+
2. **`app_world_time_mcp_server.py`** (Upgraded)
|
| 13 |
+
- Accepts a `city` parameter.
|
| 14 |
+
- Returns time for 25+ cities.
|
| 15 |
+
- Demonstrates how LLMs pass arguments to tools.
|
|
|
|
|
|
|
| 16 |
|
| 17 |
---
|
| 18 |
|
| 19 |
+
## π Understanding the Components
|
| 20 |
|
| 21 |
+
### 1. The Core Function
|
| 22 |
|
| 23 |
+
**Simple (Berlin):**
|
| 24 |
```python
|
| 25 |
def get_berlin_time():
|
| 26 |
+
# No arguments needed
|
| 27 |
+
return {"time": "..."}
|
|
|
|
| 28 |
```
|
| 29 |
|
| 30 |
+
**Advanced (World):**
|
| 31 |
+
```python
|
| 32 |
+
def get_time_for_city(city: str = "Berlin"):
|
| 33 |
+
# Takes an argument!
|
| 34 |
+
# LLM will send: {"city": "Tokyo"}
|
| 35 |
+
return {"city": "Tokyo", "time": "..."}
|
| 36 |
+
```
|
|
|
|
|
|
|
| 37 |
|
| 38 |
### 2. The Gradio Interface
|
| 39 |
|
| 40 |
```python
|
| 41 |
demo = gr.Interface(
|
| 42 |
+
fn=get_time_for_city,
|
| 43 |
+
inputs=gr.Textbox(...), # Defines input schema for MCP
|
| 44 |
+
outputs=gr.JSON(...),
|
| 45 |
+
api_name="get_time_for_city"
|
| 46 |
)
|
| 47 |
```
|
| 48 |
|
| 49 |
+
### 3. The MCP Magic
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 50 |
|
| 51 |
```python
|
| 52 |
demo.launch(mcp_server=True)
|
| 53 |
```
|
| 54 |
+
This single line turns your web app into an AI tool server!
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 55 |
|
| 56 |
---
|
| 57 |
|
| 58 |
+
## π Deploying to HuggingFace Spaces (Critical Details)
|
| 59 |
|
| 60 |
+
Deploying is easy, but there are **two common pitfalls** to watch out for.
|
| 61 |
|
| 62 |
+
### Step 1: Configure the Entry File
|
| 63 |
|
| 64 |
+
You don't need to rename your file to `app.py`! You can tell HuggingFace which file to run.
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 65 |
|
| 66 |
+
1. Go to your Space's **Files** tab.
|
| 67 |
+
2. Click on `README.md` to edit it.
|
| 68 |
+
3. Look at the **YAML Header** (the metadata at the top between `---`).
|
| 69 |
+
4. Change the `app_file` line:
|
| 70 |
|
| 71 |
+
**For Berlin Time:**
|
| 72 |
+
```yaml
|
| 73 |
+
app_file: app_time_mcp_server.py
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 74 |
```
|
| 75 |
|
| 76 |
+
**For World Time:**
|
| 77 |
+
```yaml
|
| 78 |
+
app_file: app_world_time_mcp_server.py
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 79 |
```
|
| 80 |
|
| 81 |
+
This is much cleaner than renaming files!
|
| 82 |
|
| 83 |
+
### Step 2: β οΈ Check the Port Number
|
| 84 |
|
| 85 |
+
**This is the most common error!**
|
|
|
|
|
|
|
|
|
|
|
|
|
| 86 |
|
| 87 |
+
HuggingFace Spaces **must** run on port **7860**.
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 88 |
|
| 89 |
+
- `app_time_mcp_server.py` is already set to 7860. β
|
| 90 |
+
- `app_world_time_mcp_server.py` is set to **7861** (for local testing). β
|
| 91 |
|
| 92 |
+
**You MUST change this line in `app.py` before deploying:**
|
| 93 |
|
| 94 |
```python
|
| 95 |
+
# CHANGE THIS:
|
| 96 |
+
server_port=7861
|
|
|
|
|
|
|
| 97 |
|
| 98 |
+
# TO THIS:
|
| 99 |
+
server_port=7860
|
|
|
|
|
|
|
|
|
|
| 100 |
```
|
| 101 |
|
| 102 |
+
If you forget this, you will see: `OSError: Cannot find empty port`.
|
| 103 |
|
| 104 |
+
### Step 3: Upload to Spaces
|
|
|
|
|
|
|
|
|
|
| 105 |
|
| 106 |
+
1. Create a new Space (SDK: **Gradio**).
|
| 107 |
+
2. Upload:
|
| 108 |
+
- `app.py` (your chosen server)
|
| 109 |
+
- `requirements.txt`
|
| 110 |
+
3. Wait for "Running" status.
|
| 111 |
|
| 112 |
---
|
| 113 |
|
| 114 |
+
## π Connecting Your Agent
|
|
|
|
|
|
|
| 115 |
|
| 116 |
+
Once deployed, your agent needs to know where to look.
|
|
|
|
|
|
|
| 117 |
|
| 118 |
+
### Update `src/config/settings.py`
|
|
|
|
|
|
|
|
|
|
| 119 |
|
| 120 |
+
```python
|
| 121 |
+
servers["berlin_time"] = {
|
| 122 |
+
# 1. Use your Space URL
|
| 123 |
+
# Format: https://huggingface.co/spaces/USERNAME/SPACE_NAME/gradio_api/mcp/
|
| 124 |
+
"url": "https://gfiamon-date-time-mpc-server-tool.hf.space/gradio_api/mcp/",
|
| 125 |
+
|
| 126 |
+
# 2. Use 'sse' transport (Server-Sent Events)
|
| 127 |
+
"transport": "sse"
|
| 128 |
+
}
|
| 129 |
+
```
|
| 130 |
|
| 131 |
+
### How It Works
|
| 132 |
|
| 133 |
+
1. **Agent Starts:** Connects to that URL via SSE.
|
| 134 |
+
2. **Discovery:** Asks "What tools do you have?"
|
| 135 |
+
3. **World Time:** Server replies "I have `get_time_for_city` which takes a `city` string".
|
| 136 |
+
4. **User Asks:** "Time in Tokyo?"
|
| 137 |
+
5. **LLM:** "Call `get_time_for_city(city='Tokyo')`"
|
| 138 |
+
6. **Agent:** Sends command to HF Space -> Gets result -> Shows user.
|
| 139 |
|
| 140 |
---
|
| 141 |
|
| 142 |
+
## π Teaching This to Colleagues
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 143 |
|
| 144 |
+
**Key Teaching Points:**
|
| 145 |
|
| 146 |
+
1. **One Codebase, Two Interfaces:**
|
| 147 |
+
- **Humans** use the Web UI (click buttons).
|
| 148 |
+
- **AI Agents** use the MCP API (hidden endpoint).
|
| 149 |
+
- Both are powered by the *same Python function*.
|
|
|
|
| 150 |
|
| 151 |
+
2. **Deployment Simplicity:**
|
| 152 |
+
- No Docker, no Nginx, no complex config.
|
| 153 |
+
- Just `app.py` + `requirements.txt` on HF Spaces.
|
|
|
|
|
|
|
| 154 |
|
| 155 |
+
3. **The "Port Trap":**
|
| 156 |
+
- Remind them: Local dev can use any port, but HF Spaces enforces port 7860.
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 157 |
|
| 158 |
+
4. **Dynamic Discovery:**
|
| 159 |
+
- Show them how you can update the tool on HF (e.g., add "Mars Time"), restart the agent, and it *instantly* knows about the new feature without changing agent code.
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|