Skip to main content

ALTR MCP Server

PyPI Python License: GPL v3 CI Security

ALTR provides tag-based data masking, access governance, and classification for Snowflake, Databricks, and OLTP databases. This MCP server enables AI assistants (Claude, Cursor, and other MCP clients) to manage data security on the ALTR platform, covering database connections, tag masking, policies, classification, access management, audits, telemetry, and sidecar configuration.

New to ALTR? See the ALTR documentation for an overview of the platform, concepts, and supported data sources.

All tools return structured {success, data, error} responses and can run over stdio, SSE, or streamable-http transports.

Table of Contents

Quick Start

  1. Install from PyPI:

    pip install altr-mcp
    

    Or run directly with uvx (no install required):

    uvx altr-mcp
    

    uvx is part of the uv Python package manager. Install it with pip install uv or see the uv installation guide.

  2. Set the three required environment variables (see Getting Credentials for where to find each in the ALTR console):

    export ORG_ID=your-org-id
    export MAPI_KEY=your-api-key
    export MAPI_SECRET=your-api-secret
    
  3. Wire it into your AI client — see Setup for Claude Desktop, Claude Code, Cursor, VS Code, and Windsurf. The same three env vars go into the client's env block.

  4. Verify by asking your AI assistant to run a read-only tool:

    • "List my ALTR databases" → calls get_databases
    • "Show me the tags connected to ALTR" → calls get_tags
    • "List the ALTR roles in my org" → calls get_roles

    If these return data, your setup is working.

Getting Credentials

You need three values from the ALTR platform to configure this server. See Manage API keys for the full reference.

Credential Where to find it
ORG_ID In the ALTR console: Settings > Preferences > Organization — copy the value from "ALTR Organization ID"
MAPI_KEY In the ALTR console: Settings > Preferences > API > Add New — give it a description, then copy the key
MAPI_SECRET Shown once when you create the API key above — copy and store it securely

Configuration

Set the following environment variables before starting the server:

Variable Required Description
ORG_ID Yes ALTR organization ID
MAPI_KEY Yes ALTR management API key
MAPI_SECRET Yes ALTR management API secret
MCP_TRANSPORT No Transport protocol: stdio (default), sse, or streamable-http
MCP_HOST No Bind address for HTTP transports (default: 127.0.0.1). See Running over HTTP
MCP_PORT No Port for HTTP transports (default: 8000)
MCP_AUTH_TOKEN No Bearer token every HTTP request must carry: at least 32 characters, letters, digits and -._~+/, with = only at the end. Required when MCP_HOST is not a loopback address
MCP_ALLOW_UNAUTHENTICATED No Set true to listen beyond loopback without MCP_AUTH_TOKEN, when a gateway in front authenticates every request (default: false)
RESTRICTED_TOOLS No Comma-separated tool names to hide from clients
LOG_FORMAT No Log output format: console (default) or json
LOG_LEVEL No Log level (default: INFO)
MAX_RETRIES No Attempts per API call before giving up (default: 3, minimum 1)
DISABLE_RETRY No Set true to disable retries entirely (default: false)
REQUEST_TIMEOUT No Per-request timeout in seconds (default: 30)
MAX_RETRY_AFTER No Ceiling in seconds on a server-sent Retry-After (default: 60)

MAX_RETRIES counts total attempts, not retries on top of the first, so 1 disables retrying without disabling the retry path. Backoff is exponential with jitter; a Retry-After response header overrides it, clamped to MAX_RETRY_AFTER so a server cannot park a call indefinitely.

What gets logged

Every tool call is logged to stderr at INFO with its arguments, which is what makes a session traceable. An argument is redacted when its value is a credential or user-supplied free text — values, text, comment, comments, attestation, justification, statement_text_contains, filters, filter_tree, content, content_base64, connection_string, connection_properties, the bare credential names (password, secret, credentials, passphrase, private_key, api_key, auth_token, access_key), and anything ending _password, _secret, _credential, _credentials, _private_key or _passphrase. Identifiers, enums and pagination cursors are logged in full.

