Repository navigation
Commit 0efab5c
feat: Add standalone MCP server as a first-class component
* 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 <[email protected]>
* 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 <[email protected]>
* 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 <[email protected]>
* 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 <[email protected]>
* 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 <[email protected]>
* 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 <[email protected]>
* 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 <[email protected]>
* 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 <[email protected]>
---------
Signed-off-by: Chaitany Patel <[email protected]>1 parent 0ed3285 commit 0efab5c
66 files changed
Lines changed: 27843 additions & 16776 deletions
File tree
- docs
- reference/feature-servers
- examples
- feast_mcp_server
- kubernetes
- infra/feast-operator
- api/v1
- bundle/manifests
- config
- crd/bases
- samples
- dist
- docs/api/markdown
- internal/controller
- services
- test/api
- sdk/python
- feast
- cli
- mcp
- docker
- requirements
- tests
- integration/doctest
- unit/mcp
Some content is hidden
Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
176 | 176 | | |
177 | 177 | | |
178 | 178 | | |
| 179 | + | |
| 180 | + | |
| 181 | + | |
| 182 | + | |
| 183 | + | |
| 184 | + | |
| 185 | + | |
| 186 | + | |
179 | 187 | | |
180 | 188 | | |
181 | 189 | | |
| |||
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
61 | 61 | | |
62 | 62 | | |
63 | 63 | | |
| 64 | + | |
64 | 65 | | |
65 | 66 | | |
66 | 67 | | |
| |||
206 | 207 | | |
207 | 208 | | |
208 | 209 | | |
| 210 | + | |
209 | 211 | | |
210 | 212 | | |
211 | 213 | | |
| |||
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
16 | 16 | | |
17 | 17 | | |
18 | 18 | | |
19 | | - | |
| 19 | + | |
| 20 | + | |
| 21 | + | |
| 22 | + | |
| 23 | + | |
| 24 | + | |
| 25 | + | |
| 26 | + | |
| 27 | + | |
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
4 | 4 | | |
5 | 5 | | |
6 | 6 | | |
| 7 | + | |
| 8 | + | |
7 | 9 | | |
8 | 10 | | |
9 | 11 | | |
| |||
0 commit comments