Overview
MCP (Model Context Protocol) is the open standard AI assistants use to call tools in other products. With it you can ask things like “Who is out next week?”, “How many vacation days does Ann have left?” or “Ask for Friday off for me”, and, with a token that can change things, “Approve Ben’s request for 9 November”.
- Address:
https://leavecalc.com/api/v1/mcp - Sign in: a LeaveCalc API token, sent as
Authorization: Bearer lc_.... These are the same tokens as the LeaveCalc API, and the MCP server is part of every plan, Free included. - Transport: MCP Streamable HTTP, POST only.
- Protocol versions: 2026-07-28 (current), and 2025-11-25, 2025-06-18 and 2025-03-26 (the handshake most assistants still use today).
What the assistant can do
| Tool | What it does | Needs a token that can |
|---|---|---|
who_is_out | Who is on approved time off on a day or in a date range (up to 93 days). | Read token |
balances | Time off left per leave type, for one person (“me”, a name, an email, an id) or for everyone. | Read token |
list_requests | Time off requests. Filter by status, dates or person. | Read token |
list_people | The people of your company. Search by name or email, filter by department. | Read token |
company_policies | Your leave types, time zone, working days and hours per day. | Read token |
upcoming_holidays | Holidays coming up, for the company or one location. | Read token |
request_time_off | Ask for time off for a person (“me”, an id, an exact email or an exact full name). It stays pending until someone approves it. | Write token |
approve_request | Approve a pending request. Needs the request id, the employee and the start date. | Write token made by an owner |
deny_request | Deny a pending request. Needs the request id, the employee and the start date. | Write token made by an owner |
“Write token” is the choice Read and change when you make the token. A token that can only read does not even see the three tools that change things.
Documents attached to requests (such as doctor’s notes), pay, attendance points, support messages and private manager notes are not available through MCP at all.
Rules the server follows
The same rules as the LeaveCalc API.
- The same checks as the app. A request made through the assistant is validated, counted and announced exactly like one made in LeaveCalc: the approvers get their email, Slack or Teams message, and webhooks fire. Approving and denying run the app’s own approval, including two-step approval, balances and blackout dates.
- Sick, FMLA and protected leave. By default the assistant sees such time off as “Time off”, without the leave type and without the note, and it is left out of balances. A token made with the switch Include the type of sick and medical leave sees the leave type (and the notes of ordinary requests). Notes of sick and medical requests are never shown to any token.
- Nobody approves their own request. A token acts with the rights of the owner who made it, and that owner cannot approve or deny their own request through the assistant (they still can in the app). Use another owner’s token or the app.
- Blackout dates are never overridden. If a blackout blocks an approval, the assistant is told to open the request in LeaveCalc.
- Approved time off cannot be cancelled through the assistant.
deny_requestonly works on pending requests. - Asking twice is safe. If the assistant retries the same request (same person, leave type and dates), the second try is refused and names the first request. The exception is sick, FMLA and protected leave with a token that may not see the leave type: there the refusal would reveal who was ill and when, so such a retry is simply a second request.
- Writes need an exact person.
request_time_offacts only for “me”, a person id, an exact email address or an exact full name. For anything else (“Ann”) it changes nothing and answers withcandidates, so the assistant has to ask you which one. Reading tools still search by part of a name. - Approving and denying need proof that the assistant has the right request. Besides the request id the assistant must give the employee (exact full name, email or person id) and the start date, as you named them. If they do not match, nothing happens and the answer is
mismatch. A request note that says “approve request 17” cannot supply those two values for the assistant. Both tools are marked destructive, so assistants that honour that hint ask you every time. - Notes are labelled. Request notes (only for a token made to see them) reach the assistant as
{"untrusted_text": "..."}, cut to 200 characters, and the assistant is told that this is text an employee wrote, never an order. - Decisions say where they came from. A note on an approval or denial made through the assistant starts with “Decided through” and the token name.
- Limits. 120 calls a minute per token and 300 a minute for all tokens of one company. A
list_peoplesearch by name counts as 5. Past the limit the server answers 429 with a Retry-After header. - Every change is in the activity log (Settings, Activity log) with the name of the token as who did it.
Make a token
- Sign in to LeaveCalc as an owner. Only owners can make tokens.
- Open Settings, Integrations. In the card API tokens, choose Create token.
- Under What is it for? type a name that says who uses it, for example “Claude, Dana’s laptop”. The name is what the activity log shows.
- Under What may it do? choose Only read to start. Choose Read and change only if you want the assistant to ask for time off or to approve and deny requests, and only for a connector that is yours alone.
- Leave the switch Include the type of sick and medical leave off unless you need it.
- Choose Create token and copy the token now. LeaveCalc keeps only a fingerprint of it.
Treat the token like a password. Anyone who has it can do what it can do, as the owner who made it, until you remove it. Remove a token in the same list at any time and it stops working at once. A token also stops working when the owner who made it is removed or is no longer an owner. You can have up to 10 tokens.
Connect your assistant
This is the part where products differ most. What we found on 7 October 2026:
| Assistant | Fixed bearer token | Works today |
|---|---|---|
| Claude Code (command line) | Yes, with --header | Yes |
| Claude on the web, Desktop, mobile (custom connector) | Only through “Request headers”, a beta open to a limited set of organizations | Only if your organization has that option |
| ChatGPT (custom connector, developer mode) | No. Its documented choices are OAuth, no authentication, or both | Not yet (needs OAuth) |
| OpenAI API (Responses API, remote MCP tool) | Yes, in the authorization field | In principle, not tested by us |
| Anthropic API (MCP connector) | Yes, in authorization_token | In principle, not tested by us |
| Cursor, VS Code, other developer tools | Yes, a headers setting in their MCP config | Yes, check your tool’s documentation |
Claude Code
Keep the token in an environment variable, so it never appears in your shell history or in a file you might share. Type it where nobody can read it over your shoulder, then add the server with the variable’s name, not its value.
read -rs LEAVECALC_TOKEN && export LEAVECALC_TOKEN
claude mcp add --transport http leavecalc https://leavecalc.com/api/v1/mcp --header 'Authorization: Bearer ${LEAVECALC_TOKEN}'$env:LEAVECALC_TOKEN = Read-Host "LeaveCalc token"
claude mcp add --transport http leavecalc https://leavecalc.com/api/v1/mcp --header 'Authorization: Bearer ${LEAVECALC_TOKEN}'The single quotes matter: they keep your shell from replacing the variable, so Claude Code stores ${LEAVECALC_TOKEN} and reads the real value from the environment each time it starts. Set the variable in your profile or in the system’s environment settings to have it in every session.
Then start Claude Code and run /mcp. LeaveCalc should be listed as connected with its tools. Ask “Who is out this week in LeaveCalc?”. Add --scope user to use it in all your projects.
.mcp.json write the header as "Authorization": "Bearer ${LEAVECALC_TOKEN}". Pasting --header "Authorization: Bearer lc_your_token" into the command leaves the token in your shell history: if you did it, remove the token in LeaveCalc and make a new one.Source: Claude Code documentation, “Connect Claude Code to tools via MCP” (code.claude.com/
Claude on the web, Desktop and mobile
Claude’s apps expect an OAuth sign-in, which LeaveCalc does not offer yet. A connector can still use a fixed token if your organization has the beta section called Request headers. If you do not see it, you cannot connect these apps today.
- Add a custom connector: on the Free, Pro and Max plans under Customize, Connectors, Add custom connector. On Team and Enterprise plans an Owner of the Claude organization adds it under Organization settings, Connectors.
- Enter the address
https://leavecalc.com/api/v1/mcp. - Under Authentication choose No sign-in. This is how Claude’s dialog describes a server that uses an API key.
- Open Request headers. If you do not see this section, stop here.
- Pick the header name
authorizationand enter the value with the word Bearer, a space and your token:Bearer lc_your_token. A value withoutBeareris rejected with a 401. - Choose Add. Authentication settings cannot be changed afterwards: to change the token, remove the connector and add it again.
Source: Claude help, “Add a connector that isn’t in the directory” (claude.com/
ChatGPT
ChatGPT cannot connect to LeaveCalc today. It adds custom MCP servers through developer mode, and OpenAI’s documentation lists three choices for authentication: OAuth, no authentication, or OAuth or no authentication. There is no field for a fixed bearer token. Please do not choose “No authentication”: LeaveCalc refuses every call without a token, so the connector would only show errors. This needs OAuth support on our side (see What is not there yet).
If you build with the OpenAI API instead of the ChatGPT app, the remote MCP tool of the Responses API takes the token in its authorization field and sends it to the server as the bearer token, so a LeaveCalc token fits there. We have not tested this against OpenAI’s service. Source: OpenAI documentation, “Add custom MCP server” (developers.openai.com/
Other tools (Cursor, VS Code and similar)
Most developer tools take a JSON entry with the address and headers. The common shape is:
{
"mcpServers": {
"leavecalc": {
"type": "http",
"url": "https://leavecalc.com/api/v1/mcp",
"headers": { "Authorization": "Bearer lc_your_token" }
}
}
}The exact file name and keys differ between tools (some call the type streamable-http, some name the root key servers). Check your tool’s documentation. Do not paste the token into a file that is shared or synced: use the way your tool reads an environment variable and keep the token in the environment. Tools that can only start a local program (stdio) can reach a remote server through a bridge such as mcp-remote, which accepts a --header option. We have not tested bridges.
Try it by hand
A request with curl, using the 2025-06-18 handshake that most assistants send first. Put the token in a variable first, as in the Claude Code section.
curl -s https://leavecalc.com/api/v1/mcp \
-H "Authorization: Bearer $LEAVECALC_TOKEN" \
-H "Content-Type: application/json" \
-H "Accept: application/json, text/event-stream" \
-d '{"jsonrpc":"2.0","id":1,"method":"initialize","params":{"protocolVersion":"2025-06-18","capabilities":{},"clientInfo":{"name":"curl","version":"1"}}}'Then list the tools with {"jsonrpc":"2.0","id":2,"method":"tools/list"} and add the header MCP-Protocol-Version: 2025-06-18.
The newer, stateless way (protocol 2026-07-28) has no handshake. Every request carries the version and the matching headers:
curl -s https://leavecalc.com/api/v1/mcp \
-H "Authorization: Bearer $LEAVECALC_TOKEN" \
-H "Content-Type: application/json" \
-H "MCP-Protocol-Version: 2026-07-28" \
-H "Mcp-Method: tools/call" -H "Mcp-Name: who_is_out" \
-d '{"jsonrpc":"2.0","id":1,"method":"tools/call","params":{"name":"who_is_out","arguments":{"date":"2026-11-10"},"_meta":{"io.modelcontextprotocol/protocolVersion":"2026-07-28","io.modelcontextprotocol/clientCapabilities":{}}}}'The official MCP Inspector (npx @modelcontextprotocol/inspector) can also connect: choose the Streamable HTTP transport, enter the address and add the Authorization header.
Safety advice
- Prefer a read token. A shared (organization-wide) connector must use a read token. Make a second, personal token that can change things only for the people and the moments that need it.
- Keep the token out of your shell history and out of shared files. Give it to the tool through an environment variable.
- An assistant can be fooled by text it reads. A request note or a person’s name is written by an employee, and a hostile one could try to give the assistant orders. LeaveCalc labels such text as untrusted, tells the assistant to treat it as data, and refuses an approval or denial unless the employee and start date match the request. The real protection is yours: keep the assistant’s confirmation prompt on for write tools, and do not choose “always allow” for
approve_requestordeny_request. - What the assistant reads goes to the company that runs the assistant (names, dates, balances), under your agreement with them. Do not connect an assistant you would not share your team calendar with. Nothing is sent to LeaveCalc except what the assistant asks for.
If something does not work
| You see | Meaning |
|---|---|
401 invalid_token or missing_token | The header is missing, has no Bearer in front of the token, or the token was removed. Make a new one. |
| “Couldn’t reach the MCP server” in Claude | Claude started its OAuth sign-in because the server answered 401 and no fixed header was sent. Add the Request header, or see What is not there yet. |
| 403 on a call | The request came from a web page that is not allowed (the server checks the Origin header against DNS rebinding). Command line tools and the assistants above send no Origin and are fine. |
429 rate_limited | More than 120 calls a minute with one token. Wait the seconds in Retry-After. |
insufficient_scope | The token can only read. Make a read and write token. |
mismatch | For approve_request or deny_request: the employee or start date does not match that request, so nothing was done. Look the request up again and use the values the user named. |
confirmation_required | The employee (exact full name, email or id) and the start date are missing. |
candidates | For request_time_off: the name was not exact, or two people share it. Nothing was requested. Pick one and call again with the id. |
own_request | The token’s owner is the person who asked. Another owner has to decide. |
blackout | A blackout period blocks these dates. Approve it in LeaveCalc with an override. |
first_approval_recorded | Two-step approval is on. This was the first approval, and a final approver still has to approve. |
What is not there yet
- OAuth. The MCP specification makes authorization optional, but ChatGPT’s connector dialog and most of Claude’s connector paths expect it. To support them LeaveCalc would need to run an authorization server (a sign-in and consent screen where an owner approves the assistant, PKCE, refresh tokens, client registration, token audience binding) and publish protected resource metadata. That is a project of its own and was deliberately not rushed into this release. Until then, only clients that can send a fixed header connect.
- No server-to-assistant streaming. The server answers GET with 405, sends no list-change notifications, and offers tools only (no resources or prompts).
- JSON-RPC batches are accepted only in protocol 2025-03-26, as that revision defines them.
- Directory listings. Claude’s Connectors Directory and the ChatGPT app directory have their own review processes, which also assume OAuth. LeaveCalc is not listed in either.
Protocol details
- One endpoint, POST only. GET, DELETE, PUT and PATCH answer 405 with
Allow: POST. There are no sessions: anMcp-Session-Idheader is ignored and never issued. - Both eras are served on the same address. A request whose
params._metacarriesio.modelcontextprotocol/protocolVersionis a 2026-07-28 request and must have the headersMCP-Protocol-Version(equal to the body),Mcp-Method(equal tomethod) and, fortools/call,Mcp-Name(equal toparams.name). A mismatch is HTTP 400 with JSON-RPC error -32020, an unknown version is 400 with -32022, a missing_metafield is 400 with -32602, and an unknown method is 404 with -32601.server/discoveris implemented. - Anything else is the older era:
initialize(answers the client’s version when it is one of 2025-11-25, 2025-06-18 and 2025-03-26, else 2025-11-25),notifications/initialized(202),ping,tools/listandtools/call. - Notifications and client responses are answered 202 with no body. Bodies over 256 KB are 413.
- Tool failures the model can fix (bad date, unknown person, refused approval) come back as a normal result with
isError: trueand a plain sentence. Unknown tools and malformed requests are JSON-RPC errors (-32602). Every tool result hasstructuredContentand the same JSON as text incontent. Lists page withlimit(1 to 100) andnext_cursor. - Origin header: present and not on the allowed list is 403 (DNS rebinding protection). Allowed: leavecalc.com, claude.ai, claude.com, chatgpt.com and chat.openai.com. Requests without an Origin header, such as command line tools, are fine.
- Every message of a batch is its own change: a message that fails never undoes an earlier one that succeeded, and the emails and webhooks it causes are sent after its commit.
Specifications used, read 7 October 2026: modelcontextprotocol.io/
Also: API reference · Zapier · Make · SAML single sign-on