An argument can also reach a log by travelling in a request URL, which redaction keyed on argument names cannot see. httpx's per-request line is therefore held at WARNING, so it does not appear at the default INFO.

Dictionary keys survive, so a line reads values={'ssn': '<redacted>', 'email': '<redacted>'}: you keep which fields were sent and lose the data. Tokens are not redacted — a token exists to be handled freely, and ALTR's own Shield audit log is keyed by token.

Redaction covers the invocation line, tracebacks, and the argument-coercion error returned to the caller.

LOG_FORMAT applies to dependency output as well as this server's own — under json, every line on the stream is a JSON object, and dependency lines carry the correlation_id of the tool call they occurred inside. See Logging.

Upgrading from 0.6.0 or earlier? Arguments were not redacted before 0.7.0. Treat any credential passed as a tool argument as exposed in your logs and rotate it — in practice database_password and connection_string. Those logs may also hold plaintext passed to the tokenize tools, so review who can read them and how long they are kept. Log output also changed shape; see the 0.7.0 entry in the CHANGELOG.

Endpoint overrides

Every ALTR service endpoint can be pointed elsewhere, which is useful against a non-production ALTR environment. All are optional — leave them unset in normal use.

The eight per-service endpoints are derived from your ORG_ID as https://<ORG_ID>.<service>.live.altr.com, five of them with a path appended (a version, or /v1/dam-alerting). An override replaces the whole value, so it must include that path where the default has one — see the table.

Variable Default
ALTR_API_BASE_URL https://api.live.altr.com
ALTR_ALTRNET_BASE_URL https://altrnet.live.altr.com
ALTR_CLASSIFICATION_BASE_URL https://<ORG_ID>.classification.live.altr.com
ALTR_SC_CONTROL_BASE_URL https://<ORG_ID>.sc-control.live.altr.com
ALTR_SERVICE_USER_BASE_URL https://<ORG_ID>.service-user.live.altr.com
ALTR_AUDIT_REPORT_BASE_URL https://<ORG_ID>.audit-report.live.altr.com/v1
ALTR_VAULT_BASE_URL https://<ORG_ID>.vault.live.altr.com/api/v2
ALTR_CRITICAL_BASE_URL https://<ORG_ID>.critical.live.altr.com/v2
ALTR_KMA_BASE_URL https://<ORG_ID>.kma.live.altr.com/v1
ALTR_DAM_ALERTING_BASE_URL https://<ORG_ID>.dam-alerting.live.altr.com/v1/dam-alerting

Restricting Tools

Use RESTRICTED_TOOLS to hide specific tools from MCP clients. Restricted tools are removed from the tool list and blocked if called directly.

Names must match the registered tool name exactly. An entry that matches nothing restricts nothing, and is logged as a warning the first time a client lists tools. Note that 11 tools were renamed from delete_* to disconnect_* in 0.4.0.

For example, to give a team read-only access without any destructive operations:

RESTRICTED_TOOLS=disconnect_database,delete_policy,delete_rule,disconnect_tag,disconnect_tag_by_details,delete_classifier,delete_collection,disconnect_sc_repo,disconnect_sc_sidecar

Or in the Claude Desktop config:

{
  "mcpServers": {
    "altr": {
      "command": "uvx",
      "args": ["altr-mcp"],
      "env": {
        "ORG_ID": "your-org-id",
        "MAPI_KEY": "your-api-key",
        "MAPI_SECRET": "your-api-secret",
        "RESTRICTED_TOOLS": "disconnect_database,delete_policy,delete_rule,disconnect_tag"
      }
    }
  }
}

This is an operator-level safety net — it prevents accidental or unwanted tool usage but is not a substitute for proper API key permissions.

Running over HTTP

