Repository navigation
feat(mcp): Serve each exposed CLI command as its own MCP tool - #1922
Open
sentry-junior[bot] wants to merge 18 commits into
Open
sentry-junior[bot] wants to merge 18 commits into
sentry-junior[bot] wants to merge 18 commits into
Conversation
…ools `sentry mcp --commands` replaces the hand-written tool catalog with three tools generated from the CLI command catalog: `search_sentry` finds commands, `execute_sentry_read` runs read commands, and `execute_sentry_write` runs write and destructive ones. `--read-only` drops the write tool. Calls are validated against each command's flag schema, pinned to the session's org and project, and run through the SDK, which loads only the routes a call needs. The SDK can now run without its own telemetry, and `run()` reports failures again: the fake process started with `exitCode: 0`, which hid every error Stricli recorded with `??=`. Closes #1890 Co-Authored-By: BYK <126780+BYK@users.noreply.github.com>
|
The latest updates on your projects. Learn more about Vercel for GitHub. 1 Skipped Deployment
|
A result over the size cap that is not a list was sliced mid-JSON with a note appended, so agents could not parse it, and the text ran past the cap. It now returns the start of the result's JSON text as a string in `result`, with `truncated.characters` and a hint, inside the cap. Co-Authored-By: BYK <126780+BYK@users.noreply.github.com>
3 of 38 tasks
Harnesses search large tool lists themselves, so `sentry mcp --commands`
no longer adds `search_sentry`, `execute_sentry_read`, and
`execute_sentry_write`. Each exposed command in the command catalog is its
own tool, named from its path (`sentry issue list` → `sentry_issue_list`),
with the catalog's brief, examples, and `{ positional, flags }` schema.
Read commands are marked read-only and write and destructive ones
destructive. `sentry api` is one tool marked destructive, since each call
takes the class of its method; under `--read-only` it is marked read-only
and refuses every method but GET, HEAD, and OPTIONS. `--read-only` drops
the write tools.
The schema rides on permissive Zod types as metadata, so `tools/list` shows
it as is, no defaults are filled in, and the existing validator still
returns errors that name the allowed values.
Co-Authored-By: BYK <126780+BYK@users.noreply.github.com>
…cli-first-mcp-execute # Conflicts: # packages/cli/src/command-manifest.ts Co-Authored-By: BYK <126780+BYK@users.noreply.github.com>
Treat a `target` positional as `<org>/<project>`, check every `[<org>/]<id>` word and a leading `<org> <id>` org, and read a nested `organizations/<org>/projects/<project>/` path for `sentry api`. Before, a scoped session could reach another organization or project through these. Co-Authored-By: BYK <126780+BYK@users.noreply.github.com>
`<org>/<project>/<suffix>` under a one-word title (`feedback`, `issue`) names a project, so a project-scoped session now refuses another project there. Co-Authored-By: BYK <126780+BYK@users.noreply.github.com>
In a project-scoped session, check every --project value (repeated or comma-separated) and pin an `<org>/` target to the session's project. Drop nextCursor from a result cut to fit, since it points past the items that were cut.
- Check the org and project of Sentry URLs, including /settings/<org>/ and feedbackSlug links, against the session. - Resolve sentry api paths as the request will (dot segments), and read teams/<org>/ as scoped to that org. - Refuse status show --url, which fetches a host the caller picks. - List write commands only for the skill that covers them (seer, triage, or project-management), and refuse sentry api writes without one. - Refuse the last and previous cursor aliases when hosted. - Treat null flags and positionals as none. - Serve --commands with the stored login that knows its <org>/ target.
The CLI strips an api/0/ prefix with or without a leading slash, so session pinning must too, or a valid endpoint is refused as unscoped. Co-Authored-By: BYK <126780+BYK@users.noreply.github.com>
In a project session, sentry api takes only endpoints that name the session's project, since organization-wide ones span every project. GitHub-style (org/project#ID, project#ID) and project:ID issue references are checked like their org/project/ID form.
Co-Authored-By: BYK <126780+BYK@users.noreply.github.com>
#1991 made `title` required on every tool. Command tools take it from the command path, title-cased (`sentry issue list` → `Issue List`). Co-Authored-By: BYK <126780+BYK@users.noreply.github.com>
Co-Authored-By: BYK <126780+BYK@users.noreply.github.com>
sentry api sends an absolute URL to that URL's own host, so an agent could make it fetch any host it picks, as status show --url could. Agents pass the path relative to /api/0/ instead.
… feat/cli-first-mcp-execute
Co-Authored-By: BYK <126780+BYK@users.noreply.github.com>
… feat/cli-first-mcp-execute
Contributor
There was a problem hiding this comment.
Cursor Bugbot has reviewed your changes and found 1 potential issue.
❌ Bugbot Autofix is OFF. To automatically fix reported issues with cloud agents, enable autofix in the Cursor dashboard.
Reviewed by Cursor Bugbot for commit 0b80422. Configure here.
A leading bare word of dashboard view is the organization, as for agent-conversation view, so it must match the session's. An org/project target under a longer title (span list acme/api, trace view acme/api <id>, log list acme/api) names its project, so a project session checks it.
This branch was previously deployed
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.

