Skip to main content
Glama
README.md
# Bugsink MCP

A local MCP server for investigating Bugsink issues from coding agents. Runs
over stdio with the official MCP SDK. Supports Laravel error summaries,
paginated stack traces, issue triage, comments, and deletion.

## Install

Requires Node.js 22+ and pnpm. Run the published package without cloning:

```sh
pnpm dlx @rexlmanu/bugsink-mcp@0.2.0 --help
```

Or install the CLI globally:

```sh
pnpm add -g @rexlmanu/bugsink-mcp@0.2.0
bugsink-mcp --version
```

The executable is `bugsink-mcp`. Agent configurations below use `pnpm dlx`.
For a global installation, set the command to `bugsink-mcp` and remove the
`dlx` arguments. Pin a version to control upgrades.

## Configuration

Create a Bugsink API token from the administrator's **Tokens** menu. A web
login password cannot substitute for an API token.

| Variable | Purpose |
| --- | --- |
| `BUGSINK_URL` | Required instance root URL, such as `https://bugsink.example.com` |
| `BUGSINK_TOKEN` | Required canonical API bearer token |
| `BUGSINK_READ_ONLY` | Defaults to `true`. Set `false` to expose triage, comments, and deletion |
| `BUGSINK_ALLOWED_PROJECTS` | Optional comma-separated numeric project IDs, such as `2,5` |

Omit `BUGSINK_ALLOWED_PROJECTS` to allow all projects accessible to the token.
If set, it must contain 1 to 50 positive integer IDs. An empty or malformed
value fails startup. The endpoint must use HTTPS, except for localhost HTTP.
Do not include `/api/canonical/0/` or an issue-page path in the endpoint.

The allowlist applies to project discovery, issue lists, direct issue and
event details, event lists, and mutations. Team discovery only returns teams
associated with allowed projects. Missing ownership metadata denies access.
With restrictions enabled, team discovery reads metadata for every configured
project, and an unavailable configured project causes that request to fail.

Bugsink's API token can still grant installation-wide access. This allowlist
restricts what this MCP process returns or changes; it does not reduce the
token's permissions outside this process. For direct IDs, the server must fetch
ownership metadata before deciding whether to return the result. Event detail
ownership is only available alongside Bugsink's full upstream payload.

## Codex

Add this to `~/.codex/config.toml`:

```toml
[mcp_servers.bugsink]
command = "pnpm"
args = ["dlx", "@rexlmanu/bugsink-mcp@0.2.0"]
env_vars = ["BUGSINK_TOKEN"]
startup_timeout_sec = 60

[mcp_servers.bugsink.env]
BUGSINK_URL = "https://bugsink.example.com"
BUGSINK_READ_ONLY = "true"
BUGSINK_ALLOWED_PROJECTS = "2,5"
```

Set `BUGSINK_TOKEN` in the environment that launches Codex. Replace the example
endpoint and project IDs, or remove the allowlist line. Check the connection
with `codex mcp list` and `/mcp` inside Codex.