With the default stdio transport, your AI client starts the server as its own subprocess, so nothing else can reach it. With MCP_TRANSPORT=sse or streamable-http, the server listens on a port, and every tool call runs with your organization's API key. So:

  • The default address is loopback. MCP_HOST defaults to 127.0.0.1, so only clients on the same machine can connect, and no token is needed. Without a token, the server also rejects any request whose Host or Origin header is not a loopback name (localhost, 127.0.0.1 or [::1]), so a web page open in a local browser cannot use it. Pages served from this machine are trusted, whatever their port, so local tools such as the MCP Inspector keep working.
  • Any other address needs a token. To accept connections from other machines, set MCP_HOST (for example 0.0.0.0) and MCP_AUTH_TOKEN. The server refuses to start with a non-loopback MCP_HOST and no token. Clients send the token as Authorization: Bearer <token>, and a request without it gets 401. The token may contain only letters, digits and -._~+/, with = only at the end. A reverse proxy on the same machine should also use a token, since it sends its own Host header.
  • Use TLS. The server speaks plain HTTP, and a bearer token sent in the clear can be read on the network. Put it behind a reverse proxy or gateway that terminates TLS.
  • Or let a gateway authenticate. If a gateway in front of the server checks every request itself, for example with your identity provider, set MCP_ALLOW_UNAUTHENTICATED=true instead of a token. This also turns off the Host and Origin check on a loopback address, so a gateway on the same machine that passes those headers through keeps working. The server logs a warning at startup, since it then accepts any request that reaches it.

Generate a token with:

python3 -c "import secrets; print(secrets.token_urlsafe(32))"

For example, in a container that a gateway reaches over the network:

MCP_TRANSPORT=streamable-http MCP_HOST=0.0.0.0 MCP_AUTH_TOKEN=<token> uvx altr-mcp

The token is a shared secret: anyone who has it can call every tool the server exposes. Treat it like the API key, and combine it with RESTRICTED_TOOLS to limit what a client can do.

Setup

Claude Desktop

Add the following to your claude_desktop_config.json (Settings > Developer > Edit Config):

{
  "mcpServers": {
    "altr": {
      "command": "uvx",
      "args": ["altr-mcp"],
      "env": {
        "ORG_ID": "your-org-id",
        "MAPI_KEY": "your-api-key",
        "MAPI_SECRET": "your-api-secret"
      }
    }
  }
}

Claude Code (CLI)

claude mcp add altr -e ORG_ID=your-org-id -e MAPI_KEY=your-api-key -e MAPI_SECRET=your-api-secret -- uvx altr-mcp

This writes the config to .mcp.json which can be committed to share with your team.

Cursor

Add to ~/.cursor/mcp.json (global) or .cursor/mcp.json (project-scoped):

{
  "mcpServers": {
    "altr": {
      "command": "uvx",
      "args": ["altr-mcp"],
      "env": {
        "ORG_ID": "your-org-id",
        "MAPI_KEY": "your-api-key",
        "MAPI_SECRET": "your-api-secret"
      }
    }
  }
}

VS Code (GitHub Copilot)

Open User Settings JSON (Ctrl+Shift+P → "Preferences: Open User Settings (JSON)") and add:

{
  "mcp": {
    "servers": {
      "altr": {
        "command": "uvx",
        "args": ["altr-mcp"],
        "env": {
          "ORG_ID": "your-org-id",
          "MAPI_KEY": "your-api-key",
          "MAPI_SECRET": "your-api-secret"
        }
      }
    }
  }
}

Windsurf

Add to ~/.codeium/windsurf/mcp_config.json:

{
  "mcpServers": {
    "altr": {
      "command": "uvx",
      "args": ["altr-mcp"],
      "env": {
        "ORG_ID": "your-org-id",
        "MAPI_KEY": "your-api-key",
        "MAPI_SECRET": "your-api-secret"
      }
    }
  }
}

Running from Local Source

To run from a local clone instead of the published PyPI package:

Claude Code:

claude mcp add altr \
  -e ORG_ID=your-org-id \
  -e MAPI_KEY=your-api-key \
  -e MAPI_SECRET=your-api-secret \
  -- uv run --directory /path/to/altr-mcp altr-mcp

Claude Desktop:

{
  "mcpServers": {
    "altr": {
      "command": "uv",
      "args": ["run", "--directory", "/path/to/altr-mcp", "altr-mcp"],
      "env": {
        "ORG_ID": "your-org-id",
        "MAPI_KEY": "your-api-key",
        "MAPI_SECRET": "your-api-secret"
      }
    }
  }
}

