The command line, and the MCP server inside it

One npm package does three jobs: it uploads the source maps that make a stack trace readable, it sends a diff for review, and it serves your telemetry to a coding agent over MCP. The third is the one worth reading about — it puts your production errors in front of the agent that is editing the code.

Install it

It needs Node 20.19 or newer. There is nothing to install if you only want to try it: npx fetches and runs it in one step, which is the right form for a CI job that should pin a version rather than track whatever is latest.

Every command prints what it will do before it does it, and --dry-run on the two commands that send something will show you the payload and send nothing.

Shell
# once, without installing
npx [email protected] whoami

# or install it
npm install -g snagspy
snagspy --help

Give it a token, in the environment

Authentication is an API key from your organisation’s settings. The CLI reads SNAGSPY_TOKEN, and there is a --token flag that you should prefer not to use: an argument is visible to anything on the machine that can list processes, and it lands in your shell history. The flag exists because sometimes there is no other way, not because it is the normal way.

SNAGSPY_API points at the API and only needs setting if you are not on the hosted platform. whoami is the command to run when something is refused and you want to know which organisation and which scopes the token actually carries — it prints those two things and nothing else, so it is safe to paste into a bug report.

Shell
export SNAGSPY_TOKEN=slk_...
snagspy whoami

organisation: Example Ltd (cafb3c85-07d2-44a8-bab1-a7f04fffb0e6)
scopes:       events:read, issues:write

Each command needs its own scope, and no more

The four commands need four different scopes, so a token minted for CI to upload source maps cannot read a single event. That is the point of splitting them: the credential that lives in your build system should be able to do the one thing your build system does.

A token carrying more than one scope is fine and common — a developer’s own token usually carries the two the MCP server uses. The separation matters most for the tokens you will never look at again.

Scope per command
snagspy upload    artifacts:write
snagspy review    code:review
snagspy mcp       events:read     (reading)
snagspy mcp       issues:write    (setting an issue status)
snagspy whoami    any

Upload source maps, so a stack trace names your code

A minified stack trace names t.js:1:4821, which tells nobody anything. Uploading the maps for a release turns that back into the file and line somebody wrote. Do it in the build, after the bundler runs and before the deploy.

--release is optional and you should always pass it. A map uploaded without one cannot be matched to the build that produced the error, so the resolution silently does not happen — and an unresolved stack looks exactly like a stack from a release you never uploaded maps for.

The command reports what it sent and what it skipped. A file with no source map alongside it is skipped rather than treated as an error, because a dist directory normally holds both.

Shell
snagspy upload --project <project-id> --release v1.4.2 ./dist

snagspy upload: 1 sent, 0 skipped, from ./dist

Send a change for review

snagspy review diffs your branch and sends the change back for comment. With no flags it works out a merge base against origin/HEAD; --base origin/main says it explicitly, and --diff reads a unified diff from a file if you would rather run git yourself.

--fail-on decides whether a finding fails your build, and it defaults to never. That default is deliberate: adopting this on a Friday should not start failing every pipeline in the organisation on the same afternoon. Move it to high once you have seen what it reports on your own code.

--format github emits inline annotations, which is what you want inside Actions. --fix applies the edits it offers to your working tree — it commits nothing and pushes nothing, so git diff is still how you decide whether to keep them.

Shell
snagspy review --base origin/main
snagspy review --format github --fail-on high
snagspy review --dry-run          # print what would be sent, send nothing

The MCP server: your telemetry, inside the agent

snagspy mcp serves your organisation’s telemetry over MCP on stdio, which is the transport Claude Code, Cursor and the other agent clients speak. The agent that is editing a file can then ask what is actually failing in production, instead of you copying a stack trace into a chat window.

It is the same binary and the same token. Point your client at the command and give it the environment; there is no separate daemon and nothing listening on a port.

Agent client configuration
{
  "mcpServers": {
    "snagspy": {
      "command": "npx",
      "args": ["-y", "[email protected]", "mcp"],
      "env": { "SNAGSPY_TOKEN": "slk_..." }
    }
  }
}

What the agent can ask for

Ten tools, and the server registers only the ones your token can call. Nine of them read; update_issue_status is the only one that writes, and it appears only for a token carrying issues:write. A token carrying neither scope is refused when the server starts rather than connecting and offering an empty tool list — a server that starts successfully and can do nothing is the worse of the two failures, because the agent reports it as "no results".

Assignment is deliberately not offered. The API assigns an issue by self-claim, and an API key is not a person, so there is no coherent thing for an agent to claim.

Nothing here escapes the organisation the token belongs to. A tool that takes a project_id is narrowing a search, not widening one.

Tools
list_issues          grouped errors, newest activity first
get_issue            one issue and its most recent event
search_logs          log records for one project
list_traces          trace summaries, one line each
get_trace            every span of one trace
service_map          which services called which
list_anomalies       rate departures from the recent baseline
list_releases        releases derived from deployments
deployment_health    telemetry either side of one deployment
update_issue_status  resolve, ignore or reopen   (issues:write)

Two answers worth reading carefully

A resolved stack trace is only resolved if the maps were uploaded for that release. get_issue returns stack_is_resolved for exactly this reason — check it before you trust a file and line number, because an unresolved frame is not wrong so much as it is about the bundle rather than the source.

deployment_health can answer insufficient_data, and that is not a clean bill of health. It means there was too little telemetry around that deployment to compare either side of it. Read it as unknown; a quiet service and a healthy one look identical from here.

The service map draws an edge from a span whose parent belongs to a different service. A project whose spans all name one service therefore has no edges, and an empty map usually means single-service instrumentation rather than a broken one.

← Documentation