FazBrowse GitHub Viewer | Trending |
URL:
| Home
Tools: [Download Repo ZIP]   [Original HTTPS Page]

feat: Add standalone MCP server as a first-class component by patelchaitany · Pull Request #6957 · feast-dev/feast · GitHub

Repository navigation

feat: Add standalone MCP server as a first-class component - #6957

Merged
ntkathole merged 2 commits into
feast-dev:masterfrom
patelchaitany:feat/standalone-mcp-server-upstream
Oct 7, 2026
Merged

ntkathole merged 2 commits into
feast-dev:masterfrom
patelchaitany:feat/standalone-mcp-server-upstream

Conversation

Copy link
Copy Markdown
Contributor

What this PR does / why we need it:

Adds feast mcp, a standalone Model Context Protocol server, and makes it a served component of the Feast operator.

feast mcp (Python SDK)

  • Runs in its own process and proxies to a running Feast deployment over HTTP. It holds no registry or online store of its own.
  • Mounts two sub-servers behind one MCP endpoint, each only when its upstream URL is configured:
    • features → the Python feature server (online features, vector search, push, materialization)
    • registry → the REST registry server (feature views, entities, data sources, lineage)
  • Settings resolve CLI > environment > feast_mcp.yaml > defaults.
  • Enforces no RBAC of its own: it forwards the caller's bearer token upstream and Feast applies its permission model. --auth-mode oidc additionally fronts an OIDC provider so IDE clients can complete a browser login.
  • Ships as a new mcp-server extra (fastmcp, httpx, python-dotenv), included in minimal so the feature-server image can run it. The feast mcp subcommand loads lazily, so commands like feast apply don't import FastMCP.

This is separate from feast serve with mcp_enabled: true, which mounts an OpenAPI-derived MCP endpoint inside the feature server itself.

Operator

  • spec.services.mcpServer adds a feast mcp container to the FeatureStore deployment, exposed on its own Service on port 8100. It shares the pod with the online and registry servers and reaches them over localhost.
  • The operator sets only --host and --port. Everything else comes from a feast_mcp.yaml in a ConfigMap, mounted read-only at /etc/feast/mcp.
  • A CEL rule requires at least one upstream: an online store that is present (or omitted) and not disabled, or registry.local.server.restAPI: true.
  • Readiness is reported on the McpServer status condition and the Service hostname on status.serviceHostnames.mcpServer.
  • Operator-managed TLS is not supported for this container yet; its tls field is ignored.

