feat(qr-server): migrate to uv with PEP 723 inline dependencies
- Replace requirements.txt with inline script dependencies in server.py - Add package.json with npm scripts for run-all.ts integration - Update CI workflow to install uv via astral-sh/setup-uv@v5 - Update Docker commands to install uv for e2e tests - Add Playwright golden screenshot for qr-server - Update README with uv installation and usage instructions
This commit is contained in:
parent
96daa46a1d
commit
0927445025
10 changed files with 54 additions and 23 deletions
2
.github/workflows/ci.yml
vendored
2
.github/workflows/ci.yml
vendored
|
|
@ -73,6 +73,8 @@ jobs:
|
||||||
with:
|
with:
|
||||||
node-version: "20"
|
node-version: "20"
|
||||||
|
|
||||||
|
- uses: astral-sh/setup-uv@v5
|
||||||
|
|
||||||
- run: npm ci
|
- run: npm ci
|
||||||
|
|
||||||
- name: Install Playwright browsers
|
- name: Install Playwright browsers
|
||||||
|
|
|
||||||
|
|
@ -11,18 +11,19 @@ A minimal Python MCP server that generates customizable QR codes with an interac
|
||||||
- Interactive widget that displays in MCP-UI enabled clients
|
- Interactive widget that displays in MCP-UI enabled clients
|
||||||
- Supports both HTTP (for web clients) and stdio (for Claude Desktop)
|
- 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
|
## Quick Start
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
# Create virtual environment
|
# Run server (HTTP mode) - uv handles dependencies automatically
|
||||||
python3 -m venv .venv
|
uv run server.py
|
||||||
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
|
# → QR Server listening on http://localhost:3108/mcp
|
||||||
```
|
```
|
||||||
|
|
||||||
|
|
@ -31,7 +32,7 @@ python server.py
|
||||||
### HTTP Mode (for basic-host / web clients)
|
### HTTP Mode (for basic-host / web clients)
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
python server.py
|
uv run server.py
|
||||||
```
|
```
|
||||||
|
|
||||||
Connect from basic-host:
|
Connect from basic-host:
|
||||||
|
|
@ -43,7 +44,7 @@ SERVERS='["http://localhost:3108/mcp"]' bun serve.ts
|
||||||
### Stdio Mode (for Claude Desktop)
|
### Stdio Mode (for Claude Desktop)
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
python server.py --stdio
|
uv run server.py --stdio
|
||||||
```
|
```
|
||||||
|
|
||||||
Add to Claude Desktop config (`~/Library/Application Support/Claude/claude_desktop_config.json`):
|
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": {
|
"mcpServers": {
|
||||||
"qr": {
|
"qr": {
|
||||||
"command": "/path/to/qr-server/.venv/bin/python",
|
"command": "uv",
|
||||||
"args": ["/path/to/qr-server/server.py", "--stdio"]
|
"args": ["run", "/path/to/qr-server/server.py", "--stdio"]
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -135,9 +136,8 @@ Generate a QR code with optional customization.
|
||||||
|
|
||||||
```
|
```
|
||||||
qr-server/
|
qr-server/
|
||||||
├── server.py # MCP server (FastMCP + uvicorn)
|
├── server.py # MCP server (FastMCP + uvicorn, deps inline via PEP 723)
|
||||||
├── widget.html # Interactive UI widget
|
├── widget.html # Interactive UI widget
|
||||||
├── requirements.txt
|
|
||||||
└── README.md
|
└── README.md
|
||||||
```
|
```
|
||||||
|
|
||||||
|
|
@ -153,10 +153,12 @@ The widget uses MCP Apps SDK protocol:
|
||||||
|
|
||||||
## Dependencies
|
## 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
|
- `qrcode[pil]` - QR code generation with Pillow
|
||||||
- `uvicorn` - ASGI server (included with mcp)
|
- `uvicorn` - ASGI server
|
||||||
- `starlette` - CORS middleware (included with mcp)
|
- `starlette` - CORS middleware
|
||||||
|
|
||||||
## License
|
## License
|
||||||
|
|
||||||
|
|
|
||||||
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
|
|
||||||
10
examples/qr-server/server.py
Normal file → Executable file
10
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
|
QR Code MCP Server - Generates QR codes from text
|
||||||
"""
|
"""
|
||||||
|
|
|
||||||
|
|
@ -27,7 +27,7 @@
|
||||||
<body>
|
<body>
|
||||||
<div id="qr"></div>
|
<div id="qr"></div>
|
||||||
<script type="module">
|
<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" });
|
const app = new App({ name: "QR Widget", version: "1.0.0" });
|
||||||
|
|
||||||
|
|
|
||||||
8
package-lock.json
generated
8
package-lock.json
generated
|
|
@ -577,6 +577,10 @@
|
||||||
"dev": true,
|
"dev": true,
|
||||||
"license": "MIT"
|
"license": "MIT"
|
||||||
},
|
},
|
||||||
|
"examples/qr-server": {
|
||||||
|
"name": "@modelcontextprotocol/server-qr",
|
||||||
|
"version": "1.0.0"
|
||||||
|
},
|
||||||
"examples/scenario-modeler-server": {
|
"examples/scenario-modeler-server": {
|
||||||
"name": "@modelcontextprotocol/server-scenario-modeler",
|
"name": "@modelcontextprotocol/server-scenario-modeler",
|
||||||
"version": "0.4.0",
|
"version": "0.4.0",
|
||||||
|
|
@ -2412,6 +2416,10 @@
|
||||||
"resolved": "examples/pdf-server",
|
"resolved": "examples/pdf-server",
|
||||||
"link": true
|
"link": true
|
||||||
},
|
},
|
||||||
|
"node_modules/@modelcontextprotocol/server-qr": {
|
||||||
|
"resolved": "examples/qr-server",
|
||||||
|
"link": true
|
||||||
|
},
|
||||||
"node_modules/@modelcontextprotocol/server-scenario-modeler": {
|
"node_modules/@modelcontextprotocol/server-scenario-modeler": {
|
||||||
"resolved": "examples/scenario-modeler-server",
|
"resolved": "examples/scenario-modeler-server",
|
||||||
"link": true
|
"link": true
|
||||||
|
|
|
||||||
|
|
@ -54,8 +54,8 @@
|
||||||
"test:e2e": "playwright test",
|
"test:e2e": "playwright test",
|
||||||
"test:e2e:update": "playwright test --update-snapshots",
|
"test:e2e:update": "playwright test --update-snapshots",
|
||||||
"test:e2e:ui": "playwright test --ui",
|
"test:e2e:ui": "playwright test --ui",
|
||||||
"test:e2e:docker": "docker run --rm -v $(pwd):/work -w /work -it mcr.microsoft.com/playwright:v1.57.0-noble sh -c 'npm i -g bun && npm ci && npx playwright test'",
|
"test:e2e:docker": "docker run --rm -v $(pwd):/work -w /work -it mcr.microsoft.com/playwright:v1.57.0-noble sh -c 'apt-get update -qq && apt-get install -qq -y python3-venv curl > /dev/null && curl -LsSf https://astral.sh/uv/install.sh | sh && export PATH=\"$HOME/.local/bin:$PATH\" && npm i -g bun && npm ci && npx playwright test'",
|
||||||
"test:e2e:docker:update": "npm run build:all && docker run --rm -v $(pwd):/work -w /work -it mcr.microsoft.com/playwright:v1.57.0-noble sh -c 'npm i -g bun && npm ci && npx playwright test --update-snapshots'",
|
"test:e2e:docker:update": "npm run build:all && docker run --rm -v $(pwd):/work -w /work -it mcr.microsoft.com/playwright:v1.57.0-noble sh -c 'apt-get update -qq && apt-get install -qq -y python3-venv curl > /dev/null && curl -LsSf https://astral.sh/uv/install.sh | sh && export PATH=\"$HOME/.local/bin:$PATH\" && npm i -g bun && npm ci && npx playwright test --update-snapshots'",
|
||||||
"preexamples:build": "npm run build",
|
"preexamples:build": "npm run build",
|
||||||
"examples:build": "bun examples/run-all.ts build",
|
"examples:build": "bun examples/run-all.ts build",
|
||||||
"examples:start": "NODE_ENV=development npm run build && bun examples/run-all.ts start",
|
"examples:start": "NODE_ENV=development npm run build && bun examples/run-all.ts start",
|
||||||
|
|
@ -64,7 +64,7 @@
|
||||||
"prepare": "node scripts/setup-bun.mjs && npm run build && husky",
|
"prepare": "node scripts/setup-bun.mjs && npm run build && husky",
|
||||||
"docs": "typedoc",
|
"docs": "typedoc",
|
||||||
"docs:watch": "typedoc --watch",
|
"docs:watch": "typedoc --watch",
|
||||||
"generate:screenshots": "npm run build:all && docker run --rm -v $(pwd):/work -w /work mcr.microsoft.com/playwright:v1.57.0-noble sh -c 'npm i -g bun && npm ci && npx playwright test tests/e2e/generate-grid-screenshots.spec.ts'",
|
"generate:screenshots": "npm run build:all && docker run --rm -v $(pwd):/work -w /work mcr.microsoft.com/playwright:v1.57.0-noble sh -c 'apt-get update -qq && apt-get install -qq -y python3-venv curl > /dev/null && curl -LsSf https://astral.sh/uv/install.sh | sh && export PATH=\"$HOME/.local/bin:$PATH\" && npm i -g bun && npm ci && npx playwright test tests/e2e/generate-grid-screenshots.spec.ts'",
|
||||||
"prettier": "prettier -u \"**/*.{js,jsx,ts,tsx,mjs,json,md,yml,yaml}\" --check",
|
"prettier": "prettier -u \"**/*.{js,jsx,ts,tsx,mjs,json,md,yml,yaml}\" --check",
|
||||||
"prettier:fix": "prettier -u \"**/*.{js,jsx,ts,tsx,mjs,json,md,yml,yaml}\" --write",
|
"prettier:fix": "prettier -u \"**/*.{js,jsx,ts,tsx,mjs,json,md,yml,yaml}\" --write",
|
||||||
"check:versions": "node scripts/check-versions.mjs"
|
"check:versions": "node scripts/check-versions.mjs"
|
||||||
|
|
|
||||||
|
|
@ -49,6 +49,7 @@ const SERVERS = [
|
||||||
{ key: "customer-segmentation", name: "Customer Segmentation Server" },
|
{ key: "customer-segmentation", name: "Customer Segmentation Server" },
|
||||||
{ key: "map-server", name: "CesiumJS Map Server" },
|
{ key: "map-server", name: "CesiumJS Map Server" },
|
||||||
{ key: "pdf-server", name: "PDF Server" },
|
{ key: "pdf-server", name: "PDF Server" },
|
||||||
|
{ key: "qr-server", name: "QR Server" },
|
||||||
{ key: "scenario-modeler", name: "SaaS Scenario Modeler" },
|
{ key: "scenario-modeler", name: "SaaS Scenario Modeler" },
|
||||||
{ key: "shadertoy", name: "ShaderToy Server" },
|
{ key: "shadertoy", name: "ShaderToy Server" },
|
||||||
{ key: "sheet-music", name: "Sheet Music Server" },
|
{ key: "sheet-music", name: "Sheet Music Server" },
|
||||||
|
|
|
||||||
BIN
tests/e2e/servers.spec.ts-snapshots/qr-server.png
Normal file
BIN
tests/e2e/servers.spec.ts-snapshots/qr-server.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 33 KiB |
Loading…
Reference in a new issue