Closes #1890. Part of the
cli-first-mcpplan (#1357).Stacked on #1919 (
feat/command-catalog), which is stacked on #1916. Retarget this tomainonce those merge.sentry mcp --commandsreplaces the hand-written tool catalog with one MCP tool for eachexposedcommand in the CLI command catalog. Each tool is named from its command path (sentry issue list→sentry_issue_list). Its description is the command's brief and examples, and its input schema is the catalog's{ positional, flags }JSON Schema. Harnesses search large tool lists themselves, so this PR no longer adds thesearch_sentry,execute_sentry_read, orexecute_sentry_writemeta-tools. They are gone.Hints. Read commands get
readOnlyHint; write and destructive commands getdestructiveHint.sentry apitakes its class from the--methodof each call. It stays a single tool marked destructive, because no per-call hint exists and splitting it into GET and non-GET tools would add a tool without changing what a host can allowlist. Under--read-onlyit is marked read-only and refuses every method except GET, HEAD, and OPTIONS.--read-onlyalso drops every write tool: 85 tools become 52.How a call runs. The execution path is unchanged:
seer,triage, orproject-management);sentry apiwrites needtriageorproject-management.targetpositionals, every[<org>/]<id>word,<org>/<project>/<suffix>IDs, Sentry URLs including/settings/<org>/projects/<project>/, andsentry apipaths underorganizations/,projects/, orteams/, resolved like the request) must match it, and a bare project gets the session's org.createSentrySDK().run(), which loads only the routes it needs.nextCursoris lifted out for paginated commands.Hidden and stdio-only commands are not listed.
localPathflags,--web, streaming flags, andstatus show --url(it fetches a caller-picked host) are refused. The schema is attached as metadata on permissive Zod types, sotools/listshows the catalog schema as is, the SDK fills in no defaults, and the validator's messages reach the agent.SDK fixes this needed.
SentryOptions.telemetry: falseskips the SDK's own Sentry init, which otherwise closed the MCP server's client on every call.run()also reports failures again: the fake process started withexitCode: 0, and since Stricli records failures withexitCode ??= code, every failure was hidden.Tokens (
pnpm run measure-tokens):--commands, one tool per command (this PR)--commandswith search/execute meta-tools (earlier version of this PR)QA. Over stdio,
sentry mcp --commands --read-onlylisted 49 tools before the latest restack, none of them write tools.sentry_issue_listreturned real issues from thesentryorg with anextCursor, and asentry_apiPOST was refused. The slim@sentry/mcp-serverbundle still stubs this path out and points users to the CLI.Known gap. Examples in tool descriptions drop any that pipe output elsewhere or use a refused flag's long name. Short aliases such as
-wstill show, because the catalog doesn't record aliases.Left for follow-ups:
examples.--commandsuses one account per session: the stored login that knows its<org>/target, else the startup account. Calls are not routed between logins.via @BYK.
--
View Session in Sentry