SEUyishu commited on
Commit
d0dfe88
·
verified ·
1 Parent(s): f7b4d0f

Upload 3 files

Browse files
Files changed (3) hide show
  1. Dockerfile +1 -2
  2. entrypoint.py +55 -7
  3. mcp_server.py +16 -7
Dockerfile CHANGED
@@ -12,8 +12,7 @@ ENV PYTHONDONTWRITEBYTECODE=1 \
12
  PIP_DISABLE_PIP_VERSION_CHECK=1 \
13
  GNOME_DATA_DIR=/app/gnome_data \
14
  GNOME_MODEL_DIR=/app/models \
15
- HF_HOME=/app/huggingface \
16
- MCP_TRANSPORT_SECURITY_DISABLE_HOST_VALIDATION=1
17
 
18
  # Install system dependencies
19
  RUN apt-get update && apt-get install -y --no-install-recommends \
 
12
  PIP_DISABLE_PIP_VERSION_CHECK=1 \
13
  GNOME_DATA_DIR=/app/gnome_data \
14
  GNOME_MODEL_DIR=/app/models \
15
+ HF_HOME=/app/huggingface
 
16
 
17
  # Install system dependencies
18
  RUN apt-get update && apt-get install -y --no-install-recommends \
entrypoint.py CHANGED
@@ -10,10 +10,6 @@ import os
10
  import sys
11
  import logging
12
 
13
- # Disable MCP host validation for HuggingFace Spaces
14
- # This allows connections from *.hf.space domains
15
- os.environ["MCP_TRANSPORT_SECURITY_DISABLE_HOST_VALIDATION"] = "1"
16
-
17
  # Add current directory to path
18
  sys.path.insert(0, os.path.dirname(os.path.abspath(__file__)))
19
 
@@ -111,17 +107,69 @@ def main():
111
  import uvicorn
112
  from starlette.applications import Starlette
113
  from starlette.routing import Mount, Route
114
- from starlette.responses import JSONResponse
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
115
 
116
  async def health_check(request):
117
  """Health check endpoint."""
118
  return JSONResponse({"status": "healthy", "service": "GNoME MCP Server"})
119
 
120
- # Create Starlette app
 
121
  app = Starlette(
122
  routes=[
 
123
  Route("/health", health_check),
124
- Mount("/", app=create_sse_app()),
125
  ]
126
  )
127
 
 
10
  import sys
11
  import logging
12
 
 
 
 
 
13
  # Add current directory to path
14
  sys.path.insert(0, os.path.dirname(os.path.abspath(__file__)))
15
 
 
107
  import uvicorn
108
  from starlette.applications import Starlette
109
  from starlette.routing import Mount, Route
110
+ from starlette.responses import JSONResponse, HTMLResponse
111
+
112
+ async def homepage(request):
113
+ """Homepage with service info."""
114
+ html_content = """
115
+ <!DOCTYPE html>
116
+ <html>
117
+ <head>
118
+ <title>GNoME Materials Discovery MCP Server</title>
119
+ <style>
120
+ body { font-family: Arial, sans-serif; max-width: 800px; margin: 50px auto; padding: 20px; }
121
+ h1 { color: #2c3e50; }
122
+ .status { color: #27ae60; font-weight: bold; }
123
+ .endpoint { background: #f5f5f5; padding: 10px; border-radius: 5px; margin: 10px 0; }
124
+ code { background: #e8e8e8; padding: 2px 6px; border-radius: 3px; }
125
+ </style>
126
+ </head>
127
+ <body>
128
+ <h1>🔬 GNoME Materials Discovery MCP Server</h1>
129
+ <p class="status">✅ Service is running</p>
130
+ <h2>Endpoints</h2>
131
+ <div class="endpoint">
132
+ <strong>SSE Endpoint:</strong> <code>/sse</code><br>
133
+ <small>Connect your MCP client (Cursor, Claude Desktop) to this endpoint</small>
134
+ </div>
135
+ <div class="endpoint">
136
+ <strong>Health Check:</strong> <code>/health</code>
137
+ </div>
138
+ <h2>Connection Example</h2>
139
+ <p>Add to your Cursor MCP settings:</p>
140
+ <pre><code>{
141
+ "mcpServers": {
142
+ "gnome-materials": {
143
+ "url": "https://YOUR-SPACE.hf.space/sse"
144
+ }
145
+ }
146
+ }</code></pre>
147
+ <h2>Available Tools</h2>
148
+ <ul>
149
+ <li>query_materials - Search GNoME materials database</li>
150
+ <li>get_dataset_statistics - Get dataset overview</li>
151
+ <li>calculate_decomposition_energy - Calculate stability</li>
152
+ <li>get_phase_diagram - Build phase diagrams</li>
153
+ <li>calculate_air_stability - Analyze air stability</li>
154
+ <li>get_structure - Load crystal structures</li>
155
+ <li>And more...</li>
156
+ </ul>
157
+ </body>
158
+ </html>
159
+ """
160
+ return HTMLResponse(content=html_content)
161
 
