amirkiarafiei commited on
Commit
42f1822
·
1 Parent(s): 6934b27

feat: enhance configuration and API key handling in MCP server

Browse files
Files changed (4) hide show
  1. .env.example +10 -1
  2. README.md +10 -0
  3. main.py +57 -13
  4. utils/config.py +4 -0
.env.example CHANGED
@@ -5,5 +5,14 @@ DS_API_MULTIMODULE_ENDPOINT=/mcp_multi_module_bug_localization
5
  DS_API_SINGLEMODULE_ENDPOINT=/mcp_single_module_bug_localization
6
  DS_API_SEARCHSPACE_ENDPOINT=/mcp_search_space_routing
7
 
 
 
 
8
  # Request timeout in seconds (for requests between MCP Server and Defect Solver API)
9
- TIMEOUT=120
 
 
 
 
 
 
 
5
  DS_API_SINGLEMODULE_ENDPOINT=/mcp_single_module_bug_localization
6
  DS_API_SEARCHSPACE_ENDPOINT=/mcp_search_space_routing
7
 
8
+ # Hugging Face Access Token for when the API is hosted on Hugging Face Spaces
9
+ HF_ACCESS_TOKEN=your_hf_access_token_here
10
+
11
  # Request timeout in seconds (for requests between MCP Server and Defect Solver API)
12
+ TIMEOUT=120
13
+
14
+ # MCP Server Configuration
15
+ TRANSPORT_MODE=streamable-http
16
+ HOST=0.0.0.0
17
+ PORT=8000
18
+ LOG_LEVEL=INFO
README.md CHANGED
@@ -1,3 +1,13 @@
 
 
 
 
 
 
 
 
 
 
1
  # Defect Solver MCP Server
2
 
3
  This project implements a Model Context Protocol (MCP) server for defect solver bug localization using FastMCP. It forwards bug description data (ticket) to a remote endpoint for prediction and analysis.
 
1
+ ---
2
+ title: Defect Solver API
3
+ emoji: 🛠️
4
+ colorFrom: orange
5
+ colorTo: yellow
6
+ sdk: docker
7
+ pinned: false
8
+ short_description: Defect Solver - MCP Server
9
+ ---
10
+
11
  # Defect Solver MCP Server
12
 
13
  This project implements a Model Context Protocol (MCP) server for defect solver bug localization using FastMCP. It forwards bug description data (ticket) to a remote endpoint for prediction and analysis.
main.py CHANGED
@@ -9,6 +9,9 @@ import uuid
9
  from utils.config import API_CONFIG
10
  from utils.model import MultiModuleRequest, SingleModuleRequest, SearchSpaceRoutingRequest
11
 
 
 
 
12
 
13
  @dataclass
14
  class DSContext:
