JC321 commited on
Commit
505a787
Β·
verified Β·
1 Parent(s): 309ddb4

Upload mcp_server_sse.py

Browse files
Files changed (1) hide show
  1. mcp_server_sse.py +56 -35
mcp_server_sse.py CHANGED
@@ -2,6 +2,7 @@
2
  MCP Server for Hugging Face Space Deployment
3
  Uses Server-Sent Events (SSE) transport for remote MCP access
4
  Fully compatible with MCP clients like Claude Desktop
 
5
  """
6
 
7
  from fastapi import FastAPI, Request, HTTPException
@@ -176,30 +177,22 @@ MCP_TOOLS = [
176
  ]
177
 
178
 
179
- def format_tool_result(data: Any) -> str:
180
- """Format tool execution result as readable text"""
181
- if isinstance(data, dict):
182
- return json.dumps(data, indent=2, ensure_ascii=False)
183
- elif isinstance(data, list):
184
- return json.dumps(data, indent=2, ensure_ascii=False)
185
- else:
186
- return str(data)
187
-
188
-
189
  def execute_tool(tool_name: str, arguments: Dict[str, Any]) -> Dict[str, Any]:
190
- """Execute MCP tool and return formatted result"""
191
  try:
192
  if tool_name == "search_company":
193
  result = edgar_client.search_company_by_name(arguments["company_name"])
194
  if result:
195
  return {
196
  "type": "text",
197
- "text": f"βœ… Company Found:\n\n{format_tool_result(result)}"
198
  }
199
  else:
200
  return {
201
  "type": "text",
202
- "text": f"❌ No company found with name: {arguments['company_name']}"
 
 
203
  }
204
 
205
  elif tool_name == "get_company_info":
@@ -207,26 +200,36 @@ def execute_tool(tool_name: str, arguments: Dict[str, Any]) -> Dict[str, Any]:
207
  if result:
208
  return {
209
  "type": "text",
210
- "text": f"πŸ“Š Company Information:\n\n{format_tool_result(result)}"
211
  }
212
  else:
213
  return {
214
  "type": "text",
215
- "text": f"❌ No company found with CIK: {arguments['cik']}"
 
 
216
  }
217
 
218
  elif tool_name == "get_company_filings":
219
  form_types = arguments.get("form_types")
220
  result = edgar_client.get_company_filings(arguments["cik"], form_types)
221
  if result:
 
 
222
  return {
223
  "type": "text",
224
- "text": f"πŸ“ Company Filings ({len(result)} found):\n\n{format_tool_result(result[:20])}" # Limit to 20
 
 
 
 
225
  }
226
  else:
227
  return {
228
  "type": "text",
229
- "text": f"❌ No filings found for CIK: {arguments['cik']}"
 
 
230
  }
231
 
232
  elif tool_name == "get_financial_data":
@@ -234,12 +237,14 @@ def execute_tool(tool_name: str, arguments: Dict[str, Any]) -> Dict[str, Any]:
234
  if result and "period" in result:
235
  return {
236
  "type": "text",
237
- "text": f"πŸ’° Financial Data for {result['period']}:\n\n{format_tool_result(result)}"
238
  }
239
  else:
240
  return {
241
  "type": "text",
242
- "text": f"❌ No financial data found for CIK: {arguments['cik']}, Period: {arguments['period']}"
 
 
243
  }
244
 
245
  elif tool_name == "extract_financial_metrics":
@@ -247,7 +252,9 @@ def execute_tool(tool_name: str, arguments: Dict[str, Any]) -> Dict[str, Any]:
247
  if years < 1 or years > 10:
248
  return {
249
  "type": "text",
250
- "text": "❌ Years parameter must be between 1 and 10"
 
 
251
  }
252
 
253
  metrics = financial_analyzer.extract_financial_metrics(arguments["cik"], years)
@@ -255,12 +262,17 @@ def execute_tool(tool_name: str, arguments: Dict[str, Any]) -> Dict[str, Any]:
255
  formatted = financial_analyzer.format_financial_data(metrics)
256
  return {
257
  "type": "text",
258
- "text": f"πŸ“ˆ Financial Metrics ({len(formatted)} periods):\n\n{format_tool_result(formatted)}"
 
 
 
259
  }
260
  else:
261
  return {
262
  "type": "text",
263
- "text": f"❌ No financial metrics found for CIK: {arguments['cik']}"
 
 
264
  }
265
 
266
  elif tool_name == "get_latest_financial_data":
@@ -268,36 +280,45 @@ def execute_tool(tool_name: str, arguments: Dict[str, Any]) -> Dict[str, Any]:
268
  if result and "period" in result:
269
  return {
270
  "type": "text",
271
- "text": f"πŸ†• Latest Financial Data:\n\n{format_tool_result(result)}"
272
  }
273
  else:
274
  return {
275
  "type": "text",
276
- "text": f"❌ No latest financial data found for CIK: {arguments['cik']}"
 
 
277
  }
278
 
279
- elif tool_name == "advanced_search_company":
 
280
  result = financial_analyzer.search_company(arguments["company_input"])
281
  if result.get("error"):
282
  return {
283
  "type": "text",
284
- "text": f"❌ {result['error']}"
 
 
285
  }
286
  return {
287
  "type": "text",
288
- "text": f"πŸ” Search Result:\n\n{format_tool_result(result)}"
289
  }
290
 
291
  else:
292
  return {
293
  "type": "text",
294
- "text": f"❌ Unknown tool: {tool_name}"
 
 
295
  }
296
 
297
  except Exception as e:
298
  return {
299
  "type": "text",
300
- "text": f"❌ Error executing {tool_name}: {str(e)}"
 
 
301
  }
302
 
303
 
@@ -482,10 +503,10 @@ async def root():
482
  </head>
483
  <body>
484
  <div class="container">
485
- <h1>πŸš€ SEC Financial Report MCP Server</h1>
486
  <p><span class="badge">MCP READY</span> Model Context Protocol Server for SEC EDGAR Financial Data</p>
487
 
488
- <h2>πŸ“‘ Connect to this MCP Server</h2>
489
  <p>Add the following configuration to your MCP client (e.g., Claude Desktop):</p>
490
 
491
  <div class="config-box">
@@ -500,7 +521,7 @@ async def root():
500
 
501
  <p><strong>Use the URL above to connect to this MCP Server.</strong></p>
502
 
503
- <h2>πŸ› οΈ Available Tools (7)</h2>
504
  <div class="tools">
505
  <div class="tool">
506
  <h3>search_company</h3>
@@ -519,7 +540,7 @@ async def root():
519
  <p>Get financial data for a specific period (annual or quarterly)</p>
520
  </div>
521
  <div class="tool">
522
- <h3>extract_financial_metrics ⭐</h3>
523
  <p>Extract comprehensive financial metrics for multiple years</p>
524
  </div>
525
  <div class="tool">
@@ -532,7 +553,7 @@ async def root():
532
  </div>
533
  </div>
534
 
535
- <h2>πŸ’¬ Example Usage</h2>
536
  <p>Once connected, you can ask your AI assistant:</p>
537
  <ul>
538
  <li>"Search for Microsoft and show me their latest financial data"</li>
@@ -540,7 +561,7 @@ async def root():
540
  <li>"Compare NVIDIA and AMD's revenue trends"</li>
541
  </ul>
542
 
543
- <h2>πŸ“š Documentation</h2>
544
  <p>Visit <code>/tools</code> to see all available tools in JSON format.</p>
545
 
546
  <hr style="margin: 30px 0; border: none; border-top: 1px solid #e0e0e0;">
 
2
  MCP Server for Hugging Face Space Deployment
3
  Uses Server-Sent Events (SSE) transport for remote MCP access
4
  Fully compatible with MCP clients like Claude Desktop
5
+ Returns clean JSON without emoji formatting
6
  """
