Conversation
Signed-off-by: aaronzuo <[email protected]>
Signed-off-by: aaronzuo <[email protected]>
Signed-off-by: aaronzuo <[email protected]>
Signed-off-by: aaronzuo <[email protected]>
Signed-off-by: aaronzuo <[email protected]>
Signed-off-by: aaronzuo <[email protected]>
.github/workflows/unit_tests.yml
Outdated
| - name: Minimize uv cache | ||
| run: uv cache prune --ci | ||
|
|
||
| mcp-feature-server-runtime: |
There was a problem hiding this comment.
this should go in integration tests please
There was a problem hiding this comment.
Is it this one? .github/workflows/pr_integration_tests.yml
sdk/python/feast/ui_server.py
Outdated
| tls_key_path: str = "", | ||
| tls_cert_path: str = "", | ||
| ): | ||
| import uvicorn |
There was a problem hiding this comment.
why move this here?
There was a problem hiding this comment.
No need to import this if start_server is not called. But this is not essential. Will move it to the top.
franciscojavierarceo
left a comment
There was a problem hiding this comment.
overall this lgtm with two minor nits, thanks for doing this!
Signed-off-by: aaronzuo <[email protected]>
3ee0133 to
36f1bdf
Compare
|
Resolved your comments. @franciscojavierarceo |
Signed-off-by: aaronzuo <[email protected]>
|
@franciscojavierarceo Perhaps we can merge this one? |
franciscojavierarceo
left a comment
There was a problem hiding this comment.
this lgtm, let's wait for @YassinNouh21 to review
sdk/python/feast/feature_server.py
Outdated
| ) | ||
|
|
||
| mcp_transport_not_supported_error = McpTransportNotSupportedError | ||
| except Exception as e: |
There was a problem hiding this comment.
except Exception here catches SyntaxError, AttributeError, etc. — not just a missing package. Use except ImportError so real bugs in mcp_server.py are not silently swallowed. @franciscojavierarceo worth fixing before merge.
There was a problem hiding this comment.
| # Mount the MCP server to the FastAPI app | ||
| mcp.mount() | ||
| transport: Literal["sse", "http"] = ( | ||
| getattr(config, "mcp_transport", "sse") or "sse" |
There was a problem hiding this comment.
or "sse" handles None but mcp_transport is now Literal["sse", "http"] so None is impossible. Can simplify to getattr(config, "mcp_transport", "sse").
| if mount_sse is not None: | ||
| mount_sse() | ||
| else: | ||
| mcp.mount() |
There was a problem hiding this comment.
Silent fallback to the deprecated mount() with no warning. Operator configured mcp_transport: sse but gets legacy behavior with no indication. Worth a logger.warning here.
| else: | ||
| mcp.mount() | ||
| else: | ||
| raise McpTransportNotSupportedError( |
There was a problem hiding this comment.
This branch is unreachable — Literal["sse", "http"] in the config rejects anything else at parse time. Either remove it or add a comment that it's a defensive guard for programmatic callers.
| except McpTransportNotSupportedError: | ||
| raise | ||
| except Exception as e: | ||
| logger.error(f"Failed to initialize MCP integration: {e}") |
There was a problem hiding this comment.
Missing exc_info=True — loses the traceback. Without it, debugging a broken init means guessing from just the exception message string.
| -H "Content-Type: application/json" \ | ||
| -H "mcp-protocol-version: 2025-03-26" \ | ||
| --data '{}' \ | ||
| http://127.0.0.1:6566/mcp || true |
There was a problem hiding this comment.
|| true swallows connection failures. If the server crashed or is unreachable, curl exits non-zero but the step continues and later grep on a missing/empty file gives a confusing error. Remove || true and let curl fail the step directly.
| SERVER_PID=$! | ||
| echo $SERVER_PID > /tmp/feast_server_pid | ||
| for i in $(seq 1 60); do | ||
| if curl -fsS http://127.0.0.1:6566/health >/dev/null; then |
There was a problem hiding this comment.
If the server crashes immediately after backgrounding, this loop burns 60 seconds before failing. Add kill -0 "$SERVER_PID" || { echo "server died"; exit 1; } at the top of the loop body.
There was a problem hiding this comment.
Signed-off-by: aaronzuo <[email protected]>
7d4360c to
0c897c6
Compare
Signed-off-by: aaronzuo <[email protected]>
|
Addressed all of the reviews. Waiting for CI to go green. |
Signed-off-by: aaronzuo <[email protected]>
|
@franciscojavierarceo @YassinNouh21 It's green now. |
|
@franciscojavierarceo @YassinNouh21 gentle ping |
What this PR does / why we need it:
This PR adds first-class support for Streamable HTTP MCP transport in the Feast Python Feature Server to address reliability issues with the legacy SSE-based MCP endpoint and eliminate the need for external proxies in common MCP clients.
Key changes:
Adds mcp_transport configuration for MCP feature server ( sse | http ), defaulting to sse for backwards compatibility.
When mcp_transport=http , mounts MCP using Streamable HTTP via FastApiMCP.mount_http() .
When mcp_transport=sse , preserves existing behavior, preferring mount_sse() when available (fallback to deprecated mount() for older fastapi_mcp versions).
Fails fast with a clear error when mcp_transport=http is configured but the installed fastapi_mcp version does not support mount_http() .
Adds/updates unit + integration tests covering transport selection and failure modes.
Updates docs and example configuration to show how to enable Streamable HTTP and avoid the GET /mcp 406 by using the correct Accept header.
Touched areas:
MCP config + mounting logic: mcp_config.py , mcp_server.py , feature_server.py
Tests: test_mcp_server.py , test_mcp_feature_server.py
Docs/examples: genai.md , mcp-feature-server.md , feature_store.yaml
Which issue(s) this PR fixes:
Fixes #5853.
Misc
Tests run locally:
pytest sdk/python/tests/unit/infra/feature_servers/test_mcp_server.py
pytest sdk/python/tests/integration/test_mcp_feature_server.py
Notes:
Default remains mcp_transport: sse to avoid behavior changes for existing deployments.
For Streamable HTTP, a plain GET /mcp may return 406 unless the client includes Accept: text/event-stream (expected by the transport).