@@ -56,7 +59,21 @@ async def multi_module_bug_localization(request: MultiModuleRequest, ctx: Contex
56
  api_url = API_CONFIG["api_base_url"] + API_CONFIG["api_multimodule_endpoint"]
57
  hf_token = API_CONFIG.get("hf_access_token", None)
58
 
59
- headers = {"Authorization": f"Bearer {hf_token}", "Content-Type": "application/json"}
 
 
 
 
 
 
 
 
 
 
 
 
 
 
60
 
61
  try:
62
  # Generate a UUID for issue_key even if provided (overwrite)
@@ -90,7 +107,7 @@ async def multi_module_bug_localization(request: MultiModuleRequest, ctx: Contex
90
  logger.error(f"Request error while calling multimodule bug localization endpoint: {e}")
91
  return {"error": "Request error", "details": str(e)}
92
  except Exception as e:
93
- logger.exception("Unexpected error during multimodule bug localization request")
94
  return {"error": "Unexpected error", "details": str(e)}
95
 
96
 
@@ -118,7 +135,21 @@ async def single_module_bug_localization(request: SingleModuleRequest, ctx: Cont
118
  api_url = API_CONFIG["api_base_url"] + API_CONFIG["api_singlemodule_endpoint"]
119
  hf_token = API_CONFIG.get("hf_access_token", None)
120
 
121
- headers = {"Authorization": f"Bearer {hf_token}", "Content-Type": "application/json"}
 
 
 
 
 
 
 
 
 
 
 
 
 
 
122
 
123
  try:
124
  # Generate a UUID for issue_key even if provided (overwrite)
@@ -151,7 +182,7 @@ async def single_module_bug_localization(request: SingleModuleRequest, ctx: Cont
151
  logger.error(f"Request error while calling endpoint: {e}")
152
  return {"error": "Request error", "details": str(e)}
153
  except Exception as e:
154
- logger.exception("Unexpected error during single-module bug localization")
155
  return {"error": "Unexpected error", "details": str(e)}
156
 
157
 
@@ -179,7 +210,21 @@ async def search_space_routing(request: SearchSpaceRoutingRequest, ctx: Context)
179
  api_url = API_CONFIG["api_base_url"] + API_CONFIG["api_searchspace_endpoint"]
180
  hf_token = API_CONFIG.get("hf_access_token", None)
181
 
182
- headers = {"Authorization": f"Bearer {hf_token}", "Content-Type": "application/json"}
 
 
 
 
 
 
 
 
 
 
 
 
 
 
183
 
184
  try:
185
  # Generate a UUID for issue_key even if provided (overwrite)
@@ -211,7 +256,7 @@ async def search_space_routing(request: SearchSpaceRoutingRequest, ctx: Context)
211
  logger.error(f"Request error while calling endpoint: {e}")
212
  return {"error": "Request error", "details": str(e)}
213
  except Exception as e:
214
- logger.exception("Unexpected error during search space routing")
215
  return {"error": "Unexpected error", "details": str(e)}
216
 
217
 
@@ -340,11 +385,10 @@ Return a 2-3x more detailed/enhanced bug report with precise technical terms for
340
  """
341
 
342
 
343
-
344
-
345
-
346
-
347
-
348
-
349
  if __name__ == "__main__":
350
- mcp.run(transport="streamable-http")
 
 
 
 
 
 
9
  from utils.config import API_CONFIG
10
  from utils.model import MultiModuleRequest, SingleModuleRequest, SearchSpaceRoutingRequest
11
 
12
+ from fastmcp.server.dependencies import get_http_request
13
+ from starlette.requests import Request
14
+
15
 
16
  @dataclass
17
  class DSContext:
 
59
  api_url = API_CONFIG["api_base_url"] + API_CONFIG["api_multimodule_endpoint"]
60
  hf_token = API_CONFIG.get("hf_access_token", None)
61
 
62
+ # Get per-user API key from MCP Context
63
+ user_request: Request = get_http_request()
64
+ defect_solver_api_key = user_request.headers.get("DS-API-Key", None)
65
+ logger.info(
66
+ "Using API key: {}".format(defect_solver_api_key)
67
+ if defect_solver_api_key
68
+ else "No Defect Solver API key provided"
69
+ )
70
+
71
+ headers = {
72
+ "Content-Type": "application/json",
73
+ "Authorization": f"Bearer {hf_token}" if hf_token else None,
74
+ "DS-API-Key": defect_solver_api_key,
75
+ }
76
+ headers = {k: v for k, v in headers.items() if v is not None}
77
 
78
  try:
79
  # Generate a UUID for issue_key even if provided (overwrite)
 
107
  logger.error(f"Request error while calling multimodule bug localization endpoint: {e}")
108
  return {"error": "Request error", "details": str(e)}
109
  except Exception as e:
110
+ logger.error("Unexpected error during multimodule bug localization request")
111
  return {"error": "Unexpected error", "details": str(e)}
112
 
113
 
 
135
  api_url = API_CONFIG["api_base_url"] + API_CONFIG["api_singlemodule_endpoint"]
136
  hf_token = API_CONFIG.get("hf_access_token", None)
137
 
138
+ # Get per-user API key from MCP Context
139
+ user_request: Request = get_http_request()
140
+ defect_solver_api_key = user_request.headers.get("DS-API-Key", None)
141
+ logger.info(
142
+ "Using API key: {}".format(defect_solver_api_key)
143
+ if defect_solver_api_key
144
+ else "No Defect Solver API key provided"
145
+ )
146
+
147
+ headers = {
148
+ "Content-Type": "application/json",
149
+ "Authorization": f"Bearer {hf_token}" if hf_token else None,
150
+ "DS-API-Key": defect_solver_api_key,
151
+ }
152
+ headers = {k: v for k, v in headers.items() if v is not None}
153
 
154
  try:
155
  # Generate a UUID for issue_key even if provided (overwrite)
 
182
  logger.error(f"Request error while calling endpoint: {e}")
183
  return {"error": "Request error", "details": str(e)}
184
  except Exception as e:
185
+ logger.error("Unexpected error during single-module bug localization")
186
  return {"error": "Unexpected error", "details": str(e)}
187
 
188
 
 
210
  api_url = API_CONFIG["api_base_url"] + API_CONFIG["api_searchspace_endpoint"]
211
  hf_token = API_CONFIG.get("hf_access_token", None)
212
 
213
+ # Get per-user API key from MCP Context
214
+ user_request: Request = get_http_request()
215
+ defect_solver_api_key = user_request.headers.get("DS-API-Key", None)
216
+ logger.info(
217
+ "Using API key: {}".format(defect_solver_api_key)
218
+ if defect_solver_api_key
219
+ else "No Defect Solver API key provided"
220
+ )
221
+
222
+ headers = {
223
+ "Content-Type": "application/json",
224
+ "Authorization": f"Bearer {hf_token}" if hf_token else None,
225
+ "DS-API-Key": defect_solver_api_key,
226
+ }
227
+ headers = {k: v for k, v in headers.items() if v is not None}
228
 
229
  try:
230
  # Generate a UUID for issue_key even if provided (overwrite)
 
256
  logger.error(f"Request error while calling endpoint: {e}")
257
  return {"error": "Request error", "details": str(e)}
258
  except Exception as e:
259
+ logger.error("Unexpected error during search space routing")
260
  return {"error": "Unexpected error", "details": str(e)}
261
 
262
 
 
385
  """
386
 
387
 
 
 
 
 
 
 
388
  if __name__ == "__main__":
389
+ TRANSPORT_MODE = API_CONFIG["transport_mode"]
390
+ HOST = API_CONFIG["host"]
391
+ PORT = API_CONFIG["port"]
392
+ LOG_LEVEL = API_CONFIG["log_level"]
393
+
394
+ mcp.run(transport=TRANSPORT_MODE, host=HOST, port=PORT, log_level=LOG_LEVEL)
utils/config.py CHANGED
@@ -11,4 +11,8 @@ API_CONFIG = {
11
  "api_searchspace_endpoint": os.getenv("DS_API_SEARCHSPACE_ENDPOINT", "/mcp_search_space_routing"),
12
  "hf_access_token": os.getenv("HF_ACCESS_TOKEN", None),
13
  "timeout": os.getenv("TIMEOUT", 120),
 
 
 
 
14
  }
 
11
  "api_searchspace_endpoint": os.getenv("DS_API_SEARCHSPACE_ENDPOINT", "/mcp_search_space_routing"),
12
  "hf_access_token": os.getenv("HF_ACCESS_TOKEN", None),
13
  "timeout": os.getenv("TIMEOUT", 120),
14
+ "transport_mode": os.getenv("TRANSPORT_MODE", "streamable-http"),
15
+ "host": os.getenv("HOST", "0.0.0.0"),
16
+ "port": os.getenv("PORT", 8000),
17
+ "log_level": os.getenv("LOG_LEVEL", "INFO"),
18
  }