bugsink-mcp
by fers4t
README.md
# bugsink-mcp
A full read/write [MCP](https://modelcontextprotocol.io) server for [Bugsink](https://www.bugsink.com/)
(self-hosted, Sentry-protocol-compatible error tracking), built directly against Bugsink's
`/api/canonical/0/` OpenAPI schema.
It exists because the existing `bugsink-mcp` package on npm only wraps the **read** side of the
API (list/get). This one covers the full canonical API surface: resolving, muting, reopening and
deleting issues, commenting, and creating/updating teams, projects and releases — plus a couple of
correctness fixes over the original (see [Fixes over the original](#fixes-over-the-original)).
## Setup
Requires Node.js 18.17+.
1. In Bugsink, go to **Account Settings → Auth Tokens** and create a token.
2. Add the server to your MCP client.
### Claude Code
One-liner, using the [`claude mcp` CLI](https://docs.claude.com/en/docs/claude-code/mcp):
```bash
claude mcp add bugsink \
-e BUGSINK_URL=https://bugs.example.com \
-e BUGSINK_TOKEN=<your token> \
-- npx -y github:fers4t/bugsink-mcp
```
This writes the equivalent of the following into `~/.claude.json` (or pass `--scope project` to
write a shared `.mcp.json` instead of the user-local config):
```json
{
"mcpServers": {
"bugsink": {
"type": "stdio",
"command": "npx",
"args": ["-y", "github:fers4t/bugsink-mcp"],
"env": {
"BUGSINK_URL": "https://bugs.example.com",
"BUGSINK_TOKEN": "<your token>"
}
}
}
}
```
Restart Claude Code (or start a new session) afterwards — MCP tool lists are loaded at session
start and won't pick up a config change mid-conversation.
### Other MCP clients
Any client that reads a `mcpServers` map (Cursor, Windsurf, etc.) can use the same JSON shape
shown above — point it at `command: npx`, `args: ["-y", "github:fers4t/bugsink-mcp"]`, and the two
required env vars.
`npx` installs straight from GitHub (no npm publish involved) and runs the `prepare` script to
compile TypeScript on first use, then reuses its local cache on subsequent launches.
### Environment variables
| Variable | Required | Description |
| --------------------- | -------- | ---------------------------------------------------------- |
| `BUGSINK_URL` | yes | Base URL of your Bugsink instance, e.g. `https://bugs.example.com` |
| `BUGSINK_TOKEN` | yes | Personal API token (Bearer auth) |
| `BUGSINK_TIMEOUT_MS` | no | Per-request timeout in ms (default `15000`, clamped to `1000–120000`) |
See `.env.example`. Never commit a real token — the server reads it from the environment only.
## Tools
### Connectivity
| Tool | Description |
| --- | --- |
| `test_connection` | Verify the URL/token work and report how many teams are visible |
### Teams
| Tool | Description |
| --- | --- |
| `list_teams` | List all teams |
| `get_team` | Get a team by UUID |
| `create_team` | Create a team |
| `update_team` | Rename a team or change its visibility |
### Projects
| Tool | Description |
| --- | --- |
| `list_projects` | List projects, optionally filtered by team |
| `get_project` | Get a project (including its DSN), optionally expanding the team |
| `create_project` | Create a project under a team |
| `update_project` | Update name/visibility/alert flags/retention/team |
### Issues
| Tool | Description |
| --- | --- |
| `list_issues` | List issues for a project (sort by `digest_order`, `digested_event_count` or `last_seen`) |
| `get_issue` | Get an issue by UUID or friendly ID (e.g. `PROJ-123`) |
| `delete_issue` | **Irreversibly** delete an issue and its events |
| `resolve_issue` | Resolve now |
| `resolve_issue_in_next_release` | Resolve, regressing if a later release reports it again |
| `resolve_issue_in_latest_release` | Resolve as of the current latest release |
| `reopen_issue` | Reopen a resolved issue |
| `mute_issue` | Mute indefinitely |
| `mute_issue_for` | Mute for N periods (e.g. 3 days) |
| `mute_issue_until` | Mute until an event-count threshold is crossed in a period |
| `unmute_issue` | Unmute |
| `add_issue_comment` | Add a comment to an issue |
### Events
| Tool | Description |
| --- | --- |
| `list_events` | List events (occurrences) for an issue |
| `get_event` | Get full event detail, including tags/contexts/raw payload |
| `get_stacktrace` | Render a rendered-Markdown stacktrace for an event |
### Releases
| Tool | Description |
| --- | --- |
| `list_releases` | List releases for a project |
| `get_release` | Get a release by UUID |
| `create_release` | Create a release (needed for `resolve_issue_in_next_release` to regress correctly) |
## Fixes over the original
- **`get_stacktrace` actually works.** Bugsink's stacktrace endpoint returns `text/markdown`, not
JSON. The original package called `res.json()` unconditionally and threw
`Unexpected token '#', "# TypeError"... is not valid JSON` on every call. This server reads that
endpoint as text.
- **Write support**: resolve/mute/reopen/delete/comment on issues, and create/update for teams,
projects and releases — none of which the read-only original exposed.
- **Bounded timeouts** (`AbortSignal.timeout`, default 15s) on every request, so a hung upstream
can't hang the MCP process indefinitely.
- **Safe retries**: idempotent `GET` requests get a bounded exponential-backoff-with-jitter retry
on `502/503/504` or network failure. Mutating requests (`POST`/`PATCH`/`DELETE`) are never
auto-retried, since retrying a write whose response was merely lost could duplicate side effects
(e.g. a second identical comment).
- **Input validation** via Zod on every tool argument (numeric IDs, UUIDs, enums), so malformed
input is rejected locally with a clear message instead of reaching the API.
- **No secrets in output.** Errors report the HTTP status and a truncated response body; the
`Authorization` header value is never included in any log or thrown error.
## Security notes
- This is a local **stdio** process — it does not open a network listener. Access control is
whatever your MCP client already provides plus possession of `BUGSINK_TOKEN`.
- All diagnostics go to `stderr`; `stdout` is reserved for the JSON-RPC protocol stream.
- `BUGSINK_URL` must be `http:` or `https:`; plain HTTP to a non-local host prints a warning
(your token would be sent unencrypted) but is not blocked, to support internal networks.
- Treat `BUGSINK_TOKEN` like any other credential: keep it out of version control, rotate it in
Bugsink if it ever leaks, and scope it to the least-privileged user your workflow allows.
## Development
```bash
npm install # installs deps and runs the TypeScript build (prepare script)
npm run typecheck
npm run build # compile src/ -> dist/
npm run dev # watch mode
```
## License
MIT
This server cannot be deployed
Maintenance
ActivityMaintained
ResponsivenessUnresponsive