Relay docs

Connectors

A connector lets an agent read a user's own SaaS account. Attach the Microsoft connector to an agent and the model can search that person's Outlook mail, look at their calendar, and find and read files in their OneDrive and the SharePoint sites they have access to — as them, read-only.

This is the third way to ground an agent, alongside knowledge bases and datasets. A knowledge base grounds it on documents you ingested; a dataset grounds it on tables; a connector grounds it on the asking user's own working material, which nobody had to ingest.

#The shape of it

There are two rows, and keeping them apart is what makes the rest make sense.

A connector is one OAuth app registration, created once by an administrator. It holds a client id and secret and the scopes to ask for. It grants nothing by itself.

A connection is one person's consented account on that connector, created when they click Connect and sign in to Microsoft themselves. It holds their refresh token, encrypted with the same Encryption:MasterKey that protects provider API keys. An agent with a connector attached reads through the acting user's connection — so a user who has never connected gets told exactly that, and no one else's mailbox is reachable in their name.

#What the model can do

Eight read-only tools, all scoped to the acting user:

ToolWhat it reads
microsoft_whoamiThe connected account's name, address and job title
microsoft_list_emailsOutlook mail, searched or listed newest first
microsoft_get_emailOne message in full, body as plain text
microsoft_list_calendar_eventsCalendar events in a window, recurrences expanded
microsoft_search_filesFiles across OneDrive and every SharePoint site the user can reach
microsoft_read_fileA file's text — plain text, Markdown, CSV, JSON, HTML, PDF and Word
microsoft_list_sharepoint_sitesSharePoint sites by name
microsoft_find_peopleColleagues, with addresses and job titles

There are no write tools. The connector cannot send mail, reply, accept a meeting, edit a document or delete anything, and the default scopes do not ask for permission to. The agent is told this, so it says so rather than pretending to have sent something.

#Setting one up

1. Register the app in Entra. Create an app registration in your tenant. Under Authentication, add a Web redirect URI of:

https://your-relay-host/api/connectors/callback

The Connectors page shows the exact URI for the host you are on — copy it from there rather than typing it, because Entra matches it character for character.

2. Grant delegated permissions. Under API permissions, add these delegated Microsoft Graph permissions: Mail.Read, Calendars.Read, Files.Read.All, Sites.Read.All, People.Read, User.Read, offline_access. Grant admin consent if your tenant requires it; otherwise each user consents for themselves on first connect.

3. Create a client secret and copy its value — Entra shows it once.

4. Add the connector in Relay. Go to Connectors → Add connector, pick Microsoft Graph, and paste the client id, secret and tenant. Leave the scopes at their default unless you are deliberately narrowing them.

5. Connect an account. Click Connect on the row. You are sent to Microsoft, you sign in and consent, and you come back with the account listed. Every user who will use the agent does this once, for themselves.

6. Attach it to an agent. In Agents, tick the connector in the editor.

If you have already published a version of that agent, snapshot and publish again. A run prefers a published snapshot, and an older snapshot has no connector in it — so attaching one appears to do nothing until you publish.

#Calling it

curl -s -X POST http://localhost:5300/v1/agents/AGENT_ID/chat/completions \
  -H "Authorization: Bearer $RELAY_KEY" \
  -H "X-Relay-User-Id: $END_USER_ID" \
  -H "Content-Type: application/json" \
  -d '{"messages":[{"role":"user","content":"What did Ana send me about the tender?"}]}'

Two things are required and both return a clear 4xx when missing:

  • X-Relay-User-Id, the acting end user's Entra object id. This is the same header and the same id space dataset agents use, so an agent that is both needs one header, not two. X-User-Id is accepted as a fallback.
  • The connectors.use scope on the API key.

GET /v1/agents reports "connectors": true and "requires_user_header": true, so a client can tell which agents need this before its first failed call.

#Who can read whose mail

Relay holds the tokens and picks one by the X-Relay-User-Id header, and that header is caller-asserted — the gateway trusts the API key holder to name its end user. So a key holding connectors.use can read the mailbox of any user who has connected an account, by varying the header.

This is the same trust model dataset agents use, but it is not the same risk. A dataset query is re-checked by the data app, which applies that user's own grants and is the real authority; nothing downstream re-checks a Graph call. That is why connectors.use is a separate scope rather than part of chat.completions: grant it only to applications that authenticate their own end users and send the id of the person actually asking. Every connect, disconnect and configuration change is written to the audit log.

Two things the header cannot do: it cannot reach a user who has never connected, and it cannot widen what a connection can see. Graph applies the connected user's own permissions to every call, so a connector can never read a site or mailbox that person could not open themselves.

#When a connection stops working

Refresh tokens are rotated on every use and stored re-encrypted. If Microsoft answers invalid_grant — consent withdrawn, password changed, or the token simply aged out — the connection is flagged and the panel shows needs reconnect against it. The tools tell the model in words the user can act on, so the answer becomes "your Microsoft connection has expired, reconnect it in Relay" rather than a failed run.

Disconnecting from the Connectors page discards Relay's copy of the tokens. It does not withdraw consent at Microsoft — to do that, remove Relay from your account's app permissions. Deleting the connector discards every user's tokens at once.

#Configuration

KeyDefaultWhat it does
Encryption:MasterKey—Required. Must match on the panel host and the gateway, or stored tokens cannot be decrypted.
Connectors:RedirectUriderived from the requestOverride for a reverse proxy that rewrites the host.
Gateway:Connectors:MaxIterations8Tool-loop budget for a connector agent. Higher than the shared default because a question often costs a people lookup, a search and a read before the model has anything to say.
Gateway:Connectors:MaxFileBytes8388608Largest file microsoft_read_file will download.
Gateway:Connectors:MaxFileChars20000How much extracted text reaches the model.

#Limitations

A connector agent does not stream. The gateway has to run the tool calls before it can answer, so "stream": true is served as a single response rather than a token stream — the same behaviour an agent with MCP servers attached already has.

Teams messages, mail search inside attachments, and anything that writes are not covered. The tool pack is a list in one file; adding to it is a declaration plus a case.