Merge pull request #272 from modelcontextprotocol/uv-qr-server
feat(qr-server): migrate to uv with PEP 723 inline dependencies
This commit is contained in:
commit
be8d725974
6 changed files with 62 additions and 30 deletions
|
|
@ -11,19 +11,20 @@ A minimal Python MCP server that generates customizable QR codes with an interac
|
|||
- Interactive widget that displays in MCP-UI enabled clients
|
||||
- Supports both HTTP (for web clients) and stdio (for Claude Desktop)
|
||||
|
||||
## Prerequisites
|
||||
|
||||
This server uses [uv](https://docs.astral.sh/uv/) for dependency management. Install it first:
|
||||
|
||||
```bash
|
||||
curl -LsSf https://astral.sh/uv/install.sh | sh
|
||||
```
|
||||
|
||||
## Quick Start
|
||||
|
||||
```bash
|
||||
# Create virtual environment
|
||||
python3 -m venv .venv
|
||||
source .venv/bin/activate
|
||||
|
||||
# Install dependencies
|
||||
pip install -r requirements.txt
|
||||
|
||||
# Run server (HTTP mode)
|
||||
python server.py
|
||||
# → QR Server listening on http://localhost:3108/mcp
|
||||
# Run server (HTTP mode) - uv handles dependencies automatically
|
||||
uv run server.py
|
||||
# → QR Code Server listening on http://localhost:3108/mcp
|
||||
```
|
||||
|
||||
## Usage
|
||||
|
|
@ -31,7 +32,7 @@ python server.py
|
|||
### HTTP Mode (for basic-host / web clients)
|
||||
|
||||
```bash
|
||||
python server.py
|
||||
uv run server.py
|
||||
```
|
||||
|
||||
Connect from basic-host:
|
||||
|
|
@ -43,7 +44,7 @@ SERVERS='["http://localhost:3108/mcp"]' bun serve.ts
|
|||
### Stdio Mode (for Claude Desktop)
|
||||
|
||||
```bash
|
||||
python server.py --stdio
|
||||
uv run server.py --stdio
|
||||
```
|
||||
|
||||
Add to Claude Desktop config (`~/Library/Application Support/Claude/claude_desktop_config.json`):
|
||||
|
|
@ -52,8 +53,8 @@ Add to Claude Desktop config (`~/Library/Application Support/Claude/claude_deskt
|
|||
{
|
||||
"mcpServers": {
|
||||
"qr": {
|
||||
"command": "/path/to/qr-server/.venv/bin/python",
|
||||
"args": ["/path/to/qr-server/server.py", "--stdio"]
|
||||
"command": "uv",
|
||||
"args": ["run", "/path/to/qr-server/server.py", "--stdio"]
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -135,9 +136,8 @@ Generate a QR code with optional customization.
|
|||
|
||||
```
|
||||
qr-server/
|
||||
├── server.py # MCP server (FastMCP + uvicorn)
|
||||
├── server.py # MCP server (FastMCP + uvicorn, deps inline via PEP 723)
|
||||
├── widget.html # Interactive UI widget
|
||||
├── requirements.txt
|
||||
└── README.md
|
||||
```
|
||||
|
||||
|
|
@ -153,10 +153,12 @@ The widget uses MCP Apps SDK protocol:
|
|||
|
||||
## Dependencies
|
||||
|
||||
- `mcp[cli]` - MCP Python SDK with FastMCP
|
||||
Dependencies are declared inline in `server.py` using [PEP 723](https://peps.python.org/pep-0723/) and managed by [uv](https://docs.astral.sh/uv/):
|
||||
|
||||
- `mcp` - MCP Python SDK with FastMCP
|
||||
- `qrcode[pil]` - QR code generation with Pillow
|
||||
- `uvicorn` - ASGI server (included with mcp)
|
||||
- `starlette` - CORS middleware (included with mcp)
|
||||
- `uvicorn` - ASGI server
|
||||
- `starlette` - CORS middleware
|
||||
|
||||
## License
|
||||
|
||||
|
|
|
|||
BIN
examples/qr-server/grid-cell.png
Normal file
BIN
examples/qr-server/grid-cell.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 39 KiB |
10
examples/qr-server/package.json
Normal file
10
examples/qr-server/package.json
Normal file
|
|
@ -0,0 +1,10 @@
|
|||
{
|
||||
"name": "@modelcontextprotocol/server-qr",
|
||||
"version": "1.0.0",
|
||||
"private": true,
|
||||
"scripts": {
|
||||
"start": "uv run server.py",
|
||||
"dev": "uv run server.py",
|
||||
"build": "echo 'No build step needed for Python server'"
|
||||
}
|
||||
}
|
||||
|
|
@ -1,2 +0,0 @@
|
|||
mcp[cli]>=1.23.3
|
||||
qrcode[pil]>=7.4
|
||||
16
examples/qr-server/server.py
Normal file → Executable file
16
examples/qr-server/server.py
Normal file → Executable file
|
|
@ -1,3 +1,13 @@
|
|||
#!/usr/bin/env uv run
|
||||
# /// script
|
||||
# requires-python = ">=3.10"
|
||||
# dependencies = [
|
||||
# "mcp>=1.9.0",
|
||||
# "qrcode[pil]>=8.0",
|
||||
# "uvicorn>=0.34.0",
|
||||
# "starlette>=0.46.0",
|
||||
# ]
|
||||
# ///
|
||||
"""
|
||||
QR Code MCP Server - Generates QR codes from text
|
||||
"""
|
||||
|
|
@ -17,12 +27,12 @@ WIDGET_URI = "ui://qr-server/widget.html"
|
|||
HOST = os.environ.get("HOST", "0.0.0.0") # 0.0.0.0 for Docker compatibility
|
||||
PORT = int(os.environ.get("PORT", "3108"))
|
||||
|
||||
mcp = FastMCP("QR Server", port=PORT, stateless_http=True)
|
||||
mcp = FastMCP("QR Code Server", port=PORT, stateless_http=True)
|
||||
|
||||
|
||||
@mcp.tool(meta={"ui/resourceUri": WIDGET_URI})
|
||||
def generate_qr(
|
||||
text: str,
|
||||
text: str = "https://modelcontextprotocol.io",
|
||||
box_size: int = 10,
|
||||
border: int = 4,
|
||||
error_correction: str = "M",
|
||||
|
|
@ -122,5 +132,5 @@ if __name__ == "__main__":
|
|||
allow_methods=["*"],
|
||||
allow_headers=["*"],
|
||||
)
|
||||
print(f"QR Server listening on http://{HOST}:{PORT}/mcp")
|
||||
print(f"QR Code Server listening on http://{HOST}:{PORT}/mcp")
|
||||
uvicorn.run(app, host=HOST, port=PORT)
|
||||
|
|
|
|||
|
|
@ -27,7 +27,7 @@
|
|||
<body>
|
||||
<div id="qr"></div>
|
||||
<script type="module">
|
||||
import { App } from "https://unpkg.com/@modelcontextprotocol/ext-apps@0.3.1/app-with-deps";
|
||||
import { App } from "https://unpkg.com/@modelcontextprotocol/ext-apps@0.4.0/app-with-deps";
|
||||
|
||||
const app = new App({ name: "QR Widget", version: "1.0.0" });
|
||||
|
||||
|
|
|
|||
Loading…
Reference in a new issue