MCP
Give an agent your inbox, on your terms.
The Ledger Mail runs a Model Context Protocol server, so an AI client can read and search your mail and manage your aliases — signed in as you, over an OAuth token you granted and can see.
What MCP is
The Model Context Protocol is an open standard that lets an AI application call tools on a server it did not write, over a normal HTTP connection. The Ledger Mail publishes one such server, so an assistant can work with your mailbox directly instead of you copying messages into a chat window.
The server
One endpoint, Streamable HTTP, authenticated with an OAuth 2.1 access token.
https://api.theledgermail.com/mcp| Detail | Value |
|---|---|
| Transport | Streamable HTTP, JSON responses. There is no session id: each request stands alone. |
| Server identity | ledger-mail 1.0.0 |
| Authentication | Bearer access token issued by the mail server's OAuth 2.1 endpoint (PKCE, dynamic client registration). |
| Authorization server | https://mail.theledgermail.com |
| Scope of access | The token's own mailbox. No tool takes an account or an address to act on. |
A request with no token, or with one the mail server does not accept, answers 401 and points at the protected-resource metadata, as RFC 9728 describes — which is how a well-behaved client discovers where to sign you in:
www-authenticate: Bearer resource_metadata="https://api.theledgermail.com/.well-known/oauth-protected-resource"
{"error":"Missing or invalid Authorization header"}Claude Desktop and claude.ai
The supported path today. Add the server as a custom connector and sign in with your Ledger Mail address.
- Open your connector settings and choose to add a custom connector.
- Give it a name — “Ledger Mail” does nicely — and paste the server URL.
- Connect. You are sent to the mail server's sign-in page; enter your full Ledger Mail address and password, and a six-digit code if you have two-factor turned on.
- You are returned to the client, and the tools below appear in its tool list.
https://api.theledgermail.com/mcpClaude Code
Not yet supported by the built-in sign-in, for one specific reason.
claude mcp add cannot complete the OAuth flow today.
Claude Code builds its OAuth callback URL with the hostname localhost, and the mail server accepts only https:// URLs, the loopback literals http://127.0.0.1/ and http://[::1]/, or a private-use scheme. Registration is therefore refused before you ever see a sign-in page:
{"error":"invalid_redirect_uri","error_description":"Redirect URI must be an https URL, a loopback (http://127.0.0.1/, http://[::1]/) or a private-use scheme URI."}Neither --client-id nor --callback-port changes the hostname, so there is no flag that works around it. We are fixing this on the mail server — loopback by name is permitted by RFC 8252, and the server is being stricter than the specification.
In the meantime, if you already hold an access token — from the device flow, or from a PKCE flow you ran yourself against a 127.0.0.1 redirect — you can pin it as a static header. Claude Code will not refresh it, so the connection stops working when the token expires and you will need to replace it by hand:
claude mcp add --transport http ledger-mail https://api.theledgermail.com/mcp \
--header "Authorization: Bearer <your access token>"Any other MCP client
Standard discovery, standard OAuth 2.1. Point your client at the server URL and it can find everything else.
- 1. Read
https://api.theledgermail.com/.well-known/oauth-protected-resource— it names the authorization server. The RFC 9728 path-suffixed form, with/mcpappended, answers identically. - 2. Read
https://mail.theledgermail.com/.well-known/oauth-authorization-serverfor the endpoints. - 3. Register a client at
https://mail.theledgermail.com/auth/register. Registration is open and needs no credential. - 4. Send the user to
https://mail.theledgermail.com/loginwith your PKCE challenge, and exchange the code athttps://mail.theledgermail.com/auth/token.
What the authorization server requires
| Requirement | Value |
|---|---|
| PKCE | Required, and S256 only — plain is not offered. |
| Response type | code |
| Client authentication | Public clients are supported: token_endpoint_auth_method of none, alongside client_secret_post and client_secret_basic. |
| Redirect URI | An https:// URL, http://127.0.0.1:<port>/…, http://[::1]:<port>/… or a private-use scheme. Not http://localhost. |
| Grant types | authorization_code, refresh_token and the device code grant. |
| Authorization endpoint | /login — not /authorize. |
curl -X POST https://mail.theledgermail.com/auth/register \
-H "Content-Type: application/json" \
-d '{"client_name":"My Agent","redirect_uris":["http://127.0.0.1:33418/callback"],"grant_types":["authorization_code","refresh_token"],"response_types":["code"],"token_endpoint_auth_method":"none","application_type":"native"}'The answer echoes the registration and adds a client_id. No client secret and no registration access token are issued, so a registration cannot be read back, changed or deleted afterwards — register once and keep the id.
What you see when you sign in
A plain sign-in page served by the mail server itself. Know what to expect, so you know when something is not it.
The page is titled Sign in, with the subtitle “Enter your credentials to continue”, a Username field (your full Ledger Mail address) and a Password field. If two-factor is turned on, it swaps to a Two-factor authentication screen and submits by itself once you have typed six digits. A wrong password says “Invalid username or password. Please try again.”
There is no consent screen.
Signing in goes straight back to the client: no scope-approval step, no app name, no Allow or Deny. Anything that shows you an approval screen in our name is not us. Only connect a client you already trust, and check the address bar is the mail server before you type your password.
Tools
Six tools, all of them acting on the mailbox the token belongs to and nothing else.
| Tool | Parameters | Returns |
|---|---|---|
list_foldersList mail folders | none | Every folder with its total and unread message counts. |
list_messagesList messages | folder (default INBOX), page (1 or more, default 1), limit (1–100, default 20) | Summaries, newest first: uid, from, to, subject, date, flags, size and a preview of at most 256 characters. |
search_messagesSearch messages | query (required), folder, page, limit | The same summaries, for messages whose subject, sender, recipients or body match. One folder at a time. |
get_messageRead a message | uid (required), folder | Headers, body and the attachment list. The body is the plain-text part; the HTML part comes back only when there is no plain-text one. |
list_aliasesList aliases | none | The mailbox address, and each alias with whether it is enabled. |
create_aliasCreate an alias Writes | domain (required), name (optional: 2–64 lower-case letters, digits, dots, hyphens or underscores) | The new alias address. Leave the name out and a random one is generated. |
The first five are annotated read-only. create_alias is not, and it is enabled: an MCP client you connect can create real alias addresses on your account. You can see and remove them in the web app at any time.
What is not possible
Worth knowing before you plan around it.
- Sending mail. The send tool is disabled in production, and a disabled tool does not appear in the tool list at all — a client cannot see it, let alone call it.
- Changing a message through a tool. No tool moves, flags or deletes a message, creates a folder, or touches the profile, the password or two-factor — but read the note below about what the token itself reaches.
- Reaching another account. Every call runs as the token's own mailbox, and no tool takes an account or an address to act on.
- Searching the whole mailbox at once. Search covers one folder per call, so list the folders first and loop.
- Server-initiated messages. There is no event stream: a GET or DELETE to the endpoint answers 405 once you are authenticated.
The token is broader than the tool list.
The tools above are what an MCP client can call, but the access token it holds is an ordinary Ledger Mail credential. On our REST API it carries mail:read, mail:write and aliases:read, so a client that calls the API directly can mark your messages read, move them, delete them, and list the aliases you have made. It cannot create or change an alias, and it cannot read your profile: aliases:write and profile:read are never granted to a token minted this way.
Sending is governed by the same switch as the send tool above. While that switch is off — as it is on this service today — mail:send is not granted either, so the token can no more send as you through the API than through a tool.
So connect clients you trust, and see the API reference for what each scope allows.
Rate limits
120 requests a minute, counted per signed-in user.
The limit counts JSON-RPC HTTP requests rather than tool calls, and the bucket is the authenticated user — so one agent cannot spend another user's budget. Every response carries X-RateLimit-Limit, X-RateLimit-Remaining and X-RateLimit-Reset, and going over answers 429 with a Retry-After header.
{"error":"Too many requests, please try again later"}Disconnecting
Remove the connector in your client. Server-side revocation is the one thing this deployment does not offer yet.
Removing or disconnecting the connector in your MCP client is what stops it calling: the client discards the token it holds.
There is no self-service token revocation yet.
The mail server publishes no revocation endpoint, so an access token already issued cannot be withdrawn from the web app. If you believe a token has been taken, contact support and we will revoke it for you.
The API asks the mail server whether a token is still good and caches that answer for up to 60 seconds, so a revocation can take about a minute to take effect everywhere.
One thing to be clear about: the sessions and app passwords listed in Settings are a different kind of credential. Revoking one of those ends a browser session or a mail client's access — it does not revoke an MCP access token.