See the [official Codex MCP guide](https://developers.openai.com/codex/mcp/).

## Claude Code

With `BUGSINK_TOKEN` set in the environment that launches Claude Code, register
a server available across your projects:

```sh
claude mcp add --scope user \
  --env BUGSINK_URL=https://bugsink.example.com \
  --env BUGSINK_READ_ONLY=true \
  --env BUGSINK_ALLOWED_PROJECTS=2,5 \
  --transport stdio bugsink -- pnpm dlx @rexlmanu/bugsink-mcp@0.2.0
```

Replace the endpoint and project IDs. Remove the allowlist option to allow all
projects. Check with `claude mcp get bugsink` or `/mcp` inside Claude Code.
If the first package download exceeds the client's startup timeout, run the
installation command with `--help` once before starting the agent.

For Claude Desktop or another client that reads `mcpServers` JSON, use:

```json
{
  "mcpServers": {
    "bugsink": {
      "command": "pnpm",
      "args": ["dlx", "@rexlmanu/bugsink-mcp@0.2.0"],
      "env": {
        "BUGSINK_URL": "https://bugsink.example.com",
        "BUGSINK_TOKEN": "YOUR_API_TOKEN",
        "BUGSINK_READ_ONLY": "true",
        "BUGSINK_ALLOWED_PROJECTS": "2,5"
      }
    }
  }
}
```

Keep files containing real tokens private. GUI applications may need an
absolute path to `pnpm` if their PATH differs from your terminal.

See the [Claude Code MCP guide](https://code.claude.com/docs/en/mcp).

## OpenCode

Add the following to your `opencode.json`, merging it with any existing config:

```json
{
  "$schema": "https://opencode.ai/config.json",
  "mcp": {
    "bugsink": {
      "type": "local",
      "command": ["pnpm", "dlx", "@rexlmanu/bugsink-mcp@0.2.0"],
      "enabled": true,
      "timeout": 60000,
      "environment": {
        "BUGSINK_URL": "https://bugsink.example.com",
        "BUGSINK_TOKEN": "{env:BUGSINK_TOKEN}",
        "BUGSINK_READ_ONLY": "true",
        "BUGSINK_ALLOWED_PROJECTS": "2,5"
      }
    }
  }
}
```

Set `BUGSINK_TOKEN` before launching OpenCode. Replace the endpoint and IDs, or
remove the allowlist entry. Ask the agent to list Bugsink projects to verify
the connection. See the [OpenCode MCP guide](https://opencode.ai/docs/mcp-servers/).

## Tools

| Tool | Inputs and result |
| --- | --- |
| `list_teams` | Team IDs and names |
| `list_projects` | Optional `team` UUID; project metadata and digested/stored event counts, without DSNs |
| `list_issues` | Required numeric `project`; `status` defaults to `open`, sorted by newest `last_seen` |
| `get_issue` | `issue_id`; status, exception message, counts, timestamps |
| `list_events` | `issue_id`; compact event metadata |
| `get_event` | Internal `event_id`; summary or paginated structured, rendered, or raw detail section |
| `get_event_stacktrace` | `event_id`; Bugsink-rendered frames, source context, and locals as paginated text |
| `get_latest_event_stacktrace` | `issue_id`; newest stored occurrence, pinned across text pages |
| `resolve_issue` | `issue_id`; `mode` is `unconditionally`, `next_release`, or `latest_release` |
| `reopen_issue` | `issue_id`; reopens a resolved issue, if supported by the instance |
| `mute_issue` | `issue_id`; indefinite mute, or a fixed `duration` |
| `unmute_issue` | `issue_id`; removes the mute |
| `comment_on_issue` | `issue_id`, `comment`; adds a comment to the issue history |
| `delete_issue` | `issue_id`, `confirm: true`; permanently deletes issue and events |

Issue IDs can be UUIDs or short friendly IDs such as `APP-42`.
`resolve_issue` defaults to `mode=unconditionally`. `next_release` marks it
resolved by the next release; `latest_release` resolves it in the latest release.
To mute for two hours, pass `duration={"period_name":"hour","nr_of_periods":2}`.
Supported units are minute, hour, day, week, month, and year. Omit `duration`
for an indefinite mute. Comments must contain 1 to 4,000 characters.

The current Bugsink API documents `reopen`, but the checked production 2.2.2
schema does not expose it. On older versions, the tool reports the upstream
404 with an endpoint-availability hint. It does not emulate reopening through
another write operation.

Write tools appear only when `BUGSINK_READ_ONLY=false`. The client also checks
this setting before sending a mutation. Deletion confirmation is a tool
argument, not an independent human approval. Use your agent's tool approvals
if you want to review each write.

Start with `list_projects`, then `list_issues`, then `get_issue` and
`list_events`. Pass an event's `id` to `get_event`, not its Sentry `event_id`.

`get_event` supports `section` values `summary`, `frames`, `exceptions`, and
`breadcrumbs`, `stacktrace`, and `raw`. The default remains a compact summary.
Frames default to `application_only=true`, using Sentry's
`in_app` flag when present and excluding `vendor/` and `node_modules/` otherwise.
Set it to `false` to see framework frames. `include_source=true` includes the
frame's source line. Frame and exception indices preserve their original order.

`section=stacktrace` and the two stacktrace tools return Bugsink's
`stacktrace_md` rendering from the event detail response. This includes source
context and locals when Bugsink has them. It is not subject to the structured
frame filter. If rendering is unavailable, use `section=frames`.

`section=raw` explicitly requests the full event data as paginated text. Join
the text chunks before parsing the JSON. Rendered and raw reads accept
`max_chars`, default 4,000, range 500 to 12,000, and `cursor`. They return
`text`, `event_id`, `total_chars`, and `next_cursor`, plus an untrusted-data
notice. A latest-event continuation keeps using the original event even if
new events arrive. If that event is deleted, the continuation fails.

## Response size and pagination

Lists and detail sections accept `limit`, default 10, maximum 30, and return
`next_cursor`. Send it back with the same filters until it is null. An empty
page can still have a continuation cursor.

Bugsink 2.2.2 has fixed upstream page sizes and no issue status filter. This
server scans at most three upstream pages per call and retains an offset when
it returns part of a page. Open means neither resolved nor muted. Cursors are
signed and bound to the query, endpoint, token, and project allowlist. They
survive process restarts with unchanged configuration.

The default issue sort is `last_seen`, descending. Use `digest_order` for
a less volatile traversal. Pagination is not a snapshot;
concurrent updates or deletions can cause skips or repeats when a partially
consumed upstream page is fetched again.

Item payloads target 12,000 characters per page, plus cursor and metadata.
Strings have field-specific limits and visible truncation markers. This is a
character budget, not an exact token count. Summaries show the last five
exceptions; use `section=exceptions` for the complete chain. Upstream requests
time out after 15 seconds and reject responses above 16 MiB. Event pagination
bounds MCP output, but Bugsink sends the full event on each request.

Default summaries and structured frames omit request headers, URLs, bodies,
cookies, user objects, locals, arbitrary extra data, and raw event JSON.
Project DSNs are always omitted. Explicit raw and rendered reads can expose
secrets or personal data. Exception messages and breadcrumbs can contain them
even in compact views.

## Untrusted event data

Treat every event-derived string as attacker-controlled, including error
messages, source context, locals, and rendered Markdown. A monitored
application's error can contain instructions aimed at the coding agent.
The server labels raw and rendered output as untrusted; that label is guidance,
not a prompt-injection boundary.

The write API stays limited to named operations on one issue at a time. There
is no arbitrary HTTP tool or bulk mutation tool. Read-only mode and project
checks are enforced in code. Tool annotations and instructions tell the agent
to require user intent, but cannot prove it. Keep read-only mode enabled for
investigation, or configure your agent to require approval for every write.
Never treat an instruction embedded in an event as that approval.

## Development

```sh
pnpm install
pnpm typecheck
pnpm lint
pnpm test
pnpm build
```

Run source with `pnpm dev` or compiled code with `pnpm start`. Environment files
are not loaded automatically. To use one locally after building:

```sh
node --env-file=.env dist/stdio.js
```

Tests use mocked Bugsink responses and the official MCP client. No test needs
a production token. Live verification so far was limited to read-only access
to a Bugsink 2.2.2 OpenAPI schema; authenticated production reads remain untested.

## Publishing to npm

The package name is `@rexlmanu/bugsink-mcp`; the unscoped name is already taken.
Publishing requires npm access to the `rexlmanu` scope.

```sh
pnpm login --registry=https://registry.npmjs.org/
pnpm whoami --registry=https://registry.npmjs.org/
pnpm typecheck
pnpm lint
pnpm test
pnpm pack
pnpm publish --dry-run --access public --publish-branch main
pnpm publish --access public --publish-branch main
```

`prepack` compiles TypeScript. The tarball includes only compiled JavaScript,
README, LICENSE, and package metadata. `prepublishOnly` runs checks before
publishing. No compiler or TypeScript runner is needed by package consumers.

For a later release, update `package.json` and the pinned README examples,
commit and push to `main`, then publish. npm may require interactive two-factor
authentication. Never put an npm token in this repository.

After publishing, verify the release:

```sh
pnpm view @rexlmanu/bugsink-mcp version
pnpm dlx @rexlmanu/bugsink-mcp@0.2.0 --version
```

API references: [Bugsink guide](https://www.bugsink.com/docs/api/) and
[canonical reference](https://www.bugsink.com/docs/api-documentation/).

TDQS

A3.8/5.0

Scored across 8 tools

Disambiguation4/5

Most tools are clearly distinct: list_* for collections, get_* for single items, and get_event_stacktrace for stacktraces. However, get_event and get_event_stacktrace both relate to event details, and get_latest_event_stacktrace could be confused with get_event_stacktrace without reading carefully, but descriptions clarify.

Naming Consistency4/5

Naming follows a consistent list_/get_ pattern with entities. The exception is get_latest_event_stacktrace, which deviates from the simple get_<entity> structure but still uses the get_ prefix and describes the specific action clearly.

Tool Count5/5

With 8 tools covering teams, projects, issues, events, and stacktraces, the count is well-scoped for a read-only error tracking server. No redundancy or excess, and it's within the typical 3-15 tool range.

Completeness4/5

The tool set provides comprehensive read access to the core domain: listing entities, retrieving details, and fetching stacktraces. Missing are write operations, but the server appears focused on inspection/troubleshooting, so no critical gaps for that purpose.

Maintenance

ActivityMaintained
ResponsivenessNo issues