Skip to content

Keep BambooHR salary data out of AI assistants

Two layers keep BambooHR salary data away from Claude and ChatGPT: the access level behind the API key, and an allow rule per role in Elaichi.

Nachi Raman 10 min read
An HR employee record open in an AI assistant with the compensation fields absent

How do you keep BambooHR salary data out of an AI assistant?

HR wants Claude to answer the routine questions: who reports to whom, who is on leave next week, when a new hire starts. Someone in finance points out that the same connection could read pay bands and payroll deductions. Both positions are reasonable, and the argument stalls there.

Keeping BambooHR salary data out of the assistant takes two layers, and neither one alone is enough:

Layer What it controls Where it lives Fails open or closed if misconfigured?
1. API key identity Whether compensation fields exist in BambooHR's response at all BambooHR access levels Fails open: a key from a high-access user returns pay fields wherever an allowed read includes them
2. Allow rule (restriction) Which of the 406 BambooHR tools a role can call Elaichi, per role Fails closed for tools the rule does not name; with no rule at all, the role reaches everything

The order matters. Build layer one first, because it holds even if someone later misconfigures layer two. A bad allow rule can only expose tools the API key is itself permitted to run. It can never expose a field BambooHR already hides from that key.

MCP (Model Context Protocol) is the standard way an AI assistant calls tools in other apps. Elaichi is a governed MCP control plane. Every company account is connected once and served through one organization-wide endpoint. Restrictions are enforced per role before any tool reaches the model.

Layer one: which BambooHR user does the API key act as?

An API key in BambooHR carries its creator's reach. BambooHR's own documentation puts it plainly: "The API can only view or update data that the user can access" (BambooHR help, checked October 2026). The question is not what the key is allowed to do. It is who made it.

Two details decide whether compensation leaks:

  1. Pay data lives in the compensation table and in the payRate, payType and paidPer fields (BambooHR table and field names, checked October 2026).
  2. Get Employee drops fields the caller cannot view while returning no error (BambooHR Get Employee, checked October 2026). A model asking for an employee record gets a shorter record and no sign that anything was withheld.

That silent drop is the behavior you want. It is also the behavior that makes testing necessary. A 200 response with a short record looks identical to success whether or not compensation was ever in scope. Steps to verify:

  1. In BambooHR, confirm the access level that will own the API key does not have compensation visibility, and that its field settings reflect that.
  2. Create the API key from a user account at that access level.
  3. Call Get Employee for a salaried employee whose pay rate you already know.
  4. Read the response. If payRate comes back, the key belongs to the wrong user. Fix the access level, not the restriction.

BambooHR's OAuth scopes separate employee from employee:compensation and sensitive_employee:protected_info, which covers SSN, SIN and birthday (BambooHR Get Employee, checked October 2026). Elaichi's connector takes an API key rather than an OAuth app. So the access level behind that key, not an OAuth scope, is the control you have at this layer.

Layer two: what does an allow rule for an HR reader name?

An allow rule on the role, naming the specific read tools that role uses, and nothing else. Elaichi's bamboohr connector carries 406 tools: 182 have names starting with list_ or get_, and most of the other 224 create, update, delete or bulk-change records. The full, current list is on the BambooHR connector page, rather than reproduced here, since tool counts change as BambooHR's API surface grows.

The pay-related tools are easy to spot and easy to miss one of:

Tool What it returns
list_all_bamboohr_compensation_planning_cycles Compensation review cycles and their status
list_all_bamboohr_pay_grades_and_bands_pay_bands Pay grade/band ranges
get_single_bamboohr_compensation_total_reward_by_id Total rewards statement for one employee
list_all_bamboohr_payroll_deductions Payroll deduction records

A block list that names those four leaves every one of the other 402 tools reachable. With 406 tools, that is not a boundary. It is a guess. Intune runs the same arithmetic: 198 tools, 69 of them reads, and six blocks do not hold a role to reading.

So write an allow rule instead of a block rule. Two properties of Elaichi restrictions shape how it has to look:

  • A restriction targets a role or a single user. In Elaichi, restriction targets are role or user only; the organization default is the absence of a rule, which means allow everything.
  • An allow rule is the target's whole allowlist across every connector, not just the app it mentions. Once the HR role holds one allow rule, every connector its allow rules do not name is denied. Add an allow rule naming each of the role's other apps whole, or HR loses Slack and Google Calendar once the BambooHR rule takes effect.

Two traps to know before writing the rule:

  1. An allow rule that names the bamboohr connector whole and also lists some of its tools reaches all of it. The tool entries grant nothing additional once the connector itself is named.
  2. An allow rule naming nothing at all denies everything. This is the strictest thing the system can express.

Allow rules match the operation pinned against the catalog at write time. Blocks match the tool name or the operation. The mechanical difference is covered in why blocks match names and allows do not. A restriction change takes effect within about two minutes, on every surface. Custom roles are a Gold-plan feature, so a dedicated HR reader role requires that plan.