162
  async def health_check(request):
163
  """Health check endpoint."""
164
  return JSONResponse({"status": "healthy", "service": "GNoME MCP Server"})
165
 
166
+ # Create Starlette app with proper routing
167
+ # SSE app is mounted at /sse path, root serves info page
168
  app = Starlette(
169
  routes=[
170
+ Route("/", homepage),
171
  Route("/health", health_check),
172
+ Mount("/sse", app=create_sse_app()),
173
  ]
174
  )
175
 
mcp_server.py CHANGED
@@ -25,11 +25,8 @@ from typing import Optional, List, Dict, Any
25
  from contextlib import asynccontextmanager
26
  from collections.abc import AsyncIterator
27
 
28
- # Disable host validation for HuggingFace Spaces deployment BEFORE importing MCP
29
- # This is needed because HuggingFace uses custom domain names like *.hf.space
30
- os.environ["MCP_TRANSPORT_SECURITY_DISABLE_HOST_VALIDATION"] = "1"
31
-
32
  from mcp.server.fastmcp import FastMCP
 
33
 
34
  # Import local modules
35
  from data_utils import DataManager, get_data_manager
@@ -87,8 +84,16 @@ async def app_lifespan(server: FastMCP) -> AsyncIterator[Dict[str, Any]]:
87
  data_manager.close()
88
 
89
 
90
- # Create FastMCP server
91
- mcp = FastMCP("GNoME Materials Discovery")
 
 
 
 
 
 
 
 
92
 
93
 
94
  # ============================================================================
@@ -915,7 +920,11 @@ async def check_data_status() -> Dict[str, Any]:
915
  # ============================================================================
916
 
917
  def create_sse_app():
918
- """Create SSE app for mounting in Starlette."""
 
 
 
 
919
  return mcp.sse_app()
920
 
921
 
 
25
  from contextlib import asynccontextmanager
26
  from collections.abc import AsyncIterator
27
 
 
 
 
 
28
  from mcp.server.fastmcp import FastMCP
29
+ from mcp.server.transport_security import TransportSecuritySettings
30
 
31
  # Import local modules
32
  from data_utils import DataManager, get_data_manager
 
84
  data_manager.close()
85
 
86
 
87
+ # Create FastMCP server with DNS rebinding protection disabled for HuggingFace Spaces
88
+ # This allows connections from *.hf.space domains
89
+ mcp = FastMCP(
90
+ "GNoME Materials Discovery",
91
+ host="0.0.0.0",
92
+ port=7860,
93
+ transport_security=TransportSecuritySettings(
94
+ enable_dns_rebinding_protection=False
95
+ )
96
+ )
97
 
98
 
99
  # ============================================================================
 
920
  # ============================================================================
921
 
922
  def create_sse_app():
923
+ """Create SSE app for mounting in Starlette.
924
+
925
+ Note: DNS rebinding protection is disabled in FastMCP initialization
926
+ to allow connections from HuggingFace Spaces domains.
927
+ """
928
  return mcp.sse_app()
929
 
930