Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
26 commits
Select commit Hold shift + click to select a range
788ed29
feat(mcp-cli): add generated CLI with dual auth over Streamable HTTP
abhinavmathur-atlan Apr 27, 2026
8325525
fix(mcp-cli): auto-load .env from script directory
abhinavmathur-atlan Apr 27, 2026
6ea2091
fix(mcp-cli): add --oauth flag and ATLAN_AUTH=oauth to force OAuth mode
abhinavmathur-atlan Apr 27, 2026
42bb821
fix(mcp-cli): strip --oauth from argv before cyclopts; add README
abhinavmathur-atlan Apr 27, 2026
98325ac
fix(mcp-cli): add PEP 723 inline deps so uv run auto-installs fastmcp…
abhinavmathur-atlan Apr 27, 2026
c541aad
feat(mcp-cli): persist OAuth tokens to ~/.atlan/mcp-tokens via FileTr…
abhinavmathur-atlan Apr 27, 2026
1cc775f
fix(mcp-cli): replace FileTreeStore with inline JsonFileStore for tok…
abhinavmathur-atlan Apr 27, 2026
9e663bc
docs(mcp-cli): update README for uv auto-install, OAuth token caching
abhinavmathur-atlan Apr 27, 2026
d4d4e71
feat(mcp-cli): add pyproject.toml and flatten call-tool subcommand
abhinavmathur-atlan Apr 28, 2026
052ee1e
fix(mcp-cli): lazy auth init so --help works without ATLAN_BASE_URL
abhinavmathur-atlan Apr 28, 2026
483e059
fix(mcp-cli): pass auth as keyword arg and load .env from cwd
abhinavmathur-atlan Apr 28, 2026
ca94098
docs(mcp-cli): update README for installable package and flat commands
abhinavmathur-atlan Apr 28, 2026
7d9c3dd
docs(mcp-cli): add improvement plan from team discussion
abhinavmathur-atlan Apr 28, 2026
75f5460
docs(mcp-cli): expand plan with refresh-token reuse and full P0-P2 de…
abhinavmathur-atlan Apr 28, 2026
6a6a1a3
feat(mcp-cli): persistent login, refresh tokens, rich UI, PyPI publis…
abhinavmathur-atlan Apr 28, 2026
54ae896
fix(mcp-cli): clear FastMCP token cache on logout so login --oauth al…
abhinavmathur-atlan Apr 28, 2026
0bfa71f
refactor(mcp-cli): simplify code and make JSON arg parsing schema-aware
abhinavmathur-atlan Apr 28, 2026
88ac215
fix(mcp-cli): replace questionary with rich.prompt for interactive login
abhinavmathur-atlan Apr 28, 2026
25c40a4
fix(mcp-cli): use input() for API key prompt to avoid getpass hang
abhinavmathur-atlan Apr 28, 2026
74e7284
chore(mcp-cli): fix publish workflow, gitignore, and README polish
abhinavmathur-atlan Apr 28, 2026
8be7be3
style(mcp-cli): fix ruff lint and format (f-strings, formatting)
abhinavmathur-atlan Apr 28, 2026
c19b02a
ci(mcp-cli): switch publish to PyPI Trusted Publisher (OIDC)
abhinavmathur-atlan Apr 28, 2026
a245cd8
ci(mcp-cli): match MCP server release pattern with versioned tags
abhinavmathur-atlan Apr 28, 2026
c6fe72c
chore: consolidate mcp-cli gitignore into root, remove PLAN.md
abhinavmathur-atlan Apr 28, 2026
cd83333
chore: revert unnecessary gitignore additions to root
abhinavmathur-atlan Apr 28, 2026
e328703
chore: remove plugin artifact patterns from gitignore
abhinavmathur-atlan Apr 28, 2026
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
141 changes: 141 additions & 0 deletions .github/workflows/mcp-cli-publish.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,141 @@
name: Publish atlan-cli

on:
pull_request:
types: [closed]
branches:
- main
workflow_dispatch:

jobs:
prepare-release:
if: >
github.event_name == 'workflow_dispatch' ||
(github.event.pull_request.merged == true &&
contains(github.event.pull_request.labels.*.name, 'release-cli'))
runs-on: ubuntu-latest
permissions:
contents: write
outputs:
version: ${{ steps.get_version.outputs.version }}
should_release: ${{ steps.check_tag.outputs.exists == 'false' }}
steps:
- name: Checkout
uses: actions/checkout@v4
with:
fetch-depth: 0

- name: Get version
id: get_version
run: |
VERSION=$(grep -m 1 "__version__" mcp-cli/atlan_cli.py | cut -d'"' -f2)
echo "version=$VERSION" >> $GITHUB_OUTPUT
echo "Found version: $VERSION"

