# AI assistants

Source: https://www.pingtower.com/docs/service/ai-assistants/

Connect Claude, ChatGPT or another MCP client to a hosted team, ask what is firing, whether it has fired before, and who is on call, and, if you allow it, let it acknowledge alerts, mute rules and edit checks.

pingtower.com runs a [Model Context Protocol](https://modelcontextprotocol.io) server at `https://api.pingtower.com/mcp`. Connect an AI assistant to it and you can ask, in plain sentences, the questions you would otherwise answer with a handful of API calls: what is firing in billing right now, has this alert fired before, who is on call for payments, which checks watch that host.

The connector covers **one hosted team** per connection. It reads by default. It can change things only through the permissions listed under [What it can change](#what-it-can-change), and only after an owner or admin, or any role with `team_settings:write`, turns those on for the team. It is not available for a [self-hosted box](/docs/self-hosting/).

## Connect

You add the server by its URL. The assistant sends you to pingtower.com to sign in; you pick a team, choose what it may read and change, and approve.

<div class="docs-tabs">
  <div role="tablist"><button type="button" role="tab" aria-selected="true">Claude</button><button type="button" role="tab" aria-selected="false">Claude Code</button><button type="button" role="tab" aria-selected="false">ChatGPT</button><button type="button" role="tab" aria-selected="false">API key</button></div><div role="tabpanel"><p>In Claude (web, desktop or mobile), open <strong>Settings → Connectors</strong>, choose <strong>Add custom connector</strong>, and enter:</p>
<pre tabindex="0"><code>https://api.pingtower.com/mcp
</code></pre></div><div role="tabpanel" hidden><div class="highlight"><pre tabindex="0" style="color:#cdd6f4;background-color:#1e1e2e;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"><code class="language-sh" data-lang="sh"><span style="display:flex;"><span>claude mcp add --transport http pingtower https://api.pingtower.com/mcp
</span></span></code></pre></div><p>The first time a tool is used, Claude Code opens your browser to sign in.</p></div><div role="tabpanel" hidden>Turn on <strong>developer mode</strong> in ChatGPT&rsquo;s connector settings, create a connector, and enter <code>https://api.pingtower.com/mcp</code> as its URL.</div><div role="tabpanel" hidden><p>Any MCP client that can send a header can use a tenant API key instead of signing in:</p>
<div class="highlight"><pre tabindex="0" style="color:#cdd6f4;background-color:#1e1e2e;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"><code class="language-sh" data-lang="sh"><span style="display:flex;"><span>claude mcp add --transport http pingtower https://api.pingtower.com/mcp <span style="color:#89b4fa">\
</span></span></span><span style="display:flex;"><span>  --header <span style="color:#a6e3a1">&#34;Authorization: Bearer ptk_&lt;tenant&gt;_…&#34;</span>
</span></span></code></pre></div><p>A <code>ptk_</code> key already reaches the whole tenant through the REST API, so on <code>/mcp</code> it is granted every permission below, including the ones that change things. It also follows the team&rsquo;s <strong>Allow AI connectors</strong> switch: while that is off, <code>/mcp</code> refuses the key with a 401 (the key still works on the REST API). The team switches under <a href="#what-it-can-change">What it can change</a> apply to the key as well. Prefer signing in, which grants only what you approve and can be disconnected on its own.</p>
</div></div>


The consent page shows which app is asking, where it will send you back to, and which account you are signed in as. If the link says it has expired or was opened in a different browser, start again from the assistant. A Connect link opened from another website, rather than from the app it names, stops with an error page; only continue on the consent page if you just clicked Connect in that app yourself. Connecting is rate limited per address and per network, with `429` and `Retry-After`.

## What it can read

You choose the permissions at consent, one per line:

| Permission | Tool | What it returns |
| --- | --- | --- |
| Alerts | `pingtower_alerts` | Open alerts, and alerts resolved in the last hours: project, rule, state, level, how many times it has fired, first and last seen, and its latest log message |
| Configuration | `pingtower_projects`, `pingtower_rules`, `pingtower_checks` | Projects, one project's alert rules, and one project's checks with the host each one watches. Check credentials, headers, bodies and URL paths are never returned |
| On-call | `pingtower_oncall` | Who each of a project's schedules pages right now, by email, and whether an override put them there |
| Raw log lines | `pingtower_logtail` | The newest retained log lines, for one project or all of them |

**Raw log lines are off unless you tick them.** Log lines are the data most likely to contain your own users' personal data, and an assistant can answer "what is firing, and has it fired before" without them.

## What it can change

The permissions below change things, so none of them is ticked for you at consent. Each tool is shown to the assistant only if the connection holds its permission and its [tool list](#limit-an-apps-tools) allows it.

| Permission | Tool | What it does |
| --- | --- | --- |
| Incidents (`incidents:write`) | `pingtower_open_incident`, `pingtower_attach_alerts`, `pingtower_add_note`, `pingtower_draft_resolution`, `pingtower_link_issue` | Suggests an incident, which opens for triage and not as a declared incident. Adds alerts that are on no incident to one, adds internal notes, and drafts a resolution that a person accepts. Attaching, and suggesting an incident, skip any alert in a project where the connected member's role lacks `incidents:write`. Links a GitHub or GitLab issue, pull request or merge request to an incident from its pasted URL, and the incident's timeline records that the assistant linked it. Only links on github.com, gitlab.com and the host of a self-managed GitLab your team has connected are accepted. GitHub Enterprise links are refused |
| Acknowledge and resolve alerts (`alerts:write`) | `pingtower_ack_alert`, `pingtower_resolve_alert` | Acknowledges or resolves one alert |
| Mute rules (`rules:mute`) | `pingtower_mute_rule` | Mutes one alert rule for up to 24 hours |
| Schedule maintenance (`maintenance:write`) | `pingtower_create_maintenance` | Schedules one one-off maintenance window, which must end within 24 hours from now |
| Create and edit checks (`checks:write`) | `pingtower_create_check`, `pingtower_update_check` | Creates a check, or edits one: its interval, timeout, sources and parameters, including the address it watches. It can turn a check on but never off |

A connection never does more than its account's [role](/docs/getting-started/concepts/#roles) allows, whatever it was granted. A viewer's connection only reads. A responder's keeps the incident, alert and mute permissions but not maintenance or checks. Members and above keep everything granted. A [custom role](/docs/getting-started/concepts/#custom-roles)'s connection keeps what that role's permissions allow. If the account is [limited to some projects](/docs/getting-started/concepts/#per-project-roles), so is the connection: read tools return only those projects, and write tools check the role granted on the project they touch.

A permission alone is not enough. Each group also needs a team switch under **Connected apps**, and both switches are off until an owner or admin, or any role with `team_settings:write`, turns them on:

- **Let connected AI apps suggest incidents and add notes** covers the incident tools, including linking issues.
- **Let AI agents act** covers alerts, mutes, maintenance and checks.

Some limits hold whatever is granted:

- **Nothing can be deleted.** No tool deletes or disables a check, rule, alert, window or incident. A mute longer than 24 hours, or a maintenance window that ends more than 24 hours from now, is refused.
- **Checks pass the same checks as in the app.** A check created or edited this way goes through the same validation and plan limits as one made in the web app or the API. That includes refusing addresses on private networks.
- **Hourly limits.** Each account can make, per team and per hour, up to 60 acknowledgements, resolutions, mutes and maintenance windows combined, and up to 20 check creates and edits.
- **Every change is audited** under the account that approved the connection, so the audit log shows who connected the assistant that did it. With a `ptk_` key, changes are audited under the account the key belongs to and count against that account's hourly limits, which it shares with the account's signed-in connections.
- **Allow AI connectors** stops all of it at once, reads and changes alike.

<div class="docs-callout warn"><svg viewBox="0 0 16 16" fill="none" stroke="currentColor" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round"><path d="M8 2 1.5 13.5h13L8 2Z"/><path d="M8 6.5v3M8 11.5v.5"/></svg><div><span class="t">Log text is written by the systems you monitor</span>An alert&rsquo;s message and every log line come from your applications, and anyone who can make them log a line — a request path, a user agent, a form field — can put instructions in it aimed at the assistant. With only read permissions, those instructions can&rsquo;t act through pingtower. Once you grant a permission that changes things, a crafted line could talk the assistant into using it: acknowledging the alert that reports it, muting its rule for a day, linking an issue of the attacker&rsquo;s choosing to an incident, or pointing a check somewhere else. An assistant that also has other tools connected (web access, email, chat) could be talked into sending what it read elsewhere. pingtower returns that text only in fields named <code>untrusted_log_text</code>, returns notes an assistant wrote on an incident under <code>untrusted_content</code>, and replaces recognisable secrets with <code>[redacted]</code>, but the scrubbing is best effort. Connect assistants you trust. Leave raw log lines and the permissions that change things off unless you need them, and prefer a client that asks you before it calls a tool.</div>
</div>


### What gets redacted

Before anything leaves pingtower through `/mcp`, text your systems wrote is checked for these shapes. The whole secret is replaced with `[redacted]`. Where the match has a label, such as a key name, a scheme or `Bearer`, the label is kept:

- `Authorization: Basic …` values and `Bearer …` tokens
- a user name and password in a URL, such as `https://user:pass@host` (the scheme and host are kept)
- JSON Web Tokens
- AWS access key IDs
- pingtower's own API keys and tokens
- `key=value` and `"key": "value"` pairs whose key names a secret: `password`, `passwd`, `pwd`, `secret`, `token`, `api_key`, `access_key`, `secret_key`, `private_key` or `authorization`, including prefixed names such as `DB_PASSWORD` or `stripe_api_key`

It applies to alert messages, alert templates, the values an alert is grouped by, raw log lines, the address a check watches, and incident titles, descriptions, causes, fixes and notes.

**Only the assistant's copy is redacted.** The stored log line, the web app, the mobile apps, notifications, webhooks and the REST API all keep the text as your system sent it. A secret in a shape not listed above reaches the assistant unchanged. The only complete fix is to stop logging it.

## Connected apps

Every connection is listed under **Settings → Connected apps** in the [web app](https://app.pingtower.com): the app, its permissions, when it was connected and last used, and a **Disconnect** button that takes effect on the assistant's next call.

- **Members** see and disconnect their own connections.
- **Owners and admins**, and any role with `members:write`, also see and disconnect the connections of members whose team role and every project grant's role they could give themselves. An owner sees everyone's; an admin sees everyone's but an owner's. A [project-limited](/docs/getting-started/concepts/#per-project-roles) member sees and disconnects only their own, whatever their role. Anyone else's connection is a `404` `unknown grant`, exactly as an unknown one is.
- **Owners and admins** can also turn **Allow AI connectors** off for the team, as can any role with `team_settings:write`. That stops every connection immediately without deleting any; turning it back on restores them. They also turn on or off the two switches under [What it can change](#what-it-can-change).

A connection also ends when you leave the team, change or reset your password, or delete your account; after 90 days without use; and a year after you approved it. Access tokens last an hour and refresh on their own until then.

### Limit an app's tools

On top of its permissions, each member's AI app has a tool list. It is set with the **Tools** button on any of that app's rows under **Connected apps**, and every connection the member makes from that app follows it, including a second connection and one made after disconnecting:

- **All tools**: every tool its permissions allow. This is the default.
- **Only these**: just the tools ticked, out of those its permissions allow.
- **All except these**: every tool its permissions allow but the ones ticked.

A tool outside the list is not shown to the assistant, and calling it by name gets the same error as a tool that does not exist (JSON-RPC `-32602`, `unknown tool`). The list narrows what the permissions allow and never adds a tool the connection lacks the permission for. Disconnecting does not clear the list; setting **All tools** does.

Only owners and admins, and any role with `members:write`, can set a list, and not while [limited to some projects](/docs/getting-started/concepts/#per-project-roles). Anyone else gets a `403`, even for their own apps, so a member can disconnect an app but can't change its list. Those who can set lists do so for their own apps and for those of members whose team role and every project grant's role they could give themselves; any other connection is a `404` `unknown grant`. Every change goes to the audit log. Through the API it is `PUT /v1/tenants/{tid}/grants/{gid}/tools` with `{"mode": "all" | "allow" | "deny", "tools": [...]}`, which sets the list for that connection's member and app, and `GET /v1/tenants/{tid}/grants` returns each connection's `tool_mode` and `tools` and the `mcp_tools` to choose from.

A client can narrow its own tools further, per request, with an `X-MCP-Tools-Only` header: a comma-separated list of tool names, at most 64 names and 4 KiB; a longer header is refused with a `400` before any tool runs. It works with a `ptk_` key as well, which has no tool list of its own. The assistant then sees only the tools that are both in the header and allowed by the app's list. Names the connection can't use, and names that don't exist, are ignored, so the header never adds a tool; a header that names no tool the connection can use leaves the assistant with none.

```sh
claude mcp add --transport http pingtower https://api.pingtower.com/mcp \
  --header "X-MCP-Tools-Only: pingtower_alerts,pingtower_oncall"
```

**What a list doesn't cover.** A list limits one AI app for one member. The same member's other apps (Claude Code and Claude on claude.ai count as different apps, as does ChatGPT) and any `ptk_` API key they hold are not limited by it: those keep every tool their permissions and role allow, and a key is narrowed only by `X-MCP-Tools-Only`. To limit what a person can do, change their [role](/docs/getting-started/concepts/#roles), or turn off **Allow AI connectors** for the team. Nothing on `/mcp` ever lets anyone past what their role allows.

## What the assistant's provider receives

What the assistant reads is sent to the company that runs it — Anthropic for Claude, OpenAI for ChatGPT — under that company's own terms. See the [privacy policy](/privacy/#ai-assistants-the-mcp-connector).
