ryoshimu commited on
Commit
cb04ff5
·
1 Parent(s): ad95a4d
Files changed (4) hide show
  1. README1.md +2 -1
  2. __pycache__/app.cpython-39.pyc +0 -0
  3. app.py +160 -2
  4. requirements.txt +2 -1
README1.md CHANGED
@@ -11,6 +11,7 @@ FastMCP 2.12.4 を使った MCP サーバーのサンプルです。`app.py` で
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": "..."}` を受け取り同じ内容を返します。
@@ -18,4 +19,4 @@ FastMCP 2.12.4 を使った MCP サーバーのサンプルです。`app.py` で
18
  ## ChatGPT からの接続手順
19
  1. ChatGPT アプリの MCP サーバー設定に、新規エンドポイントとして `https://<your-space>.hf.space/mcp` を登録します。
20
  2. FastMCP のクライアント (例: `client.py`) で事前に疎通確認すると安心です。
21
- 3. ChatGPT 側で接続後、`echo` ツールを呼び出すと、入力テキストがそのままレスポンスとして返ります。
 
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
+ 4. `/gradio` パスにアクセスすると、Gradio ベースの「MCP Server Configurator」が起動します。Space の公開 URL やサーバー名を入力すると、`servers.json` のエントリー例や ChatGPT 側の設定手順、ローカル検証用コマンドが自動生成されます。
15
  ## サーバー仕様メモ
16
  - `/mcp` は HTTP ベースの MCP エンドポイントです (WebSocket ではありません)。
17
  - `@mcp.tool` を追加することで、任意のツールを拡張できます。例: `echo` ツールは `{"text": "..."}` を受け取り同じ内容を返します。
 
19
  ## ChatGPT からの接続手順
20
  1. ChatGPT アプリの MCP サーバー設定に、新規エンドポイントとして `https://<your-space>.hf.space/mcp` を登録します。
21
  2. FastMCP のクライアント (例: `client.py`) で事前に疎通確認すると安心です。
22
+ 3. ChatGPT 側で接続後、`echo` ツールを呼び出すと、入力テキストがそのままレスポンスとして返ります。
__pycache__/app.cpython-39.pyc ADDED
Binary file (4.49 kB). View file
 