- name: Check if tag exists
id: check_tag
run: |
TAG_NAME="mcp-cli-v${{ steps.get_version.outputs.version }}"
if git rev-parse "$TAG_NAME" >/dev/null 2>&1; then
echo "Tag $TAG_NAME already exists, stopping workflow"
echo "exists=true" >> $GITHUB_OUTPUT
else
echo "Tag $TAG_NAME does not exist, continuing"
echo "exists=false" >> $GITHUB_OUTPUT
fi

- name: Generate changelog
id: changelog
if: steps.check_tag.outputs.exists == 'false'
run: |
set +e
VERSION="${{ steps.get_version.outputs.version }}"
RELEASE_DATE=$(date +"%Y-%m-%d")
PREV_TAG=$(git describe --tags --abbrev=0 HEAD~1 2>/dev/null || echo "")

if [ -z "$PREV_TAG" ]; then
FIRST_COMMIT=$(git rev-list --max-parents=0 HEAD)
RANGE="$FIRST_COMMIT..HEAD"
else
RANGE="$PREV_TAG..HEAD"
fi

echo "## [$VERSION] - $RELEASE_DATE" > RELEASE_NOTES.md
echo "" >> RELEASE_NOTES.md

git log $RANGE --format="* %s (%h)" --grep="^feat" --perl-regexp --no-merges 2>/dev/null > features.txt || touch features.txt
git log $RANGE --format="* %s (%h)" --grep="^fix" --perl-regexp --no-merges 2>/dev/null > fixes.txt || touch fixes.txt

if [ -s features.txt ]; then
echo "### Added" >> RELEASE_NOTES.md
echo "" >> RELEASE_NOTES.md
sed 's/^\* feat[[:space:]]*\([^:]*\):[[:space:]]*/\* /' features.txt >> RELEASE_NOTES.md
echo "" >> RELEASE_NOTES.md
fi

if [ -s fixes.txt ]; then
echo "### Fixed" >> RELEASE_NOTES.md
echo "" >> RELEASE_NOTES.md
sed 's/^\* fix[[:space:]]*\([^:]*\):[[:space:]]*/\* /' fixes.txt >> RELEASE_NOTES.md
echo "" >> RELEASE_NOTES.md
fi

if [ ! -s features.txt ] && [ ! -s fixes.txt ]; then
echo "### Changed" >> RELEASE_NOTES.md
echo "" >> RELEASE_NOTES.md
echo "* Release version $VERSION" >> RELEASE_NOTES.md
echo "" >> RELEASE_NOTES.md
fi

rm -f features.txt fixes.txt
cat RELEASE_NOTES.md

- name: Create tag
if: steps.check_tag.outputs.exists == 'false'
run: |
git tag mcp-cli-v${{ steps.get_version.outputs.version }}
git push --tags

- name: Create GitHub Release
if: steps.check_tag.outputs.exists == 'false'
uses: softprops/action-gh-release@v2
with:
tag_name: mcp-cli-v${{ steps.get_version.outputs.version }}
name: atlan-cli v${{ steps.get_version.outputs.version }}
body_path: RELEASE_NOTES.md
token: ${{ secrets.GITHUB_TOKEN }}
draft: false
prerelease: false

- name: Upload release notes
if: steps.check_tag.outputs.exists == 'false'
uses: actions/upload-artifact@v4
with:
name: release-notes
path: RELEASE_NOTES.md
retention-days: 1

publish:
needs: prepare-release
if: needs.prepare-release.outputs.should_release == 'true'
runs-on: ubuntu-latest
permissions:
contents: read
id-token: write # required for PyPI Trusted Publisher (OIDC)
defaults:
run:
working-directory: mcp-cli
steps:
- name: Checkout
uses: actions/checkout@v4
with:
ref: mcp-cli-v${{ needs.prepare-release.outputs.version }}

- name: Install uv
uses: astral-sh/setup-uv@v5

- name: Build
run: uv build

- name: Publish to PyPI
run: uv publish
160 changes: 160 additions & 0 deletions mcp-cli/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,160 @@
# Atlan MCP CLI

A standalone CLI for calling Atlan MCP tools directly from your terminal — no IDE, no agent required. Works on macOS, Windows, and Linux.

## Installation

