ryoshimu commited on
Commit
87173b8
·
1 Parent(s): e2537fe
Files changed (5) hide show
  1. Dockerfile +0 -15
  2. README1.md +0 -39
  3. app.py +0 -96
  4. client.py +0 -55
  5. requirements.txt +0 -3
Dockerfile DELETED
@@ -1,15 +0,0 @@
1
- FROM python:3.11-slim
2
-
3
- ENV PYTHONDONTWRITEBYTECODE=1 \
4
- PYTHONUNBUFFERED=1 \
5
- PIP_NO_CACHE_DIR=1
6
-
7
- WORKDIR /code
8
-
9
- COPY requirements.txt .
10
- RUN pip install --upgrade pip \
11
- && pip install --no-cache-dir -r requirements.txt
12
-
13
- COPY . .
14
-
15
- CMD ["uvicorn", "app:app", "--host", "0.0.0.0", "--port", "7860"]
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
README1.md DELETED
@@ -1,39 +0,0 @@
1
- ## サンプル MCP サーバー (Hugging Face Spaces デプロイ用)
2
-
3
- このリポジトリは、Hugging Face Spaces にデプロイできるシンプルな MCP 互換 WebSocket サーバーのサンプルです。`/mcp` エンドポイントへ接続すると、以下の 3 種類のアクションで動作確認ができます。
4
-
5
- - `ping` : サーバーが `pong` を返却します。
6
- - `tools.list` : 利用可能なツール(ここでは `echo`)の一覧を返却します。
7
- - `tool.call` : `echo` ツールに文字列を渡すと、そのまま返却します。
8
-
9
- ### 1. ローカルでの動作確認
10
-
11
- ```bash
12
- python -m venv .venv
13
- source .venv/bin/activate # Windows の場合は .venv\Scripts\activate
14
- pip install -r requirements.txt
15
- uvicorn app:app --host 0.0.0.0 --port 7860
16
- ```
17
-
18
- 別ターミナルで以下を実行すると、WebSocket プロトコルのやり取りを確認できます。
19
-
20
- ```bash
21
- python client.py --url ws://localhost:7860/mcp
22
- ```
23
-
24
- ### 2. Hugging Face Spaces へのデプロイ手順
25
-
26
- 1. Hugging Face で新しい Space を作成し、**Space SDK** として **Docker** を選択します。
27
- 2. このリポジトリのファイルをそのままアップロード(または `git push`)します。
28
- 3. ビルドが完了すると自動で `uvicorn` が起動し、`https://<your-space>.hf.space/mcp` で WebSocket が待ち受けます。
29
- 4. ローカルまたは別サービスから WebSocket クライアントで接続すれば、手元と同じように動作確認できます。
30
-
31
- ### 3. サーバー仕様メモ
32
-
33
- - HTTP `GET /` : ヘルスチェック用。`{"status": "ok"}` を返します。
34
- - WebSocket `/mcp` :
35
- - 接続直後に `server_hello` を送信。
36
- - `ping` / `tools.list` / `tool.call` のシンプルな 3 種類を実装。
37
- - `tool.call` (`echo`) は `{"text": "..."} ` をそのまま返します。
38
-
39
- 必要に応じて `mcp_endpoint` 内にツールを追加することで、独自の MCP サーバーとして発展させられます。
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
app.py DELETED
@@ -1,96 +0,0 @@
1
- """
2
- Hugging Face Space friendly FastAPI application that exposes a minimal MCP-style
3
- WebSocket endpoint. It can be used to verify deployment and basic tool calls.
4
- """
5
-
6
- import json
7
- from typing import Any, Dict
8
-
9
- from fastapi import FastAPI, WebSocket, WebSocketDisconnect
10
- from fastapi.responses import JSONResponse
11
- import uvicorn
12
-
13
-
14
- app = FastAPI(title="Sample MCP Server", version="0.1.0")
15
-
16
-
17
- @app.get("/")
18
- async def healthcheck() -> JSONResponse:
19
- """Simple HTTP healthcheck so Spaces can mark the app as ready."""
20
- return JSONResponse({"status": "ok", "message": "Sample MCP server is running."})
21
-
22
-
23
- @app.websocket("/mcp")
24
- async def mcp_endpoint(socket: WebSocket) -> None:
25
- """
26
- Minimal MCP-compatible WebSocket endpoint.
27
-
28
- Protocol highlights:
29
- - Sends a server hello message immediately after accepting a connection.
30
- - Supports `ping` messages and a toy `echo` tool for demonstration.
31
- """
32
-
33
- await socket.accept()
34
- await socket.send_json(
35
- {
36
- "type": "server_hello",
37
- "version": "0.1.0",
38
- "capabilities": ["ping", "tools.list", "tool.call"],
39
- }
40
- )
41
-
42
- try:
43
- while True:
44
- raw = await socket.receive_text()
45
- message: Dict[str, Any] = json.loads(raw)
46
- kind = message.get("type")
47
-
48
- if kind == "ping":
49
- await socket.send_json({"type": "pong", "echo": message.get("payload")})
50
- elif kind == "tools.list":
51
- await socket.send_json(
52
- {
53
- "type": "tools",
54
- "tools": [
55
- {
56
- "name": "echo",
57
- "description": "Echoes back the provided text payload.",
58
- }
59
- ],
60
- }
61
- )
62
- elif kind == "tool.call":
63
- tool_name = message.get("name")
64
- request_id = message.get("id")
65
- arguments = message.get("arguments", {})
66
-
67
- if tool_name == "echo":
68
- await socket.send_json(
69
- {
70
- "type": "tool.result",
71
- "id": request_id,
72
- "result": {
73
- "text": arguments.get("text", ""),
74
- },
75
- }
76
- )
77
- else:
78
- await socket.send_json(
79
- {
80
- "type": "error",
81
- "error": f"Unknown tool '{tool_name}'.",
82
- "id": request_id,
83
- }
84
- )
85
- else:
86
- await socket.send_json(
87
- {"type": "error", "error": f"Unsupported message type '{kind}'."}
88
- )
89
- except WebSocketDisconnect:
90
- # Client disconnected; nothing else to do.
91
- return
92
-
93
-
94
- if __name__ == "__main__":
95
- uvicorn.run("app:app", host="0.0.0.0", port=7860, reload=False)
96
-
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
client.py DELETED
@@ -1,55 +0,0 @@
1
- """
2
- Simple asyncio client to verify the sample MCP server.
3
-
4
- Usage:
5
- python client.py --url ws://localhost:7860/mcp
6
- """
7
-
8
- import argparse
9
- import asyncio
10
- import json
11
- from typing import Any, Dict
12
-
13
- import websockets
14
-
15
-
16
- async def run_client(url: str) -> None:
17
- async with websockets.connect(url) as websocket:
18
- hello_raw = await websocket.recv()
19
- hello_message: Dict[str, Any] = json.loads(hello_raw)
20
- print("hello:", hello_message)
21
-
22
- await websocket.send(json.dumps({"type": "ping", "payload": "test"}))
23
- print("pong :", await websocket.recv())
24
-
25
- await websocket.send(json.dumps({"type": "tools.list"}))
26
- print("tools:", await websocket.recv())
27
-
28
- await websocket.send(
29
- json.dumps(
30
- {
31
- "type": "tool.call",
32
- "id": "demo-1",
33
- "name": "echo",
34
- "arguments": {"text": "Hello MCP"},
35
- }
36
- )
37
- )
38
- print("tool :", await websocket.recv())
39
-
40
-
41
- def main() -> None:
42
- parser = argparse.ArgumentParser(description="Sample MCP client")
43
- parser.add_argument(
44
- "--url",
45
- default="ws://localhost:7860/mcp",
46
- help="WebSocket endpoint of the MCP server.",
47
- )
48
- args = parser.parse_args()
49
-
50
- asyncio.run(run_client(args.url))
51
-
52
-
53
- if __name__ == "__main__":
54
- main()
55
-
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
requirements.txt DELETED
@@ -1,3 +0,0 @@
1
- fastapi==0.110.3
2
- uvicorn[standard]==0.30.1
3
- websockets==12.0