Skill + CLI over MCP: Replacing Sentry MCP with a multi-profile CLI wrapper
Background
I want to use Sentry's CLI tool sentry-cli with multiple organizations, but it has no native multi-profile feature like the AWS CLI's --profile.
Installing sentry-cli
brew install getsentry/tools/sentry-cli
Configuration Priority
According to the official documentation (Configuration and Authentication), settings are loaded in the following order of priority.
- Command-line arguments (
-o,-p,--auth-token) - Environment variables (
SENTRY_AUTH_TOKEN,SENTRY_ORG,SENTRY_PROJECT) - A
.sentryclircfile, searched for upward from the current directory ~/.sentryclirc(global default)
The .sentryclirc file name is fixed. A file renamed to something else (such as .sentryclirc-staging) is not loaded (reference).
What About Sentry MCP Server?
Sentry also provides an MCP server, which lets an AI agent operate Sentry directly. But it has several problems.
- The old version (stdio transport + Auth Token) has in effect been replaced by its successor. The sentry-mcp-stdio repository remains "for educational purposes", but the remote MCP server is now the recommended one
- The new version (OAuth + Streamable HTTP) needs re-authentication every time the session expires. I have to go through the OAuth flow in the browser again, and having my work interrupted is stressful
- It consumes a lot of context. Sentry event and issue data has a complex structure, and the MCP tool definitions alone use quite a lot of tokens
- It does not support multiple accounts. Creating multiple MCP server instances works around this, but the context consumed grows in proportion to the number of instances, which is painful
In the end, a CLI wrapper plus an AI agent skill is lighter and more flexible to work with.
Solution: zsh Wrapper Function
A zsh function always takes priority over a binary of the same name on PATH, so just defining a function named sentry-cli wraps the real sentry-cli installed with brew.
Profile Storage
~/.config/sentry-cli/profiles/<name>.env
The content is a simple env file.
SENTRY_AUTH_TOKEN=sntrys_xxx...
SENTRY_ORG=my-org
SENTRY_URL=https://my-org.sentry.io/
It is better not to fix SENTRY_PROJECT in the profile and to pass it with -p when running a command, because one org usually has several projects.
The Wrapper Function
Add the following function to ~/.zshrc, an alias file, or similar.
# sentry-cli wrapper with --profile support
# Profiles: ~/.config/sentry-cli/profiles/<name>.env
function sentry-cli () {
local _sentry_cli
# whence -p: ignores functions and returns only the binary path
_sentry_cli=$(whence -p sentry-cli) || { echo "sentry-cli not found in PATH" >&2; return 1; }
local profile_dir="${HOME}/.config/sentry-cli/profiles"
local profile=""
local setup=0
local args=()
while [[ $# -gt 0 ]]; do
case "$1" in
--profile=*) profile="${1#--profile=}"; shift ;;
--profile) profile="$2"; shift 2 ;;
--profiles)
if [[ -d "$profile_dir" ]]; then
for f in "$profile_dir"/*.env(N); do
echo "${f:t:r}"
done
else
echo "No profiles directory: $profile_dir" >&2
fi
return 0
;;
--setup) setup=1; shift ;;
*) args+=("$1"); shift ;;
esac
done
# --setup: create or edit a profile
if [[ $setup -eq 1 ]]; then
if [[ -z "$profile" ]]; then
echo "Usage: sentry-cli --profile=<name> --setup" >&2
return 1
fi
mkdir -p "$profile_dir"
local pfile="${profile_dir}/${profile}.env"
if [[ -f "$pfile" ]]; then
echo "Editing existing profile: $profile"
else
echo "Creating new profile: $profile"
cat > "$pfile" <<TMPL
SENTRY_AUTH_TOKEN=
SENTRY_ORG=${profile}
SENTRY_URL=https://${profile}.sentry.io/
TMPL
fi
${EDITOR:-vim} "$pfile"
return 0
fi
# No profile: passthrough
if [[ -z "$profile" ]]; then
"$_sentry_cli" "${args[@]}"
return $?
fi
# Load profile and run
local pfile="${profile_dir}/${profile}.env"
if [[ ! -f "$pfile" ]]; then
echo "Profile not found: $pfile" >&2
echo "Run: sentry-cli --profile=${profile} --setup" >&2
return 1
fi
# Source in a subshell so the current environment variables are not polluted
(
set -a
source "$pfile"
set +a
"$_sentry_cli" "${args[@]}"
)
}
Gotcha: The command -v Trap
My first implementation got the binary path with command -v sentry-cli, but zsh's command -v also returns the function of the same name itself, so it went into infinite recursion and failed with the error maximum nested function level reached; increase FUNCNEST?.
With whence -p, you can ignore functions and get only the binary path. This is a zsh-specific builtin command.
Usage
# Create a profile (opens an editor)
sentry-cli --profile=myorg --setup
# Check the connection
sentry-cli --profile=myorg info
# List projects
sentry-cli --profile=myorg projects list
# List releases (with a project specified)
sentry-cli --profile=myorg releases list -p my-project
# List profiles
sentry-cli --profiles
# Without a profile (works as the normal sentry-cli)
sentry-cli info
Registering as a Claude Code Skill
I also registered this wrapper as a Claude Code skill. With a SKILL.md written, the AI agent can naturally use sentry-cli --profile=xxx to operate Sentry.
The whole skill definition is below.
---
name: sentry-cli
description: Multi-profile wrapper for Sentry CLI. Release management, sourcemap uploads, event sending, etc.
allowed-tools: Bash(sentry-cli:*)
---
# Sentry CLI (multi-profile wrapper)
A zsh wrapper for using Sentry CLI with multiple profiles.
## Important: Check the help before operating
If a sentry-cli subcommand or argument is unclear, read the help first.
sentry-cli --help
sentry-cli <subcommand> --help
## Profile management
### Create or edit a profile
sentry-cli --profile=<name> --setup
### List profiles
sentry-cli --profiles
### Run with a profile
sentry-cli --profile=<name> <subcommand> [options]
### Run without a profile (works as the normal sentry-cli)
sentry-cli <subcommand> [options]
## Common subcommands
- info: Check connection info and auth status
- releases: List, create, and finalize releases
- sourcemaps: Upload sourcemaps
- send-event: Send a test event
- deploys: Record deploys
- issues: List and resolve issues
- projects: List projects
The points are as follows.
allowed-tools: Bash(sentry-cli:*)allows the agent to run thesentry-clicommand- Including an instruction to read
--helpbefore operating prevents wrong subcommand arguments - Profile management commands and common subcommands are listed as a reference so the agent can use them right away
We look forward to discussing your development needs.