app.py CHANGED
@@ -1,12 +1,32 @@
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."""
@@ -14,8 +34,146 @@ async def health_check(_request) -> 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)
 
1
+ """FastMCP sample MCP server implementation with a Gradio configuration UI."""
2
+ import json
3
+ import os
4
+ from pathlib import Path
5
+ from typing import List, Tuple
6
+
7
+ import gradio as gr
8
+ import uvicorn
9
  from fastmcp import FastMCP
10
  from starlette.responses import JSONResponse
11
+
12
  mcp = FastMCP(name="Sample MCP Server", version="0.1.0")
13
+
14
+ AVAILABLE_TOOLS = [
15
+ {
16
+ "name": "echo",
17
+ "description": "Return the provided text unchanged.",
18
+ }
19
+ ]
20
+
21
+ SERVER_DESCRIPTION = "Sample FastMCP server deployed to Hugging Face Spaces."
22
+
23
+
24
  @mcp.tool(name="echo")
25
  async def echo(text: str) -> str:
26
  """Return the provided text unchanged."""
27
  return text
28
+
29
+
30
  @mcp.custom_route("/", methods=["GET"])
31
  async def health_check(_request) -> JSONResponse:
32
  """Basic health-check endpoint for Hugging Face Spaces."""
 
34
  {
35
  "status": "ok",
36
  "message": "Sample MCP server is running with FastMCP.",
37
+ "ui_path": "/gradio",
38
  }
39
  )
40
+
41
+
42
+ def _default_space_url() -> str:
43
+ """Best-effort default Space URL for Hugging Face deployments."""
44
+ explicit_url = os.getenv("SPACE_URL")
45
+ if explicit_url:
46
+ return explicit_url.rstrip("/")
47
+ space_host = os.getenv("SPACE_HOST")
48
+ if space_host:
49
+ prefix = "" if space_host.startswith("http") else "https://"
50
+ return f"{prefix}{space_host}".rstrip("/")
51
+ space_id = os.getenv("SPACE_ID")
52
+ if space_id:
53
+ space_slug = space_id.replace("/", "-")
54
+ return f"https://{space_slug}.hf.space"
55
+ return "http://localhost:7860"
56
+
57
+
58
+ def _available_tools_table() -> List[List[str]]:
59
+ """Return tool metadata for display in the Gradio UI."""
60
+ return [[tool["name"], tool["description"]] for tool in AVAILABLE_TOOLS]
61
+
62
+
63
+ def build_configuration(
64
+ space_url: str, server_name: str, server_description: str
65
+ ) -> Tuple[str, str, str, str]:
66
+ """Build connection details for MCP clients."""
67
+ base_url = (space_url or "").strip() or _default_space_url()
68
+ base_url = base_url.rstrip("/")
69
+ endpoint = f"{base_url}/mcp"
70
+ resolved_name = (server_name or "").strip() or mcp.name
71
+ resolved_description = (server_description or "").strip() or SERVER_DESCRIPTION
72
+
73
+ servers_json = json.dumps(
74
+ {
75
+ "version": 1,
76
+ "servers": [
77
+ {
78
+ "name": resolved_name,
79
+ "url": endpoint,
80
+ "type": "http",
81
+ "description": resolved_description,
82
+ }
83
+ ],
84
+ },
85
+ indent=2,
86
+ )
87
+
88
+ chatgpt_steps = "\n".join(
89
+ [
90
+ "1. Open ChatGPT and navigate to Settings -> Developer -> Model Context Protocol.",
91
+ f"2. Choose 'Add server' and paste `{endpoint}` into the URL field.",
92
+ "3. Save the configuration to enable the tools listed below.",
93
+ ]
94
+ )
95
+
96
+ script_dir = Path(__file__).resolve().parent
97
+ client_script = (
98
+ "client.py" if (script_dir / "client.py").exists() else "clinet.py"
99
+ )
100
+ client_command = f"python {client_script} --url {endpoint}"
101
+
102
+ return endpoint, servers_json, chatgpt_steps, client_command
103
+
104
+
105
+ with gr.Blocks(title="MCP Server Configurator", theme=gr.themes.Soft()) as demo:
106
+ gr.Markdown(
107
+ (
108
+ "# MCP Server Configuration Helper\n"
109
+ "Generate ready-to-use connection details for MCP-compatible clients."
110
+ )
111
+ )
112
+ with gr.Row():
113
+ space_url_input = gr.Textbox(
114
+ label="Space base URL",
115
+ value=_default_space_url(),
116
+ placeholder="https://username-space.hf.space",
117
+ )
118
+ server_name_input = gr.Textbox(
119
+ label="Server name",
120
+ value=mcp.name,
121
+ placeholder="Sample MCP Server",
122
+ )
123
+ server_description_input = gr.Textbox(
124
+ label="Server description",
125
+ value=SERVER_DESCRIPTION,
126
+ placeholder="Brief description shown to clients.",
127
+ )
128
+ generate_button = gr.Button("Generate configuration", variant="primary")
129
+
130
+ endpoint_output = gr.Textbox(
131
+ label="MCP endpoint",
132
+ interactive=False,
133
+ )
134
+ servers_json_output = gr.Code(
135
+ label="servers.json entry",
136
+ language="json",
137
+ )
138
+ chatgpt_output = gr.Markdown()
139
+ available_tools_output = gr.Dataframe(
140
+ headers=["Tool", "Description"],
141
+ value=_available_tools_table(),
142
+ interactive=False,
143
+ label="Available tools",
144
+ )
145
+ client_command_output = gr.Textbox(
146
+ label="FastMCP client command",
147
+ interactive=False,
148
+ value="",
149
+ )
150
+
151
+ generate_button.click(
152
+ build_configuration,
153
+ inputs=[space_url_input, server_name_input, server_description_input],
154
+ outputs=[
155
+ endpoint_output,
156
+ servers_json_output,
157
+ chatgpt_output,
158
+ client_command_output,
159
+ ],
160
+ queue=False,
161
+ )
162
+
163
+ demo.load(
164
+ build_configuration,
165
+ inputs=[space_url_input, server_name_input, server_description_input],
166
+ outputs=[
167
+ endpoint_output,
168
+ servers_json_output,
169
+ chatgpt_output,
170
+ client_command_output,
171
+ ],
172
+ queue=False,
173
+ )
174
+
175
  app = mcp.http_app()
176
+ gr.mount_gradio_app(app, demo, path="/gradio")
177
+
178
  if __name__ == "__main__":
179
  uvicorn.run("app:app", host="0.0.0.0", port=7860, reload=False)
requirements.txt CHANGED
@@ -1,2 +1,3 @@
1
  fastmcp==2.12.4
2
- uvicorn[standard]==0.30.1
 
 
1
  fastmcp==2.12.4
2
+ gradio==4.44.0
3
+ uvicorn[standard]==0.30.1