# MCP endpoint

HollyHR exposes a hosted Model Context Protocol endpoint at your tenant app
origin:

```text
https://{workspace}.hollyhr.com/api/mcp
```

The endpoint is a framing layer over the same public API substrate documented in
this developer portal. It uses organisation-scoped API keys, the Pro API
entitlement, public API scopes, public IDs, generated contracts, request logs,
rate limits, idempotency, and ETags.

For client-specific setup, see [Claude and ChatGPT](/ai-connectors). For a
repeatable deployment check, see the [MCP smoke test](/mcp-smoke).

Agent-readable discovery is available at:

```text
https://{workspace}.hollyhr.com/auth.md
```

That document summarizes the current access mode, PRM URL, MCP endpoint, scope
surface, and write-safety posture for human readers and agent tooling.

## Authentication

Use a HollyHR public API key as a bearer token:

```text
Authorization: Bearer hhr_test_...
```

The MCP endpoint derives the organisation from the API key. Do not provide a
tenant ID or workspace ID to any tool.

For write tools, grant `mcp:write` in addition to the relevant data write scope,
for example `people:write` or `time_off:write`. A key with REST write scopes but
without `mcp:write` can still use read tools, but write preparation and commit
tools reject it. HollyHR also keeps MCP writes disabled by default unless the
tenant environment has `HOLLYHR_MCP_WRITE_MODE=enabled`.

OAuth protected-resource metadata is available under:

```text
https://{workspace}.hollyhr.com/.well-known/oauth-protected-resource/api/mcp
```

The endpoint returns a `WWW-Authenticate` challenge on unauthenticated requests
with the same `resource_metadata` URL, so capable MCP clients can discover the
protected-resource metadata automatically. The challenge also includes a narrow
read-scope hint for the first useful MCP connection:

```text
WWW-Authenticate: Bearer resource_metadata="https://{workspace}.hollyhr.com/.well-known/oauth-protected-resource/api/mcp", scope="organisation:read people:read reference:read time_off:read"
```

The metadata `scopes_supported` list advertises only scopes used by executable
MCP operations with explicit output projections. Excluded public API surfaces
such as personal profiles, payroll exports, provider mappings, and webhook
management are intentionally not advertised as MCP scopes.

The initial `/api/mcp/.well-known/oauth-protected-resource` route remains
available as a compatibility alias, but it is not the primary discovery path.

Bearer API-key auth is HollyHR's first supported developer-preview access mode.
When OAuth is enabled for a tenant, the MCP endpoint also accepts
issuer-verified OAuth access tokens whose audience is the tenant `/api/mcp`
resource and whose claims bind the token to a real active HollyHR API-key actor
row. When an authorization server issues HollyHR data scopes, those scopes must
be part of the executable MCP surface and are intersected with that API-key
actor's scopes. WorkOS/AuthKit currently issues identity-scoped MCP tokens
(`openid profile email`) plus resource and custom consent claims, so HollyHR
derives data access from the selected API-key actor profile filtered to the
MCP-safe scope surface. OAuth cannot grant broader access than the underlying
HollyHR integration actor.

For WorkOS/AuthKit, configure:

- `HOLLYHR_OAUTH_ISSUER_URL` to the AuthKit issuer;
- `HOLLYHR_OAUTH_JWKS_URL` only when the JWKS endpoint is non-standard;
  otherwise HollyHR derives `https://<authkit-domain>/oauth2/jwks`;
- `HOLLYHR_OAUTH_AUDIENCE` only when the AuthKit resource indicator differs
  from the tenant MCP URL;
- `HOLLYHR_OAUTH_ORG_ID_CLAIM` and `HOLLYHR_OAUTH_API_KEY_ID_CLAIM` when custom
  claim names differ from `hollyhr_org_id` and `hollyhr_api_key_id`.
- `WORKOS_API_KEY` and `HOLLYHR_OAUTH_CONNECT_API_KEY_NAME` for Standalone
  Connect Login URI completion.

HollyHR advertises `authorization_servers` in protected-resource metadata only
when the issuer is HTTPS and the JWKS verification URL is usable. For older MCP
or OAuth clients that look at the resource origin, HollyHR also proxies:

```text
https://{workspace}.hollyhr.com/.well-known/oauth-authorization-server
```

to the configured authorization server metadata.

Connector-gallery support remains a GA launch gate until the tenant's issuer,
JWKS, audience, actor claims, client registration, and compliance approvals are
configured and smoke-tested in production.

This is API-key-backed OAuth resource-server mode, not true delegated-user
OAuth. Per-user consent, user-role intersection, OAuth app records, grant
revocation, and user-attributed audit are a separate future architecture phase.
Do not treat an empty `authorization_servers` array as a broken preview
endpoint; it means the tenant is currently using API-key bearer auth only.

## Transport

The hosted endpoint uses MCP Streamable HTTP:

```text
POST https://{workspace}.hollyhr.com/api/mcp
Accept: application/json, text/event-stream
Content-Type: application/json
Authorization: Bearer hhr_test_...
MCP-Protocol-Version: 2025-11-25
```

The server runs in stateless mode for Vercel/serverless compatibility. Browser
clients must use the same origin or a configured trusted Origin; server-to-server
clients normally omit the `Origin` header. Authenticated `GET /api/mcp` returns
`405 Method Not Allowed` because GET/SSE session streaming is not part of the
first hosted surface. The server does not require clients to preserve an
`MCP-Session-Id`.

## Tools

The endpoint includes contract-aware discovery tools:

- `list_api_operations`
- `get_api_operation`
- `call_api_operation`
- `prepare_api_write`
- `commit_api_write`

It also includes workflow-shaped read tools for common HR work:

- `whoami`
- `search_people`
- `get_person`
- `get_person_context`
- `list_time_off`
- `get_time_off`
- `list_reference`

`call_api_operation` executes read operations only. Mutations require
`prepare_api_write` followed by `commit_api_write`.

Stable tools publish output schemas and return MCP `structuredContent` so
clients can validate common results without parsing freeform text.

`whoami` includes a `catalogue_version` fingerprint. Treat it as the current
server-side MCP tool/catalogue contract version for compatibility checks.

## Resources And Prompts

The server exposes read-only MCP resources for the developer guide, OpenAPI
reference, safe-write workflow, and HR data-handling policy. It also exposes
prompts for planning safe read-only lookups and reviewing prepared writes before
commit. These resources and prompts contain public guidance only; tenant data is
available through scoped tools, not static resources.

## Write Safety

Writes use a two-step flow:

1. Call `prepare_api_write` with the operation ID, path parameters, query
   parameters, and body.
2. Review the frozen payload and confirmation token returned by the server.
3. Call `commit_api_write` with the confirmation token.

The confirmation token is signed by HollyHR, tied to the API key and
organisation, expires quickly, and contains a server-generated idempotency key.
For conditional updates, the server captures the current ETag during
preparation. The model cannot change the write body, ETag, or idempotency key
between preparation and commit.

When writes are enabled, `commit_api_write` also asks the MCP host for user
approval through form elicitation before committing. If the initialized client
does not advertise form elicitation, if the host cannot provide approval, or if
the user declines, the write fails closed.

## Data Handling

MCP output is projected and sanitized before it is returned to clients. Each
operation has a positive MCP output projection, so newly added upstream public
API fields are omitted from MCP until they are deliberately reviewed and added
to that projection:

- bearer tokens, API keys, webhook secrets, and secret-like values are redacted;
- links and document/download URLs are redacted;
- document filenames are redacted and document categories are bucketed;
- payroll, bank, tax/government, compensation, and home-address fields are
  redacted;
- absence category labels are bucketed to `Absence` by default, and time-off
  category IDs are omitted from MCP output to prevent category-label joins;
- time-off balance category names and category IDs are also bucketed/omitted so
  composite tools such as `get_person_context` keep the same projection ceiling.

Webhook management operations are intentionally excluded from the MCP tool
surface while the secret-returning and DPIA gates are open.

## Debugging

Every MCP tool call writes a public API request-log row with a route shaped like
`mcp:<tool_name>` and `source` set to `mcp`. Budgeted HR-data reads also record
`pii_row_count`.

HollyHR enforces a rolling daily MCP HR-data row ceiling per organisation. The
default is 500 rows per 24 hours unless the tenant environment sets
`HOLLYHR_MCP_DAILY_PII_ROW_LIMIT`. If a tool call would exceed the remaining
budget, it fails closed with a rate-limit error before returning the rows.

Public API service calls still return structured errors that MCP tools surface
as tool errors rather than protocol errors, so agents can correct missing
scopes, validation mistakes, ETag preconditions, and rate-limit issues without
losing the session.

## Smoke Testing

Use the repository smoke harness with a disposable tenant API key when validating
a deployment:

```bash
HOLLYHR_MCP_URL="https://{workspace}.hollyhr.com/api/mcp" \
HOLLYHR_MCP_TOKEN="hhr_test_..." \
pnpm mcp:smoke
```

When validating a tenant that should have OAuth enabled, add:

```bash
HOLLYHR_MCP_EXPECT_OAUTH=1 \
HOLLYHR_MCP_EXPECT_AUTHORIZATION_SERVER="https://auth.example.com" \
HOLLYHR_MCP_URL="https://{workspace}.hollyhr.com/api/mcp" \
HOLLYHR_MCP_TOKEN="<oauth-access-token-or-api-key>" \
pnpm mcp:smoke
```

The smoke covers protected-resource metadata, authorization-server metadata
when OAuth is expected, unauthenticated discovery, the authenticated
`GET`/SSE-disabled `405` response, SDK initialization, `tools/list`, `whoami`,
and safe write preparation. Write commits are tested only when the host supports
MCP form elicitation and the production write-mode gate is intentionally
enabled.

For WorkOS/AuthKit connector readiness, run the provider smoke as well:

```bash
HOLLYHR_OAUTH_ISSUER_URL="https://<authkit-domain>" \
HOLLYHR_WORKOS_CONNECT_RESOURCE="https://{workspace}.hollyhr.com/api/mcp" \
pnpm mcp:workos:smoke
```

It checks WorkOS authorization-server metadata, DCR, PKCE S256, that WorkOS
accepts the default identity scopes, and that the tenant MCP resource is
accepted by WorkOS before an interactive reviewer login. HollyHR data
authorization is then enforced from the selected backing API-key actor profile,
not custom WorkOS data scopes. For diagnostic custom-scope probes, operators can
set `HOLLYHR_WORKOS_CONNECT_ALLOW_CUSTOM_SCOPES=1` and
`HOLLYHR_WORKOS_CONNECT_SCOPES`, but that is not the normal WorkOS setup path
unless WorkOS begins advertising those scopes.

For an API + MCP time-to-first-call check, use
`pnpm developer:ttfc:smoke` from [Sandbox and TTFC](/sandbox).