The role layer is not optional, because a shared connection runs on its owner's credential. Share the BambooHR connection with the HR team at use, and every grantee's call reaches BambooHR as the account behind that key. Those grantees never see the key itself: reading an account's configuration back returns the list of dot-paths that were encrypted, and none of their values. The restriction is what makes one shared connection serve different people differently. The per-tool or per-app decision runs through the same reasoning for other apps.

Checklist for locking down an HR reader role:

  1. API key created from a BambooHR access level without compensation visibility (layer one, verified by test call)
  2. Custom role created in Elaichi for HR readers
  3. Allow rule naming only list_*/get_* BambooHR tools the role actually needs (not all 182)
  4. Pay-related tools (table above) confirmed absent from the allow list
  5. Allow rules added for the role's other connectors (Slack, Google Calendar, etc.), named whole, so they aren't silently denied
  6. Connection shared with the HR team at use
  7. Test call made as a role member to confirm pay tools are unreachable and routine tools work

What a withheld BambooHR tool looks like to the model

Invisible, and indistinguishable from a tool the connector never had. Restrictions filter the index before it is searched. So a withheld tool reaches neither the tool list nor the search, and its name never goes on the wire. The model cannot call it and gets no permission error to reason about.

Connected tools are never listed in tools/list, however few there are. The model finds one with search_tools and runs it with execute_tool, and those two are the only way in. A BambooHR tool missing from a list is therefore usually a permission gap rather than a bug. MCP tools not showing up walks the diagnostic ladder in order.

One consequence of that shape: search_tools is annotated read-only, while execute_tool is annotated destructive and open-world, because it runs whatever connected tool it is handed. A client that prompts on anything not marked read-only will prompt on every BambooHR call, reads included. This is a client-side UX behavior, not something the restriction layer controls.

Should you use BambooHR's own MCP server instead?

If BambooHR is the only app you need in the assistant, yes. BambooHR runs an official MCP server, in beta, at {subdomain}.bamboohr.com/api/mcp, and it powers BambooHR's own Claude and ChatGPT connectors. An admin gate decides who may use it. BambooHR says it enforces BambooHR's existing permissions, omitting restricted fields without warning (BambooHR MCP server docs, checked October 2026). Ask BambooHR answers from data the user can access, and HR can read the chats (BambooHR help, checked October 2026).

Per-person permissions, enforced by the system that owns the data, with no second vendor in the path. That is a genuinely good answer for a single app, and the silent field omission matches the API behavior either way.

What BambooHR's own pages do not claim is the part that decides the rest of the question:

  • One address covering apps from different vendors (BambooHR, Jira, Zendesk, a payroll provider) rather than one MCP server per app.
  • Restrictions written once for a role, applying across all of those apps rather than configured separately in each vendor's admin panel.
  • One audit trail spanning them, instead of one log per vendor.
  • Ending a person's access to all of them in one action.

If HR also needs Jira, Zendesk and a payroll provider in the same assistant, those four gaps are the reason to put a control plane in front. If it does not, adding one is unnecessary overhead. Removal in Elaichi ends access through Elaichi and nothing more; the person's BambooHR account still exists and must be deprovisioned on BambooHR's side separately.

Decision rule: for a single-app HR assistant, BambooHR's own MCP server. For an assistant spanning HR, support and project tools under one role model, a control plane in front of all of them.

Adding one endpoint in Claude or ChatGPT

Every connected account is served through one organization-wide endpoint: POST https://api.elaichi.ai/mcp. There are no per-user URLs and no embedded tokens. An admin adds the address once where the client allows it. Each member then signs in with their own OAuth grant. OAuth is the browser sign-in that issues a client its access, with no key to paste.

In Claude Team and Enterprise, an Owner or Primary Owner adds it under Organization settings, Connectors, Add, Custom, Web. Members then connect it under Customize, Connectors (Anthropic support, checked October 2026). In ChatGPT, custom MCP apps with write actions are in beta on Business, Enterprise and Edu. Only Admins and Owners publish one (OpenAI help, checked October 2026). OpenAI now manages apps under Plugins in the Admin Console, so follow the current path in the ChatGPT guide below. Step-by-step versions are in connecting Elaichi to Claude and connecting Elaichi to ChatGPT.

On the consent screen, every scope the client asked for is pre-ticked except delete, which is never pre-ticked. With "Run your connected tools" ticked, a second step offers All my tools or Only the ones I pick. Read one line carefully here: for a connected app's tools, "Run your connected tools" covers reads and writes alike. Leaving "Create and change data" unticked does not make BambooHR read-only, because that checkbox governs Elaichi's own operations, not the connector's. Read-only BambooHR access is a restriction (layer two above), not a consent-screen setting. A finance team reaches the same conclusion in QuickBooks read-only for a finance team.

What the audit trail records for a BambooHR call

Elaichi writes one entry per tool-call attempt, succeeded or failed, naming the account actually reached. Each entry records the operation and tool, the connection, the classification, whether it was approved, the outcome, and an error code. Argument names and counts are logged. Argument values never are.

For HR data that default is the right one, and it is also a limit. The log proves that a given member ran an employee lookup through Claude at a given time. It does not record which employee id was passed. An investigation that needs that detail has to look on BambooHR's side.