Dependency pins

  • fastmcp needs httpx>=0.28.1. The ci extra pinned httpx==0.27.2 because python-keycloak<4.7.3 passed the proxies argument that httpx 0.28 removed (python-keycloak#623). This raises python-keycloak to >=4.7.3,<5 and httpx to >=0.28.1.
  • virtualenv moves from ==20.23.0 to >=20.26,<21.
  • Python lockfiles are regenerated for the new extra.

Also included

  • Docs: docs/reference/feature-servers/mcp-server.md, linked from SUMMARY and the feature-servers index.
  • Example: examples/feast_mcp_server (local walkthrough and a Kubernetes example using the operator).
  • A feast-mcp container image Dockerfile and a test-python-unit-mcp Makefile target.
  • Unit tests for config resolution, token forwarding, upstream error handling, and every tool's upstream request; operator controller and CRD admission tests.

This was first merged downstream in opendatahub-io/feast (commit 98abb56) and is cherry-picked here.

Which issue(s) this PR fixes:

N/A

Checks

  • I've made sure the tests are passing.
  • My commits are signed off (git commit -s)
  • My PR title follows conventional commits format

Testing Strategy

  • Unit tests
  • Integration tests
  • Manual tests
  • Testing is not required for this change

Misc

patelchaitany requested a review from a team as a code owner October 6, 2026 10:39

codecov-commenter commented Oct 6, 2026 •
edited
Loading

Copy link
Copy Markdown

⚠️ Please install the to ensure uploads and comments are reliably processed by Codecov.

Codecov Report

❌ Patch coverage is 68.18182% with 175 lines in your changes missing coverage. Please review.
✅ Project coverage is 49.31%. Comparing base (0ed3285) to head (1870e37).

Files with missing lines Patch % Lines
sdk/python/feast/mcp/server.py 36.89% 64 Missing and 1 partial ⚠️
sdk/python/feast/mcp/logging_config.py 30.00% 61 Missing and 2 partials ⚠️
sdk/python/feast/cli/mcpServer.py 42.10% 22 Missing ⚠️
sdk/python/feast/mcp/auth.py 80.21% 16 Missing and 2 partials ⚠️
sdk/python/feast/mcp/client.py 92.68% 1 Missing and 2 partials ⚠️
sdk/python/feast/mcp/config.py 96.55% 2 Missing ⚠️
sdk/python/feast/mcp/features.py 96.72% 1 Missing and 1 partial ⚠️
❗ Your organization needs to install the Codecov GitHub app to enable full functionality.
Additional details and impacted files

@@            Coverage Diff             @@
##           master    #6957      +/-   ##
==========================================
+ Coverage   49.06%   49.31%   +0.25%     
==========================================
  Files         435      443       +8     
  Lines       54528    55078     +550     
  Branches     7954     8015      +61     
==========================================
+ Hits        26752    27161     +409     
- Misses      25898    26032     +134     
- Partials     1878     1885       +7     
Flag Coverage Δ
go-feature-server 30.58% <ø> (ø)
python-unit 50.70% <68.18%> (+0.25%) ⬆️
Files with missing lines Coverage Δ
sdk/python/feast/cli/cli.py 55.97% <100.00%> (+0.33%) ⬆️
sdk/python/feast/mcp/registry.py 100.00% <100.00%> (ø)
sdk/python/feast/mcp/config.py 96.55% <96.55%> (ø)
sdk/python/feast/mcp/features.py 96.72% <96.72%> (ø)
sdk/python/feast/mcp/client.py 92.68% <92.68%> (ø)
sdk/python/feast/mcp/auth.py 80.21% <80.21%> (ø)
sdk/python/feast/cli/mcpServer.py 42.10% <42.10%> (ø)
sdk/python/feast/mcp/logging_config.py 30.00% <30.00%> (ø)
sdk/python/feast/mcp/server.py 36.89% <36.89%> (ø)

... and 2 files with indirect coverage changes


Continue to review full report in Codecov by Harness.

Legend - Click here to learn more
Δ = absolute <relative> (impact), ø = not affected, ? = missing data
Powered by Codecov. Last update 0ed3285...1870e37. Read the comment docs.

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.
  • 📦 JS Bundle Analysis: Save yourself from yourself by tracking and limiting bundle sizes in JS merges.

@@ -0,0 +1,24 @@
# Container image for the standalone Feast MCP server (`feast mcp`).

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Choose a reason Spam Abuse Off Topic Outdated Duplicate Resolved Low Quality

can you please also raise a different PR or commit in same to add CI to push this image to quay.io ?

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

Choose a reason Spam Abuse Off Topic Outdated Duplicate Resolved Low Quality

Will raise different PR for adding the CI to push the image to quay.io

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

Choose a reason Spam Abuse Off Topic Outdated Duplicate Resolved Low Quality

Update: instead of a separate PR, I've added the CI change to this branch.

patelchaitany force-pushed the feat/standalone-mcp-server-upstream branch from d276fdd to 4d2223a Compare October 7, 2026 05:35
* feat: Add standalone feast mcp server

Adds `feast mcp`, a Model Context Protocol server that runs in its own
process and proxies to a running Feast deployment over HTTP. It holds no
registry or online store of its own; two sub-servers are mounted behind a
single MCP endpoint, each only when its upstream URL is configured:

- `features` -> the Python feature server (online features, vector search,
  push, materialization)
- `registry` -> the REST registry server (feature views, entities, data
  sources, lineage)

This is distinct from `feast serve` with `mcp_enabled: true`, which mounts
an OpenAPI-derived MCP endpoint inside the feature server itself.

Settings resolve CLI > environment > feast_mcp.yaml > defaults. The server
enforces no RBAC of its own: it forwards the caller's bearer token upstream
and lets Feast apply its permission model. `--auth-mode oidc` additionally
fronts an OIDC provider so IDE clients can complete a browser login.

The `feast mcp` subcommand resolves lazily so that FastMCP is not imported
by unrelated commands such as `feast apply`, and degrades to a clear error
when the optional `mcp-server` extra is absent.

Two CI pins had to move to make the dependency set solvable. fastmcp
requires httpx>=0.28.1, which the ci extra pinned down to 0.27.2 because
python-keycloak <4.7.3 passed the `proxies` argument httpx removed in 0.28
(python-keycloak#623); raising the python-keycloak floor to >=4.7.3 lifts
that constraint. virtualenv is unpinned from 20.23.0 to >=20.26,<21.

Signed-off-by: Chaitany Patel <patelchaitany93@gmail.com>

* feat: Add the MCP server as a served component in feast-operator

Setting `spec.services.mcpServer` adds a dedicated `feast mcp` container to
the FeatureStore deployment, exposed on its own Service on port 8100. The
container runs in the same pod as the online and registry servers, so it
reaches both over localhost.

The operator owns only `--host` and `--port`, so they always match the
generated Service. Everything else (transport, upstream URLs, auth,
observability) is read from a feast_mcp.yaml supplied in a ConfigMap and
mounted read-only at /etc/feast/mcp.

A CEL rule enforces that at least one upstream is actually available: either
onlineStore is present and not disabled, or registry.local.server.restAPI is
true. Readiness is reported on the McpServer status condition, and the
Service hostname on status.serviceHostnames.mcpServer.

Operator-managed TLS is not yet supported for this container; the `tls`
field is ignored.

Signed-off-by: Chaitany Patel <patelchaitany93@gmail.com>

* docs: Add standalone MCP server reference and example

Adds the reference page for `feast mcp`, covering the CLI options, the
feast_mcp.yaml schema and its environment equivalents, the available tools,
both auth modes, and deployment with the Feast Operator. Links it from
SUMMARY.md and the feature-servers index, and cross-references it from the
existing MCP feature server page so the two are not confused.

Adds examples/feast_mcp_server, an end-to-end walkthrough that starts a
local feature store, runs the MCP server against it, and calls its tools
from a client, plus the Kubernetes equivalent deployed by the operator.

Signed-off-by: Chaitany Patel <patelchaitany93@gmail.com>

* test: Add unit tests for the standalone feast mcp server

Covers the parts that are easy to get wrong and invisible until someone
else's deployment breaks:

- config resolution, asserting CLI > env > yaml > default one rung at a
  time, because a stray CLI default silently outranks feast_mcp.yaml
- token forwarding in both auth modes, including that a passthrough caller's
  bearer token still reaches Feast
- that upstream denials surface as MCP tool errors rather than being handed
  to the model as feature data
- a request matrix over every tool, asserting the upstream request each one
  builds and that optional arguments are omitted rather than sent as null

Adds the operator-side controller test for the mcpserver container, Service,
ConfigMap mount and status conditions.

Signed-off-by: Chaitany Patel <patelchaitany93@gmail.com>

* build: Relock Python requirements

Regenerates the locked requirement sets for all supported Python versions
so that the new `mcp-server` extra, and the dependency floors it forces,
are reflected in the lock files.

Signed-off-by: Chaitany Patel <patelchaitany93@gmail.com>

* build: Add the feast-mcp container image

Packages `feast mcp` as a container whose entrypoint is the server itself.
It is a thin wrapper over the feature-server image, which already installs
feast[minimal] and therefore everything the MCP server needs, so this only
sets the entrypoint and inherits the UBI base and the arbitrary-uid
permission setup.

BASE_IMAGE and BASE_TAG select the feature-server image to build on, so the
same Dockerfile serves a local build, a build against a published tag, and a
downstream rebuild from another repository.

TMPDIR is set to /dev/shm because Python needs a writable temp dir and the
usual candidates are all read-only under readOnlyRootFilesystem.

Also adds test-python-unit-mcp for iterating on the MCP server's tests
alone; they are already covered by test-python-unit.

Signed-off-by: Chaitany Patel <patelchaitany93@gmail.com>

* fix: Address review feedback on the standalone MCP server

- Treat an omitted onlineStore as available in the mcpServer CEL rule,
  matching the operator's default online feature server, and add
  admission tests for the omitted, disabled and REST-registry-only cases.
- Decode JSON text in the demo client's CallToolResult fallback so
  registry discovery works on older fastmcp versions.
- Describe the supported kubernetes auth mode in the example README and
  align the MCP docs, sample configs and API reference with the code.

Signed-off-by: Chaitany Patel <patelchaitany93@gmail.com>

* fix: Address review comments on the standalone MCP server

- Reject unknown auth modes instead of falling back to passthrough
- Percent-encode tool arguments used as URL path segments
- Log the socket peer IP instead of trusting X-Forwarded-For/X-Real-IP
- Build a fresh FastMCP instance per run and drop unused config helpers
- Default the operator-managed MCP transport to http when no config is given
- Reject an empty mcpServer.config.configMapRef.name at admission
- Require BASE_TAG for the feast-mcp image instead of defaulting to latest
- Keep the MCP API reference rows on one line and refresh the secrets baseline
- Only recurse into real packages in the doctest walker so feast.mcp does not collide with the mcp SDK

Signed-off-by: Chaitany Patel <patelchaitany93@gmail.com>

---------

Signed-off-by: Chaitany Patel <patelchaitany93@gmail.com>
patelchaitany force-pushed the feat/standalone-mcp-server-upstream branch from 5d3cb56 to 963d38a Compare October 7, 2026 06:55
The MCP server image had a Dockerfile but nothing to build or push it, so
the quay.io/feastdev/feast-mcp tags the docs reference were never produced.

Add build-feast-mcp-docker and push-feast-mcp-docker, and a release job
that runs them. The image wraps an already-published feature-server image,
so it cannot go in the existing matrix -- its base has to be pushed first.
BASE_TAG defaults to VERSION, and CI pins it to the version it just built.

Signed-off-by: Chaitany Patel <patelchaitany93@gmail.com>
ntkathole merged commit b9c65f1 into feast-dev:master Oct 7, 2026
31 checks passed
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters. Learn more about bidirectional Unicode characters
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants


Back | FazBrowse Home | New Git URL