Skip to content

Commit e44f61c

Browse files
committed
index page
1 parent 741b0ae commit e44f61c

2 files changed

Lines changed: 138 additions & 3 deletions

File tree

src/mcp_server_obp/server.py

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -37,7 +37,7 @@
3737

3838
from mcp_server_obp.lifespan import lifespan
3939
from mcp_server_obp.auth import get_auth_provider
40-
from mcp_server_obp.status import health_endpoint, ready_endpoint, status_endpoint
40+
from mcp_server_obp.status import health_endpoint, index_endpoint, ready_endpoint, status_endpoint
4141

4242
logger = logging.getLogger(__name__)
4343

@@ -626,9 +626,10 @@ def glossary_term(term_id: str) -> str:
626626

627627

628628
# ============================================================================
629-
# PUBLIC STATUS PAGE
629+
# PUBLIC INDEX AND STATUS PAGES
630630
# ============================================================================
631631

632+
mcp.custom_route("/", methods=["GET"])(index_endpoint)
632633
mcp.custom_route("/status", methods=["GET"])(status_endpoint)
633634
mcp.custom_route("/health", methods=["GET"])(health_endpoint)
634635
mcp.custom_route("/ready", methods=["GET"])(ready_endpoint)

src/mcp_server_obp/status.py

Lines changed: 135 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -296,12 +296,146 @@ def row(label: str, value: Any) -> str:
296296
297297
<footer>
298298
Generated at {esc(data["timestamp"])} ·
299-
<a href="?format=json">JSON</a>
299+
<a href="?format=json">JSON</a> ·
300+
<a href="/">Home</a>
300301
</footer>
301302
</body>
302303
</html>"""
303304

304305

306+
def _server_base_url(request: Request) -> str:
307+
"""Public base URL of this server: BASE_URL env if set, else derived
308+
from the incoming request (scheme://host[:port])."""
309+
configured = os.getenv("BASE_URL", "").rstrip("/")
310+
if configured:
311+
return configured
312+
return f"{request.url.scheme}://{request.url.netloc}"
313+
314+
315+
def _render_index_html(request: Request) -> str:
316+
esc = _html.escape
317+
base_url = _server_base_url(request)
318+
mcp_url = f"{base_url}/mcp"
319+
320+
auth_enabled = os.getenv("ENABLE_OAUTH", "false").lower() == "true"
321+
auth_provider = os.getenv("AUTH_PROVIDER", "none") if auth_enabled else "none"
322+
if auth_enabled:
323+
auth_note = (
324+
f"OAuth 2.1 is required (provider: <code>{esc(auth_provider)}</code>). "
325+
"MCP clients that support OAuth will be redirected to log in automatically."
326+
)
327+
else:
328+
auth_note = "No authentication is required to connect (development mode)."
329+
330+
obp_base_url = os.getenv("OBP_BASE_URL", "").rstrip("/")
331+
obp_line = (
332+
f'<p>This server fronts the Open Bank Project API at <a href="{esc(obp_base_url)}">{esc(obp_base_url)}</a>.</p>'
333+
if obp_base_url
334+
else ""
335+
)
336+
337+
claude_code_cmd = f"claude mcp add --transport http obp {mcp_url}"
338+
vscode_json = f"""{{
339+
"servers": {{
340+
"obp": {{
341+
"type": "http",
342+
"url": "{mcp_url}"
343+
}}
344+
}}
345+
}}"""
346+
mcp_remote_json = f"""{{
347+
"mcpServers": {{
348+
"obp": {{
349+
"command": "npx",
350+
"args": ["-y", "mcp-remote", "{mcp_url}"]
351+
}}
352+
}}
353+
}}"""
354+
355+
return f"""<!doctype html>
356+
<html lang="en">
357+
<head>
358+
<meta charset="utf-8">
359+
<title>OBP-MCP — Open Bank Project MCP Server</title>
360+
<meta name="viewport" content="width=device-width,initial-scale=1">
361+
<style>
362+
:root {{ color-scheme: light dark; }}
363+
body {{ font: 14px/1.5 -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, sans-serif;
364+
max-width: 900px; margin: 2rem auto; padding: 0 1rem; }}
365+
h1 {{ margin-bottom: 0; }}
366+
.sub {{ color: #888; font-size: 0.9em; margin-top: 0.25rem; }}
367+
section {{ margin: 1.5rem 0; padding: 1rem; border: 1px solid #8884; border-radius: 6px; }}
368+
section h2 {{ margin: 0 0 0.75rem; font-size: 1.1em; }}
369+
section h3 {{ margin: 1rem 0 0.5rem; font-size: 1em; }}
370+
pre {{ background: #8881; padding: 0.75rem; border-radius: 6px; overflow-x: auto;
371+
font-family: ui-monospace, SFMono-Regular, Menlo, monospace; font-size: 0.9em; }}
372+
code {{ font-family: ui-monospace, SFMono-Regular, Menlo, monospace; background: #8881;
373+
padding: 0.1em 0.3em; border-radius: 4px; }}
374+
pre code {{ background: none; padding: 0; }}
375+
.endpoint {{ font-size: 1.05em; }}
376+
ul {{ padding-left: 1.25rem; }}
377+
footer {{ margin: 2rem 0 1rem; color: #888; font-size: 0.85em; }}
378+
</style>
379+
</head>
380+
<body>
381+
<h1>Open Bank Project MCP Server</h1>
382+
<p class="sub">Model Context Protocol access to the Open Bank Project API</p>
383+
384+
<section>
385+
<h2>MCP endpoint</h2>
386+
<p class="endpoint"><code>{esc(mcp_url)}</code> (Streamable HTTP)</p>
387+
<p>{auth_note}</p>
388+
{obp_line}
389+
</section>
390+
391+
<section>
392+
<h2>Connect</h2>
393+
394+
<h3>Claude Code</h3>
395+
<pre><code>{esc(claude_code_cmd)}</code></pre>
396+
397+
<h3>Claude.ai / Claude Desktop (custom connector)</h3>
398+
<p>Add a custom connector in Settings &rarr; Connectors with the URL <code>{esc(mcp_url)}</code>.</p>
399+
400+
<h3>VS Code (<code>mcp.json</code>)</h3>
401+
<pre><code>{esc(vscode_json)}</code></pre>
402+
403+
<h3>Clients without native remote MCP support (via <code>mcp-remote</code>)</h3>
404+
<pre><code>{esc(mcp_remote_json)}</code></pre>
405+
</section>
406+
407+
<section>
408+
<h2>What you get</h2>
409+
<ul>
410+
<li><code>list_endpoints_by_tag</code> / <code>list_all_endpoint_tags</code> — discover OBP API endpoints by tag</li>
411+
<li><code>get_endpoint_schema</code> — full request/response schema for an endpoint</li>
412+
<li><code>call_obp_api</code> — execute calls against the OBP API</li>
413+
<li><code>list_glossary_terms</code> / <code>get_glossary_term</code> — 800+ banking and OBP glossary terms</li>
414+
</ul>
415+
</section>
416+
417+
<section>
418+
<h2>Diagnostics</h2>
419+
<ul>
420+
<li><a href="/status">Status page</a> — configuration, connectivity checks, index freshness (<a href="/status?format=json">JSON</a>)</li>
421+
<li><a href="/health">Health</a> — liveness probe</li>
422+
<li><a href="/ready">Ready</a> — readiness probe</li>
423+
</ul>
424+
</section>
425+
426+
<footer>
427+
<a href="https://github.com/OpenBankProject/OBP-MCP">OBP-MCP</a> ·
428+
<a href="https://www.openbankproject.com/">Open Bank Project</a>
429+
</footer>
430+
</body>
431+
</html>"""
432+
433+
434+
async def index_endpoint(request: Request) -> Response:
435+
"""Public index page: connectivity instructions and links to diagnostics."""
436+
return HTMLResponse(_render_index_html(request))
437+
438+
305439
async def health_endpoint(request: Request) -> Response:
306440
"""Liveness probe. Returns 200 as long as the process is serving HTTP.
307441
Makes no outbound calls and touches no indexes — safe to poll frequently.

0 commit comments

Comments
 (0)