Skip to main content

The endpoint

Point any MCP-aware client at:
https://app.haloagents.ai/api/mcp
That URL is all you need. Authentication, discovery, and consent are handled by the standard OAuth 2.1 flow that every modern MCP client implements out of the box, so the first time a client hits the endpoint Halo walks it through registration and consent automatically.
The MCP server is enabled by default for every org. If you get a 403 from the URL it means MCP has been explicitly disabled on your workspace. Ask your Halo admin to set the mcp_server feature flag back to true for your team.

What happens on first connect

The first time a client points at /api/mcp, this is the flow it walks (you only see steps 3 and 4 as a user):
1

Discovery

The client POSTs to /api/mcp, gets a 401 with WWW-Authenticate: Bearer resource_metadata="...", and follows the link to discover Halo’s authorization server.
2

Dynamic registration

The client registers itself via RFC 7591 at /api/mcp/oauth/register and receives a fresh client_id. No manual app setup is required on Halo’s side.
3

Sign in to Halo

The client opens /api/mcp/oauth/authorize in your browser. If you’re not already signed in, you bounce through /signin and back.
4

Approve the request

Halo shows the consent page (/mcp/authorize) listing the client’s name, the org you’re authorising, and the scopes it requested. You can deselect any scope before approving.
5

Token exchange

The client receives an authorization code, swaps it at /api/mcp/oauth/token (PKCE-verified), and stores the access_token + refresh_token pair. Subsequent JSON-RPC calls carry Authorization: Bearer halo_at_....
Access tokens last 1 hour. Refresh tokens are long-lived but rotate on every use, so a stolen refresh token only works until the legitimate client refreshes next (the rotation revokes the entire derived chain).

Installation by client

Claude Desktop

Open ~/Library/Application Support/Claude/claude_desktop_config.json (macOS) or the equivalent on your platform and add Halo under mcpServers:
{
  "mcpServers": {
    "halo-agents": {
      "url": "https://app.haloagents.ai/api/mcp"
    }
  }
}
Restart Claude Desktop. The first time you reference a Halo tool in a chat, Claude will pop a browser window for the OAuth flow.

Cursor

Open Cursor Settings > MCP > Add new MCP server. Configure:
FieldValue
Namehalo-agents
TypeHTTP
URLhttps://app.haloagents.ai/api/mcp
Save. Cursor will prompt for OAuth on first use.

VS Code (Continue / GitHub Copilot Chat)

Add Halo under the MCP servers section of your AI extension’s settings (the exact key varies by extension):
{
  "mcp.servers": {
    "halo-agents": {
      "url": "https://app.haloagents.ai/api/mcp"
    }
  }
}
Reload the window. The OAuth flow runs in your default browser.

Custom clients

Any client that implements the MCP HTTP transport and OAuth 2.1 with PKCE can connect to Halo. Point at /api/mcp and discovery + dynamic client registration handle the rest. See Protocol Reference for the full endpoint list.

What the client sees

After the OAuth dance, the client calls tools/list to enumerate available tools. The set you see depends on three things:
  1. Your org’s connected integrations (HubSpot, Slack, Stripe, etc. in Integrations)
  2. The scopes you approved at consent time
  3. Whether the token is bound to a specific agent (defaults to your org’s Ask AI agent)
Destructive tools (refunds, deletes, irreversible writes) are not exposed via MCP at all, regardless of scope. A token without docs:read will not see search_docs / read_doc; a token without setup:read will not see the install-snippet helpers. The protection is enforced at both tools/list (the tool is hidden) and tools/call (the call is rejected with an audited refusal), so dropping a scope is safe.

Pinning a customer to a session

When an operator uses an MCP client to research or act on behalf of a specific customer, they can pin the customer for the conversation. Halo reads the binding off the JSON-RPC _meta envelope:
{
  "jsonrpc": "2.0",
  "id": "1",
  "method": "tools/call",
  "params": {
    "name": "hubspot.create_deal",
    "arguments": { "name": "ACME renewal" },
    "_meta": {
      "bound_end_user_id": "u_abc123"
    }
  }
}
You can also pin by email with _meta.bound_email. Halo re-resolves the binding on every call against your org’s customer table, so a stale or forged id can never bind to a foreign tenant. How the pin reaches the wire depends on the client. Most clients let the user select a customer in the UI and forward the selection automatically; custom clients should set _meta.bound_end_user_id themselves.

Revoking access

Today there’s no dashboard view of connected MCP clients. Revoke by token instead:
curl -X POST https://app.haloagents.ai/api/mcp/oauth/revoke \
  -H "Content-Type: application/x-www-form-urlencoded" \
  --data-urlencode "token=halo_at_..." \
  --data-urlencode "client_id=mcp_client_..."
The endpoint follows RFC 7009: pass either an access or a refresh token under token=, idempotent, always returns 200. Confidential clients also pass client_secret (or use HTTP Basic auth); public clients only need client_id. Revoking a refresh token revokes the entire derived chain (every access and refresh token issued from the same authorization code), which is the right move if you suspect a compromise. Revoking a single access token just kills that token; the next refresh issues a new one. Most MCP clients have a “Sign out” or “Disconnect” action that calls this endpoint for you. If you’re an admin and don’t have the token in hand, contact support and we’ll revoke the chain server-side.

Rate limits

Per-token caps sit on top of the IP-based dashboard limit:
MethodCap
tools/list60 per minute
tools/call120 per minute
Other (initialize, ping)60 per minute
Hitting a cap returns 429 with Retry-After. Per-action and per-org caps still apply on top (a tool whose underlying integration has a 60/min limit will still hit that limit even if the MCP cap allows more).