The error text has a firewall around it. What the caller sees is derived from BambooHR's response body. What is written to the audit trail never is. Audit records are organization-visible and can be forwarded to a customer's own destination. A call from Claude or ChatGPT is recorded with actor_kind of user, the surface mcp, and the OAuth client named. Claude and ChatGPT are among the clients whose name is marked verified by their redirect URIs. The trail is append-only. A compliance reviewer reads it on the free Auditor seat, which lacks tool:execute. So an Auditor cannot call BambooHR at all, only read what others called. What an AI agent audit log must capture covers the record shape in full.

Who owns the BambooHR connection when its creator leaves?

Someone has to, and it will not resolve itself. Elaichi's offboarding preflight lists every connection the departing member owns, private and shared alike. A connection can be transferred to another active member or deleted, never to the admin running the removal. In Elaichi, removing or suspending a member revokes every live grant in the same transaction as the membership change.

A transfer changes one thing: the owner. The credential behind the connection is still the original person's sign-in to the app. For BambooHR that credential is an API key tied to their BambooHR user. Plan for it to stop working when that account is deactivated, which would take the whole HR team's access with it. Every toolbox entry the departing owner pinned to that connection also stops resolving after a transfer. That holds for everyone including the new owner, until someone re-pins it.

So plan the swap before the leaving date:

  1. Issue a new API key from a BambooHR account that is staying, at the same compensation-hiding access level.
  2. Connect BambooHR again in Elaichi with that key, owned by a member who is staying, and share it with the HR team at use.
  3. During the leaver's offboarding, delete the old connection or transfer it to another active member.

A private connection pinned into a toolbox its owner shared is marked needs_resolution and waits for an administrator's decision. That is one more reason to pick a long-tenured owner at the start rather than transfer reactively. Offboarding AI access covers the rest of the preflight.

Can ChatGPT see my BambooHR salary data if it's connected via MCP? Only if the credential behind the connection belongs to a user whose BambooHR access level includes compensation. A restriction can withhold the pay tools. But an employee read can still return pay fields if the key's user can see them. That is why layer one comes first.

Is MCP inherently unsafe for HR data? No. MCP is a protocol for tool discovery and invocation; it has no opinion on field-level permissions. Safety depends entirely on what the underlying API key can see, which is BambooHR's access level. It also depends on what the control plane in front of it allows, the restriction. The protocol itself neither adds nor removes risk.

Does restricting tools in Elaichi affect BambooHR's own UI or reports? No. Restrictions apply only to calls made through Elaichi's MCP endpoint. A user's direct BambooHR login and its existing access level are unaffected.


The tool list for this connector is on the BambooHR connector page. For the shape of the thing you are building, read what an MCP control plane is. For the same playbook against a payroll system, see keeping payroll data in HR with Gusto.

FAQ

Frequently asked questions

Does a BambooHR API key see salary data?

It sees whatever the BambooHR user who created it can see. BambooHR states that the API can only view or update data that the user can access ([BambooHR help](https://help.bamboohr.com/s/article/587841), checked October 2026), and Get Employee drops fields the caller cannot view without returning an error. Pay data sits in the compensation table and the payRate, payType and paidPer fields, so a key created by an account whose access level hides those fields returns records without them.

Why use an allow rule instead of blocking BambooHR's pay tools?

Because Elaichi's BambooHR connector carries 406 tools, and a block list leaves every tool it does not name reachable. An allow rule names what a role may reach and denies the rest. One caution: in Elaichi an allow rule is the target's whole allowlist across every connector, so a role that also uses other apps needs an allow rule naming each of those connectors whole, or it loses them. In Elaichi, restriction targets are role or user only; the organization default is the absence of a rule, which means allow everything.

Does BambooHR have its own MCP server?

Yes. BambooHR runs an official MCP server in beta at {subdomain}.bamboohr.com/api/mcp, which powers its Claude and ChatGPT connectors. An admin gate decides who may use it, and BambooHR says it enforces the company's existing BambooHR permissions, omitting restricted fields without warning ([BambooHR MCP server docs](https://documentation.bamboohr.com/docs/mcp-server), checked October 2026). For a company whose assistant only needs BambooHR, that is a sound choice with no second vendor involved.

What happens to a BambooHR connection when the person who created the API key leaves?

The key belongs to their BambooHR user, so it keeps working until BambooHR's side is handled and should be expected to stop working when their BambooHR account is deactivated. Elaichi's offboarding preflight lists every connection the departing member owns and allows a transfer to another active member or a deletion, never a transfer to the admin running the removal. A transfer changes only the owner, so before the leaving date connect BambooHR again with a key from a staying account at the same access level, and share that connection.

Put agents to work on your own systems

14 days on Gold, no credit card. Start with one app and one team.

Works with
Claude ChatGPT Cursor and any other MCP client, or the Elaichi Agent.
When the trial ends
Nothing is deleted. Connections, roles and the audit log stay where they are, so subscribing picks up exactly where you left off.