7
 
8
  from fastapi import FastAPI, Request, HTTPException
 
177
  ]
178
 
179
 
 
 
 
 
 
 
 
 
 
 
180
  def execute_tool(tool_name: str, arguments: Dict[str, Any]) -> Dict[str, Any]:
181
+ """Execute MCP tool and return clean JSON result"""
182
  try:
183
  if tool_name == "search_company":
184
  result = edgar_client.search_company_by_name(arguments["company_name"])
185
  if result:
186
  return {
187
  "type": "text",
188
+ "text": json.dumps(result, ensure_ascii=False)
189
  }
190
  else:
191
  return {
192
  "type": "text",
193
+ "text": json.dumps({
194
+ "error": f"No company found with name: {arguments['company_name']}"
195
+ }, ensure_ascii=False)
196
  }
197
 
198
  elif tool_name == "get_company_info":
 
200
  if result:
201
  return {
202
  "type": "text",
203
+ "text": json.dumps(result, ensure_ascii=False)
204
  }
205
  else:
206
  return {
207
  "type": "text",
208
+ "text": json.dumps({
209
+ "error": f"No company found with CIK: {arguments['cik']}"
210
+ }, ensure_ascii=False)
211
  }
212
 
213
  elif tool_name == "get_company_filings":
214
  form_types = arguments.get("form_types")
215
  result = edgar_client.get_company_filings(arguments["cik"], form_types)
216
  if result:
217
+ # Limit to 20 results
218
+ limited_result = result[:20]
219
  return {
220
  "type": "text",
221
+ "text": json.dumps({
222
+ "total": len(result),
223
+ "returned": len(limited_result),
224
+ "filings": limited_result
225
+ }, ensure_ascii=False)
226
  }
