ryoshimu commited on
Commit
ad95a4d
·
1 Parent(s): 87173b8
Files changed (5) hide show
  1. Dockerfile +15 -0
  2. README1.md +21 -0
  3. app.py +21 -0
  4. clinet.py +43 -0
  5. requirements.txt +2 -0
Dockerfile ADDED
@@ -0,0 +1,15 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ FROM python:3.10-slim
2
+
3
+ ENV PYTHONUNBUFFERED=1 \
4
+ PORT=7860
5
+
6
+ WORKDIR /app
7
+
8
+ COPY requirements.txt .
9
+ RUN pip install --no-cache-dir -r requirements.txt
10
+
11
+ COPY . .
12
+
13
+ EXPOSE 7860
14
+
15
+ CMD ["uvicorn", "app:app", "--host", "0.0.0.0", "--port", "7860"]
README1.md ADDED
@@ -0,0 +1,21 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ # FastMCP サンプル MCP サーバー (Hugging Face Spaces デプロイ用)
2
+ FastMCP 2.12.4 を使った MCP サーバーのサンプルです。`app.py` では `Sample MCP Server` (version 0.1.0) を定義し、`/mcp` エンドポイントを Streamable HTTP で公開しています。`@mcp.tool` で登録した `echo` ツールを呼び出すと、受け取ったテキストをそのまま返します。Hugging Face Spaces に配置することで、ChatGPT などの MCP 対応クライアントから簡単に利用できます。
3
+ ## セットアップ
4
+ - Python 3.10 以降を想定しています。
5
+ - 仮想環境を作成したら、`pip install -r requirements.txt` を実行して FastMCP と Uvicorn をインストールしてください。
6
+ ## ローカル動作確認
7
+ 1. `python app.py` を実行すると、`http://localhost:7860` にサーバーが立ち上がります。`/` でヘルスチェック (`{"status": "ok", ...}`) を確認できます。
8
+ 2. クライアント検証には `python client.py --url http://localhost:7860/mcp` を使用します。`ping → list_tools → call_tool("echo")` の順に呼び出し、最初の `TextContent` を標準出力に表示します。
9
+ ## Hugging Face Spaces へのデプロイ
10
+ 1. Space を作成し、SDK を「Docker」、ランタイムを「Streamable HTTP」に設定します。
11
+ 2. このリポジトリをそのままアップロードします (既存の `Dockerfile` で `uvicorn app:app --host 0.0.0.0 --port 7860` が実行される前提です)。
12
+ 3. ビルド後、Space の URL `https://<your-space>.hf.space` が発行されます。Streamable HTTP の `/mcp` エンドポイントが外部に公開され、MCP クライアントからアクセス可能になります。
13
+ 必要に応じて README に上記 Streamable HTTP 前提であること、`Dockerfile` のコマンド (`uvicorn app:app`) が FastMCP サーバーに対応していることを追記してください。
14
+ ## サーバー仕様メモ
15
+ - `/mcp` は HTTP ベースの MCP エンドポイントです (WebSocket ではありません)。
16
+ - `@mcp.tool` を追加することで、任意のツールを拡張できます。例: `echo` ツールは `{"text": "..."}` を受け取り同じ内容を返します。
17
+ - `/` は Starlette ベースのヘルスチェックを返し、Spaces の稼働監視に利用できます。
18
+ ## ChatGPT からの接続手順
19
+ 1. ChatGPT アプリの MCP サーバー設定に、新規エンドポイントとして `https://<your-space>.hf.space/mcp` を登録します。
20
+ 2. FastMCP のクライアント (例: `client.py`) で事前に疎通確認すると安心です。
21
+ 3. ChatGPT 側で接続後、`echo` ツールを呼び出すと、入力テキストがそのままレスポンスとして返ります。
app.py ADDED
@@ -0,0 +1,21 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ """FastMCP sample MCP server implementation."""
2
+ from fastmcp import FastMCP
3
+ from starlette.responses import JSONResponse
4
+ import uvicorn
5
+ mcp = FastMCP(name="Sample MCP Server", version="0.1.0")
6
+ @mcp.tool(name="echo")
7
+ async def echo(text: str) -> str:
8
+ """Return the provided text unchanged."""
9
+ return text
10
+ @mcp.custom_route("/", methods=["GET"])
11
+ async def health_check(_request) -> JSONResponse:
12
+ """Basic health-check endpoint for Hugging Face Spaces."""
13
+ return JSONResponse(
14
+ {
15
+ "status": "ok",
16
+ "message": "Sample MCP server is running with FastMCP.",
17
+ }
18
+ )
19
+ app = mcp.http_app()
20
+ if __name__ == "__main__":
21
+ uvicorn.run("app:app", host="0.0.0.0", port=7860, reload=False)
clinet.py ADDED
@@ -0,0 +1,43 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ """Utility client for validating the FastMCP sample server."""
2
+ from __future__ import annotations
3
+ import argparse
4
+ import asyncio
5
+ from typing import Any, Iterable, Optional
6
+ from fastmcp import Client
7
+ from fastmcp.types import TextContent
8
+ def extract_first_text_block(content_blocks: Optional[Iterable[Any]]) -> Optional[str]:
9
+ """Return the first text block contained in the MCP tool response."""
10
+ if not content_blocks:
11
+ return None
12
+ for block in content_blocks:
13
+ if isinstance(block, TextContent):
14
+ return block.text
15
+ return None
16
+ async def run(url: str) -> None:
17
+ """Execute a simple validation workflow against the MCP server."""
18
+ client = Client(url=url)
19
+ async with client:
20
+ ping_result = await client.ping()
21
+ print("Ping:", ping_result)
22
+ tools_response = await client.list_tools()
23
+ print("Tools:", tools_response)
24
+ tool_call = await client.call_tool("echo", {"text": "Hello MCP"})
25
+ text = extract_first_text_block(getattr(tool_call, "content", None))
26
+ if text is not None:
27
+ print("Echo response:", text)
28
+ else:
29
+ print("Echo response contains no TextContent blocks:", tool_call)
30
+ def parse_args() -> argparse.Namespace:
31
+ parser = argparse.ArgumentParser(description="FastMCP sample client")
32
+ parser.add_argument(
33
+ "--url",
34
+ default="http://localhost:7860/mcp",
35
+ help="MCP server URL (default: %(default)s)",
36
+ )
37
+ return parser.parse_args()
38
+ def main() -> None:
39
+ args = parse_args()
40
+ asyncio.run(run(args.url))
41
+ if __name__ == "__main__":
42
+ main()
43
+
requirements.txt ADDED
@@ -0,0 +1,2 @@
 
 
 
1
+ fastmcp==2.12.4
2
+ uvicorn[standard]==0.30.1