feat(mcp-cli): standalone CLI with API key & OAuth over Streamable HTTP#222
Closed
abhinavmathur-atlan wants to merge 26 commits into
Closed
feat(mcp-cli): standalone CLI with API key & OAuth over Streamable HTTP#222abhinavmathur-atlan wants to merge 26 commits into
abhinavmathur-atlan wants to merge 26 commits into
Conversation
Adds atlan_cli.py and SKILL.md to mcp-cli/ — a standalone CLI for calling all 30 Atlan MCP tools directly from the terminal. Auth modes (controlled via env vars): - API key: ATLAN_BASE_URL + ATLAN_API_KEY → /mcp/api-key with Bearer auth - OAuth (PKCE): ATLAN_BASE_URL only → /mcp with browser-based login Co-Authored-By: Claude Sonnet 4.6 (1M context) <noreply@anthropic.com>
Co-Authored-By: Claude Sonnet 4.6 (1M context) <noreply@anthropic.com>
Co-Authored-By: Claude Sonnet 4.6 (1M context) <noreply@anthropic.com>
- sys.argv.remove("--oauth") prevents cyclopts from seeing the flag
as an unknown command (was set inline before, still hit cyclopts)
- README: fix incorrect generation URL reference (was mcp.atlan.com/mcp,
which is an internal proxy); update regenerating command to use
tenant URL; add --oauth and ATLAN_AUTH=oauth auth-override docs
Co-Authored-By: Claude Sonnet 4.6 (1M context) <noreply@anthropic.com>
…/dotenv Co-Authored-By: Claude Sonnet 4.6 (1M context) <noreply@anthropic.com>
…eeStore Eliminates browser re-auth on every CLI invocation. Tokens are stored per-server-URL in ~/.atlan/mcp-tokens using key_value FileTreeStore (already a transitive dep of fastmcp). Also fixes README uv run syntax. Co-Authored-By: Claude Sonnet 4.6 (1M context) <noreply@anthropic.com>
…en persistence FileTreeStore used keys directly as filesystem paths, which broke when keys were URLs (e.g. https:/tenant/mcp created nested directories that didn't exist). _JsonFileStore hashes the collection name for the filename and uses dict keys for key lookup — safe for any key string including URLs. Co-Authored-By: Claude Sonnet 4.6 (1M context) <noreply@anthropic.com>
- Prerequisites: uv run handles PEP 723 deps automatically, no pip install needed - Auth modes: note that OAuth tokens are cached in ~/.atlan/mcp-tokens/ - Regenerating: replace fragile line-number reference with structural marker Co-Authored-By: Claude Sonnet 4.6 (1M context) <noreply@anthropic.com>
- Add pyproject.toml with setuptools build backend and atlan script entry point so users can install with `uv tool install .` instead of invoking via `uv run python3 atlan_cli.py` - Remove the `call-tool` sub-app; all tool commands now live directly on the root app so invocation is `atlan semantic_search_tool` instead of `atlan call-tool semantic_search_tool` - Add main() entry point function wired to the pyproject.toml [project.scripts] - Remove PEP 723 inline script metadata (superseded by pyproject.toml) Co-Authored-By: Claude Sonnet 4.6 (1M context) <noreply@anthropic.com>
Move auth resolution from module-level to a lazy _resolve_auth() function called only when a command actually connects to the server. Also fixes --oauth handling by stripping it in main() and setting ATLAN_AUTH=oauth. Also fix pyproject.toml build-backend to setuptools.build_meta (the legacy backend path was removed in newer setuptools versions). Co-Authored-By: Claude Sonnet 4.6 (1M context) <noreply@anthropic.com>
- Fix critical bug: Client(*_resolve_auth()) was mapping the OAuth handler to the `name` param (2nd positional arg), not `auth`. Replace all call sites with _client() helper that explicitly passes auth=auth as a keyword argument. - Load .env from cwd before script-dir so installed tool respects a .env in the working directory. Co-Authored-By: Claude Sonnet 4.6 (1M context) <noreply@anthropic.com>
Reflect new uv tool install workflow, direct tool invocation without the call-tool prefix, and OAuth token caching behaviour. Co-Authored-By: Claude Sonnet 4.6 (1M context) <noreply@anthropic.com>
Captures the agreed direction from the meeting with Ankit and Hrushikesh: persistent login state, hardcoded proxy URL, ~/.atlan config dir, PyPI distribution modeled on pyatlan, agent-friendly diagnostics, and a phased rollout aligned with the Activate demo. Co-Authored-By: Claude Sonnet 4.6 (1M context) <noreply@anthropic.com>
…sign Incorporates findings from agent-toolkit-internal:mcp_proxy: the proxy already supports refresh_token grant and derives tenant from the JWT issuer claim, so the CLI can store only the refresh token and never needs to know the tenant URL. - Detailed file layout (src/atlan_cli/auth, commands, transport) - Auth resolver pseudo-code with stale-cache wipe invariants - Refresh-token flow against mcp.atlan.com/oauth/token - Decision: keep cyclopts, add rich/questionary for prettier output - Phased breakdown with effort estimates per item - GitHub Actions publish workflow modeled on pyatlan-publish.yaml - Test plan, risks, references Co-Authored-By: Claude Sonnet 4.6 (1M context) <noreply@anthropic.com>
…hing - atlan login / logout / status commands with OS keyring storage (~/.atlan/config.json + keyring with ~/.atlan/credentials.json fallback) - OAuth refresh-token grant via mcp.atlan.com proxy; stale-cache wipe on failure; exit 2 so callers can detect auth-required vs tool errors - _resolve_auth() hierarchy: per-call override → stored config → refresh → exit 2; legacy ATLAN_BASE_URL env-var path preserved for backwards compat - Global flags --oauth / --api-key / --tenant / --json stripped in main() before cyclopts sees argv; --json routes all output to stdout, logs to stderr - Exit codes: 0 success, 1 tool error, 2 auth required, 3 config/invocation - Rich UI: list-tools as Table, status/login as Panels, questionary chooser - Package renamed atlan-cli (was atlan-mcp-cli); hatchling build backend; dynamic version from __version__; dependency version ranges pinned - .github/workflows/mcp-cli-publish.yaml: release tag → uv build + uv publish - API key validation switched from /api/meta/whoami to /api/meta/types/typedefs (whoami returns 500 on some tenants; typedefs is more reliable) - mcp-cli/.gitignore: excludes build artifacts, .env, .venv, uv.lock, .fastmcp-cache/ Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
…ways opens browser Without this, .fastmcp-cache/ survived logout and FastMCP reused cached tokens silently, making tenant switching impossible without manual cache deletion. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
- Remove dead _KeyringStore and _CapturingStore classes (never used in practice; flat keyring helpers and direct token extraction cover all paths) - Add _maybe_json() helper: safe json.loads with fallback for non-JSON strings, replacing bare json.loads() which crashed on free-form text - Make argument parsing schema-aware: pure string|null params (title, message, announcement_type, guid, qualified_name, asset_type, name_filter, group_id, default_schema, connection_qualified_name, sort_by, glossary_qualified_name, include_attributes in traverse/get_asset) now pass through without JSON decoding; object/array/integer params continue to use _maybe_json() - Fix _wipe_credentials() to reset cached _resolved auth so logout is effective in long-lived processes - Move Panel import to top-level; remove three inline from-imports - Remove # Parse JSON parameters comments throughout generated section - Improve README: namespace-type enum values, exit codes table, cross-platform keychain details, write-tool propose/execute workflow, tool category table Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
questionary was not installed (not in deps), causing atlan login to silently skip the chooser and go straight to OAuth. Now uses rich.prompt (already a required dep) for the method selector and masked API key input. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
getpass.getpass() reads char-by-char in raw terminal mode and stalls visibly when pasting long JWT tokens (1000+ chars). input() uses the terminal's own line-edit mode and handles pastes instantly. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
- workflow: allow workflow_dispatch (was blocked by tags-only if condition) - gitignore: add plugin build artifact patterns (*.tar.gz, *.zip) - README: add PyPI install snippet, document interactive login flow with example Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Three F541 bare f-strings and one formatting inconsistency flagged by pre-commit ruff hooks; auto-fixed with ruff --fix + ruff format. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Adds id-token: write permission and removes PYPI_API_TOKEN env var. OIDC trusted publisher is more secure — no long-lived secret needed. Configure the pending publisher at pypi.org with: project: atlan-cli, owner: atlanhq, repo: agent-toolkit, workflow: mcp-cli-publish.yaml Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
- Triggers on PR merge to main with 'release-cli' label (mirrors 'release' label used by mcp-server-release.yml, separate to avoid double-trigger) - Reads __version__ from mcp-cli/atlan_cli.py - Creates tag mcp-cli-vX.Y.Z, GitHub Release with auto-changelog - Publishes to PyPI via OIDC trusted publisher (no API token secret) - workflow_dispatch still works for manual runs Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
- Moved uv.lock, .fastmcp-cache/, .env.* rules into root .gitignore - Removed mcp-cli/.gitignore (redundant now) - Removed mcp-cli/PLAN.md (implementation complete, context lives in git history) Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Keep only plugin artifact patterns (.tar.gz, .zip) which cover real untracked files. Remove .env.*, uv.lock, .fastmcp-cache/ — not needed at root level. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Not needed — these are stray local files, not repo concerns. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Collaborator
Author
|
Moving mcp-cli to agent-toolkit-internal for now. Publishing to PyPI will come in a follow-up once confirmed. |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
mcp-cli/— a standaloneatlanCLI for calling Atlan MCP tools directly from the terminal (no IDE, no agent required)mcp.atlan.comproxy with automatic token refreshAuth
~/.atlan/config.jsonatlan-mcp~/.atlan/credentials.jsonInstallation
uv tool install /path/to/agent-toolkit/mcp-cli # Future: uv tool install atlan-cliExit codes
atlan loginTest plan
atlan logininteractive chooser — OAuth and API key pathsatlan login --api-key ... --tenant ...non-interactiveatlan status— shows mode, tenant, token expiryatlan logout— wipes keyring + configmcp.atlan.com)--jsonflag emits raw JSON to stdout, logs to stderr~/.atlan/credentials.jsonstring|nullparams bypass JSON parse🤖 Generated with Claude Code