How the MCP server works

What Halo's MCP server is, its endpoint, tools and scopes, how it runs, its limits, and when to use it rather than the REST API.

The Halo MCP server lets an AI tool read an organization's datasets, charts, reports, websites and directory as the person who connected it. It speaks the Model Context Protocol, so any MCP client can use it. Every tool is read-only.

https://mcp.usehalo.net/mcp

This section is for people building on it. The MCP server for members and admins covers turning it on and connecting a tool as a person.

How it runs

  • Streamable HTTP, stateless. Each POST to /mcp carries one JSON-RPC message and is authenticated on its own. There are no sessions, and nothing about one request carries into another. Answers are JSON, not event streams.

  • No GET or DELETE. With a valid token they answer 405, which MCP clients expect from a server that doesn't stream. Without one they get the usual 401, since the token is checked first.

  • One message per request. Batches get 400, so one request can't carry many calls past the limits.

  • Scoped listing. tools/list shows only the tools a connection's scopes allow, and each call checks the scope again.

  • The person, live. Every request loads the person's account, membership and role again, so a change applies on the next call. Tools run through the same services as Halo Data, with the person's access levels and row policies.

The MCP protocol has the details, with cURL.

Tools and scopes

A connection carries some of three scopes, which only narrow what the person's role allows. A token has the same three names as an API key, but they aren't interchangeable.

ToolScopeArgumentsDoes
whoamiNoneNoneSays who the token acts for: the person, their organization and role, and the token's scopes
list_datasetsdatasets.readsearch (optional)Lists datasets the person can see: id, name, description, field count and connection
describe_datasetdatasets.readdatasetIdA dataset's fields: name, label, role, type, default aggregate, format and description, plus its default date field
query_datasetdata.queryqueryRuns a read-only query as the person
get_chart_datadata.querychartIdRuns a saved chart's query, and returns the rows it draws with their columns
list_goalsdata.querydatasetId, search (both optional)Lists goals and how each stands today, with the person's row policies
read_goaldata.querygoalIdReads what a goal targets, how it stands and its recent periods
list_insightsdata.querydatasetId (optional)Lists the changes Halo flagged that the person can read, newest first
list_chartscontent.readsearch (optional)Lists saved charts: id, name, type, dataset and description
read_chartcontent.readchartIdA saved chart's name, description, dataset and spec, not its data
list_reportscontent.readsearch (optional)Lists reports: id, title, status and workspace
read_reportcontent.readreportId, version (optional)A report's document: its pages and elements, with each chart's spec or saved chart id, and its text
list_websitescontent.readsearch (optional)Lists websites: id, name, whether readers can reach it, and how many pages it has
read_websitecontent.readwebsiteIdA website's live release, custom domains, pages by path and title, and collections by name
list_listingscontent.readsearch, kind, status, region (all optional)Lists the directory's listings: id, name, kind, status and city
read_listingcontent.readlistingIdOne listing, with the phone number its page gives visitors and no email
list_businessescontent.readsearch, status, region (all optional)Lists businesses: id, name, status, listings and city
read_businesscontent.readbusinessIdOne business and its listings, with nobody's contact details

Each tool is marked readOnlyHint and idempotentHint. The full input schemas are at dev.usehalo.net/reference/mcp.

query_dataset takes a query much like the REST body, with the dataset's id inside it:

{
  "query": {
    "datasetId": "0195f3a2-…",
    "dimensions": [{ "field": "region" }],
    "measures": [{ "field": "revenue" }],
    "limit": 50
  }
}

Its schema also lists specVersion, which Halo fills in if you leave it out.

What comes back

A tool's answer is text for a model to read, wrapped in a <halo-data> fence that says the content is data, not instructions. See the fence. Treat what's inside as untrusted: Build an agent shows how.

Limits

LimitAmount
Requests a minute, per address600
Requests a minute, per connection240
Tool calls a minute, per connection120
Tool calls a minute, per person300
Tool calls running at once, per connection4 on each of Halo's API processes, so the true ceiling can be higher
Data rows a day, per person in each organization20,000
Rows a query200, or 1,000 where the organization has Let Halo AI read individual rows on
Characters in a query's answerAbout 24,000, then the rows are cut with a note
Characters in read_report's answer48,000, then the document is cut with a note
Items in a list30 from list_goals, 60 from list_datasets, 100 from list_charts, list_reports, list_websites, list_listings and list_businesses, then a line says more match. Search with more specific words
Request size1 MB

Paging (offset, keyset and cursor) is refused unless the organization allows individual rows, so paging can't walk past the row cap. Rows of Marketplace data are refused too, though their fields can be read. These tools run on your own AI provider and don't use Halo's AI credits.

Before it works

It's off until an Admin turns it on. Then, for every request, all of these must hold:

  • Halo AI is on for the organization, and its plan includes it.

  • The person's role has ai.use.

  • An Admin has turned on Let members connect their own AI tools.

  • Halo hasn't paused the organization or its tools, and its Admins haven't paused the member.

  • The member is active, and meets the organization's sign-in and two-factor rules.

What a tool reads goes to that tool and its AI provider, outside Halo. The admin guide has the steps.

The Halo MCP server or REST

MCP serverREST API
ForA model choosing what to read, in a conversation or agentYour own code, reading what it was written to read
Credentialhpat_… or OAuth hmat_…hak_…
Made inHalo Data, or an app's sign-inThe portal
By defaultOff, until an Admin turns it onOff, until an Admin turns it on
The role needsai.useapi.use, and data.export for rows
Answers inText for a modelJSON
Rows200 a query, or 1,000 where allowed, and 20,000 a day1,000 a request, and 100,000 to 2,000,000 a day by plan
PagingOnly where individual rows are allowedAlways
Sign-in for other people's toolsOAuth, with consent per connectionNone. A key is made by its person

Use the Halo MCP server when a model decides what to ask. Use REST when your code does, or when you need many rows. Both read as a person and both are read-only, so neither widens what that person can see.