CLI (Optional)

This section is for building a standalone CLI binary from the MCP server. If you just want to use the server with Claude Desktop or Claude Code, skip to Tools.

A standalone CLI lets you call ALTR tools directly from the terminal without an MCP client. It's built with mcporter, an open-source tool that compiles MCP servers into native CLI binaries. See the mcporter docs for the full set of options.

Prerequisites

  • uv (Python package manager)
  • Node.js (for npx to fetch and run mcporter)

mcporter itself does not need to be installed separately — npx downloads and runs it on demand.

Building

From the repo root:

npx mcporter generate-cli --command "uv run --directory . altr-mcp" --name altr-cli --compile ./altr-cli

This generates a compiled binary at ./altr-cli.

Usage

Set your credentials as environment variables, then run any tool:

export ORG_ID=your-org-id
export MAPI_KEY=your-api-key
export MAPI_SECRET=your-api-secret

# List databases
./altr-cli get-databases

# Get a specific database ID
./altr-cli get-database-id --database-name "my_database"

# Create a masking policy
./altr-cli create-policy --tag "STOPLIGHT"

# Add rules (pass JSON string for complex params)
./altr-cli add-rules --policy-id "TAG#abc123" --rules '[{"masking_policy": 10001, "role": "PUBLIC", "tag_value": "red"}]'

# Search query audits
./altr-cli search-query-audits --limit 10

# JSON output
./altr-cli get-databases --output json

# See all available commands
./altr-cli --help

The CLI runs the MCP server locally via uv run and requires the repo to be present at the working directory. All environment variables from the Configuration section apply.

Tools

For a full breakdown of every tool with parameters, behavior, and examples, see docs/index.md.

Domain Tools What it does
Databases 8 Connect Snowflake, OLTP, and Databricks data sources. Setup per platform: Snowflake, OLTP, Databricks.
Tags 8 Manage Snowflake tag connections to ALTR. See Connecting Snowflake Tags to ALTR.
Policies & Rules 9 Create masking policies and per-role rules. Tag-based (Snowflake, Databricks) and column-based (Snowflake only). Masking levels 10000–10009, limited by policy type (get_supported_masking_types). Includes get_roles — list all ALTR roles (called user groups in the ALTR console).
Classification 52 Run automated data classification scans. Scans run a collection of classifiers on Snowflake (ALTR Hosted or In-Warehouse), Databricks, and database and file repositories through an agent, as the console's Classify Data wizard does. Includes findings-tree navigation, human review decisions, report groups, ALTR-managed collections, and classifying single files with scan_object.
Access Management 4 Access management policies for Snowflake and OLTP.
Access Requests 6 Submit, approve, deny, and cancel data access approval requests.
Audits 6 Search sidecar, Snowflake query, and platform system audits.
Audit Reports 17 Create, schedule, and review structured audit report definitions and instances, including comments and sign-offs.
DAM Alerting 10 Create match and threshold alert rules over sidecar and Snowflake audit events; triage, comment on, and acknowledge the alerts they fire.
Telemetry 9 Monitor ALTR sidecar proxy agent and sidecar instance health.
Sidecar Configuration 38 Configure the ALTR sidecar proxy — agents, repos, repo users, service users, sidecars, listeners, and bindings.
Vault Tokenization 4 Tokenize and detokenize values using ALTR vaulted tokenization.
Critical Tokenization 4 Tokenize and detokenize values using ALTR critical tokenization.
Key Management 9 Manage FPE encryption keys and tweaks.

Critical callouts

A few things are easy to miss and worth surfacing here:

Snowflake tags vs Databricks tags. A Snowflake tag is a first-class ALTR object — you register it with connect_tag, it gets a tag_group_id, and shows up in get_tags, get_tag_details*, update_tag, and disconnect_tag*. A Databricks tag is the opposite: not an ALTR object at all, just a raw string you pass into create_policy (with policy_type="PUSHDOWN" and database_ids=[…]). Databricks tags never appear in get_tags and do not have a tag_group_id. None of the Tags tools apply to Databricks.