227
  else:
228
  return {
229
  "type": "text",
230
+ "text": json.dumps({
231
+ "error": f"No filings found for CIK: {arguments['cik']}"
232
+ }, ensure_ascii=False)
233
  }
234
 
235
  elif tool_name == "get_financial_data":
 
237
  if result and "period" in result:
238
  return {
239
  "type": "text",
240
+ "text": json.dumps(result, ensure_ascii=False)
241
  }
242
  else:
243
  return {
244
  "type": "text",
245
+ "text": json.dumps({
246
+ "error": f"No financial data found for CIK: {arguments['cik']}, Period: {arguments['period']}"
247
+ }, ensure_ascii=False)
248
  }
249
 
250
  elif tool_name == "extract_financial_metrics":
 
252
  if years < 1 or years > 10:
253
  return {
254
  "type": "text",
255
+ "text": json.dumps({
256
+ "error": "Years parameter must be between 1 and 10"
257
+ }, ensure_ascii=False)
258
  }
259
 
260
  metrics = financial_analyzer.extract_financial_metrics(arguments["cik"], years)
 
262
  formatted = financial_analyzer.format_financial_data(metrics)
263
  return {
264
  "type": "text",
265
+ "text": json.dumps({
266
+ "periods": len(formatted),
267
+ "data": formatted
268
+ }, ensure_ascii=False)
269
  }
270
  else:
271
  return {
272
  "type": "text",
273
+ "text": json.dumps({
274
+ "error": f"No financial metrics found for CIK: {arguments['cik']}"
275
+ }, ensure_ascii=False)
276
  }
277
 
278
  elif tool_name == "get_latest_financial_data":
 
280
  if result and "period" in result:
281
  return {
282
  "type": "text",
283
+ "text": json.dumps(result, ensure_ascii=False)
284
  }
285
  else:
286
  return {
287
  "type": "text",
288
+ "text": json.dumps({
289
+ "error": f"No latest financial data found for CIK: {arguments['cik']}"
290
+ }, ensure_ascii=False)
291
  }
292
 
293
+ elif tool_name == "advanced_search_company" or tool_name == "advanced_search":
294
+ # Support both names for backward compatibility
295
  result = financial_analyzer.search_company(arguments["company_input"])
296
  if result.get("error"):
297
  return {
298
  "type": "text",
299
+ "text": json.dumps({
300
+ "error": result["error"]
301
+ }, ensure_ascii=False)
302
  }
303
  return {
304
  "type": "text",
305
+ "text": json.dumps(result, ensure_ascii=False)
306
  }
307
 
308
  else:
309
  return {
310
  "type": "text",
311
+ "text": json.dumps({
312
+ "error": f"Unknown tool: {tool_name}"
313
+ }, ensure_ascii=False)
314
  }
315
 
316
  except Exception as e:
317
  return {
318
  "type": "text",
319
+ "text": json.dumps({
320
+ "error": f"Error executing {tool_name}: {str(e)}"
321
+ }, ensure_ascii=False)
322
  }
323
 
324
 
 
503
  </head>
504
  <body>
505
  <div class="container">
506
+ <h1>SEC Financial Report MCP Server</h1>
507
  <p><span class="badge">MCP READY</span> Model Context Protocol Server for SEC EDGAR Financial Data</p>
508
 
509
+ <h2>Connect to this MCP Server</h2>
510
  <p>Add the following configuration to your MCP client (e.g., Claude Desktop):</p>
511
 
512
  <div class="config-box">
 
521
 
522
  <p><strong>Use the URL above to connect to this MCP Server.</strong></p>
523
 
524
+ <h2>Available Tools (7)</h2>
525
  <div class="tools">
526
  <div class="tool">
527
  <h3>search_company</h3>
 
540
  <p>Get financial data for a specific period (annual or quarterly)</p>
541
  </div>
542
  <div class="tool">
543
+ <h3>extract_financial_metrics</h3>
544
  <p>Extract comprehensive financial metrics for multiple years</p>
545
  </div>
546
  <div class="tool">
 
553
  </div>
554
  </div>
555
 
556
+ <h2>Example Usage</h2>
557
  <p>Once connected, you can ask your AI assistant:</p>
558
  <ul>
559
  <li>"Search for Microsoft and show me their latest financial data"</li>
 
561
  <li>"Compare NVIDIA and AMD's revenue trends"</li>
562
  </ul>
563
 
564
+ <h2>Documentation</h2>
565
  <p>Visit <code>/tools</code> to see all available tools in JSON format.</p>
566
 
567
  <hr style="margin: 30px 0; border: none; border-top: 1px solid #e0e0e0;">