MCP Server
Tindra ships a built-in Model Context Protocol server. Connect any MCP-compatible AI client (Claude Desktop, Cursor, Windsurf, and others) and query issues, transactions, monitors, logs, and releases, or make changes, without leaving the tool you're already in.
Connecting
Tindra exposes a remote MCP server over Streamable HTTP:
https://your-hostname.tindra.sh/mcp
For Tindra Managed that is https://yourname.tindra.sh/mcp. Self-hosted, it is POST /mcp on whatever host and port you bound.
Nothing to install. No local process. Authentication uses the same API tokens as everything else: create one in Settings > API Tokens and send it as a Bearer header.
Authorization: Bearer tindra_your_token_here
Tokens are project-scoped. Read queries return data for that project only. See API Tokens.
Claude Code
One command, using the built-in HTTP transport:
claude mcp add --transport http tindra https://your-hostname.tindra.sh/mcp \
--header "Authorization: Bearer tindra_your_token_here"
Add --scope user to make it available in every project, or --scope project to write it to .mcp.json for your team. Verify with claude mcp list, which should report ✔ Connected. Project-scoped servers show ⏸ Pending approval until you approve them once inside claude.
Codex CLI
In ~/.codex/config.toml. bearer_token_env_var names the environment variable Codex reads the token from, so the token itself stays out of the config file:
[mcp_servers.tindra]
url = "https://your-hostname.tindra.sh/mcp"
bearer_token_env_var = "TINDRA_TOKEN"
Cursor
In .cursor/mcp.json (project) or ~/.cursor/mcp.json (global):
{
"mcpServers": {
"tindra": {
"url": "https://your-hostname.tindra.sh/mcp",
"headers": {
"Authorization": "Bearer tindra_your_token_here"
}
}
}
}
Cursor also resolves ${env:NAME} inside headers, so you can write "Bearer ${env:TINDRA_TOKEN}" and keep the token out of a committed mcp.json.
VS Code (GitHub Copilot)
In .vscode/mcp.json. Using an input keeps the token out of the committed file. VS Code prompts for it once and stores it in the secret store:
{
"inputs": [
{
"id": "tindra-token",
"type": "promptString",
"description": "Tindra API token",
"password": true
}
],
"servers": {
"tindra": {
"type": "http",
"url": "https://your-hostname.tindra.sh/mcp",
"headers": {
"Authorization": "Bearer ${input:tindra-token}"
}
}
}
}
Claude Desktop
Claude Desktop's custom connectors expect OAuth, so bearer tokens go through the mcp-remote bridge. Add to claude_desktop_config.json (macOS: ~/Library/Application Support/Claude/claude_desktop_config.json):
{
"mcpServers": {
"tindra": {
"command": "npx",
"args": [
"-y",
"mcp-remote",
"https://your-hostname.tindra.sh/mcp",
"--header",
"Authorization:${TINDRA_AUTH}"
],
"env": {
"TINDRA_AUTH": "Bearer tindra_your_token_here"
}
}
}
}
Two things matter here and are easy to get wrong:
- The header must be passed with
--header.mcp-remotedoes not read an environment variable on its own, it only expands${...}inside the argument you give it. Setting the env var alone results in a 401. - The
--headerargument must contain no spaces at all, which is why the wordBearerlives in the environment variable rather than in the argument. Claude Desktop on Windows does not escape spaces correctly when spawningnpxand would pass a mangled header.
Restart Claude Desktop and the Tindra tools appear.
Other MCP clients
Any client with remote MCP support works. Point it at https://your-hostname.tindra.sh/mcp, choose the http (Streamable HTTP) transport, and set the Authorization: Bearer header. Only clients with no remote transport at all need the mcp-remote bridge shown above.
Read vs write access
Most MCP tools are read-only and work with any valid token.
Three tools perform mutations: update_issue, bulk_update_issues, and create_alert_rule. These require a writable token. When creating a token, check Allow write access to enable mutations. Read-only tokens get a 403 from any write tool.
Available tools
Read tools
| Tool | What it returns |
|---|---|
get_overview |
Health summary: open issue count, error rate, monitor states, recent alert activity |
list_issues |
Issues with event counts, filterable by status, level, and search text |
get_issue |
Issue detail plus the event payload (exception, stack trace, breadcrumbs, request, user, contexts). Pass offset to inspect older occurrences (0 = newest). |
list_transactions |
Transaction summaries sorted by P95 latency |
get_transaction |
Full span waterfall for a single transaction |
list_span_summaries |
Aggregated span data (DB, cache, job spans) across all transactions |
list_monitors |
Cron monitors with current state (ok, missed, error) |
get_monitor |
Single monitor with check-in history |
list_releases |
Releases with new and regressed issue counts |
list_alerts |
Alert rules with channels and last-fired time |
list_issue_events |
Recent occurrences (timestamps, environment, release). Use get_issue with offset for the full payload. |
get_logs |
Structured log search, filterable by level, environment, and trace ID |
Write tools
Write tools require a writable token.
| Tool | What it does |
|---|---|
update_issue |
Change an issue's status (resolve, ignore, re-open) or assignee |
bulk_update_issues |
Apply a status change to multiple issues at once |
create_alert_rule |
Create a new alert rule with conditions and notification channel |
get_issue
Required: id. Optional: offset (integer, newest first, default 0).
The event payload is source-map resolved and matches what the issue detail UI shows. N+1 issues also include perf_events.
create_alert_rule
Required: name, trigger, channel.
| Argument | Notes |
|---|---|
trigger |
new_issue, regressed, new_or_regressed, event_count, log_count, cron_missed, cron_error, uptime_down, or uptime_recovered |
channel |
webhook, slack, discord, teams, or email |
threshold / window_mins |
Required for event_count and log_count. Log count windows max out at 60 minutes. |
filter_level |
Required for log_count: fatal, error, or warning |
filter_search |
Log body search. Required when log_count min level is warning. |
project_id |
Required for log_count. Defaults to the token's project, or all projects for session auth. |
cooldown_mins |
Minutes between repeated firings. Default 60. |
See Alert Rules for the full constraints.
Verifying the connection
A plain curl tells you whether your token is accepted, before you debug the client:
curl -sS https://your-hostname.tindra.sh/mcp \
-H "Authorization: Bearer tindra_your_token_here" \
-H "Content-Type: application/json" \
-H "Accept: application/json, text/event-stream" \
-d '{"jsonrpc":"2.0","id":1,"method":"tools/list"}'
You should get back a JSON-RPC result listing the tools. A 401 means the token is missing, wrong, or revoked.
Troubleshooting
The client tries to open a browser for login. It saw a WWW-Authenticate header on a 401 and started an OAuth flow. Tindra does not use OAuth for MCP. Your token never reached the server. Check that the header is actually configured.
405 Method Not Allowed. The client is configured for the older SSE transport and is opening a GET connection. Tindra speaks Streamable HTTP, which is POST only. Set the transport to http, not sse.
Tools are listed but every write call fails. The token is valid but read-only. Create a new token with Allow write access checked.
Self-hosted instances
The MCP server is built into the Tindra binary and enabled by default. No extra configuration is needed. The endpoint is available at POST /mcp on whatever port Tindra is listening on.