Databricks create_policy requirements. When creating a masking policy for a Databricks metastore, you must pass database_ids as a list — even for a single database (e.g. database_ids=[2167]) — and set policy_type="PUSHDOWN". Omitting database_ids or using policy_type="TAG" will be rejected by the API. Snowflake policies do the opposite: omit database_ids and let policy_type default to TAG.

Data Source Support

Platform setup guides on the ALTR docs site:

Feature Snowflake OLTP (via sidecar) Databricks
Database connections ✅ — ✅
Masking policies ✅ ❌ ✅
Classification ✅ ✅ ⚠️ Partial
Access management policies ✅ ✅ ❌
Access requests ✅ ❌ ❌
Query audit logging ✅ ✅ ❌
System audit logging ✅ ✅ ❌
Sidecar configuration — ✅ —
Telemetry & monitoring — ✅ —

Legend: ✅ Supported   ⚠️ Partial   ❌ Not supported   — Not applicable

Classification processing locations: every scan runs a collection of classifiers, and where it runs depends on the source, as in the console.

Source Tool Processing location
Snowflake create_snowflake_job ALTR Hosted (default) or In-Warehouse
Databricks create_databricks_job ALTR Hosted
Database repositories (Oracle, MSSQL, PostgreSQL, MySQL, MongoDB, Cassandra) create_oltp_job Agent
File repositories (S3, filesystem) create_file_classification_job Agent

Google DLP and Amazon Comprehend conditions in a collection run with ALTR's own services on ALTR Hosted scans, and with the agent's own Google Cloud and AWS credentials on agent scans; In-Warehouse scans skip Google DLP, Content Type and Amazon Comprehend conditions. An agent scan fails at start if the agent isn't configured for a kind its collection has.

Access management policies (Databricks): This MCP server does not currently expose Databricks grant or access management APIs. For Databricks access control, use the Databricks UI or REST API directly.

OLTP refers to relational databases (PostgreSQL, MySQL, Oracle, SQL Server) accessed through a customer-managed ALTR sidecar proxy.

Troubleshooting

Checking which version you are running

uvx altr-mcp --version

This works without credentials. Your AI client also reports the same version as the server version when it connects, which is the quickest way to confirm the client actually picked up an upgrade.

uvx: command not found

Install uv: pip install uv or via the official installer.

Server not appearing in your AI client

Restart your AI client after editing the config file — changes are not picked up automatically.

ERROR: Missing required environment variables

Verify ORG_ID, MAPI_KEY, and MAPI_SECRET are set in the env block of your client config. Variable names are case-sensitive.

Tools returning {"success": false, ...}

HTTP status Likely cause Fix
401 Invalid credentials Verify MAPI_KEY / MAPI_SECRET in the ALTR console under Settings > Preferences > API
403 Feature not enabled for this organization The endpoint exists but is gated by an ALTR feature flag your org doesn't have turned on. Contact ALTR support to confirm the feature is enabled for your account.
404 Resource not found Confirm the ID exists in your organization
429 Rate limited The server retries automatically up to 3× with backoff; if persistent, reduce request frequency

A tool is missing from the tool list

Check whether the tool name appears in the RESTRICTED_TOOLS env var in your client config. Restricted tools are hidden from the tool list entirely.

A restricted tool is still exposed

RESTRICTED_TOOLS matches names exactly, so a misspelled or renamed entry restricts nothing. Check the server log for tool_restriction_middleware.unknown_tools, which names any entry that matched no registered tool.

Timeouts on large result sets

Use pagination parameters (limit, offset, or cursor) available on audit, telemetry, and classification tools to reduce response size.

Development

Running Tests

# Install dependencies
uv sync --extra dev

# Run all tests
uv run pytest

# Run with verbose output
uv run pytest -v

# Run a specific test file
uv run pytest tests/integration/test_database.py

# Run a specific test
uv run pytest tests/integration/test_database.py::test_create_database_with_service_user

