AI & MCP
MCP server
Connect Claude or any MCP client to your Elevate Team account: endpoint, authentication, the tool catalogue, scopes and what a key cannot reach.
Elevate Team ships a Model Context Protocol server so an AI client can use your account's tools directly, to find a client, check who is free on Thursday or draft a quote, instead of being handed a scraped copy of your data.
The endpoint
POST https://your-elevateteam-host/mcp
Authorization: Bearer sp_…
Content-Type: application/json
One endpoint carries the whole protocol. It speaks JSON-RPC 2.0 and
implements protocol revision 2025-06-18. Three methods do the work,
initialize, tools/list and tools/call, plus ping and notifications.
It is deliberately not streaming. Every tool answers in one shot, so a Streamable HTTP transport with SSE would be a second code path to keep correct for no benefit. Plain JSON responses, which the specification allows and every client handles.
Protocol errors are HTTP 200
A JSON-RPC error is a 200 response with an error member. Returning a 400 is
the single most common way to break an MCP client, which reports the server as
unreachable instead of showing you the message.
Authentication
The same bearer API key the REST API uses. Create one in Settings → Developers; the token is shown once and stored only as a hash.
Three things follow from that, and they are the whole security model:
- The key decides the tenant. There is no account id to send and no header to get wrong.
- The key acts as a person. It carries the permissions of the membership that created it, and audit entries name that person. A key can never do what its holder could not.
- A suspended holder is a dead key. If that person leaves the business, their keys stop working immediately. Issue integration keys from an account that will outlive the integration.
Scopes
| Scope | Reaches |
| --- | --- |
| read | the read tools only |
| write | read tools plus the short write list below |
Write scope is checked per call, not per connection, so a read-only key can never reach a write tool even if it asks for one by name.
Connecting a client
Claude Code
claude mcp add elevate-team \
--transport http \
https://your-elevateteam-host/mcp \
--header "Authorization: Bearer sp_…"
Claude Desktop and other config-file clients
{
"mcpServers": {
"elevate-team": {
"url": "https://your-elevateteam-host/mcp",
"headers": { "Authorization": "Bearer sp_…" }
}
}
}
Checking it by hand
curl -sX POST https://your-elevateteam-host/mcp \
-H "Authorization: Bearer sp_…" \
-H "Content-Type: application/json" \
-d '{"jsonrpc":"2.0","id":1,"method":"tools/list"}' | jq '.result.tools[].name'
What the server tells a client on connect
initialize returns the protocol version, a tools capability (only tools:
no resources, no prompts, no sampling) and an instructions string generated for
your account. That string names the business, the person the key acts as, the
account currency and timezone, and states plainly that nothing reachable here
sends a message, takes a payment or cancels work.
Declaring a capability the server does not serve is how a client ends up calling something that answers "method not found", so it declares only what it has.
The tool catalogue
Tools are filtered twice before a client sees them: by the scope on the key, and by the role of the membership that owns it. A key issued by a coordinator reaches exactly what a coordinator reaches.
Read
| Tool | What it answers |
| --- | --- |
| find_client | Look up a client by name or email before quoting |
| find_job | A job with its visits, quote and status |
| find_visit | A single visit with its crew and window |
| list_requests | Inbound work not yet turned into jobs |
| list_service_items | Your price book |
| list_tasks / list_documents | Open tasks; documents on a record |
| list_team / list_service_areas | Who works here; where you work |
| list_checklist_templates | Checklists by job type |
| list_booking_fields | Questions your intake form asks |
| list_message_templates | The wording customers receive |
| check_availability | Whether a person or crew is free |
| find_open_slots | Bookable gaps matching a duration and area |
| find_conflicts | Double bookings and impossible drive times |
| team_workload / suggest_crew | Load per crew; who fits a job |
| list_exceptions / daily_briefing | What needs attention today |
| job_economics | Cost against revenue for a job |
| check_stock | What is on hand, including per van |
| list_receivables / list_payments | What is owed; what has been paid |
Write
Deliberately short. Every one of these creates work rather than changing money or reaching a customer, and every one is reversible from the board.
create_client · update_client · create_quote · create_job ·
update_job · schedule_visit · reschedule_visit · reassign_visit ·
create_task · update_task · update_request · add_visit_note ·
record_stock_use
What a key cannot reach
This is the part worth reading before you connect anything.
Nothing that sends. No tool that emails a customer, texts a window or issues a document is on the list. In the app those actions require a person to press a confirm button; there is nobody on the other end of an MCP call to press it, and a send an outside model can reach is a send an injected instruction can reach. This is enforced at boot, not by convention: if a tool that requires confirmation is ever added to the MCP lists, the server refuses to start.
Nothing that moves money. No invoicing, no payments, no refunds.
Nothing destructive. No cancel, no delete, no archive.
Three reads the in-app assistant has and a key does not:
list_propertiesandread_notescarry access notes: gate codes, alarm codes, where the key is hidden. Those are the keys to customers' homes, and they should not travel by API token pasted into a config file.list_leavecarries why somebody is off work, which can be medical.check_availabilityalready reports that a person is unavailable, which is the part scheduling actually needs.
Errors you will see
| Condition | Response |
| --- | --- |
| Body will not parse | -32700 Invalid JSON, HTTP 200 |
| Not a JSON-RPC message | -32600 Not a JSON-RPC message |
| Unknown method | -32601 Unknown method: … |
| Unknown tool name | -32602 with "no such tool" |
| Write tool, read-only key | -32602 naming the scope, not a typo |
| Anything unexpected | -32603 Something went wrong, logged server-side |
The distinction between "no such tool" and "not with this key" matters: the second is a scope a business can fix, and reporting it as unknown would send someone hunting for a spelling mistake.
Batches and notifications
A JSON array of requests is answered as an array. Messages without an id are
notifications: acknowledged with 202 and no body, however interesting they
were. A batch of only notifications produces no body at all, which is what the
specification says and what clients wait for.
Practical advice
- Issue a dedicated key. Not your personal one. Name it after the integration so the audit log reads clearly.
- Start read-only for a fortnight. You will find out quickly where the model misreads your vocabulary.
- Read the audit log. Every tool call is recorded with who the key acts as, what ran and what changed.
- Revoke on laptop changes. A key is a machine credential and travels with the machine.