JC321 commited on
Commit
47c4f0e
Β·
verified Β·
1 Parent(s): 7fca351

Upload 3 files

Browse files
Files changed (3) hide show
  1. app.py +14 -594
  2. templates/index.html +453 -0
  3. templates/test.html +135 -0
app.py CHANGED
@@ -3,8 +3,9 @@ Simple FastAPI web interface for MCP Server usage guide
3
  Integrated with MCP server directly
4
  """
5
  from fastapi import FastAPI, Request
6
- from fastapi.responses import HTMLResponse, JSONResponse, Response
7
  from fastapi.middleware.cors import CORSMiddleware
 
8
  import uvicorn
9
  import json
10
 
@@ -249,605 +250,24 @@ async def mcp_http_endpoint(request: Request):
249
  status_code=500
250
  )
251
 
252
- HTML_CONTENT = """
253
- <!DOCTYPE html>
254
- <html lang="en">
255
- <head>
256
- <meta charset="UTF-8">
257
- <meta name="viewport" content="width=device-width, initial-scale=1.0">
258
- <title>SEC Financial Data MCP Server</title>
259
- <style>
260
- body { font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', sans-serif; max-width: 1200px; margin: 0 auto; padding: 20px; background: #f5f5f5; }
261
- .container { background: white; border-radius: 8px; padding: 30px; box-shadow: 0 2px 4px rgba(0,0,0,0.1); }
262
- h1 { color: #2563eb; border-bottom: 3px solid #2563eb; padding-bottom: 10px; }
263
- h2 { color: #1e40af; margin-top: 30px; }
264
- h3 { color: #1e3a8a; }
265
- .endpoint { background: #e0e7ff; padding: 15px; border-radius: 5px; margin: 15px 0; font-family: monospace; }
266
- .tool { background: #f0f9ff; border-left: 4px solid #2563eb; padding: 15px; margin: 10px 0; border-radius: 4px; }
267
- .tool-header { display: flex; align-items: center; cursor: pointer; user-select: none; }
268
- .tool-header:hover { background: #e0f2fe; margin: -5px -10px; padding: 5px 10px; border-radius: 4px; }
269
- .tool-toggle { font-size: 14px; margin-right: 10px; transition: transform 0.3s; display: inline-block; }
270
- .tool-toggle.expanded { transform: rotate(90deg); }
271
- .tool-name { font-weight: bold; color: #1e40af; font-size: 18px; flex: 1; }
272
- .tool-content { display: none; margin-top: 15px; padding-top: 15px; border-top: 1px solid #e0e7ff; }
273
- .tool-content.expanded { display: block; }
274
- .test-panel { background: #f8fafc; padding: 15px; border-radius: 5px; margin-top: 15px; border: 1px solid #e2e8f0; }
275
- .test-input { width: 100%; padding: 8px; margin: 5px 0; border: 1px solid #cbd5e1; border-radius: 4px; font-family: monospace; font-size: 13px; }
276
- .test-button { background: #2563eb; color: white; border: none; padding: 10px 20px; border-radius: 5px; cursor: pointer; font-weight: bold; margin-top: 10px; }
277
- .test-button:hover { background: #1e40af; }
278
- .test-button:disabled { background: #94a3b8; cursor: not-allowed; }
279
- .test-result { background: #1e293b; color: #e2e8f0; padding: 15px; border-radius: 5px; margin-top: 10px; white-space: pre-wrap; word-wrap: break-word; font-family: monospace; font-size: 12px; max-height: 400px; overflow-y: auto; }
280
- .test-status { padding: 8px 12px; border-radius: 4px; margin-top: 10px; font-size: 14px; }
281
- .status-loading { background: #dbeafe; color: #1e40af; }
282
- .status-success { background: #dcfce7; color: #166534; }
283
- .status-error { background: #fee2e2; color: #991b1b; }
284
- .code { background: #1e293b; color: #e2e8f0; padding: 15px; border-radius: 5px; overflow-x: auto; margin: 10px 0; }
285
- .code pre { margin: 0; }
286
- .badge { display: inline-block; padding: 4px 12px; border-radius: 12px; font-size: 12px; font-weight: bold; }
287
- .badge-success { background: #dcfce7; color: #166534; }
288
- .badge-info { background: #dbeafe; color: #1e40af; }
289
- .feature { display: inline-block; margin: 5px; padding: 8px 15px; background: #e0e7ff; border-radius: 5px; }
290
- table { width: 100%; border-collapse: collapse; margin: 15px 0; }
291
- th, td { padding: 12px; text-align: left; border-bottom: 1px solid #e5e7eb; }
292
- th { background: #f3f4f6; font-weight: 600; }
293
- .status { position: fixed; top: 20px; right: 20px; background: #22c55e; color: white; padding: 10px 20px; border-radius: 20px; z-index: 1000; }
294
- </style>
295
- </head>
296
- <body>
297
- <div class="status">🟒 Server Running</div>
298
- <div class="container">
299
- <h1>πŸ“Š SEC Financial Data MCP Server</h1>
300
- <p style="font-size: 18px; color: #64748b;">Access real-time SEC EDGAR financial data via Model Context Protocol</p>
301
-
302
- <h2>πŸ”— MCP Endpoint</h2>
303
- <div class="endpoint">
304
- https://jc321-easyreportsmcpserver.hf.space/mcp
305
- </div>
306
- <p><span class="badge badge-info">Protocol: MCP 2024-11-05</span> <span class="badge badge-info">Transport: HTTP</span></p>
307
- <p style="text-align: center; margin: 20px 0;">
308
- <a href="/test" style="display: inline-block; padding: 12px 24px; background: #2563eb; color: white; text-decoration: none; border-radius: 6px; font-weight: bold;">πŸ§ͺ Test MCP Server Live</a>
309
- </p>
310
-
311
- <h2>πŸ› οΈ Available Tools (7)</h2>
312
-
313
- <div class="tool">
314
- <div class="tool-header" onclick="toggleTool('tool1')">
315
- <span class="tool-toggle" id="toggle-tool1">β–Ά</span>
316
- <div class="tool-name">1. search_company</div>
317
- </div>
318
- <div class="tool-content" id="content-tool1">
319
- <p>Search for a company by name</p>
320
- <strong>Parameters:</strong>
321
- <ul>
322
- <li><code>company_name</code> (string): Company name (e.g., "Tesla", "Apple")</li>
323
- </ul>
324
- <strong>Example:</strong>
325
- <div class="code"><pre>{
326
- "company_name": "Tesla"
327
- }</pre></div>
328
- <strong>Returns:</strong> Company CIK, name, tickers, SIC code
329
-
330
- <div class="test-panel">
331
- <strong>πŸ§ͺ Test this tool:</strong>
332
- <input type="text" id="input-tool1-company_name" class="test-input" placeholder="Company name (e.g., Tesla)" value="Tesla">
333
- <button class="test-button" onclick="testTool1()">Run Test</button>
334
- <div id="status-tool1"></div>
335
- <div id="result-tool1"></div>
336
- </div>
337
- </div>
338
- </div>
339
-
340
- <div class="tool">
341
- <div class="tool-header" onclick="toggleTool('tool2')">
342
- <span class="tool-toggle" id="toggle-tool2">β–Ά</span>
343
- <div class="tool-name">2. get_company_info</div>
344
- </div>
345
- <div class="tool-content" id="content-tool2">
346
- <p>Get detailed company information</p>
347
- <strong>Parameters:</strong>
348
- <ul>
349
- <li><code>cik</code> (string): Company CIK code (10-digit format)</li>
350
- </ul>
351
- <strong>Example:</strong>
352
- <div class="code"><pre>{
353
- "cik": "0001318605"
354
- }</pre></div>
355
-
356
- <div class="test-panel">
357
- <strong>πŸ§ͺ Test this tool:</strong>
358
- <input type="text" id="input-tool2-cik" class="test-input" placeholder="CIK (e.g., 0001318605)" value="0001318605">
359
- <button class="test-button" onclick="testTool2()">Run Test</button>
360
- <div id="status-tool2"></div>
361
- <div id="result-tool2"></div>
362
- </div>
363
- </div>
364
- </div>
365
-
366
- <div class="tool">
367
- <div class="tool-header" onclick="toggleTool('tool3')">
368
- <span class="tool-toggle" id="toggle-tool3">β–Ά</span>
369
- <div class="tool-name">3. get_company_filings</div>
370
- </div>
371
- <div class="tool-content" id="content-tool3">
372
- <p>Get list of SEC filings (10-K, 10-Q, etc.)</p>
373
- <strong>Parameters:</strong>
374
- <ul>
375
- <li><code>cik</code> (string): Company CIK code</li>
376
- <li><code>form_types</code> (array, optional): Filter by form types</li>
377
- </ul>
378
- <strong>Example:</strong>
379
- <div class="code"><pre>{
380
- "cik": "0001318605",
381
- "form_types": ["10-K", "10-Q"]
382
- }</pre></div>
383
-
384
- <div class="test-panel">
385
- <strong>πŸ§ͺ Test this tool:</strong>
386
- <input type="text" id="input-tool3-cik" class="test-input" placeholder="CIK" value="0001318605">
387
- <input type="text" id="input-tool3-form_types" class="test-input" placeholder="Form types (JSON array, e.g., [\"10-K\",\"10-Q\"])" value='["10-K","10-Q"]'>
388
- <button class="test-button" onclick="testTool3()">Run Test</button>
389
- <div id="status-tool3"></div>
390
- <div id="result-tool3"></div>
391
- </div>
392
- </div>
393
- </div>
394
-
395
- <div class="tool">
396
- <div class="tool-header" onclick="toggleTool('tool4')">
397
- <span class="tool-toggle" id="toggle-tool4">β–Ά</span>
398
- <div class="tool-name">4. get_financial_data</div>
399
- </div>
400
- <div class="tool-content" id="content-tool4">
401
- <p>Get financial data for a specific period</p>
402
- <strong>Parameters:</strong>
403
- <ul>
404
- <li><code>cik</code> (string): Company CIK code</li>
405
- <li><code>period</code> (string): Period format "YYYY" or "YYYYQX"</li>
406
- </ul>
407
- <strong>Examples:</strong>
408
- <div class="code"><pre>// Annual data
409
- {
410
- "cik": "0001318605",
411
- "period": "2024"
412
- }
413
-
414
- // Quarterly data
415
- {
416
- "cik": "0001318605",
417
- "period": "2024Q3"
418
- }</pre></div>
419
-
420
- <div class="test-panel">
421
- <strong>πŸ§ͺ Test this tool:</strong>
422
- <input type="text" id="input-tool4-cik" class="test-input" placeholder="CIK" value="0001318605">
423
- <input type="text" id="input-tool4-period" class="test-input" placeholder="Period (e.g., 2024 or 2024Q3)" value="2024">
424
- <button class="test-button" onclick="testTool4()">Run Test</button>
425
- <div id="status-tool4"></div>
426
- <div id="result-tool4"></div>
427
- </div>
428
- </div>
429
- </div>
430
-
431
- <div class="tool">
432
- <div class="tool-header" onclick="toggleTool('tool5')">
433
- <span class="tool-toggle" id="toggle-tool5">β–Ά</span>
434
- <div class="tool-name">5. extract_financial_metrics ⭐</div>
435
- </div>
436
- <div class="tool-content" id="content-tool5">
437
- <p>Extract comprehensive financial metrics for multiple years (annual + quarterly)</p>
438
- <strong>Parameters:</strong>
439
- <ul>
440
- <li><code>cik</code> (string): Company CIK code</li>
441
- <li><code>years</code> (integer): Number of years (1-10, default: 3)</li>
442
- </ul>
443
- <strong>Example:</strong>
444
- <div class="code"><pre>{
445
- "cik": "0001318605",
446
- "years": 3
447
- }</pre></div>
448
- <strong>Returns:</strong> Multi-year data sorted newest first (FY β†’ Q4 β†’ Q3 β†’ Q2 β†’ Q1)
449
-
450
- <div class="test-panel">
451
- <strong>πŸ§ͺ Test this tool:</strong>
452
- <input type="text" id="input-tool5-cik" class="test-input" placeholder="CIK" value="0001318605">
453
- <input type="number" id="input-tool5-years" class="test-input" placeholder="Years (1-10)" value="3" min="1" max="10">
454
- <button class="test-button" onclick="testTool5()">Run Test</button>
455
- <div id="status-tool5"></div>
456
- <div id="result-tool5"></div>
457
- </div>
458
- </div>
459
- </div>
460
-
461
- <div class="tool">
462
- <div class="tool-header" onclick="toggleTool('tool6')">
463
- <span class="tool-toggle" id="toggle-tool6">β–Ά</span>
464
- <div class="tool-name">6. get_latest_financial_data</div>
465
- </div>
466
- <div class="tool-content" id="content-tool6">
467
- <p>Get the most recent financial data available</p>
468
- <strong>Parameters:</strong>
469
- <ul>
470
- <li><code>cik</code> (string): Company CIK code</li>
471
- </ul>
472
- <strong>Example:</strong>
473
- <div class="code"><pre>{
474
- "cik": "0001318605"
475
- }</pre></div>
476
-
477
- <div class="test-panel">
478
- <strong>πŸ§ͺ Test this tool:</strong>
479
- <input type="text" id="input-tool6-cik" class="test-input" placeholder="CIK" value="0001318605">
480
- <button class="test-button" onclick="testTool6()">Run Test</button>
481
- <div id="status-tool6"></div>
482
- <div id="result-tool6"></div>
483
- </div>
484
- </div>
485
- </div>
486
-
487
- <div class="tool">
488
- <div class="tool-header" onclick="toggleTool('tool7')">
489
- <span class="tool-toggle" id="toggle-tool7">β–Ά</span>
490
- <div class="tool-name">7. advanced_search_company</div>
491
- </div>
492
- <div class="tool-content" id="content-tool7">
493
- <p>Advanced search supporting both company name and CIK code</p>
494
- <strong>Parameters:</strong>
495
- <ul>
496
- <li><code>company_input</code> (string): Company name, ticker, or CIK</li>
497
- </ul>
498
- <strong>Examples:</strong>
499
- <div class="code"><pre>// By company name
500
- {
501
- "company_input": "Tesla"
502
- }
503
-
504
- // By CIK
505
- {
506
- "company_input": "0001318605"
507
- }</pre></div>
508
-
509
- <div class="test-panel">
510
- <strong>πŸ§ͺ Test this tool:</strong>
511
- <input type="text" id="input-tool7-company_input" class="test-input" placeholder="Company name or CIK" value="Tesla">
512
- <button class="test-button" onclick="testTool7()">Run Test</button>
513
- <div id="status-tool7"></div>
514
- <div id="result-tool7"></div>
515
- </div>
516
- </div>
517
- </div>
518
-
519
- <h2>πŸ“ How to Use</h2>
520
-
521
- <h3>Option 1: Claude Desktop (Recommended)</h3>
522
- <p>Add to your <code>claude_desktop_config.json</code>:</p>
523
- <div class="code"><pre>{
524
- "mcpServers": {
525
- "sec-financial-data": {
526
- "url": "https://jc321-easyreportsmcpserver.hf.space/mcp",
527
- "transport": "http"
528
- }
529
- }
530
- }</pre></div>
531
- <p><strong>Then ask Claude:</strong></p>
532
- <ul>
533
- <li>"Search for Tesla's financial information"</li>
534
- <li>"Get Apple's latest financial data"</li>
535
- <li>"Show me Microsoft's revenue trends for the last 3 years"</li>
536
- </ul>
537
-
538
- <h3>Option 2: Direct API Call</h3>
539
- <p><strong>List Available Tools:</strong></p>
540
- <div class="code"><pre>curl -X POST https://jc321-easyreportsmcpserver.hf.space/mcp \\
541
- -H "Content-Type: application/json" \\
542
- -d '{
543
- "jsonrpc": "2.0",
544
- "method": "tools/list",
545
- "id": 1
546
- }'</pre></div>
547
-
548
- <p><strong>Search Company (Tesla):</strong></p>
549
- <div class="code"><pre>curl -X POST https://jc321-easyreportsmcpserver.hf.space/mcp \\
550
- -H "Content-Type: application/json" \\
551
- -d '{
552
- "jsonrpc": "2.0",
553
- "method": "tools/call",
554
- "params": {
555
- "name": "search_company",
556
- "arguments": {"company_name": "Tesla"}
557
- },
558
- "id": 2
559
- }'</pre></div>
560
-
561
- <p><strong>Get 3-Year Financial Trends:</strong></p>
562
- <div class="code"><pre>curl -X POST https://jc321-easyreportsmcpserver.hf.space/mcp \\
563
- -H "Content-Type: application/json" \\
564
- -d '{
565
- "jsonrpc": "2.0",
566
- "method": "tools/call",
567
- "params": {
568
- "name": "extract_financial_metrics",
569
- "arguments": {"cik": "0001318605", "years": 3}
570
- },
571
- "id": 3
572
- }'</pre></div>
573
-
574
- <h2>πŸ”‘ Key Features</h2>
575
- <div class="feature">βœ… Pure JSON responses</div>
576
- <div class="feature">βœ… Chronological ordering</div>
577
- <div class="feature">βœ… Comprehensive metrics</div>
578
- <div class="feature">βœ… Real-time SEC EDGAR data</div>
579
- <div class="feature">βœ… 7 powerful tools</div>
580
-
581
- <h2>πŸ“Š Response Example</h2>
582
- <div class="code"><pre>{
583
- "jsonrpc": "2.0",
584
- "id": 2,
585
- "result": {
586
- "content": [{
587
- "type": "text",
588
- "text": "{\\"cik\\":\\"0001318605\\",\\"name\\":\\"TESLA, INC.\\",\\"tickers\\":[\\"TSLA\\"]}"
589
- }]
590
- }
591
- }</pre></div>
592
-
593
- <h2>ℹ️ About</h2>
594
- <table>
595
- <tr><th>Version</th><td>1.0.0 (FastMCP)</td></tr>
596
- <tr><th>Protocol</th><td>Model Context Protocol (MCP) 2024-11-05</td></tr>
597
- <tr><th>Transport</th><td>HTTP (Stateless)</td></tr>
598
- <tr><th>Data Source</th><td>SEC EDGAR Database</td></tr>
599
- <tr><th>Framework</th><td>Anthropic FastMCP SDK</td></tr>
600
- <tr><th>Maintained by</th><td>Juntao Peng (jtyxabc@gmail.com)</td></tr>
601
- </table>
602
-
603
- <p style="text-align: center; color: #64748b; margin-top: 40px;">
604
- <strong>Status:</strong> <span class="badge badge-success">Online</span> |
605
- <strong>Uptime:</strong> Always-On
606
- </p>
607
- </div>
608
-
609
- <script>
610
- // Toggle tool content
611
- function toggleTool(toolId) {
612
- const content = document.getElementById('content-' + toolId);
613
- const toggle = document.getElementById('toggle-' + toolId);
614
-
615
- if (content.classList.contains('expanded')) {
616
- content.classList.remove('expanded');
617
- toggle.classList.remove('expanded');
618
- } else {
619
- content.classList.add('expanded');
620
- toggle.classList.add('expanded');
621
- }
622
- }
623
-
624
- // Common function to call MCP API
625
- async function callMCP(toolName, arguments, statusId, resultId) {
626
- const statusDiv = document.getElementById(statusId);
627
- const resultDiv = document.getElementById(resultId);
628
- const button = event.target;
629
-
630
- statusDiv.innerHTML = '<div class="test-status status-loading">⏳ Sending request...</div>';
631
- resultDiv.innerHTML = '';
632
- button.disabled = true;
633
-
634
- try {
635
- const response = await fetch('/mcp', {
636
- method: 'POST',
637
- headers: { 'Content-Type': 'application/json' },
638
- body: JSON.stringify({
639
- jsonrpc: '2.0',
640
- method: 'tools/call',
641
- params: {
642
- name: toolName,
643
- arguments: arguments
644
- },
645
- id: Date.now()
646
- })
647
- });
648
-
649
- const data = await response.json();
650
- statusDiv.innerHTML = '<div class="test-status status-success">βœ… Success!</div>';
651
- resultDiv.innerHTML = '<div class="test-result">' + JSON.stringify(data, null, 2) + '</div>';
652
- } catch (error) {
653
- statusDiv.innerHTML = '<div class="test-status status-error">❌ Error: ' + error.message + '</div>';
654
- resultDiv.innerHTML = '<div class="test-result">' + JSON.stringify({error: error.toString()}, null, 2) + '</div>';
655
- } finally {
656
- button.disabled = false;
657
- }
658
- }
659
-
660
- // Tool-specific test functions
661
- function testTool1() {
662
- const companyName = document.getElementById('input-tool1-company_name').value;
663
- callMCP('search_company', { company_name: companyName }, 'status-tool1', 'result-tool1');
664
- }
665
-
666
- function testTool2() {
667
- const cik = document.getElementById('input-tool2-cik').value;
668
- callMCP('get_company_info', { cik: cik }, 'status-tool2', 'result-tool2');
669
- }
670
-
671
- function testTool3() {
672
- const cik = document.getElementById('input-tool3-cik').value;
673
- const formTypesStr = document.getElementById('input-tool3-form_types').value;
674
- try {
675
- const formTypes = formTypesStr ? JSON.parse(formTypesStr) : null;
676
- callMCP('get_company_filings', { cik: cik, form_types: formTypes }, 'status-tool3', 'result-tool3');
677
- } catch (e) {
678
- document.getElementById('status-tool3').innerHTML = '<div class="test-status status-error">❌ Invalid JSON for form_types</div>';
679
- }
680
- }
681
-
682
- function testTool4() {
683
- const cik = document.getElementById('input-tool4-cik').value;
684
- const period = document.getElementById('input-tool4-period').value;
685
- callMCP('get_financial_data', { cik: cik, period: period }, 'status-tool4', 'result-tool4');
686
- }
687
-
688
- function testTool5() {
689
- const cik = document.getElementById('input-tool5-cik').value;
690
- const years = parseInt(document.getElementById('input-tool5-years').value);
691
- callMCP('extract_financial_metrics', { cik: cik, years: years }, 'status-tool5', 'result-tool5');
692
- }
693
-
694
- function testTool6() {
695
- const cik = document.getElementById('input-tool6-cik').value;
696
- callMCP('get_latest_financial_data', { cik: cik }, 'status-tool6', 'result-tool6');
697
- }
698
-
699
- function testTool7() {
700
- const companyInput = document.getElementById('input-tool7-company_input').value;
701
- callMCP('advanced_search_company', { company_input: companyInput }, 'status-tool7', 'result-tool7');
702
- }
703
- </script>
704
- </body>
705
- </html>
706
- """
707
 
708
  @app.get("/", response_class=HTMLResponse)
709
  async def root():
710
- return HTML_CONTENT
 
 
 
 
711
 
712
  @app.get("/test", response_class=HTMLResponse)
713
  async def test_page():
714
- return """
715
- <!DOCTYPE html>
716
- <html>
717
- <head>
718
- <title>MCP Server Test</title>
719
- <style>
720
- body { font-family: monospace; padding: 20px; max-width: 1000px; margin: 0 auto; }
721
- button { padding: 10px 20px; margin: 5px; cursor: pointer; background: #2563eb; color: white; border: none; border-radius: 5px; }
722
- button:hover { background: #1e40af; }
723
- .result { background: #1e293b; color: #e2e8f0; padding: 15px; margin: 10px 0; border-radius: 5px; white-space: pre-wrap; word-wrap: break-word; }
724
- .status { padding: 10px; margin: 10px 0; border-radius: 5px; }
725
- .success { background: #dcfce7; color: #166534; }
726
- .error { background: #fee2e2; color: #991b1b; }
727
- </style>
728
- </head>
729
- <body>
730
- <h1>πŸ§ͺ MCP Server Live Test</h1>
731
- <p>Test the MCP server at: <code>https://jc321-easyreportsmcpserver.hf.space/mcp</code></p>
732
-
733
- <div>
734
- <button onclick="testToolsList()">πŸ“‹ Test: List Tools</button>
735
- <button onclick="testSearchCompany()">πŸ” Test: Search Tesla</button>
736
- <button onclick="testFinancialMetrics()">πŸ“Š Test: Get Financial Metrics</button>
737
- </div>
738
-
739
- <div id="status"></div>
740
- <div id="result"></div>
741
-
742
- <script>
743
- const endpoint = '/mcp'; // Use relative path for same-origin requests
744
-
745
- function showStatus(msg, isError) {
746
- document.getElementById('status').innerHTML =
747
- `<div class="status ${isError ? 'error' : 'success'}">${msg}</div>`;
748
- }
749
-
750
- function showResult(data) {
751
- document.getElementById('result').innerHTML =
752
- `<div class="result">${JSON.stringify(data, null, 2)}</div>`;
753
- }
754
-
755
- async function testToolsList() {
756
- showStatus('⏳ Sending request to list tools...');
757
- try {
758
- const response = await fetch(endpoint, {
759
- method: 'POST',
760
- headers: { 'Content-Type': 'application/json' },
761
- body: JSON.stringify({
762
- jsonrpc: '2.0',
763
- method: 'tools/list',
764
- id: 1
765
- })
766
- });
767
-
768
- const text = await response.text();
769
- showStatus('βœ… Response received!', false);
770
-
771
- // Try to parse as JSON or show raw text
772
- try {
773
- const json = JSON.parse(text);
774
- showResult(json);
775
- } catch {
776
- showResult({ raw_response: text });
777
- }
778
- } catch (error) {
779
- showStatus('❌ Error: ' + error.message, true);
780
- showResult({ error: error.toString() });
781
- }
782
- }
783
-
784
- async function testSearchCompany() {
785
- showStatus('⏳ Searching for Tesla...');
786
- try {
787
- const response = await fetch(endpoint, {
788
- method: 'POST',
789
- headers: { 'Content-Type': 'application/json' },
790
- body: JSON.stringify({
791
- jsonrpc: '2.0',
792
- method: 'tools/call',
793
- params: {
794
- name: 'search_company',
795
- arguments: { company_name: 'Tesla' }
796
- },
797
- id: 2
798
- })
799
- });
800
-
801
- const text = await response.text();
802
- showStatus('βœ… Response received!', false);
803
-
804
- try {
805
- const json = JSON.parse(text);
806
- showResult(json);
807
- } catch {
808
- showResult({ raw_response: text });
809
- }
810
- } catch (error) {
811
- showStatus('❌ Error: ' + error.message, true);
812
- showResult({ error: error.toString() });
813
- }
814
- }
815
-
816
- async function testFinancialMetrics() {
817
- showStatus('⏳ Getting Tesla financial metrics (3 years)...');
818
- try {
819
- const response = await fetch(endpoint, {
820
- method: 'POST',
821
- headers: { 'Content-Type': 'application/json' },
822
- body: JSON.stringify({
823
- jsonrpc: '2.0',
824
- method: 'tools/call',
825
- params: {
826
- name: 'extract_financial_metrics',
827
- arguments: { cik: '0001318605', years: 3 }
828
- },
829
- id: 3
830
- })
831
- });
832
-
833
- const text = await response.text();
834
- showStatus('βœ… Response received!', false);
835
-
836
- try {
837
- const json = JSON.parse(text);
838
- showResult(json);
839
- } catch {
840
- showResult({ raw_response: text });
841
- }
842
- } catch (error) {
843
- showStatus('❌ Error: ' + error.message, true);
844
- showResult({ error: error.toString() });
845
- }
846
- }
847
- </script>
848
- </body>
849
- </html>
850
- """
851
 
852
  if __name__ == "__main__":
853
  uvicorn.run(app, host="0.0.0.0", port=7860)
 
3
  Integrated with MCP server directly
4
  """
5
  from fastapi import FastAPI, Request
6
+ from fastapi.responses import HTMLResponse, JSONResponse, Response, FileResponse
7
  from fastapi.middleware.cors import CORSMiddleware
8
+ from pathlib import Path
9
  import uvicorn
10
  import json
11
 
 
250
  status_code=500
251
  )
252
 
253
+ # Get the template directory path
254
+ TEMPLATES_DIR = Path(__file__).parent / "templates"
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
255
 
256
  @app.get("/", response_class=HTMLResponse)
257
  async def root():
258
+ """Serve the main index page"""
259
+ index_path = TEMPLATES_DIR / "index.html"
260
+ if index_path.exists():
261
+ return FileResponse(index_path)
262
+ return HTMLResponse("<h1>Error: Template not found</h1>", status_code=404)
263
 
264
  @app.get("/test", response_class=HTMLResponse)
265
  async def test_page():
266
+ """Serve the test page"""
267
+ test_path = TEMPLATES_DIR / "test.html"
268
+ if test_path.exists():
269
+ return FileResponse(test_path)
270
+ return HTMLResponse("<h1>Error: Test page not found</h1>", status_code=404)
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
271
 
272
  if __name__ == "__main__":
273
  uvicorn.run(app, host="0.0.0.0", port=7860)
templates/index.html ADDED
@@ -0,0 +1,453 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <!DOCTYPE html>
2
+ <html lang="en">
3
+ <head>
4
+ <meta charset="UTF-8">
5
+ <meta name="viewport" content="width=device-width, initial-scale=1.0">
6
+ <title>SEC Financial Data MCP Server</title>
7
+ <style>
8
+ body { font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', sans-serif; max-width: 1200px; margin: 0 auto; padding: 20px; background: #f5f5f5; }
9
+ .container { background: white; border-radius: 8px; padding: 30px; box-shadow: 0 2px 4px rgba(0,0,0,0.1); }
10
+ h1 { color: #2563eb; border-bottom: 3px solid #2563eb; padding-bottom: 10px; }
11
+ h2 { color: #1e40af; margin-top: 30px; }
12
+ h3 { color: #1e3a8a; }
13
+ .endpoint { background: #e0e7ff; padding: 15px; border-radius: 5px; margin: 15px 0; font-family: monospace; }
14
+ .tool { background: #f0f9ff; border-left: 4px solid #2563eb; padding: 15px; margin: 10px 0; border-radius: 4px; }
15
+ .tool-header { display: flex; align-items: center; cursor: pointer; user-select: none; }
16
+ .tool-header:hover { background: #e0f2fe; margin: -5px -10px; padding: 5px 10px; border-radius: 4px; }
17
+ .tool-toggle { font-size: 14px; margin-right: 10px; transition: transform 0.3s; display: inline-block; }
18
+ .tool-toggle.expanded { transform: rotate(90deg); }
19
+ .tool-name { font-weight: bold; color: #1e40af; font-size: 18px; flex: 1; }
20
+ .tool-content { display: none; margin-top: 15px; padding-top: 15px; border-top: 1px solid #e0e7ff; }
21
+ .tool-content.expanded { display: block; }
22
+ .test-panel { background: #f8fafc; padding: 15px; border-radius: 5px; margin-top: 15px; border: 1px solid #e2e8f0; }
23
+ .test-input { width: 100%; padding: 8px; margin: 5px 0; border: 1px solid #cbd5e1; border-radius: 4px; font-family: monospace; font-size: 13px; }
24
+ .test-button { background: #2563eb; color: white; border: none; padding: 10px 20px; border-radius: 5px; cursor: pointer; font-weight: bold; margin-top: 10px; }
25
+ .test-button:hover { background: #1e40af; }
26
+ .test-button:disabled { background: #94a3b8; cursor: not-allowed; }
27
+ .test-result { background: #1e293b; color: #e2e8f0; padding: 15px; border-radius: 5px; margin-top: 10px; white-space: pre-wrap; word-wrap: break-word; font-family: monospace; font-size: 12px; max-height: 400px; overflow-y: auto; }
28
+ .test-status { padding: 8px 12px; border-radius: 4px; margin-top: 10px; font-size: 14px; }
29
+ .status-loading { background: #dbeafe; color: #1e40af; }
30
+ .status-success { background: #dcfce7; color: #166534; }
31
+ .status-error { background: #fee2e2; color: #991b1b; }
32
+ .code { background: #1e293b; color: #e2e8f0; padding: 15px; border-radius: 5px; overflow-x: auto; margin: 10px 0; }
33
+ .code pre { margin: 0; }
34
+ .badge { display: inline-block; padding: 4px 12px; border-radius: 12px; font-size: 12px; font-weight: bold; }
35
+ .badge-success { background: #dcfce7; color: #166534; }
36
+ .badge-info { background: #dbeafe; color: #1e40af; }
37
+ .feature { display: inline-block; margin: 5px; padding: 8px 15px; background: #e0e7ff; border-radius: 5px; }
38
+ table { width: 100%; border-collapse: collapse; margin: 15px 0; }
39
+ th, td { padding: 12px; text-align: left; border-bottom: 1px solid #e5e7eb; }
40
+ th { background: #f3f4f6; font-weight: 600; }
41
+ .status { position: fixed; top: 20px; right: 20px; background: #22c55e; color: white; padding: 10px 20px; border-radius: 20px; z-index: 1000; }
42
+ </style>
43
+ </head>
44
+ <body>
45
+ <div class="status">🟒 Server Running</div>
46
+ <div class="container">
47
+ <h1>πŸ“Š SEC Financial Data MCP Server</h1>
48
+ <p style="font-size: 18px; color: #64748b;">Access real-time SEC EDGAR financial data via Model Context Protocol</p>
49
+
50
+ <h2>πŸ”— MCP Endpoint</h2>
51
+ <div class="endpoint">
52
+ https://jc321-easyreportsmcpserver.hf.space/mcp
53
+ </div>
54
+ <p><span class="badge badge-info">Protocol: MCP 2024-11-05</span> <span class="badge badge-info">Transport: HTTP</span></p>
55
+ <p style="text-align: center; margin: 20px 0;">
56
+ <a href="/test" style="display: inline-block; padding: 12px 24px; background: #2563eb; color: white; text-decoration: none; border-radius: 6px; font-weight: bold;">πŸ§ͺ Test MCP Server Live</a>
57
+ </p>
58
+
59
+ <h2>πŸ› οΈ Available Tools (7)</h2>
60
+
61
+ <div class="tool">
62
+ <div class="tool-header" onclick="toggleTool('tool1')">
63
+ <span class="tool-toggle" id="toggle-tool1">β–Ά</span>
64
+ <div class="tool-name">1. search_company</div>
65
+ </div>
66
+ <div class="tool-content" id="content-tool1">
67
+ <p>Search for a company by name</p>
68
+ <strong>Parameters:</strong>
69
+ <ul>
70
+ <li><code>company_name</code> (string): Company name (e.g., "Tesla", "Apple")</li>
71
+ </ul>
72
+ <strong>Example:</strong>
73
+ <div class="code"><pre>{
74
+ "company_name": "Tesla"
75
+ }</pre></div>
76
+ <strong>Returns:</strong> Company CIK, name, tickers, SIC code
77
+
78
+ <div class="test-panel">
79
+ <strong>πŸ§ͺ Test this tool:</strong>
80
+ <input type="text" id="input-tool1-company_name" class="test-input" placeholder="Company name (e.g., Tesla)" value="Tesla">
81
+ <button class="test-button" onclick="testTool1()">Run Test</button>
82
+ <div id="status-tool1"></div>
83
+ <div id="result-tool1"></div>
84
+ </div>
85
+ </div>
86
+ </div>
87
+
88
+ <div class="tool">
89
+ <div class="tool-header" onclick="toggleTool('tool2')">
90
+ <span class="tool-toggle" id="toggle-tool2">β–Ά</span>
91
+ <div class="tool-name">2. get_company_info</div>
92
+ </div>
93
+ <div class="tool-content" id="content-tool2">
94
+ <p>Get detailed company information</p>
95
+ <strong>Parameters:</strong>
96
+ <ul>
97
+ <li><code>cik</code> (string): Company CIK code (10-digit format)</li>
98
+ </ul>
99
+ <strong>Example:</strong>
100
+ <div class="code"><pre>{
101
+ "cik": "0001318605"
102
+ }</pre></div>
103
+
104
+ <div class="test-panel">
105
+ <strong>πŸ§ͺ Test this tool:</strong>
106
+ <input type="text" id="input-tool2-cik" class="test-input" placeholder="CIK (e.g., 0001318605)" value="0001318605">
107
+ <button class="test-button" onclick="testTool2()">Run Test</button>
108
+ <div id="status-tool2"></div>
109
+ <div id="result-tool2"></div>
110
+ </div>
111
+ </div>
112
+ </div>
113
+
114
+ <div class="tool">
115
+ <div class="tool-header" onclick="toggleTool('tool3')">
116
+ <span class="tool-toggle" id="toggle-tool3">β–Ά</span>
117
+ <div class="tool-name">3. get_company_filings</div>
118
+ </div>
119
+ <div class="tool-content" id="content-tool3">
120
+ <p>Get list of SEC filings (10-K, 10-Q, etc.)</p>
121
+ <strong>Parameters:</strong>
122
+ <ul>
123
+ <li><code>cik</code> (string): Company CIK code</li>
124
+ <li><code>form_types</code> (array, optional): Filter by form types</li>
125
+ </ul>
126
+ <strong>Example:</strong>
127
+ <div class="code"><pre>{
128
+ "cik": "0001318605",
129
+ "form_types": ["10-K", "10-Q"]
130
+ }</pre></div>
131
+
132
+ <div class="test-panel">
133
+ <strong>πŸ§ͺ Test this tool:</strong>
134
+ <input type="text" id="input-tool3-cik" class="test-input" placeholder="CIK" value="0001318605">
135
+ <input type="text" id="input-tool3-form_types" class="test-input" placeholder="Form types (JSON array, e.g., [\"10-K\",\"10-Q\"])" value='["10-K","10-Q"]'>
136
+ <button class="test-button" onclick="testTool3()">Run Test</button>
137
+ <div id="status-tool3"></div>
138
+ <div id="result-tool3"></div>
139
+ </div>
140
+ </div>
141
+ </div>
142
+
143
+ <div class="tool">
144
+ <div class="tool-header" onclick="toggleTool('tool4')">
145
+ <span class="tool-toggle" id="toggle-tool4">β–Ά</span>
146
+ <div class="tool-name">4. get_financial_data</div>
147
+ </div>
148
+ <div class="tool-content" id="content-tool4">
149
+ <p>Get financial data for a specific period</p>
150
+ <strong>Parameters:</strong>
151
+ <ul>
152
+ <li><code>cik</code> (string): Company CIK code</li>
153
+ <li><code>period</code> (string): Period format "YYYY" or "YYYYQX"</li>
154
+ </ul>
155
+ <strong>Examples:</strong>
156
+ <div class="code"><pre>// Annual data
157
+ {
158
+ "cik": "0001318605",
159
+ "period": "2024"
160
+ }
161
+
162
+ // Quarterly data
163
+ {
164
+ "cik": "0001318605",
165
+ "period": "2024Q3"
166
+ }</pre></div>
167
+
168
+ <div class="test-panel">
169
+ <strong>πŸ§ͺ Test this tool:</strong>
170
+ <input type="text" id="input-tool4-cik" class="test-input" placeholder="CIK" value="0001318605">
171
+ <input type="text" id="input-tool4-period" class="test-input" placeholder="Period (e.g., 2024 or 2024Q3)" value="2024">
172
+ <button class="test-button" onclick="testTool4()">Run Test</button>
173
+ <div id="status-tool4"></div>
174
+ <div id="result-tool4"></div>
175
+ </div>
176
+ </div>
177
+ </div>
178
+
179
+ <div class="tool">
180
+ <div class="tool-header" onclick="toggleTool('tool5')">
181
+ <span class="tool-toggle" id="toggle-tool5">β–Ά</span>
182
+ <div class="tool-name">5. extract_financial_metrics ⭐</div>
183
+ </div>
184
+ <div class="tool-content" id="content-tool5">
185
+ <p>Extract comprehensive financial metrics for multiple years (annual + quarterly)</p>
186
+ <strong>Parameters:</strong>
187
+ <ul>
188
+ <li><code>cik</code> (string): Company CIK code</li>
189
+ <li><code>years</code> (integer): Number of years (1-10, default: 3)</li>
190
+ </ul>
191
+ <strong>Example:</strong>
192
+ <div class="code"><pre>{
193
+ "cik": "0001318605",
194
+ "years": 3
195
+ }</pre></div>
196
+ <strong>Returns:</strong> Multi-year data sorted newest first (FY β†’ Q4 β†’ Q3 β†’ Q2 β†’ Q1)
197
+
198
+ <div class="test-panel">
199
+ <strong>πŸ§ͺ Test this tool:</strong>
200
+ <input type="text" id="input-tool5-cik" class="test-input" placeholder="CIK" value="0001318605">
201
+ <input type="number" id="input-tool5-years" class="test-input" placeholder="Years (1-10)" value="3" min="1" max="10">
202
+ <button class="test-button" onclick="testTool5()">Run Test</button>
203
+ <div id="status-tool5"></div>
204
+ <div id="result-tool5"></div>
205
+ </div>
206
+ </div>
207
+ </div>
208
+
209
+ <div class="tool">
210
+ <div class="tool-header" onclick="toggleTool('tool6')">
211
+ <span class="tool-toggle" id="toggle-tool6">β–Ά</span>
212
+ <div class="tool-name">6. get_latest_financial_data</div>
213
+ </div>
214
+ <div class="tool-content" id="content-tool6">
215
+ <p>Get the most recent financial data available</p>
216
+ <strong>Parameters:</strong>
217
+ <ul>
218
+ <li><code>cik</code> (string): Company CIK code</li>
219
+ </ul>
220
+ <strong>Example:</strong>
221
+ <div class="code"><pre>{
222
+ "cik": "0001318605"
223
+ }</pre></div>
224
+
225
+ <div class="test-panel">
226
+ <strong>πŸ§ͺ Test this tool:</strong>
227
+ <input type="text" id="input-tool6-cik" class="test-input" placeholder="CIK" value="0001318605">
228
+ <button class="test-button" onclick="testTool6()">Run Test</button>
229
+ <div id="status-tool6"></div>
230
+ <div id="result-tool6"></div>
231
+ </div>
232
+ </div>
233
+ </div>
234
+
235
+ <div class="tool">
236
+ <div class="tool-header" onclick="toggleTool('tool7')">
237
+ <span class="tool-toggle" id="toggle-tool7">β–Ά</span>
238
+ <div class="tool-name">7. advanced_search_company</div>
239
+ </div>
240
+ <div class="tool-content" id="content-tool7">
241
+ <p>Advanced search supporting both company name and CIK code</p>
242
+ <strong>Parameters:</strong>
243
+ <ul>
244
+ <li><code>company_input</code> (string): Company name, ticker, or CIK</li>
245
+ </ul>
246
+ <strong>Examples:</strong>
247
+ <div class="code"><pre>// By company name
248
+ {
249
+ "company_input": "Tesla"
250
+ }
251
+
252
+ // By CIK
253
+ {
254
+ "company_input": "0001318605"
255
+ }</pre></div>
256
+
257
+ <div class="test-panel">
258
+ <strong>πŸ§ͺ Test this tool:</strong>
259
+ <input type="text" id="input-tool7-company_input" class="test-input" placeholder="Company name or CIK" value="Tesla">
260
+ <button class="test-button" onclick="testTool7()">Run Test</button>
261
+ <div id="status-tool7"></div>
262
+ <div id="result-tool7"></div>
263
+ </div>
264
+ </div>
265
+ </div>
266
+
267
+ <h2>πŸ“ How to Use</h2>
268
+
269
+ <h3>Option 1: Claude Desktop (Recommended)</h3>
270
+ <p>Add to your <code>claude_desktop_config.json</code>:</p>
271
+ <div class="code"><pre>{
272
+ "mcpServers": {
273
+ "sec-financial-data": {
274
+ "url": "https://jc321-easyreportsmcpserver.hf.space/mcp",
275
+ "transport": "http"
276
+ }
277
+ }
278
+ }</pre></div>
279
+ <p><strong>Then ask Claude:</strong></p>
280
+ <ul>
281
+ <li>"Search for Tesla's financial information"</li>
282
+ <li>"Get Apple's latest financial data"</li>
283
+ <li>"Show me Microsoft's revenue trends for the last 3 years"</li>
284
+ </ul>
285
+
286
+ <h3>Option 2: Direct API Call</h3>
287
+ <p><strong>List Available Tools:</strong></p>
288
+ <div class="code"><pre>curl -X POST https://jc321-easyreportsmcpserver.hf.space/mcp \
289
+ -H "Content-Type: application/json" \
290
+ -d '{
291
+ "jsonrpc": "2.0",
292
+ "method": "tools/list",
293
+ "id": 1
294
+ }'</pre></div>
295
+
296
+ <p><strong>Search Company (Tesla):</strong></p>
297
+ <div class="code"><pre>curl -X POST https://jc321-easyreportsmcpserver.hf.space/mcp \
298
+ -H "Content-Type: application/json" \
299
+ -d '{
300
+ "jsonrpc": "2.0",
301
+ "method": "tools/call",
302
+ "params": {
303
+ "name": "search_company",
304
+ "arguments": {"company_name": "Tesla"}
305
+ },
306
+ "id": 2
307
+ }'</pre></div>
308
+
309
+ <p><strong>Get 3-Year Financial Trends:</strong></p>
310
+ <div class="code"><pre>curl -X POST https://jc321-easyreportsmcpserver.hf.space/mcp \
311
+ -H "Content-Type: application/json" \
312
+ -d '{
313
+ "jsonrpc": "2.0",
314
+ "method": "tools/call",
315
+ "params": {
316
+ "name": "extract_financial_metrics",
317
+ "arguments": {"cik": "0001318605", "years": 3}
318
+ },
319
+ "id": 3
320
+ }'</pre></div>
321
+
322
+ <h2>πŸ”‘ Key Features</h2>
323
+ <div class="feature">βœ… Pure JSON responses</div>
324
+ <div class="feature">βœ… Chronological ordering</div>
325
+ <div class="feature">βœ… Comprehensive metrics</div>
326
+ <div class="feature">βœ… Real-time SEC EDGAR data</div>
327
+ <div class="feature">βœ… 7 powerful tools</div>
328
+
329
+ <h2>πŸ“Š Response Example</h2>
330
+ <div class="code"><pre>{
331
+ "jsonrpc": "2.0",
332
+ "id": 2,
333
+ "result": {
334
+ "content": [{
335
+ "type": "text",
336
+ "text": "{\"cik\":\"0001318605\",\"name\":\"TESLA, INC.\",\"tickers\":[\"TSLA\"]}"
337
+ }]
338
+ }
339
+ }</pre></div>
340
+
341
+ <h2>ℹ️ About</h2>
342
+ <table>
343
+ <tr><th>Version</th><td>1.0.0 (FastMCP)</td></tr>
344
+ <tr><th>Protocol</th><td>Model Context Protocol (MCP) 2024-11-05</td></tr>
345
+ <tr><th>Transport</th><td>HTTP (Stateless)</td></tr>
346
+ <tr><th>Data Source</th><td>SEC EDGAR Database</td></tr>
347
+ <tr><th>Framework</th><td>Anthropic FastMCP SDK</td></tr>
348
+ <tr><th>Maintained by</th><td>Juntao Peng (jtyxabc@gmail.com)</td></tr>
349
+ </table>
350
+
351
+ <p style="text-align: center; color: #64748b; margin-top: 40px;">
352
+ <strong>Status:</strong> <span class="badge badge-success">Online</span> |
353
+ <strong>Uptime:</strong> Always-On
354
+ </p>
355
+ </div>
356
+
357
+ <script>
358
+ // Toggle tool content
359
+ function toggleTool(toolId) {
360
+ const content = document.getElementById('content-' + toolId);
361
+ const toggle = document.getElementById('toggle-' + toolId);
362
+
363
+ if (content.classList.contains('expanded')) {
364
+ content.classList.remove('expanded');
365
+ toggle.classList.remove('expanded');
366
+ } else {
367
+ content.classList.add('expanded');
368
+ toggle.classList.add('expanded');
369
+ }
370
+ }
371
+
372
+ // Common function to call MCP API
373
+ async function callMCP(toolName, arguments, statusId, resultId) {
374
+ const statusDiv = document.getElementById(statusId);
375
+ const resultDiv = document.getElementById(resultId);
376
+ const button = event.target;
377
+
378
+ statusDiv.innerHTML = '<div class="test-status status-loading">⏳ Sending request...</div>';
379
+ resultDiv.innerHTML = '';
380
+ button.disabled = true;
381
+
382
+ try {
383
+ const response = await fetch('/mcp', {
384
+ method: 'POST',
385
+ headers: { 'Content-Type': 'application/json' },
386
+ body: JSON.stringify({
387
+ jsonrpc: '2.0',
388
+ method: 'tools/call',
389
+ params: {
390
+ name: toolName,
391
+ arguments: arguments
392
+ },
393
+ id: Date.now()
394
+ })
395
+ });
396
+
397
+ const data = await response.json();
398
+ statusDiv.innerHTML = '<div class="test-status status-success">βœ… Success!</div>';
399
+ resultDiv.innerHTML = '<div class="test-result">' + JSON.stringify(data, null, 2) + '</div>';
400
+ } catch (error) {
401
+ statusDiv.innerHTML = '<div class="test-status status-error">❌ Error: ' + error.message + '</div>';
402
+ resultDiv.innerHTML = '<div class="test-result">' + JSON.stringify({error: error.toString()}, null, 2) + '</div>';
403
+ } finally {
404
+ button.disabled = false;
405
+ }
406
+ }
407
+
408
+ // Tool-specific test functions
409
+ function testTool1() {
410
+ const companyName = document.getElementById('input-tool1-company_name').value;
411
+ callMCP('search_company', { company_name: companyName }, 'status-tool1', 'result-tool1');
412
+ }
413
+
414
+ function testTool2() {
415
+ const cik = document.getElementById('input-tool2-cik').value;
416
+ callMCP('get_company_info', { cik: cik }, 'status-tool2', 'result-tool2');
417
+ }
418
+
419
+ function testTool3() {
420
+ const cik = document.getElementById('input-tool3-cik').value;
421
+ const formTypesStr = document.getElementById('input-tool3-form_types').value;
422
+ try {
423
+ const formTypes = formTypesStr ? JSON.parse(formTypesStr) : null;
424
+ callMCP('get_company_filings', { cik: cik, form_types: formTypes }, 'status-tool3', 'result-tool3');
425
+ } catch (e) {
426
+ document.getElementById('status-tool3').innerHTML = '<div class="test-status status-error">❌ Invalid JSON for form_types</div>';
427
+ }
428
+ }
429
+
430
+ function testTool4() {
431
+ const cik = document.getElementById('input-tool4-cik').value;
432
+ const period = document.getElementById('input-tool4-period').value;
433
+ callMCP('get_financial_data', { cik: cik, period: period }, 'status-tool4', 'result-tool4');
434
+ }
435
+
436
+ function testTool5() {
437
+ const cik = document.getElementById('input-tool5-cik').value;
438
+ const years = parseInt(document.getElementById('input-tool5-years').value);
439
+ callMCP('extract_financial_metrics', { cik: cik, years: years }, 'status-tool5', 'result-tool5');
440
+ }
441
+
442
+ function testTool6() {
443
+ const cik = document.getElementById('input-tool6-cik').value;
444
+ callMCP('get_latest_financial_data', { cik: cik }, 'status-tool6', 'result-tool6');
445
+ }
446
+
447
+ function testTool7() {
448
+ const companyInput = document.getElementById('input-tool7-company_input').value;
449
+ callMCP('advanced_search_company', { company_input: companyInput }, 'status-tool7', 'result-tool7');
450
+ }
451
+ </script>
452
+ </body>
453
+ </html>
templates/test.html ADDED
@@ -0,0 +1,135 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <!DOCTYPE html>
2
+ <html>
3
+ <head>
4
+ <title>MCP Server Test</title>
5
+ <style>
6
+ body { font-family: monospace; padding: 20px; max-width: 1000px; margin: 0 auto; }
7
+ button { padding: 10px 20px; margin: 5px; cursor: pointer; background: #2563eb; color: white; border: none; border-radius: 5px; }
8
+ button:hover { background: #1e40af; }
9
+ .result { background: #1e293b; color: #e2e8f0; padding: 15px; margin: 10px 0; border-radius: 5px; white-space: pre-wrap; word-wrap: break-word; }
10
+ .status { padding: 10px; margin: 10px 0; border-radius: 5px; }
11
+ .success { background: #dcfce7; color: #166534; }
12
+ .error { background: #fee2e2; color: #991b1b; }
13
+ </style>
14
+ </head>
15
+ <body>
16
+ <h1>πŸ§ͺ MCP Server Live Test</h1>
17
+ <p>Test the MCP server at: <code>https://jc321-easyreportsmcpserver.hf.space/mcp</code></p>
18
+
19
+ <div>
20
+ <button onclick="testToolsList()">πŸ“‹ Test: List Tools</button>
21
+ <button onclick="testSearchCompany()">πŸ” Test: Search Tesla</button>
22
+ <button onclick="testFinancialMetrics()">πŸ“Š Test: Get Financial Metrics</button>
23
+ </div>
24
+
25
+ <div id="status"></div>
26
+ <div id="result"></div>
27
+
28
+ <script>
29
+ const endpoint = '/mcp'; // Use relative path for same-origin requests
30
+
31
+ function showStatus(msg, isError) {
32
+ document.getElementById('status').innerHTML =
33
+ `<div class="status ${isError ? 'error' : 'success'}">${msg}</div>`;
34
+ }
35
+
36
+ function showResult(data) {
37
+ document.getElementById('result').innerHTML =
38
+ `<div class="result">${JSON.stringify(data, null, 2)}</div>`;
39
+ }
40
+
41
+ async function testToolsList() {
42
+ showStatus('⏳ Sending request to list tools...');
43
+ try {
44
+ const response = await fetch(endpoint, {
45
+ method: 'POST',
46
+ headers: { 'Content-Type': 'application/json' },
47
+ body: JSON.stringify({
48
+ jsonrpc: '2.0',
49
+ method: 'tools/list',
50
+ id: 1
51
+ })
52
+ });
53
+
54
+ const text = await response.text();
55
+ showStatus('βœ… Response received!', false);
56
+
57
+ // Try to parse as JSON or show raw text
58
+ try {
59
+ const json = JSON.parse(text);
60
+ showResult(json);
61
+ } catch {
62
+ showResult({ raw_response: text });
63
+ }
64
+ } catch (error) {
65
+ showStatus('❌ Error: ' + error.message, true);
66
+ showResult({ error: error.toString() });
67
+ }
68
+ }
69
+
70
+ async function testSearchCompany() {
71
+ showStatus('⏳ Searching for Tesla...');
72
+ try {
73
+ const response = await fetch(endpoint, {
74
+ method: 'POST',
75
+ headers: { 'Content-Type': 'application/json' },
76
+ body: JSON.stringify({
77
+ jsonrpc: '2.0',
78
+ method: 'tools/call',
79
+ params: {
80
+ name: 'search_company',
81
+ arguments: { company_name: 'Tesla' }
82
+ },
83
+ id: 2
84
+ })
85
+ });
86
+
87
+ const text = await response.text();
88
+ showStatus('βœ… Response received!', false);
89
+
90
+ try {
91
+ const json = JSON.parse(text);
92
+ showResult(json);
93
+ } catch {
94
+ showResult({ raw_response: text });
95
+ }
96
+ } catch (error) {
97
+ showStatus('❌ Error: ' + error.message, true);
98
+ showResult({ error: error.toString() });
99
+ }
100
+ }
101
+
102
+ async function testFinancialMetrics() {
103
+ showStatus('⏳ Getting Tesla financial metrics (3 years)...');
104
+ try {
105
+ const response = await fetch(endpoint, {
106
+ method: 'POST',
107
+ headers: { 'Content-Type': 'application/json' },
108
+ body: JSON.stringify({
109
+ jsonrpc: '2.0',
110
+ method: 'tools/call',
111
+ params: {
112
+ name: 'extract_financial_metrics',
113
+ arguments: { cik: '0001318605', years: 3 }
114
+ },
115
+ id: 3
116
+ })
117
+ });
118
+
119
+ const text = await response.text();
120
+ showStatus('βœ… Response received!', false);
121
+
122
+ try {
123
+ const json = JSON.parse(text);
124
+ showResult(json);
125
+ } catch {
126
+ showResult({ raw_response: text });
127
+ }
128
+ } catch (error) {
129
+ showStatus('❌ Error: ' + error.message, true);
130
+ showResult({ error: error.toString() });
131
+ }
132
+ }
133
+ </script>
134
+ </body>
135
+ </html>