Add RFC 0004: MCP Registry#12
Conversation
f96cc0e to
564fe4d
Compare
There was a problem hiding this comment.
Pull request overview
This PR adds RFC 0004 proposing an MLflow-native “MCP Registry” design aligned with the upstream Model Context Protocol registry spec, including a proposed data model, API surface, and a reference database migration.
Changes:
- Adds an RFC document describing entities, lifecycle, schema, store interfaces, REST API, SDK, CLI, UI, and trace linking.
- Adds a reference Alembic migration that creates the proposed MCP registry tables and index.
Reviewed changes
Copilot reviewed 2 out of 4 changed files in this pull request and generated 2 comments.
| File | Description |
|---|---|
rfcs/0004-mcp-registry/0004-mcp-registry.md |
Full design RFC for the MCP Registry feature (schema, APIs, SDK/CLI, UI, trace linking, adoption plan). |
rfcs/0004-mcp-registry/alembic-migration.py |
Reference Alembic migration implementing the proposed schema (tables for servers, versions, tags, aliases). |
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
| # Register an MCP server from a server.json payload. | ||
| # name and version are extracted from server_json. | ||
| # The parent MCPServer is auto-created if it doesn't exist. | ||
| version = mlflow.genai.register_mcp_server( |
There was a problem hiding this comment.
It is a bit unclear to me when users should create a new version. Usually the actual server implementationis managed on github, and if it is distributed as a public package, it has a package version. Also if the server is hosted somewhere, the runtime has deployment version. Does the version defined in MLflow strictly ties to any of these, or adding a new semantic versioning on top of them?
There was a problem hiding this comment.
The stored version is the canonical server_json["version"] provided by the publisher, not an additional MLflow specific version. Deployment or runtime revisions belong in mutable runtime_metadata. Users register a new version when the canonical server definition changes, and update runtime_metadata when only the deployment of that server definition changes.`
|
|
||
| ### Out of scope | ||
|
|
||
| - **Runtime hosting or deployment** — The registry stores metadata, not runtimes. Deployment is handled by external operators |
There was a problem hiding this comment.
While the separation of registry and runtime makes sense from system perspective, the actual use case always requires some sort of runtime, which can influence the design of the registry data model.
- Local (e.g. install local mcp server to coding agent)
- MLflow MCP Gateway
- Other hosted services
Did you assume one or multiple of these runtime options as a downstream use case?
There was a problem hiding this comment.
The design intentionally assumes multiple downstream runtime models and aims to be runtime-agnostic. In other words, the same registry entry should be usable by local agent installs, an MLflow MCP Gateway, or other hosted runtimes. Optional deployment-association fields such as runtime_metadata and is_deployed support deployment discovery within an organization, while remaining intentionally unopinionated about runtime-specific details.
|
|
||
| MCP server usage is linked to traces following the same pattern as prompt registry linking. When a registered MCP server is resolved within an active trace, the registry records the association so that traces carry a record of which MCP servers were involved. | ||
|
|
||
| **Tag and attribute**: Traces carry an `mlflow.linkedMcpServers` tag containing a JSON array of `{name, version}` entries — the same format as `mlflow.linkedPrompts`: |
There was a problem hiding this comment.
Is there any potential benefit of supporting bi-directional linking (i.e. search traces that uses a particular mcp server version)? If yes, we can use EntityAssociationTable rather than trace tags.
There was a problem hiding this comment.
Yes, I think that's a good idea!
| - Trace which MCP servers are used by which agents or workflows | ||
| - Provide downstream systems (catalogs, gateways, agent frameworks) with a governed source of truth | ||
|
|
||
| ### Use cases |
There was a problem hiding this comment.
How end-users should connect to the server? One option is not go through the registry at all and simply let them specify to the downstream runtime URL. However, this option does not resolve usage control and tracing problem. To achieve that, end users should access MCP servers using MLflow's name and version. However, it is more like discovery problem (like DNS) or a gateway layer, so the current pure registry scope might not be sufficient for addressing some of these problems.
There was a problem hiding this comment.
Good point. This RFC is intended to cover the registry/discovery layer, not a gateway/proxy layer, so it does not by itself solve end-user connectivity or enforce usage control for arbitrary direct access.
The RFC's expectation is that MLflow-aware clients/runtimes resolve an MCP server via MLflow by name + version (or alias), then use deployment-specific information from runtime_metadata and server_json to connect. Trace linking follows the same assumption: it works when resolution happens through MLflow or when the runtime/server explicitly links {name, version} back to MLflow. A consumer can obviously bypass MLflow though.
The RFC should make that boundary clearer and better connect it to the future gateway integration story. I also think we should document a small set of recommended runtime_metadata conventions, such as endpoint_url, without making the field prescriptive. If/when the MLflow AI Gateway expands to be an MCP Gateway, it could reuse these runtime_metadata fields to steer users to the gateway to link trace data.
|
|
||
| ### The problem | ||
|
|
||
| As MCP adoption grows, organizations accumulate MCP server definitions across teams and environments. Today, MLflow has no way to govern them. There is no single place to: |
There was a problem hiding this comment.
Can we list unique values of using MLflow registry over the Github's public registry? It appears to be basically a private registry (analogy of private pypi/npm index), with a few extra features such as lifecycle labeling and usage tracking, is my understanding correct?
There was a problem hiding this comment.
The MLflow MCP Registry is not trying to replace the upstream/public registry, but to provide an MLflow-native governed registry for enterprise use cases.
Relative to a public GitHub-hosted registry, the main added value here is:
- workspace-scoped governance and permissions within MLflow
- lifecycle state management for versions (
active/deprecated/deleted) - stable aliases for resolution (for example,
production) - association of governed MCP definitions with deployment-specific metadata via
runtime_metadata - MLflow-native trace linking / observability when clients or runtimes resolve MCP servers through MLflow-aware flows
- future integration with other MLflow components such as the AI Gateway
So I would describe it more as a governed enterprise registry that reuses the upstream MCP metadata model, while adding MLflow-specific management and integration capabilities.
I'll update the RFC with this distinction.
There was a problem hiding this comment.
I agree that the workspace and permission management are missing in the official mcp registry (btw the official registry supports lifecycle management and versioning).
For alias, can we describe the use cases where alias is useful, since usually only the latest version can be available, and it's not clear how users use different MCP server versions based on the stage (dev, stg, prd).
For tracing, users should be able to track the MCP server info on traces as long as tracing is enabled for the client. What challenge do users have when tracing their agent's mcp usage without using MLflow MCP registry?
There was a problem hiding this comment.
I addressed this in the last commit I pushed. Please take a look!
There was a problem hiding this comment.
This is intended to complement, not replace, the public GitHub-hosted MCP registry.
I think this can be a great point of confusion, since on the surface there's some overlapping elements and terminologies. A brief note about how these would complement each other would be beneficial.
As a user I will want to know how I should use these two in my workflow.
|
@B-Step62 I addressed your comments in the latest commit, please take a look! |
There was a problem hiding this comment.
Pull request overview
Copilot reviewed 2 out of 4 changed files in this pull request and generated 9 comments.
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
There was a problem hiding this comment.
Pull request overview
Copilot reviewed 1 out of 3 changed files in this pull request and generated 4 comments.
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
| mlflow mcp-servers register --server-json-file server.json | ||
|
|
||
| # List active servers | ||
| mlflow mcp-servers search --filter "status = 'active'" |
There was a problem hiding this comment.
When/how is the server status modified? Also does it return servers, or versions?
There was a problem hiding this comment.
Status lives on versions, not servers (there's no status column on mcp_servers). Server status is derived from the latest server version at query time. Filtering search_mcp_servers by status should be feasible using a subquery + JOIN pattern similar to how MLflow model registry does it for tag filters on search_model_versions (tags live in SqlModelVersionTag, resolved via subquery join).
Maybe I can update the doc to make it clearer, and to highlight difference between these two:
mlflow mcp-servers search --filter "status = 'active'" # get server (uses subquery)
mlflow mcp-server-versions search --filter "status = 'active'" # get server version (simpler query internally)
|
|
||
| - Record which MCP servers exist and what state they are in | ||
| - Version MCP server definitions as they evolve | ||
| - Control which MCP servers are eligible for consumption by AI engineers |
There was a problem hiding this comment.
nit: users should be able to configure which mcp server are available for which end user/agent
There was a problem hiding this comment.
Is this clearer:
- Control which MCP servers are available to specific users, teams, or agents
Let me know if I've missed what you're getting at :)
| aliases: list[str] = field(default_factory=list) # read-only; alias names from parent mcp_server_aliases rows currently pointing at this version | ||
| tags: dict[str, str] = field(default_factory=dict) | ||
| source: str | None = None # provenance URI (e.g., git repository URL) | ||
| run_id: str | None = None # optional MLflow run association |
There was a problem hiding this comment.
how is this used/stored?
There was a problem hiding this comment.
This was for linking to experiment runs, but probably isn't as relevant here as for model registry.
I'm removing this.
| The store interface is implemented as a mixin class (`MCPServerRegistryMixin`) that the model registry's `AbstractStore` inherits from. This follows the same pattern used by `GatewayStoreMixin` on the tracking store — MCP server registry code lives in its own files while composing into the existing store hierarchy via multiple inheritance. | ||
|
|
||
| ``` | ||
| mlflow/store/model_registry/mcp_server_registry/ |
There was a problem hiding this comment.
Why do we want to define this mixin as part of model_registry?
There was a problem hiding this comment.
The idea was to follow the same pattern as GatewayStoreMixin on the tracking store, but this is closer in function to model registry, so it could share the model registry AbstractStore for simplicity. That said, a standalone store (e.g. mlflow/store/mcp_registry/) would also work, but it would require more work. (Or we could use tracking store instead of model registry store)
There was a problem hiding this comment.
Since mcp gateway is closer to llm gateway and we have ai gateway resources in the tracking store, I think we should use tracking store
There was a problem hiding this comment.
I updated the RFC to place the MCP registry mixin under the tracking store, following the same composition pattern as the gateway code rather than the model registry store.
|
|
||
| # Summary | ||
|
|
||
| Add an MCP Registry to MLflow — a governed, versioned registry for [Model Context Protocol](https://modelcontextprotocol.io/) (MCP) server definitions. The registry stores metadata-first records aligned with the [upstream MCP registry specification](https://registry.modelcontextprotocol.io/docs), providing stable identity, versioning, status lifecycle, workspace-scoped governance, and MLflow-native integrations for MCP server assets. This is intended to complement, not replace, the public GitHub-hosted MCP registry, adding workspace governance, stable aliases, deployment association, and traceability for MLflow-aware runtimes. |
There was a problem hiding this comment.
First of all, can we clarify the difference between MCP Registry and the MCP gateway (e.g., portkey), and why we want to introduce the MCP registry? We will certainly add MCP gateway as that's a clear tablestake as an ai gateway product, and I wonder if gateway and registry are two distinct features, or can be unified. If these are separate concepts, I need to think carefully about the potential confusions that users may have when seeing MCP gateway and registry in the same platform.
There was a problem hiding this comment.
Good point. I updated the RFC to make the registry vs. gateway split more explicit.
Short version: this RFC is for the registry/control-plane piece, not the MCP gateway/runtime piece. The registry is the governed source of truth for canonical MCP server definitions, version history, aliases, and approved deployment locations. That gives us enterprise governance and historical records that a gateway alone would not provide.
A future MCP gateway in MLflow AI Gateway would then consume those governed records for live MCP traffic, while the registry continues to provide the canonical identity/history behind what the gateway is serving. That also improves traceability, since gateway-produced traces can be linked back to the governed MCP server/version records rather than only to a live endpoint.
I added more detail in Summary, Registry vs. Gateway, and MCPHostedBinding.
| ### Out of scope | ||
|
|
||
| - **Runtime execution and orchestration** — The registry may store deployment metadata, but it does not provision, host, scale, or manage MCP runtimes | ||
| - **End-user connectivity, proxying, or usage control enforcement** — Consumers can still connect directly to an MCP endpoint unless a future MLflow gateway or proxy mediates access |
There was a problem hiding this comment.
Note - If we will provide MCP gateway, this is an essential feature
There was a problem hiding this comment.
Agreed. The RFC now makes that boundary clearer: it does not design the MCP gateway itself, but it does shape the registry so it can integrate cleanly with a future MCP gateway in MLflow AI Gateway.
The main value the registry adds beyond the gateway is governed historical state: canonical definitions, version/alias history, and approved deployment locations. That gives us enterprise governance and a better source of truth for linking gateway output traces back to the MCP server/version that was actually in use. See Summary, Registry vs. Gateway, and MCPHostedBinding sections for more details.
There was a problem hiding this comment.
Pull request overview
Copilot reviewed 1 out of 3 changed files in this pull request and generated no new comments.
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
| The MCP Registry and an MCP Gateway are related but distinct capabilities: | ||
|
|
||
| - **MCP Registry**: the control-plane system of record for governed MCP assets. It stores canonical `server_json`, version history, aliases, tags, lifecycle state, and hosted binding records that describe approved live connection paths. | ||
| - **MCP Gateway**: a runtime data-plane service that receives live client traffic and mediates connectivity, authentication, routing, policy enforcement, and request-time observability. |
There was a problem hiding this comment.
MCP gateway still needs to store a list of MCP server configurations, so there are some overlaps. I think the relationship is probably MCP gateway = subset of MCP registry capabilities + runtime proxy, authentication, observability. Can we clarify this overlap and how we plan to unify them?
There was a problem hiding this comment.
Could you please check if the last commit addresses this the way you expected?
| - **MCP Registry**: the control-plane system of record for governed MCP assets. It stores canonical `server_json`, version history, aliases, tags, lifecycle state, and hosted binding records that describe approved live connection paths. | ||
| - **MCP Gateway**: a runtime data-plane service that receives live client traffic and mediates connectivity, authentication, routing, policy enforcement, and request-time observability. | ||
|
|
||
| This RFC proposes the former, not the latter. It does **not** design an MLflow MCP Gateway, extend the existing AI Gateway into an MCP Gateway, or define MCP proxy semantics. Instead, it ensures the registry can support that future integration cleanly by storing governed MCP server identities, aliases, and hosted bindings that a future gateway could resolve to concrete `{name, version}` records for connectivity and trace association. |
There was a problem hiding this comment.
nit: Can we rephrase a bit so that it's clear that MCP gateway will be built on top of the registry layer described in this RFC?
There was a problem hiding this comment.
Addressed in the last commit.
|
|
||
| - **Endpoint mapping**: all 7 upstream endpoints (`GET /v0.1/servers`, `POST /v0.1/publish`, etc.) map directly to existing MLflow store methods — no store changes needed | ||
| - **Response translation**: wrap MLflow entities in the upstream `{servers: [{server, _meta}]}` envelope, with MLflow-specific metadata (tags, aliases, workspace) in a custom `_meta` namespace (e.g., `org.mlflow`) | ||
| - **Status mapping**: MLflow uses upstream status values (`active`/`deprecated`/`deleted`) directly. MLflow's `deleted` is a soft delete — records are preserved for history |
There was a problem hiding this comment.
How does mlflow update status? When a new version is registered, do we deprecate the older version?
There was a problem hiding this comment.
I updated the RFC to make it explicit that status changes are admin actions; there is no MLflow automation that deprecates older versions when a new version is registered.
| binding_type: MCPHostedBindingType = MCPHostedBindingType.REMOTE | ||
| endpoint_url: str | None = None # required for remote bindings | ||
| # Future extension for mlflow_gateway bindings: | ||
| # gateway_endpoint_name: str | None = None |
There was a problem hiding this comment.
nit: I guess we'll just expose one endpoint following the MCP convention, so this is probably not needed
| endpoint_url: str | None = None # required for remote bindings | ||
| # Future extension for mlflow_gateway bindings: | ||
| # gateway_endpoint_name: str | None = None | ||
| is_active: bool = True # allows a binding to be disabled without deleting its record/history |
There was a problem hiding this comment.
So in our model, the activeness is controlled per server instead of the tools?
| MCPServer ||--o{ MCPServerTag : "has tags" | ||
| MCPServer ||--o{ MCPServerAlias : "has aliases" | ||
| MCPServerVersion ||--o{ MCPServerVersionTag : "has tags" | ||
| MCPServer ||--o{ MCPHostedBinding : "has hosted bindings" |
There was a problem hiding this comment.
When does one MCPServer have multiple MCPHostedBindings? I thought usually only a version is available per the http MCP server - otherwise it's not clear for clients where to connect to access a specific tool.
|
|
||
|
|
||
| @dataclass(frozen=True) | ||
| class MCPHostedBindingTag: |
There was a problem hiding this comment.
How is this tag expected to be used? Isn't MCPServerTag and MCPServerVersionTag enough?
There was a problem hiding this comment.
I removed binding-scoped tags from the MVP to keep the model leaner.
| | `GET` | `/{name}/versions/{version}` | Get a specific version | | ||
| | `PATCH` | `/{name}/versions/{version}` | Update version (status, display name) | | ||
| | `DELETE` | `/{name}/versions/{version}` | Delete a version | | ||
| | `POST` | `/{name}/bindings` | Create a hosted binding | |
There was a problem hiding this comment.
So, in order to make a specific server version available, do users need to create a version and then create a binding separately? How does the e2e user journey look like?
|
|
||
| MLflow stores the publisher-declared `server_json["version"]` as the canonical version of a server definition. It does not introduce a second MLflow-specific version. Hosted connectivity, when present, is represented by separate `MCPHostedBinding` records rather than mutable runtime metadata on the version itself. | ||
|
|
||
| # Basic example |
There was a problem hiding this comment.
Instead of listing the basic usage of each API (which can come in "Detailed design") , can we describe an end-to-end primary user journey? I imagine the flow would be something like this?
- User registers a new MCP server
- User creates a binding for the server definition
- User's agent calls
search_mcp_hosted_bindingsto find all available/approved MCP servers - User's agent invokes the remote http MCP server directly
| # version.version == "1.0.0" (extracted from server_json) | ||
| # version.name == "io.github.anthropic/brave-search" (extracted from server_json) | ||
|
|
||
| # Set an alias for stable resolution |
There was a problem hiding this comment.
Btw, how confident are we on the alias requirement? I feel the fact that the official MCP doesn't support this feature implies that not many users want to use alias for the MCP servers.
There was a problem hiding this comment.
The upstream MCP registry specification's primary focus is on canonical publisher metadata. The RFC is adding enterprise control-plan features on top of that. In this case the RFC wants to add support for deployment promotion and stable operational pointers. In those workflows, aliases like production and staging are useful because they provide stable names that can move between versions without requiring clients to change.
@mprahl maybe the RFC would benefit from a speific user journey outlining this use case.
|
|
||
| ```python | ||
| # Record a remote hosted entrypoint for the production alias. | ||
| binding = mlflow.genai.create_mcp_hosted_binding( |
There was a problem hiding this comment.
When should users use search_mcp_servers vs search_mcp_hosted_bindings? For example, if I want to list all MCP servers I can give access to my agent, should I use search_mcp_hosted_bindings?
|
|
||
| **Typed payload**: The `server_json` field uses `dict` in the entity and store layers for simplicity. At the API layer, the `CreateMCPServerVersionRequest` uses a `ServerJSONPayload` Pydantic model (with `extra="allow"`) that validates the payload on ingestion and extracts typed fields. See [server_json validation](#server_json-validation). | ||
|
|
||
| #### MCPHostedBinding and MCPHostedBindingTag |
There was a problem hiding this comment.
I'm not following how this entire "hosted binding" works. Whether the entry point is reached directly or through the MCP gateway is a client concern, and I'm not sure if the approved connectivity needs to be modeled and tracked in this way. For example, what's the use case of allowing direct access to some MCP servers while forcing clients to use MCP gateway for others?
There was a problem hiding this comment.
I think part of the confusion may stem from the fact that MLflow does not currently expose a generic “endpoint” abstraction that can be either direct or gateway-backed. Because of this, introducing binding_type makes the RFC feel like it is creating a new endpoint model just for MCP, whereas in existing MLflow flows endpoints are implicitly associated with gateway behavior.
There was a problem hiding this comment.
I agreed the old framing was mixing direct and gateway access too much, so I simplified it. Phase 1 now only defines MCPAccessBinding for approved direct, non-gateway access paths; future gateway-managed deployment records are intentionally out of scope here and would be owned by the gateway itself. The remaining reason to keep MCPAccessBinding is to model enterprise-approved direct endpoints separately from publisher server_json metadata.
| # version.version == "1.0.0" (extracted from server_json) | ||
| # version.name == "io.github.anthropic/brave-search" (extracted from server_json) | ||
|
|
||
| # Set an alias for stable resolution |
There was a problem hiding this comment.
It's implied via the schema alias' are unique by workspace, but it's worth mentioning explicitly.
| endpoint_url="https://mcp.acme.internal/brave-search", | ||
| ) | ||
|
|
||
| # binding.is_active == True |
There was a problem hiding this comment.
Given that we have version.status == "active", this could overload the term "active", I think something like binding.enabled or binding.is_enabled feels more intuitive.
| name: str # parent MCPServer name | ||
| version: str | None = None # exactly one of version / alias must be set | ||
| alias: str | None = None | ||
| binding_type: MCPHostedBindingType = MCPHostedBindingType.REMOTE |
There was a problem hiding this comment.
I feel like binding_type to indicate the type of endpoint is not very intuitive, my preference is something like route_type.
Also it's worth pointing out that mlflow in other areas just automatically detects gateway traffic (e.g. gateway_timing_middleware).
I think it's kind of nice that the user doesn't have to think about what sort of binding_type this is. Because the admin would typically hand the user the endpoint, and the user doesn't really care if it's through the gateway or if it's a direct line to the mcp server.
There was a problem hiding this comment.
I simplified this further and removed binding_type from Phase 1 entirely. The RFC now uses MCPAccessBinding only for approved direct-access records, and future gateway-managed entities are explicitly out of scope here.
|
|
||
| ### Use cases | ||
|
|
||
| 1. **Governed registration**: Platform administrators register MCP server definitions (both internally developed packages and hosted remote endpoints) as governed, versioned assets with stable identity |
There was a problem hiding this comment.
I agree in principle but I don't think the current permission model supports this. The current design seems to be "each workspace has it's own list of registered mcp servers", and that workspace owners are the ones that would register servers. Workspace owners are not necessarily platform administrators.
Workspace plugins could potentially work around this to enforce this model though.
There was a problem hiding this comment.
This is a known gap in MLflow's workspace model. I think a true global workspace should be solved separately; for now admins can approximate that by granting access across selected workspaces.
| name: str # extracted from server_json; reverse-DNS format (e.g., "io.github.user/server"); PK within workspace | ||
| display_name: str | None = None # mutable human-readable label; falls back to server_json["title"], then name | ||
| description: str | None = None | ||
| workspace: str | None = None # resolved via resolve_entity_workspace_name() |
There was a problem hiding this comment.
On the one hand, I think it would be nice if there was just a single registry mlflow-wide that enterprises would register all their mcp servers to. Rather then each workspace having different servers.
This way an organization could tell it's members "go here for a list of all the mcp servers available for use", instead of "go here, to this workspace to find xyz mcp servers".
On the other hand, having them be workspace scoped is nice for organized tracing, evaluations, and so on.
Wondering if you have given this some consideration.
There was a problem hiding this comment.
Phase 1 intentionally stays workspace-scoped. I agree a more global discovery story is a known gap, but I think that should be solved separately from this RFC; for now admins can grant access across selected workspaces as a workaround.
There was a problem hiding this comment.
I agree with @HumairAK about the benefit of cross-workspace registry (and agree with @mprahl on the scope of this RFC). It has come up from users for other resources like trace monitoring ("can I monitor llm cost across workspaces somewhere?"). Technically it wouldn't be too complex given the workspace boundary is a thin logical isolation? It'd be great if we can address this as a platform later.
| last_registered_version: str | None = None # read-only; most recently created version string (fallback when latest_version_alias is unset) | ||
| is_deployed: bool = False # read-only; derived at query time (True if any version has an active hosted binding) | ||
| created_by: str | None = None | ||
| last_updated_by: str | None = None |
There was a problem hiding this comment.
Where does this value come from for these entities? I asked gpt about it and it seems for different pre-existing entities in MLflow that carry similar fields it can vary:
- authenticated request principal
- caller-provided freeform metadata
- MLflow context-derived username
|
|
||
| #### Future entity: MCPObservedTool (deferred) | ||
|
|
||
| A future enhancement may introduce `MCPObservedTool` and `MCPObservedToolSnapshot` entities to cache tool metadata observed from live MCP endpoints. These would store tool names, descriptions, and input schemas discovered by probing running servers — separate from the canonical `server_json` payload. This is out of scope for the initial implementation but the data model is designed to accommodate it. |
There was a problem hiding this comment.
There's also prompts, which also have a _meta field, that probably paves a path for mlflow-aware mcp servers to provide integrations with prompts in Mlflow, which could prove useful.
There was a problem hiding this comment.
Good idea, but let's punt on this one for now.
|
|
||
| **JSON columns**: `server_json` uses SQLAlchemy's `JSON` type (with `mssql.JSON` for SQL Server), following the pattern established by MLflow's evaluation dataset records and span dimension attributes. This maps to native `JSON` on PostgreSQL and MySQL (with database-level validation on write), and to `NVARCHAR(MAX)` / `TEXT` on MSSQL and SQLite. | ||
|
|
||
| **Workspace handling**: All tables are workspace-scoped. Server-scoped tables use `(workspace, name)` as their leading identity components, while hosted binding tables use `(workspace, binding_id)`. Single-tenant deployments use the `'default'` workspace. |
There was a problem hiding this comment.
while hosted binding tables use
(workspace, binding_id)
If MLflow is managing a binding_id, why do we need a composite? For consistency in db layer with the other tables?
|
|
||
| **Status transition enforcement**: `update_mcp_server_version` validates that status transitions follow the allowed paths (active→deprecated, deprecated→active, deprecated→deleted). | ||
|
|
||
| **Update mode enforcement**: When a server's `update_mode` is `SYSTEM_MANAGED`, manual version creation and version updates are rejected — only system sync processes can modify versions. To make manual edits, the user must first switch `update_mode` back to `MANUAL` via `update_mcp_server`. Likewise, when a hosted binding's `update_mode` is `SYSTEM_MANAGED`, manual updates to its target or connectivity fields are rejected until the binding is switched back to `MANUAL`. In the UI, edit controls are hidden when a server or binding is in system-managed mode; only the mode toggle is available. |
There was a problem hiding this comment.
To make manual edits, the user must first switch update_mode back to MANUAL via update_mcp_server
Why allow the user to toggle something that is switched to SYSTEM_MANAGED, doesn't that kind of defeat the purpose?
There was a problem hiding this comment.
Maybe also briefly mention the response when clients try to update something that is in SYSTEM_MANAGED, e.g. via sdk/cli/rest.
| The Python SDK exposes a single user-facing `register_mcp_server()` function in `mlflow.genai` that handles both server and version creation in one call. Internally, the store layer has separate `create_mcp_server()` and `create_mcp_server_version()` methods — this is an implementation detail not exposed to users. Similar CLI commands will be added for the same operations, but this RFC does not spell out a separate CLI surface in detail. | ||
|
|
||
| ```python | ||
| import mlflow |
There was a problem hiding this comment.
Would have been nice to see the Python SDK client API outlined similar to the store API, though they are probably close enough.
Adds a design for an MCP registry in MLflow, aligned with the upstream MCP registry specification. Signed-off-by: Jon Burdo <jon@jonburdo.com> Co-authored-by: Dan Kuc <dkuc@redhat.com> Co-authored-by: mprahl <mprahl@users.noreply.github.com> AI-assisted: Claude Code (Opus 4.6)
Signed-off-by: mprahl <mprahl@users.noreply.github.com>
…oyed This decouples runtime information from the registry and then allows for expanding the AI Gateway to be an MCP gateway. Signed-off-by: mprahl <mprahl@users.noreply.github.com>
…nale, widen access control language - Remove run_id from entity, schema, store, and API models (provenance covered by source field; tags can handle run linkage if needed) - Add version history rationale bullets under immutability contract (trace provenance, rollback, deprecation signaling, audit) - Clarify that search_mcp_servers status filter is derived from latest version - Broaden motivation bullet to "available to specific users, teams, or agents" Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com> Signed-off-by: Jon Burdo <jon@jonburdo.com>
This adds more details about how the future MCP gateway would integrate, the benefit of aliases, and the benefit of trace linking. Signed-off-by: mprahl <mprahl@users.noreply.github.com>
Signed-off-by: Jon Burdo <jon@jonburdo.com>
- refactor the Phase 1 connectivity model from hosted bindings to `MCPAccessBinding` for approved direct-access endpoints - clarify the distinction between governed server/version metadata and direct-access bindings that make an endpoint available for use - make the future gateway path more explicit with an illustrative `MCPGatewayBinding` example and a small forward-looking diagram - tighten discovery wording around registry listings, access-binding listings, and direct-access filtering - clarify upstream version-update behavior and why MLflow treats canonical `server_json` changes as new versions - expand the Python SDK section to follow model-registry-style create, get, search, update, and delete APIs, while keeping `register_*` helpers as convenience entry points - improve UI and trace-linking explanations for direct access, gateway evolution, and auditability Signed-off-by: mprahl <mprahl@users.noreply.github.com> Co-authored-by: Jon Burdo <jon@jonburdo.com> Co-authored-by: Dan Kuc <dkuc@redhat.com>
New versions now default to draft instead of active, requiring an explicit publish action (draft → active) before downstream consumers can discover them. The Phase 2 upstream compatibility router filters out draft versions since the upstream MCP registry spec only defines active/deprecated/deleted. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com> Signed-off-by: Jon Burdo <jon@jonburdo.com>
Adds a design for an MCP registry in MLflow, aligned with the upstream MCP registry specification.
mlflow issue: mlflow/mlflow#22625
authored by: @jonburdo @dkuc @mprahl