diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index e8bf7add..a0b65a9f 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -73,6 +73,8 @@ jobs: with: node-version: "20" + - uses: astral-sh/setup-uv@v5 + - run: npm ci - name: Install Playwright browsers diff --git a/README.md b/README.md index d9a24066..6057fe10 100644 --- a/README.md +++ b/README.md @@ -67,8 +67,8 @@ Or edit your `package.json` manually: | [**Scenario Modeler**](examples/scenario-modeler-server) | [**Budget Allocator**](examples/budget-allocator-server) | [**Customer Segmentation**](examples/customer-segmentation-server) | | [](examples/system-monitor-server) | [](examples/transcript-server) | [](examples/video-resource-server) | | [**System Monitor**](examples/system-monitor-server) | [**Transcript**](examples/transcript-server) | [**Video Resource**](examples/video-resource-server) | -| [](examples/pdf-server) | | | -| [**PDF Server**](examples/pdf-server) | | | +| [](examples/pdf-server) | [](examples/qr-server) | | +| [**PDF Server**](examples/pdf-server) | [**QR Code (Python)**](examples/qr-server) | | ### Starter Templates diff --git a/examples/qr-server/README.md b/examples/qr-server/README.md index c0ffa95b..e98016ec 100644 --- a/examples/qr-server/README.md +++ b/examples/qr-server/README.md @@ -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) -## Quick Start +## Prerequisites + +This server uses [uv](https://docs.astral.sh/uv/) for dependency management. Install it first: ```bash -# Create virtual environment -python3 -m venv .venv -source .venv/bin/activate +curl -LsSf https://astral.sh/uv/install.sh | sh +``` -# Install dependencies -pip install -r requirements.txt +## Quick Start -# Run server (HTTP mode) -python server.py -# → QR Server listening on http://localhost:3108/mcp +```bash +# 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 diff --git a/examples/qr-server/grid-cell.png b/examples/qr-server/grid-cell.png new file mode 100644 index 00000000..0d54384b Binary files /dev/null and b/examples/qr-server/grid-cell.png differ diff --git a/examples/qr-server/package.json b/examples/qr-server/package.json new file mode 100644 index 00000000..dd9eb1b0 --- /dev/null +++ b/examples/qr-server/package.json @@ -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'" + } +} diff --git a/examples/qr-server/requirements.txt b/examples/qr-server/requirements.txt deleted file mode 100644 index 02447fce..00000000 --- a/examples/qr-server/requirements.txt +++ /dev/null @@ -1,2 +0,0 @@ -mcp[cli]>=1.23.3 -qrcode[pil]>=7.4 diff --git a/examples/qr-server/server.py b/examples/qr-server/server.py old mode 100644 new mode 100755 index 3866f9bd..f6618c0a --- a/examples/qr-server/server.py +++ b/examples/qr-server/server.py @@ -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 @@ 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 @@ async def _read_resource_with_meta(req: types.ReadResourceRequest): 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) diff --git a/examples/qr-server/widget.html b/examples/qr-server/widget.html index 4498246d..10a594de 100644 --- a/examples/qr-server/widget.html +++ b/examples/qr-server/widget.html @@ -27,7 +27,7 @@