| <!-- |
| Licensed to the Apache Software Foundation (ASF) under one |
| or more contributor license agreements. See the NOTICE file |
| distributed with this work for additional information |
| regarding copyright ownership. The ASF licenses this file |
| to you under the Apache License, Version 2.0 (the |
| "License"); you may not use this file except in compliance |
| with the License. You may obtain a copy of the License at |
| |
| http://www.apache.org/licenses/LICENSE-2.0 |
| |
| Unless required by applicable law or agreed to in writing, |
| software distributed under the License is distributed on an |
| "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY |
| KIND, either express or implied. See the License for the |
| specific language governing permissions and limitations |
| under the License. |
| --> |
| |
| # Apache Polaris MCP Server |
| |
| This package provides a Python implementation of the [Model Context Protocol (MCP)](https://modelcontextprotocol.io) server for Apache Polaris. It wraps the Polaris REST APIs so MCP-compatible clients (IDEs, agents, chat applications) can issue structured requests via JSON-RPC on stdin/stdout. |
| |
| The implementation is built on top of [FastMCP](https://gofastmcp.com) for streamlined server registration and transport handling. |
| |
| ## Prerequisites |
| - Python 3.10 or later |
| - [uv](https://docs.astral.sh/uv/) 0.9.7 or later |
| |
| ## Building and Running |
| Run the following commands from the `mcp-server` directory: |
| - `uv sync` - install runtime dependencies |
| - `uv run polaris-mcp` - start the MCP server (stdin/stdout transport) |
| - `uv sync --all-extras` - install runtime and dev dependencies |
| - `uv run pytest` - run the test suite |
| - `uv run pre-commit run --all-files` - lint all files |
| - `uv build && uv publish --index testpypi --token [Pypi-API-token]` - Publish a nightly to test.pypi.org |
| - `uv build && uv publish --index pypi --token [Pypi-API-token]` - Publish a formal binary release to pypi.org |
| |
| For a `tools/call` invocation you will typically set environment variables such as `POLARIS_BASE_URL` and authentication settings before launching the server. A default `.polaris_mcp.env` file is included on the tool root directory, and any of the configuration variables can be specified in this file. After adding configuration variables to the `.polaris_mcp.env` file, explicitly setting these is no longer needed. However, shell environment variables will always take precedence if provided. |
| |
| ### Claude Desktop configuration |
| |
| ```json |
| { |
| "mcpServers": { |
| "polaris": { |
| "command": "uv", |
| "args": [ |
| "--directory", |
| "/path/to/polaris-tools/mcp-server", |
| "run", |
| "polaris-mcp" |
| ], |
| "env": { |
| "POLARIS_CONFIG_FILE": "/path/to/polaris-tools/mcp-server/.polaris_mcp.env" |
| } |
| } |
| } |
| } |
| ``` |
| |
| Please note: `--directory` specifies a local directory. It is not needed when we pull `polaris-mcp` from PyPI package. |
| |
| ### MCP Client |
| |
| For quick local testing without configuring a full client like Claude Desktop, you can use the included `client.py` script. |
| |
| ```bash |
| # Start client in interactative mode with STDIO transport |
| uv run int_test/client.py polaris_mcp/server.py |
| ``` |
| |
| You can also run client directly from the command line with non-interactive mode: |
| |
| ```bash |
| uv run int_test/client.py http://localhost:8000/mcp --tool polaris-catalog-request --args '{"operation": "list"}' |
| ``` |
| |
| Here are sample client commands: |
| |
| ```bash |
| # Create catalog |
| uv run int_test/client.py polaris_mcp/server.py \ |
| --tool polaris-catalog-request \ |
| --args '{ |
| "operation": "create", |
| "body": { |
| "catalog": { |
| "name": "quickstart_catalog", |
| "type": "INTERNAL", |
| "readOnly": false, |
| "properties": { |
| "default-base-location": "s3://bucket123" |
| }, |
| "storageConfigInfo": { |
| "storageType": "S3", |
| "allowedLocations": ["s3://bucket123"], |
| "endpoint": "http://localhost:9000", |
| "pathStyleAccess": true |
| } |
| } |
| } |
| }' |
| # List catalog |
| uv run int_test/client.py polaris_mcp/server.py \ |
| --tool polaris-catalog-request \ |
| --args '{"operation": "list"}' |
| # List catalog in realm "POLARIS" |
| uv run int_test/client.py polaris_mcp/server.py \ |
| --tool polaris-catalog-request \ |
| --args '{"operation": "list", "realm": "POLARIS"}' |
| # Create principal |
| uv run int_test/client.py polaris_mcp/server.py \ |
| --tool polaris-principal-request \ |
| --args '{ |
| "operation": "create", |
| "body": { |
| "principal": { |
| "name": "quickstart_user", |
| "properties": {} |
| } |
| } |
| }' |
| # Create principal role |
| uv run int_test/client.py polaris_mcp/server.py \ |
| --tool polaris-principal-role-request \ |
| --args '{ |
| "operation": "create", |
| "body": { |
| "principalRole": { |
| "name": "quickstart_user_role", |
| "properties": {} |
| } |
| } |
| }' |
| # Assign principal role |
| uv run int_test/client.py polaris_mcp/server.py \ |
| --tool polaris-principal-request \ |
| --args '{ |
| "operation": "assign-principal-role", |
| "principal": "quickstart_user", |
| "body": { |
| "principalRole": { |
| "name": "quickstart_user_role" |
| } |
| } |
| }' |
| ``` |
| |
| ## Configuration |
| |
| | Variable | Description | Default | |
| |----------------------------------------------------------------|------------------------------------------------------------------|--------------------------------------------------| |
| | `POLARIS_BASE_URL` | Base URL for all Polaris REST calls. | `http://localhost:8181/` | |
| | `POLARIS_API_TOKEN` / `POLARIS_BEARER_TOKEN` / `POLARIS_TOKEN` | Static bearer token (if supplied, overrides other auth). | _unset_ | |
| | `POLARIS_CLIENT_ID` | OAuth client id for client-credential flow. | _unset_ | |
| | `POLARIS_CLIENT_SECRET` | OAuth client secret. | _unset_ | |
| | `POLARIS_TOKEN_SCOPE` | OAuth scope string. | _unset_ | |
| | `POLARIS_TOKEN_URL` | Optional override for the token endpoint URL. | `${POLARIS_BASE_URL}api/catalog/v1/oauth/tokens` | |
| | `POLARIS_REALM_{realm}_CLIENT_ID` | OAuth client id for a specific realm. | _unset_ | |
| | `POLARIS_REALM_{realm}_CLIENT_SECRET` | OAuth client secret for a specific realm. | _unset_ | |
| | `POLARIS_REALM_{realm}_TOKEN_SCOPE` | OAuth scope for a specific realm. | _unset_ | |
| | `POLARIS_REALM_{realm}_TOKEN_URL` | Token endpoint URL for a specific realm. | _unset_ | |
| | `POLARIS_REALM_CONTEXT_HEADER_NAME` | Header name used for realm context. | `Polaris-Realm` | |
| | `POLARIS_TOKEN_REFRESH_BUFFER_SECONDS` | Minimum remaining token lifetime before refreshing in seconds. | `60.0` | |
| | `POLARIS_HTTP_TIMEOUT_SECONDS` | Default timeout in seconds for all HTTP requests. | `30.0` | |
| | `POLARIS_HTTP_CONNECT_TIMEOUT_SECONDS` | Timeout in seconds for establishing HTTP connections. | `30.0` | |
| | `POLARIS_HTTP_READ_TIMEOUT_SECONDS` | Timeout in seconds for reading HTTP responses. | `30.0` | |
| | `POLARIS_HTTP_RETRIES_TOTAL` | Total number of retries for HTTP requests. | `3` | |
| | `POLARIS_HTTP_RETRIES_BACKOFF_FACTOR` | Factor for exponential backoff between retries. | `0.5` | |
| | `POLARIS_CONFIG_FILE` | Path to a configuration file containing configuration variables. | `.polaris_mcp.env` in current working directory | |
| |
| |
| When OAuth variables are supplied, the server automatically acquires and refreshes tokens using the client credentials flow; otherwise a static bearer token is used if provided. |
| Realm-specific variables (e.g., `POLARIS_REALM_${realm}_CLIENT_ID`) override the global settings for a given realm for client ID, client secret, token scope, and token URL. If realm-specific credentials are provided but incomplete, the server will not fall back to global credentials for that realm. |
| |
| ## Tools |
| |
| The server exposes the following MCP tools: |
| |
| * `polaris-iceberg-table-request` — Perform table operations (`list`, `get`, `create`, `update`, `delete`). |
| * `polaris-namespace-request` — Perform namespace operations (`list`, `get`, `create`, `exists`, `get-properties`, `delete`). |
| * `polaris-policy-request` — Perform policy operations (`list`, `get`, `create`, `update`, `delete`, `attach`, `detach`, `applicable`). |
| * `polaris-catalog-request` — Perform catalog operations (`list`, `get`, `create`, `update`, `delete`). |
| * `polaris-principal-request` — Perform principal operations (`list`, `get`, `create`, `update`, `delete`, `rotate`, `reset`, `list-roles`, `assign-role`, `revoke-role`). |
| * `polaris-principal-role-request` — Perform principal role operations (`list`, `get`, `create`, `update`, `delete`, `list-assignees`, `list-catalog-roles`, `assign-catalog-role`, `revoke-catalog-role`). |
| * `polaris-catalog-role-request` — Perform catalog role operations (`list`, `get`, `create`, `update`, `delete`, `list-principal-roles`, `list-grants`, `add-grant`, `revoke-grant`). |
| |
| Each tool returns both a human-readable transcript of the HTTP exchange and structured metadata under `result.meta`. |