Install [`uv`](https://docs.astral.sh/uv/getting-started/installation/) if you don't have it, then install the CLI as a global tool:

```bash
# From PyPI (once published)
uv tool install atlan-cli

# From source
uv tool install /path/to/agent-toolkit/mcp-cli
```

Add `~/.local/bin` to your PATH if prompted:

```bash
export PATH="$HOME/.local/bin:$PATH"
```

## Quick Start

```bash
# One-time login — interactive: choose OAuth or API key
atlan login

# Or skip the prompt and log in directly
atlan login --oauth # browser login
atlan login --api-key sk-xxx --tenant https://your-tenant.atlan.com # API key

# Check your auth status
atlan status

# Run tools — no flags needed after login
atlan semantic_search_tool --user-query "PII tables in Snowflake"
atlan list-tools
atlan get_asset_tool --guid "abc-123"
```

`atlan login` with no flags shows an interactive prompt:

```
Choose login method:
1 OAuth — browser login via mcp.atlan.com
2 API key — paste your Atlan API key

Choice [1/2] (1): 2
API key: <paste key and press Enter>
Tenant URL (e.g. https://demo.atlan.com): https://your-tenant.atlan.com
```

## Auth Commands

| Command | Description |
|---------|-------------|
| `atlan login` | Interactive: choose OAuth browser login or API key |
| `atlan login --oauth` | Force OAuth browser flow directly |
| `atlan login --api-key KEY --tenant URL` | Log in with an Atlan API key |
| `atlan logout` | Remove all stored credentials |
| `atlan status` | Show auth mode, tenant, and token expiry |

OAuth access tokens auto-refresh via the `mcp.atlan.com` proxy — you rarely need to re-run `atlan login`. To switch tenants, run `atlan logout` then `atlan login` again.

## Global Flags

These override stored credentials for a single invocation and are not persisted:

| Flag | Description |
|------|-------------|
| `--oauth` | Force fresh OAuth browser login this call |
| `--api-key KEY --tenant URL` | One-shot API key (not saved) |
| `--json` | Raw JSON to stdout; all logs go to stderr |

```bash
# One-shot overrides
atlan --oauth semantic_search_tool --user-query "PII tables"
atlan --api-key sk-xxx --tenant https://demo.atlan.com list-tools
atlan --json get_asset_tool --guid abc-123
```

## Available Tools

Run `atlan list-tools` to see the full list (requires auth). Common tools by category:

| Category | Tools |
|----------|-------|
| **Search & discovery** | `semantic_search_tool`, `search_assets_tool`, `search_atlan_docs_tool` |
| **Lineage** | `traverse_lineage_tool` |
| **Asset detail** | `get_asset_tool`, `resolve_metadata_tool`, `get_groups_tool` |
| **Asset updates** | `update_assets_tool`, `manage_announcements_tool`, `manage_asset_lifecycle_tool` |
| **Glossary** | `create_glossaries`, `create_glossary_terms`, `create_glossary_categories` |
| **Data mesh** | `create_domains`, `create_data_products` |
| **Data quality** | `create_dq_rules_tool`, `update_dq_rules_tool`, `schedule_dq_rules_tool`, `delete_dq_rules_tool` |
| **Custom metadata** | `create_custom_metadata_set_tool`, `update_custom_metadata_tool`, `remove_custom_metadata_tool`, `add_attributes_to_cm_set_tool`, `remove_attributes_from_cm_set_tool`, `delete_custom_metadata_set_tool` |
| **Tags** | `add_atlan_tags_tool`, `remove_atlan_tag_tool` |
| **Query** | `query_assets_tool`, `query_deep_sql_tool` |

Write tools (`create_*`, `update_*`, `delete_*`) default to `--mode propose` which shows a preview without making changes. Pass `--mode execute` only after reviewing the proposal.

```bash
# Preview a change (safe — no writes)
atlan update_assets_tool --updates '{"guid":"abc","name":"t","qualified_name":"qn","type_name":"Table","user_description":"new desc"}' --mode propose

# See tool parameters
atlan semantic_search_tool --help
```

## resolve_metadata_tool — Valid Namespace Types

The `--namespace-type` argument accepts these values:

- `users` — search Atlan users
- `classifications` — Atlan tag/classification names
- `business_metadata` — custom metadata set names
- `glossary` — glossary names and terms
- `data_domain_and_product` — data domains and products

```bash
atlan resolve_metadata_tool --namespace-type users --query "john"
atlan resolve_metadata_tool --namespace-type glossary --query "revenue"
```

## How Credentials Are Stored

| Storage | Contents | Permissions |
|---------|----------|-------------|
| `~/.atlan/config.json` | Auth mode and tenant URL (no secrets) | 0600 |
| OS keychain (`atlan-mcp`) | Access token, refresh token, or API key | OS-encrypted |
| `~/.atlan/credentials.json` | Fallback when OS keychain is unavailable | 0600 |

The OS keychain is used automatically on macOS (Keychain), Windows (Credential Manager), and Linux (Secret Service / GNOME Keyring). The file fallback activates on headless servers and CI environments.

## Exit Codes

| Code | Meaning |
|------|---------|
| `0` | Success |
| `1` | Tool returned an error |
| `2` | Not authenticated — run `atlan login` |
| `3` | Config or invocation error |

## Updating

After pulling new changes:

```bash
uv tool install /path/to/agent-toolkit/mcp-cli --reinstall
```

## Regenerating the CLI

If tool schemas change (new tools added to the server), regenerate with:

```bash
fastmcp generate-cli https://your-tenant.atlan.com/mcp --auth oauth --output atlan_cli.py --force
```

Re-apply the auth/packaging block at the top after regeneration — `fastmcp` does not write auth into generated scripts.
Loading
Loading