Skip to content
Docs
Open Escouade
Documentation contents

Docs › Mail

MCP server

View as .md

MCP is Escouade Mail’s only interface. The agents’ address is https://api.subagent.fr/mcp, over Streamable HTTP. Without a key, the server only serves sign-up there. With a key, it serves the tools its permissions open. Online assistants connect to the same server through a second address, https://mail.escouade.io/mcp.

In short

PropertyValue
Agents’ addresshttps://api.subagent.fr/mcp
Online assistants’ addresshttps://mail.escouade.io/mcp: OAuth sign-in, no key to copy. See Connector.
TransportStreamable HTTP: JSON-RPC 2.0 requests over POST, responses as application/json
AuthenticationAuthorization: Bearer sak_… header. Without a header, at the agents’ address: sign-up only.
ToolsThose of the reference, filtered by the key’s permissions
ViewsOne workbench per conversation, opened by open_workspace then driven by navigate_workspace: see Views
Rules given at connectionThe instructions field of the response to initialize: under 2,000 characters

Connecting a client

The server is declared by its address, and the key by a header.

Claude Code

claude mcp add \
  --transport http subagent \
  https://api.subagent.fr/mcp \
  --header "Authorization: Bearer $SUBAGENT_KEY"

Cursor · .cursor/mcp.json

{
  "mcpServers": {
    "subagent": {
      "url": "https://api.subagent.fr/mcp",
      "headers": {
        "Authorization": "Bearer ${env:SUBAGENT_KEY}"
      }
    }
  }
}

Other client · .mcp.json

{
  "mcpServers": {
    "subagent": {
      "type": "http",
      "url": "https://api.subagent.fr/mcp",
      "headers": {
        "Authorization": "Bearer ${SUBAGENT_KEY}"
      }
    }
  }
}

No key yet: declare the address without a header, let the agent call sign_up, then add the header. See Getting started.

An online assistant (Claude, ChatGPT) declares no header: it connects to https://mail.escouade.io/mcp, where the human signs in with their Escouade account. See Connector. Client by client: Connect my agent.

Without a key

At https://api.subagent.fr/mcp, without an authorisation header, the server still answers, for sign-up. At https://mail.escouade.io/mcp, it answers 401: the assistant then opens the sign-in page.

  • It serves initialize, ping, tools/list and tools/call.
  • tools/list returns a single tool: sign_up.
  • It opens no session and serves no views.
  • Calling another tool is refused with the code unauthorized. Any other method gets the HTTP status 401.

The server reads the header on every request. After sign_up, the connection opened without a key still only shows sign_up: the key must be presented. See Keys and permissions.

With a key

  • tools/list returns the tools the key’s permissions open. sign_up is no longer among them.
  • Once the space is verified, verify and attach_human leave the list.
  • A key that is presented but unknown or revoked gets the HTTP status 401.

A single workbench

open_workspace is the visual entry point. Once it is open, the model reuses the instance_id from this conversation’s context and asks for a page with navigate_workspace: audiences, contacts, campaigns or performance. Business tools keep returning their data without asking for a new card.

The view receives requests with workspace_events, reserved for the app by _meta.ui.visibility: ["app"]. It waits 18 seconds at most per call and keeps a single wait in progress. The model must not call this tool to keep the link alive. navigate_workspace remains visible to the model and to the app.

A pending receipt means the navigation has been requested. Input in progress can delay or prevent its display: the view lets the human choose. See Workbench navigation.

A tool’s result

A successful call returns three things.

Result of tools/call
{
  "content": [{ "type": "text", "text": "Message msg_… en file dans le fil thr_… : …" }],
  "structuredContent": { "message": {}, "thread": {}, "inbox": {}, "replayed": false, "estimated_send_at": "2026-10-13T14:31:00+02:00" },
  "isError": false
}
  • content: a readable text in French. It says who, what, when, and the remaining quota.
  • structuredContent: the tool’s object, whose schema is published in https://api.subagent.fr/openapi.json. It is what a program reads.
  • isError: false.

The result also carries _meta["subagent/requestId"], a diagnostic identifier. The space’s context metadata can accompany the business object; it serves to partition and refresh the view’s data.

The readable text cuts a message’s body at 2,000 characters. The whole body is in structuredContent.

A refusal

A refusal by the service is not a protocol error. It is a tool result marked isError, with a text: the message, the code in brackets, then the lead after an arrow.

approve_messagerefused
approve_message demande la permission approve, que cette clé n’a pas. (code forbidden)
→ La validation est un geste humain : votre humain l’accomplit depuis son assistant (Claude, ChatGPT…), branché à l’adresse https://mail.escouade.io/mcp où il se connecte avec son e-mail.

Over MCP, the same refusal also appears in structuredContent.error: code, message and, when there is one, the lead hint. A client should read these fields; the text remains available for the human. Over HTTP, the object is {"error": {"code", "message", "hint"}}. See Errors.

What each tool announces

In tools/list, each tool carries:

  • name, title and description, in French;
  • inputSchema: its parameters. An unknown parameter is refused. tools/list carries no output schema (outputSchema);
  • annotations: readOnlyHint (the tool only reads), destructiveHint (its effect cannot be undone), idempotentHint;
  • _meta.ui.resourceUri and _meta["openai/outputTemplate"] for the visual entry point open_workspace;
  • _meta.ui.visibility: model and app in general, app only for workspace_events;
  • _meta["openai/widgetAccessible"]: true for the view’s calls, including tools without a new card.

The schema of each tool’s structured object can be read in https://api.subagent.fr/openapi.json.

The workbench uses the resource ui://subagent/workspace-v12.html. The addresses of the old views remain readable for conversations already open. After a connector update, the host must read the tool descriptors and their resource address again; an old cached descriptor may still ask for the previous cards.

Protocol

TopicWhat the server does
Versions2026-07-28, 2025-11-25, 2025-06-18, 2025-03-26. Any other version in the Mcp-Protocol-Version header is refused.
Sessionsinitialize opens a session and returns the Mcp-Session-Id header. It lasts 24 hours after the last request. The session is optional: a request without this header is served statelessly. An expired session is erased after 30 days.
Ending a sessionDELETE on https://api.subagent.fr/mcp, with the Mcp-Session-Id header.
GETRefused with the status 405: the server opens no stream.
BatchesRefused: one JSON-RPC message per request.
SizeA request is 1 MiB at most.
OriginA request coming from another site’s web page (Origin header) is refused.
Rate60 requests per minute without a key, 600 with a key, per client address. See Limits and quotas.

Without MCP

Every tool also exists as POST https://api.subagent.fr/v1/{operation}, with the same arguments and the same object in return. See HTTP API.

This page in Markdown: /en/mail/docs/mcp.md All the docs for an agent: /en/mail/docs/llms.txt Legal notice · Terms · Privacy · Service status