Repository navigation
Add MCP server #153
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Add MCP server #153
Changes from 4 commits
d1b51a2
4324708
f465a43
21bfea2
71fcbd1
090a24b
5bd1855
b6f8dbe
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.
| Original file line number | Diff line number | Diff line change | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
|
|
@@ -7,6 +7,7 @@ | |||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| from fastapi import FastAPI, Request, HTTPException | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| from fastapi.responses import RedirectResponse, JSONResponse | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| from fastapi.staticfiles import StaticFiles | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| from fastapi_mcp import FastApiMCP | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| from starlette.middleware.sessions import SessionMiddleware | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| from starlette.middleware.base import BaseHTTPMiddleware | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
@@ -51,10 +52,9 @@ def create_app(): | |||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| "Text2SQL with " | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| "Graph-Powered Schema Understanding" | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| ), | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| ) | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| app.add_middleware(ProxyHeadersMiddleware, trusted_hosts="*") | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| ) | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| app.add_middleware(ProxyHeadersMiddleware, trusted_hosts="*") | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| # Add session middleware with explicit settings to ensure OAuth state persists | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| app.add_middleware( | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
@@ -81,9 +81,27 @@ def create_app(): | |||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| app.include_router(auth_router) | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| app.include_router(graphs_router, prefix="/graphs") | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| app.include_router(database_router) | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| # app.include_router(mcp_router, prefix="/mcp") | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| setup_oauth_handlers(app, app.state.oauth) | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| # Control MCP endpoints via environment variable DISABLE_MCP | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| # Default: MCP is enabled unless DISABLE_MCP is set to true | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| disable_mcp = os.getenv("DISABLE_MCP", "false").lower() in ("1", "true", "yes") | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| if disable_mcp: | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| logging.info("MCP endpoints disabled via DISABLE_MCP environment variable") | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| else: | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| mcp = FastApiMCP(app, | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| name="queryweaver", | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| description="QueryWeaver MCP API, provides Text2SQL capabilities", | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| include_operations=["list_databases", | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| "connect_database", | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| "database_schema", | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| "query_database"] | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| ) | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| mcp.mount_http() | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| @app.exception_handler(Exception) | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
Comment on lines
+88
to
105
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 💡 Verification agent 🧩 Analysis chainMount MCP under an explicit base path to match docs and avoid surprises. README points clients to /mcp, but mount_http() is called with no base path. Mount explicitly and keep docs consistent. - mcp.mount_http()
+ # Mount under explicit base path to match README and client examples
+ mcp.mount_http("/mcp")Also verify the operation_id strings exist on the registered routes. 🏁 Script executed: #!/bin/bash
# Verify operation_ids exist (expect 4 matches).
rg -nP 'operation_id\s*=\s*"(list_databases|connect_database|database_schema|query_database)"' -g 'api/**/*.py' -C1Length of output: 756 Mount MCP under explicit - mcp.mount_http()
+ mcp.mount_http("/mcp")Operation IDs for list_databases, connect_database, database_schema, and query_database are already present in api/routes (no changes needed). 📝 Committable suggestion
Suggested change
🤖 Prompt for AI Agents |
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| async def handle_oauth_error(request: Request, exc: Exception): | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| """Handle OAuth-related errors gracefully""" | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
💡 Verification agent
🧩 Analysis chain
Don't trust all proxies; fix ProxyHeadersMiddleware config.
Passing trusted_hosts="*" lets any upstream spoof X-Forwarded headers. Restrict to known proxies or make it configurable via env. Also pass a list, not a raw string.
If you actually need to trust all proxies in a controlled environment, make it explicit in .env (PROXY_TRUSTED_IPS=*), not hardcoded.
🏁 Script executed:
Length of output: 131
🏁 Script executed:
Length of output: 1041
🏁 Script executed:
Length of output: 2321
🏁 Script executed:
Length of output: 2827
🏁 Script executed:
Length of output: 3609
Restrict ProxyHeadersMiddleware’s trusted_hosts via env—remove hardcoded "*"
Replace the middleware call at api/app_factory.py:57:
If you truly need to trust all proxies, set
PROXY_TRUSTED_IPS="*"in your environment—don’t hardcode it.🤖 Prompt for AI Agents