# Claude Code with Jira, GitHub and Slack, per engineer

> How to set up Claude Code with Jira, GitHub and Slack through one MCP address, so each engineer acts as themselves and destructive tools stay blocked.

**TL;DR** Elaichi serves one MCP address, https://api.elaichi.ai/mcp, that any client supporting dynamic client registration, PKCE with S256 and a browser sign-in can connect to, so each engineer's calls to Jira, Slack and the rest run on their own connection and land in one audit log. Claude Code registers only loopback addresses, so Elaichi shows the name it registered for itself rather than a verified mark. A team on Gold can bring GitHub's remote MCP server in as its own remote MCP connector.

## Why local Claude Code setups go wrong at team scale

Claude Code with Jira, GitHub and Slack is a short setup on one laptop. It does not survive twenty. Claude Code keeps local-scope and user-scope MCP servers in `~/.claude.json` ([Claude Code MCP docs](https://code.claude.com/docs/en/mcp), checked October 2026). Each person edits that file by hand. They paste a personal access token for Jira, a GitHub PAT and a Slack token. From then on nobody outside that laptop knows what those tokens can reach, or who is using them.

The tokens are the first problem, and it is bigger than "secrets in a file." A token sits on one laptop, in one file, under one person's control. Nobody else can list the tokens an engineer holds, narrow what they reach, or take them back in one action. The token outlives the project it was made for. When someone leaves, the only person who knows where their tokens live is the person leaving.

The second problem is quieter: the agent's calls never appear anywhere you can read. An issue closed, a Slack post, a repository change all happened. But there is no single log recording which tool ran, on whose behalf, across all three apps. Reconstructing "what did the agents do last week" means querying three systems and correlating by timestamp.

The third problem is the one managers find last. Nothing distinguishes a read from a delete. An agent that can read an issue with that token can usually also close it, reassign it or delete a comment. MCP tool exposure from a vendor's own server is typically all-or-nothing per connection. The token carries the whole person's access, and nobody narrowed it at the tool level.

This post describes one alternative shape. One MCP address for the organization, each engineer signing in as themselves via OAuth rather than pasting a PAT, and destructive tools blocked per role. MCP is the [Model Context Protocol](https://modelcontextprotocol.io), the open standard an AI client uses to discover and call tools over a defined transport. An endpoint, in this context, is the single HTTP address a client talks to instead of spawning a local process per server.

Everything from here forward describes Elaichi's specific implementation of that shape. It is one way to do this, not the only way. The quantitative claims (rate limits, retention windows, propagation timing) are vendor facts you should verify against your own account, not protocol guarantees. The protocol-level claims (MCP's transport model, OAuth's authorization-code-with-PKCE flow, dynamic client registration) are independently verifiable against the specs linked throughout.

If you want the general case across coding agents rather than this one team setup, [MCP for coding agents across an engineering org](/blog/coding-agents-company-tools/) covers it.

## How do you set up Claude Code with Jira, GitHub and Slack?

You set up Claude Code with Jira, GitHub and Slack by pointing the client at one address, `https://api.elaichi.ai/mcp`, and letting each engineer sign in through it. The same address serves every organization. Which organization and which person a client reaches comes from the OAuth grant behind its token, not from the URL.

The order that works:

1. **Connect the apps once, in Elaichi.** Jira and Slack are both connectors in Elaichi's catalog; the [Jira connector page](/connectors/jira/) lists its tools. Each engineer adds their own connection with their own sign-in, so the credential belongs to them, not the team.
2. **Add GitHub as a remote MCP connector.** A team on Gold can bring GitHub's remote MCP server in as its own remote MCP connector, added by an Org Owner or Org Admin.
3. **Have each engineer connect Claude Code.** Elaichi keeps no list of approved MCP clients. Any client that supports OAuth dynamic client registration ([RFC 7591](https://datatracker.ietf.org/doc/html/rfc7591)), PKCE with S256 ([RFC 7636](https://datatracker.ietf.org/doc/html/rfc7636)) and a browser sign-in can connect. Test Claude Code against those three requirements with one engineer before you roll it out to the team.
4. **Write the restriction rules before the first wide rollout.** A restriction targets a role or one member. Write the block rules on the roles your engineers hold, then widen by exception, not the reverse.

There is no per-user, per-team or per-repo MCP address to generate. Each person connects their client once and approves their own grant. Grants are what a person lists and disconnects under Settings, Connected apps. This replaces the per-laptop config file: see [MCP without JSON config files](/blog/mcp-without-json-config-files/) for the longer version.

**The alternative, without a gateway:** you can get partway here natively. GitHub fine-grained PATs scoped to specific repos and permissions, and Slack bot tokens with minimal OAuth scopes, reduce blast radius per app. What you don't get without a gateway is one place to revoke everything for a departing engineer. Nor one audit format across all three tools, nor a way to block a specific tool call without also blocking the whole connector. If your team is small, and your Jira, GitHub and Slack admins are comfortable auditing three separate systems, scoped native tokens may be sufficient. See "What this does not solve" below for where that threshold sits.

## One address, four clients, one set of rules

Claude, ChatGPT, Cursor and Microsoft Copilot can all sign in to the same Elaichi address. That matters for a plain reason: your team does not use one client. Somebody runs Claude Code in a terminal, somebody else lives in Cursor, and the product manager asks the same Jira questions from ChatGPT.

With one MCP endpoint, the access rules live in one place. You write them in Elaichi, on the roles your engineers hold, and they apply to every client that signs in to that address. Registration is open to any client that supports dynamic client registration, with no Elaichi credential needed. Elaichi's authorization server is written with Claude and Cursor in mind. It recognizes the registered redirect addresses of Claude Desktop, claude.ai connectors and Cursor.

Claude Code is a loopback client. It binds a new local port each run, a pattern [RFC 8252](https://datatracker.ietf.org/doc/html/rfc8252) for native apps explicitly allows, but a loopback-only client cannot be cryptographically verified. Elaichi's consent screen and audit entries display the name the client self-reported during registration, flagged "Name provided by the client itself." Codex CLI, Gemini CLI, Zed, Goose and Cline are in the same position: all register loopback redirects, none can be verified by name alone. Do not read a name on a consent screen as proof of identity. This is a general property of OAuth dynamic client registration with loopback redirects, not an Elaichi-specific gap.

Setup steps for Claude Code specifically live in [Connect Elaichi to Claude Code](/blog/connect-elaichi-to-claude-code/).

## Each engineer acts with their own account, not a service account

Every call made with a grant's tokens acts as the person who approved that grant, in the organization they picked. The token carries that user and organization. Permissions are looked up on each request rather than cached into the token itself.

An issue updated from one engineer's Claude Code session hits Jira as that engineer, with that engineer's Jira project permissions. Not as a bot account someone set up years ago that nobody can now describe. The apps on the far side keep enforcing what they already enforce: a developer querying Jira sees only the tickets their own Jira account can see.

The mechanism is the connection. Each person adds their own Jira connection and their own Slack connection, with their own sign-in. Connector credentials are not stored in Elaichi's main database. A separate credential service holds every connected account's secrets encrypted at rest, and Elaichi fetches them into memory only for the single call that needs them. The AI client itself never holds the Jira or Slack token; it holds only an Elaichi-issued token.

Every call through a connection fetches the credentials bound to that one connection row, regardless of who is calling. So a connection someone shares runs on its *owner's* sign-in to the third-party app. That is exactly the failure mode a per-engineer setup exists to avoid. Keep connections unshared, and let each engineer reach their own tools through their own toolbox.

There is a real trade-off. Per-engineer connections mean each engineer does a sign-in per app: three sign-ins here, not one. A shared connection would be a single setup for the whole team. You are trading setup time for identity. One extra sign-in per person, against every future action being attributable and individually revocable. For a team touching production issue trackers and repositories, that trade usually pays; for a hackathon team or a three-person side project, it may not. [AI agents with employee permissions, no shared bot](/blog/ai-agents-employee-permissions/) works through this trade-off in more detail.

## Two kinds of connector, one set of rules

Elaichi's catalog holds two kinds of connector, and an engineering team's setup usually touches both. Connectors Elaichi authors and runs itself make up most of the catalog, Jira and Slack among them. These are translated into MCP tools by Elaichi, not by the vendor. Native MCP connectors are vendors' own remote MCP servers, built and run by the vendor, that Elaichi staff publish once for every organization. [Linear](/blog/connect-linear-to-claude-for-our-product-team/) and GitLab are in the catalog this way.

A team can also bring its own remote MCP server in under the same rules. For GitHub that means adding GitHub's remote MCP server as the organization's own remote MCP connector on Gold. This requires the `connector:create` permission, which among system roles only Org Owner and Org Admin hold.

To a restriction rule, a remote MCP tool is the resource `mcp` with the upstream tool name as its method. Restrictions, OAuth scopes and the audit log govern it as they govern any connector's tools. Every gate runs before the call leaves Elaichi. The tool that runs is re-read from that connection's own active list on every call, not cached from an earlier check.

One honest limit: calls a client makes directly to GitHub's MCP server, outside Elaichi, do not pass through Elaichi and are not governed by it. Adding the remote connector does not stop an engineer from configuring GitHub's server separately in their own local config file. That is a device-management problem, not something the endpoint architecture itself solves. [Vendor MCP servers: why run them through Elaichi](/blog/vendor-mcp-servers-through-elaichi/) takes the argument further.

## Blocking the destructive tools for most roles

In Elaichi, restriction targets are role or user only; the organization default is the absence of a rule, which means allow everything. An engineering-wide rule is therefore written on the roles your engineers hold. A member holds exactly one role; to combine two personas, an admin authors a custom role.

The mechanic that catches people out: a rule layer with only block rules has no implicit allowlist, so everything it does not name passes through. Blocking some of an app's write tools leaves every write tool it does not name reachable. Illustrative example, not literal syntax:

```
role: engineer
block:
  - resource: jira, method: delete_a_jira_issue_by_id
  - resource: jira, method: delete_a_jira_issue_comment_by_id
## everything else on jira, create_a_jira_issue_comment and update_a_jira_issue_by_id included, still passes
```

If you want engineers held to reads only on one app, you have two options. Write block rules naming *every* non-read tool on it, or write an allow rule naming only the read tools. Once a role carries *any* allow rule, every tool none of its allow rules names is blocked by default on that app. Mixing the two styles without understanding this flips the default, which is the single most common misconfiguration.

The second mechanic is subtler, and is good news for durability. An allow rule matches a tool only by the operation Elaichi stored at the time the rule was saved, never by the tool's name. A block rule matches by name *or* by operation. So renaming a tool on the vendor side cannot silently slip it past a block rule. It could still fall outside an allow rule's coverage, if the operation classification also changed. [Why blocks match tool names but allows don't](/blog/block-matches-name-allow-matches-operation/) explains the asymmetry in full.

What a refused call looks like from Claude Code: the tool is left out of the tool list Elaichi advertises for search. A call by exact name returns an in-band error instead. It states that the tool is restricted for the caller's role or account, and points out that an admin can lift it through an access request. The refusal does not name the rule, who wrote it, or what else it covers. An admin resolves the request in the console, under Governance, Access requests. Approving records an access grant for that one person, lifting that one connector or tool out of their role's rules without editing the role itself.

Timing matters for a rollout plan. A role, team-membership, restriction or grant change takes effect about two minutes. In Elaichi, removing or suspending a member revokes every live grant in the same transaction as the membership change. Revoking a share and disconnecting an account are effective on the next call as well, because the connection is re-read on every request rather than cached.

For the mechanics of choosing between the two rule shapes, [MCP tool allowlist vs blocklist: which fits?](/blog/allowlist-vs-blocklist-mcp-tools/) is the better read.

## How Claude Code finds the right tool

In Elaichi, connected tools are never listed one by one, however few there are. When a grant reaches any connected tool, the client gets `search_tools`, `execute_tool` and `read_tool` instead, plus `run_code` where Code Mode is available. Claude Code searches for the Jira or Slack tool it needs, then runs it. This is a deliberate departure from MCP's default pattern of listing every tool upfront. It keeps the tool list usable once an org has connected a dozen apps with hundreds of combined tools.

Search is lexical, not semantic. A query of concrete tool-ish words ("delete issue", "post message") outperforms a natural-language sentence. A restricted tool is left out of the tools Elaichi offers a client and cannot be called. Search still names it, flagged restricted, with no schema. So an engineer can see what to *ask for*, rather than wrongly concluding the connector never had that capability.

`execute_tool` is a naming indirection only. It unwraps to the underlying tool name and arguments it was given, and meets exactly the same gates as a direct call. There is no separate execution path and no extra privilege. `read_tool` is the same shape with added refusals baked in, so it only ever runs connected reads. The practical consequence for a manager is this. A client-side permission limited to `execute_tool` covers every connected-tool call made through it, across every connected app, because one tool name carries them all. Per-app and per-tool control has to be set in Elaichi's rules, not in the client's own permission UI.

The endpoint allows 120 requests per 60 seconds per access token, a vendor-specific limit, and the brake on an agent stuck in a retry loop. Over it, Elaichi answers `HTTP 429` with `Retry-After: 60`.

## What the audit log holds after a week of use

Elaichi writes one audit row for each connected-tool call that reaches execution and then runs, fails, or is refused there. That holds whether the call came from Claude Code, another MCP client, or a Code Mode program. In Elaichi, one entry for each connected-tool call that reaches execution (a call refused earlier writes none). The MCP client's id is on the row too, so a Claude Code call reads differently from a Cursor one in the log.

Some things are not in there, and a manager planning an evidence story should know this up front. A call refused *before* execution writes no row at all. That covers a tool a restriction withheld, a missing OAuth scope, an unknown tool name, and a rate limit hit. Argument values are not recorded, with one exception: the `path` argument that names the target object, kept as a target id. Elaichi retains 90 days of audit history by default. A longer history means forwarding to your own log service, and logging destinations are gated to the Black plan, with Datadog the only delivery target currently supported.

One naming detail confuses people reading the console. Connected-tool calls, MCP ones included, sit in the audit log's `assistant` category. They are recorded under several action names, depending on how the call ran, so filter by category rather than by one action string. The `mcp` category holds grant events, such as an MCP client connecting for the first time. [Which tools AI agents call: read the audit log](/blog/which-tools-ai-agents-call/) walks through a real week of rows.

## What this does not solve

Elaichi's MCP endpoint has no prompt-injection defense of its own, and structurally cannot build one at this layer. Nothing on that path scans tool results for injected instructions or second-guesses a call's intent. The endpoint only ever sees a tool name and arguments from a `tools/call` request. It never has the user's original prompt to judge the call against. That defense has to live in the client (Claude Code, Cursor, and the rest), or in a layer that sees the full conversation, not in a tool-call gateway.

If your engineering team is three people, all of you are admins in Jira and GitHub already, and nobody is asking for an access review, local config files with personal tokens are genuinely a smaller problem than standing up a control plane. The honest threshold is the point where you cannot answer "which tools did the agents call last week" and somebody has started asking. That somebody is a security review, a customer, or a departing-employee checklist. [When you don't need an MCP gateway yet](/blog/when-you-dont-need-an-mcp-gateway/) makes this case at more length.

If what you want is scheduled, unattended automation rather than engineers asking questions in a terminal, this is the wrong shape. Elaichi's MCP sign-in supports only the authorization-code grant with PKCE, plus refresh. A new grant always needs a person to approve a consent screen in a browser. Nothing in this setup lets a client obtain a grant unattended, which rules out cron-triggered agents and CI-pipeline agents as-is.

If your blocker is that engineers already have personal Claude subscriptions, and your actual worry is what they paste into them rather than what a connected agent calls, the problem is upstream of MCP entirely and this post doesn't address it. [Engineers using ChatGPT at work: block or scope it](/blog/shadow-ai-cto-engineers-already-have-chatgpt/) covers that separate case.

If the fit is right, the next practical step is the [first-week setup checklist](/blog/first-week-governance-checklist/).

## FAQ

### Can Claude Code connect to Jira, GitHub and Slack through one MCP endpoint?

Elaichi serves one MCP endpoint, https://api.elaichi.ai/mcp, and a connected client reaches every app the signed-in person's grant covers through that one address. Elaichi requires a client to support OAuth dynamic client registration, PKCE with S256 and a browser sign-in; test Claude Code against those three before you roll it out. Jira and Slack are connectors in Elaichi's catalog. For GitHub, a team on Gold can bring GitHub's remote MCP server in as its own remote MCP connector.

### Does each engineer act with their own account when using Claude Code through an MCP control plane?

Yes, provided each engineer connects the apps with their own sign-in. In Elaichi, every call made with an OAuth grant's tokens acts as the person who approved that grant, and every call through a connection uses the credential bound to that connection row. So a connection an engineer created with their own Jira login reaches Jira as them. A connection shared with a team runs on its owner's sign-in instead, which is why a per-person setup keeps connections unshared.

### Is Claude Code shown as a verified MCP client?

No. Claude Code registers only loopback redirect addresses (localhost, 127.0.0.1 or ::1), and a loopback-only client can never be shown as verified, because a loopback address proves nothing about who the client is. Elaichi displays the name the client registered for itself, flagged "Name provided by the client itself", and shows a generic mark rather than a bundled logo. Codex CLI, Gemini CLI, Zed, Goose and Cline are treated the same way.

### How long does it take for a new tool restriction to stop an engineer's agent?

A restriction change, like a role, team-membership or access-grant change, takes effect about two minutes. Other changes land sooner. In Elaichi, removing or suspending a member revokes every live grant in the same transaction as the membership change. Revoking a share and disconnecting an account are effective on the next call too, because the grant and the connection are re-read on every request.

### How does Claude Code discover Jira or Slack tools if they are not listed?

In Elaichi, connected tools are never listed one by one, however few there are. A grant that reaches any connected tool is given search_tools, execute_tool and read_tool instead, plus run_code where Code Mode is available. The client searches for the tool it needs and then runs it. Search is lexical, so concrete tool-ish words work better than a sentence. A restricted tool is left out of the tools Elaichi offers a client and cannot be called. Search still names it, flagged restricted, with no schema.

### Where do AI tool calls from Claude Code show up in an audit log?

In Elaichi, every connected-tool call that reaches execution writes one audit row, and one entry for each connected-tool call that reaches execution (a call refused earlier writes none). Those rows sit in the audit log's assistant category under several action names, so filter by category rather than by one action string. Calls refused before execution, such as a tool a restriction withheld or a missing OAuth scope, write no row. Elaichi keeps 90 days of history, and forwarding to your own log service comes with the Black plan.

## Read next

- [Connect Linear to Claude for our product team](/blog/connect-linear-to-claude-for-our-product-team/) — To connect Linear to Claude for our product team, govern Linear's own MCP server: per-person sign-in, a block rule, review for new tools.
- [Connect Slack to Claude for the whole company](/blog/connect-slack-to-claude-for-the-whole-company/) — Connect Slack to Claude for the whole company: per-person connections, which Slack tools to block per role, and what the audit log keeps.
- [Salesforce MCP access for Claude, per rep](/blog/connect-salesforce-to-claude-per-rep/) — Give each rep Salesforce MCP access for Claude under their own login, block the delete tools, and cut access off cleanly when they leave.
