Skip to content

feat: Support HTTP in MCP#6109

Open
Anarion-zuo wants to merge 11 commits intofeast-dev:masterfrom
Anarion-zuo:aaronzuo/mcp_http_config
Open

feat: Support HTTP in MCP#6109
Anarion-zuo wants to merge 11 commits intofeast-dev:masterfrom
Anarion-zuo:aaronzuo/mcp_http_config

Conversation

@Anarion-zuo
Copy link
Contributor

@Anarion-zuo Anarion-zuo commented Mar 15, 2026

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).


Open with Devin

@Anarion-zuo Anarion-zuo requested a review from a team as a code owner March 15, 2026 13:07
Signed-off-by: aaronzuo <[email protected]>
Copy link
Contributor

@devin-ai-integration devin-ai-integration bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

✅ Devin Review: No Issues Found

Devin Review analyzed this PR and found no potential bugs to report.

View in Devin Review to see 3 additional findings.

Open in Devin Review

Signed-off-by: aaronzuo <[email protected]>
Signed-off-by: aaronzuo <[email protected]>
Signed-off-by: aaronzuo <[email protected]>
Signed-off-by: aaronzuo <[email protected]>
- name: Minimize uv cache
run: uv cache prune --ci

mcp-feature-server-runtime:

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

this should go in integration tests please

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is it this one? .github/workflows/pr_integration_tests.yml

tls_key_path: str = "",
tls_cert_path: str = "",
):
import uvicorn

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

why move this here?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

No need to import this if start_server is not called. But this is not essential. Will move it to the top.

Copy link
Member

@franciscojavierarceo franciscojavierarceo left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

overall this lgtm with two minor nits, thanks for doing this!

Signed-off-by: aaronzuo <[email protected]>
@Anarion-zuo Anarion-zuo force-pushed the aaronzuo/mcp_http_config branch from 3ee0133 to 36f1bdf Compare March 17, 2026 08:24
@Anarion-zuo
Copy link
Contributor Author

Resolved your comments. @franciscojavierarceo

devin-ai-integration[bot]

This comment was marked as resolved.

Signed-off-by: aaronzuo <[email protected]>
@Anarion-zuo
Copy link
Contributor Author

@franciscojavierarceo Perhaps we can merge this one?

Copy link
Member

@franciscojavierarceo franciscojavierarceo left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

this lgtm, let's wait for @YassinNouh21 to review

)

mcp_transport_not_supported_error = McpTransportNotSupportedError
except Exception as e:
Copy link
Collaborator

@YassinNouh21 YassinNouh21 Mar 17, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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.

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

# Mount the MCP server to the FastAPI app
mcp.mount()
transport: Literal["sse", "http"] = (
getattr(config, "mcp_transport", "sse") or "sse"
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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()
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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(
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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.

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@Anarion-zuo u didn't solve it btw :)

except McpTransportNotSupportedError:
raise
except Exception as e:
logger.error(f"Failed to initialize MCP integration: {e}")
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

|| 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
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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.

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Signed-off-by: aaronzuo <[email protected]>
@Anarion-zuo Anarion-zuo force-pushed the aaronzuo/mcp_http_config branch from 7d4360c to 0c897c6 Compare March 17, 2026 15:38
devin-ai-integration[bot]

This comment was marked as resolved.

Signed-off-by: aaronzuo <[email protected]>
@Anarion-zuo
Copy link
Contributor Author

Addressed all of the reviews. Waiting for CI to go green.

Signed-off-by: aaronzuo <[email protected]>
@Anarion-zuo
Copy link
Contributor Author

@franciscojavierarceo @YassinNouh21 It's green now.

@Anarion-zuo
Copy link
Contributor Author

@franciscojavierarceo @YassinNouh21 gentle ping

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Support Streamable HTTP transport for Feature Server MCP integration

3 participants