MCP server
Overview
The MCP server lets AI agents browse and manage Gravitino metadata through the Model Context
Protocol. Agents call tools such as get_list_of_catalogs or get_table_metadata_details, and the
server turns each call into a request to the Gravitino server on behalf of the agent's user, so
Gravitino authorizes every call exactly as it would the same request from the UI or the API.
The Helm chart installs the MCP server alongside the Gravitino server by default, and the ingress
from Install with Helm publishes it at /mcp on the UI hostname.
Quick start
The commands use the shell variables set in step 1 of Install with Helm.
-
Check that the server is running. The MCP pod starts after the Gravitino server answers, so it can sit in its init container for a minute after an install.
Check the MCP podkubectl -n "$NAMESPACE" get pods | grep mcpThe pod should show
Runningwith all containers ready. -
Point the agent at the endpoint. The address is
https://{ui_hostname}/mcp. Each request carries the agent user's own credentials, which with the chart's defaultbasicauthenticator are a user name and password in aBasicheader. Taking Cursor as an example:~/.cursor/mcp.json{
"mcpServers": {
"gravitino": {
"url": "https://{ui_hostname}/mcp",
"headers": {
"Authorization": "Basic {base64_user_password}"
}
}
}
}Produce the header value with
printf '%s' '{user}:{password}' | base64. Other agents take the same URL and header in their own configuration format. -
Ask for something the user can see. A request such as "list the catalogs in metalake
{metalake}" should return the catalogs that user is entitled to. A user with no access to the metalake gets an authorization error back from Gravitino.
Configuration
The MCP server is configured through the mcp block of my-values.yaml. The common settings:
| Setting | Description | Default |
|---|---|---|
mcp.enabled | Deploy the MCP server | true |
mcp.metalake | Metalake used when a tool call does not name one. Leave empty to have agents name the metalake on every call | (none) |
mcp.gravitinoUri | Gravitino server the MCP server calls. Leave empty to use the Gravitino server in the same release | (same release) |
mcp.extraArgs | Additional server arguments, for example ["--tag", "table"] to expose only the tools tagged table | [] |
mcp.auth.token, mcp.auth.existingSecret | Static Bearer token used for requests that carry no Authorization header. See Authentication | (none) |
mcp.auth.oauth.* | OAuth client credentials for a service identity that fetches and refreshes its own token | (none) |
mcp.auth.oauth.noServiceIdentityFallback | Reject requests that carry no Authorization header instead of using the service identity | false |
mcp.tls.enabled, mcp.tls.existingSecret | Serve HTTPS from the pod itself, from a kubernetes.io/tls Secret. Not needed when the ingress terminates TLS | false |
mcp.replicaCount | Number of replicas. The server keeps no state, so replicas scale freely | 1 |
mcp.extraVolumes, mcp.extraVolumeMounts | Additional volumes, for example to keep the audit log across restarts. See Audit Logging | [] |
Publish the endpoint through the top-level ingress, as Install with Helm does, rather
than enabling the chart's separate mcp.ingress.
Authentication
Per-request identity
Every incoming request's Authorization header is forwarded to Gravitino unchanged, so each agent
acts as its own user and Gravitino authorizes each call for that user. Concurrent sessions from
different users stay isolated, and one user's identity never reaches another's calls. Send Basic
credentials under the basic authenticator, or a Bearer token from your identity provider under
oauth. Leave the mcp.auth settings empty to require this for every request.
Service identity
A request that arrives without an Authorization header falls back to a service identity when one is
configured, and every such request then acts as that one identity. Two settings provide it:
- A static token, in
mcp.auth.tokenor in the Secret named bymcp.auth.existingSecret. The value is always sent as aBearertoken, so it must be an OAuth access token, and it stops working when that token expires. - OAuth client credentials, in
mcp.auth.oauth.tokenEndpoint,clientId, andclientSecret(orexistingSecret), which must be set together. The server fetches its own token and refreshes it, so a long-running server does not start failing when a token expires.
A static token wins when both are set. Set mcp.auth.oauth.noServiceIdentityFallback to true to
keep the client credentials while still rejecting requests that carry no identity of their own.
Authorization is always decided by Gravitino. The MCP server forwards the identity and makes no access-control decisions of its own.
Supported tools
Every tool carries a tag, and --tag in mcp.extraArgs limits the server to the tools with that
tag.
| Tool name | Description | Tag |
|---|---|---|
get_list_of_catalogs | Retrieve a list of all catalogs in the system. | catalog |
create_catalog | Create a new catalog. | catalog |
alter_catalog | Alter an existing catalog. | catalog |
drop_catalog | Drop a catalog. | catalog |
set_catalog_in_use | Enable or disable a catalog. | catalog |
get_list_of_schemas | Retrieve a list of schemas belonging to a specific catalog. | schema |
create_schema | Create a new schema. | schema |
alter_schema | Alter an existing schema. | schema |
drop_schema | Drop a schema. | schema |
get_list_of_tables | Retrieve a list of tables within a specific catalog and schema. | table |
get_table_metadata_details | Retrieve comprehensive metadata details for a specific table. | table |
create_table | Create a new table. | table |
alter_table | Alter an existing table. | table |
drop_table | Drop a table. | table |
list_of_models | Retrieve a list of models within a specific catalog and schema. | model |
load_model | Retrieve comprehensive metadata details for a specific model. | model |
list_model_versions | Retrieve a list of versions for a specific model. | model |
load_model_version | Retrieve comprehensive metadata details for a specific model version. | model |
load_model_version_by_alias | Retrieve comprehensive metadata details for a specific model version by alias. | model |
register_model | Register a new model. | model |
delete_model | Delete a model. | model |
link_model_version | Link a new version to a model. | model |
delete_model_version | Delete a model version. | model |
delete_model_version_by_alias | Delete a model version by one of its aliases. | model |
alter_model | Alter an existing model. | model |
alter_model_version | Alter a model version. | model |
alter_model_version_by_alias | Alter a model version by one of its aliases. | model |
metadata_type_to_fullname_formats | Retrieve the metadata type to fullname formats mapping. | metadata |
list_of_topics | Retrieve a list of topics within a specific catalog and schema. | topic |
load_topic | Retrieve comprehensive metadata details for a specific topic. | topic |
create_topic | Create a new topic. | topic |
alter_topic | Alter an existing topic. | topic |
delete_topic | Delete a topic. | topic |
list_of_filesets | Retrieve a list of filesets within a specific catalog and schema. | fileset |
load_fileset | Retrieve comprehensive metadata details for a specific fileset. | fileset |
list_files_in_fileset | Retrieve a list of files within a specific fileset. | fileset |
create_fileset | Create a new fileset. | fileset |
alter_fileset | Alter an existing fileset. | fileset |
drop_fileset | Drop a fileset. | fileset |
list_of_jobs | Retrieve a list of jobs | job |
get_job_by_id | Retrieve a job by its ID. | job |
list_of_job_templates | Retrieve a list of job templates. | job |
get_job_template_by_name | Retrieve a job template by its name. | job |
run_job | Run a job with the specified parameters. | job |
cancel_job | Cancel a running job by its ID. | job |
get_tag_by_name | Retrieve a tag by its name. | tag |
list_of_tags | Retrieve a list of tags. | tag |
list_tags_for_metadata | Retrieve a list of tags associated with a specific metadata item. | tag |
list_metadata_by_tag | Retrieve a list of metadata items associated with a specific tag. | tag |
associate_tag_with_metadata | Associate tags with a specific metadata item. | tag |
disassociate_tag_from_metadata | Disassociate tags from a specific metadata item. | tag |
create_tag | Create a new tag. | tag |
alter_tag | Alter an existing tag. | tag |
delete_tag | Delete a tag. | tag |
list_statistics_for_metadata | Retrieve a list of statistics associated with a specific metadata item. | statistics |
list_statistics_for_partition | Retrieve a list of statistics associated with a specific partition. | statistics |
get_list_of_policies | Retrieve a list of policies in the system. | policy |
get_policy_detail_information | Retrieve detailed information for a specific policy by policy name. | policy |
list_policies_for_metadata | List all policies associated with a specific metadata item. | policy |
list_metadata_by_policy | List all metadata items associated with a specific policy. | policy |
get_policy_for_metadata | Get a policy associated with a specific metadata item. | policy |
list_of_partitions | Retrieve partitions for a table. Only for catalogs with a partition API. | partition |
get_partition | Retrieve a partition's metadata. Only for catalogs with a partition API. | partition |
list_of_views | Retrieve a list of views for a schema. Only for catalogs supporting views. | view |
load_view | Retrieve a view's metadata. Only for catalogs supporting views. | view |
Audit logging
Every tool call is recorded as one JSON line in gravitino-mcp-audit.log, attributed to the user
derived from the request's Authorization header.
| Field | Description |
|---|---|
timestamp | UTC ISO-8601 time of the call. |
principal | Caller identity: user name for Basic credentials, bearer:{first_8_chars} for a Bearer token, or anonymous when no identity is present. |
tool | Name of the invoked MCP tool. |
outcome | allow for successful calls, deny for failed ones. deny is emitted for any tool-call exception (authorization denial being the common case); inspect error_type to disambiguate. |
error_type | Exception class name, present only when outcome is deny. |
{"timestamp": "2026-06-16T03:21:09.123456+00:00", "principal": "alice", "tool": "get_list_of_catalogs", "outcome": "allow"}
The log is written to the container's working directory and is lost when the pod restarts. To keep
it, mount a volume at the working directory with mcp.extraVolumes and mcp.extraVolumeMounts, or
collect it from the pod with your log collector.