# Run with coverage report (terminal)
uv run pytest --cov=altr_mcp --cov-report=term-missing

# Run with coverage and generate an HTML report at htmlcov/index.html
uv run pytest --cov=altr_mcp --cov-report=html

Project Structure

altr_mcp/
  server.py          # MCP server entrypoint and tool registration
  settings.py        # Pydantic settings (env vars)
  instructions.md    # System prompt for LLM tool guidance
  tools/             # Tool definitions (one file per domain)
  utils/             # API client functions (one file per API)
tests/
  unit/              # Unit tests (settings, models, annotations)
  integration/       # Integration tests (httpx mocks per domain)

Learn More

Platform setup

Data access controls

Discovery and observability

Protocol

License

Copyright (C) 2026 ALTR Solutions, Inc.

GNU General Public License v3.0 or later (GPL-3.0-or-later). See LICENSE.md for the copyright notice and the full license text.

Metadata

Release files for altr-mcp 0.9.0

For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.

Source distribution (sdist)

Source distribution for altr-mcp 0.9.0
File Size Uploaded Provenance Actions
altr_mcp-0.9.0.tar.gz 360.1 kB With provenance Details for altr_mcp-0.9.0.tar.gz

Built distribution (wheel)

Table of built distributions (wheels) for altr-mcp 0.9.0
File Interpreter ABI Platform Actions
altr_mcp-0.9.0-py3-none-any.whl Python 3 none any Details for altr_mcp-0.9.0-py3-none-any.whl

Total release size: 478.4 kB

Release files / altr_mcp-0.9.0.tar.gz

Download URL altr_mcp-0.9.0.tar.gz
Size 360.1 kB
Tags Source
SHA-256 checksum
How to use checksums
f56ce7d3c5a7b15d23c024ba0f6d082fe1d9f3911b6bcb0ba76d2e7e683c3e8b
BLAKE2b-256 checksum
How to use checksums
85b835dd4f33492bed3e17932fc06c7892b345ad4eb53dea9d3254ed1905cb62
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via twine/7.0.0 CPython/3.13.16

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

PyPI Publish Attestation

PyPI verified that this artifact, at this checksum, originated from the publisher listed below.

Signed by GitHub Actions, verified by PyPI on Nov 2, 2026.

Transparency log

Release files / altr_mcp-0.9.0-py3-none-any.whl

Download URL altr_mcp-0.9.0-py3-none-any.whl
Size 118.3 kB
Tags Python 3
SHA-256 checksum
How to use checksums
0fa4136cf57e8adcbfbdd028992dff5bf3b6807746ef10b03a44d655aca49484
BLAKE2b-256 checksum
How to use checksums
339459ba486898443a509f1d940a2bac70d78e59a38b4e3c173f3839f43c273b
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via twine/7.0.0 CPython/3.13.16

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

PyPI Publish Attestation

PyPI verified that this artifact, at this checksum, originated from the publisher listed below.

Signed by GitHub Actions, verified by PyPI on Nov 2, 2026.

Transparency log

Security for altr-mcp 0.9.0

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

Full provenance

All 2 files in this release have been uploaded with provenance metadata.

Select from 2 files

Attestation for altr_mcp-0.9.0.tar.gz

PyPI Publish Attestation

PyPI verified that this artifact, at this checksum, originated from the publisher listed below.

Signed by GitHub Actions, verified by PyPI on Nov 2, 2026.

Transparency log

A note on package security

PyPI is a repository for distributing packages, not a service for auditing them. While third-party security researchers and our staff do their best to detect and remove malicious packages, PyPI cannot guarantee the quality, security or suitability of any given package.

To learn more about protecting yourself from malicious actors, visit our package security documentation.

Anthropic, PBC Visionary sponsor Bloomberg Visionary sponsor Hudson River Trading Visionary sponsor Meta Visionary sponsor NVIDIA Visionary sponsor Microsoft Sustainability sponsor Depot Continuous Integration AWS Cloud computing and Security Sponsor Datadog Monitoring Fastly CDN Google Download Analytics Sentry Error logging StatusPage Status page