---
title: "MCP"
description: "The remote MCP server endpoint (stateless JSON-RPC over Streamable HTTP), its description document and signed attachment links, with API key or OAuth auth."
canonical: "https://machinemail.dev/docs/reference/api/mcp"
---

# MCP

> The remote MCP server endpoint (stateless JSON-RPC over Streamable HTTP), its description document and signed attachment links, with API key or OAuth auth.

Source: https://machinemail.dev/docs/reference/api/mcp

| Method   | Path                       | Summary                                                                       |
| -------- | -------------------------- | ----------------------------------------------------------------------------- |
| `GET`    | `/.well-known/mcp.json`    | [MCP Server Description](#mcp-server-description)                             |
| `GET`    | `/mcp`                     | [MCP Description or Stream](#mcp-description-or-stream)                       |
| `POST`   | `/mcp`                     | [MCP JSON-RPC (Streamable HTTP)](#mcp-json-rpc-streamable-http)               |
| `DELETE` | `/mcp`                     | [MCP Session Termination (Unsupported)](#mcp-session-termination-unsupported) |
| `GET`    | `/mcp/attachments/{token}` | [Download Attachment (Signed Link)](#download-attachment-signed-link)         |

## MCP Server Description

```http
GET /.well-known/mcp.json
```

Same document as a plain `GET /mcp`.

**Authentication:** None.

#### Response

**200** How to connect (`application/json`)

| Field | Type | | Description |
| --- | --- | --- | --- |
| `name` | `string` | required |  |
| `description` | `string` | required | What the server is for, in one line. |
| `icons` | `object[]` | required | The MachineMail mark, for clients and registries that show an icon. |
| `version` | `string` | required |  |
| `transport` | `"streamable-http"` | required |  |
| `url` | `string` | required | The canonical MCP endpoint, https://mcp.machinemail.dev/mcp. https://machinemail.dev/mcp also works (legacy alias). |
| `authentication` | `object` | required |  |
| `docs` | `string` | required |  |

#### Errors

| Status | Meaning                  |
| ------ | ------------------------ |
| `500`  | Unexpected server error. |

#### Example

```bash title="Request"
curl "https://mcp.machinemail.dev/.well-known/mcp.json"
```

```json title="Response 200"
{
  "name": "Production",
  "description": "string",
  "icons": [
    {
      "src": "string",
      "mimeType": "string",
      "sizes": ["string"]
    }
  ],
  "version": "string",
  "transport": "streamable-http",
  "url": "https://example.com/webhooks/machinemail",
  "authentication": {
    "type": "bearer",
    "header": "string",
    "resource_metadata": "string",
    "oauth": {
      "authorization_server": "string",
      "resource": "string"
    }
  },
  "docs": "string"
}
```

## MCP Description or Stream

```http
GET /mcp
```

Without `Accept: text/event-stream` (a browser, for example): the server description, no authentication. With it, this would be the standalone MCP server-to-client stream; the server is stateless and has none, so an authenticated request answers `405` (use POST) and an unauthenticated one `401` with the `WWW-Authenticate` challenge. `HEAD` needs a valid token whatever the `Accept` (`401` with the challenge otherwise), so clients can probe for the challenge.

**Authentication:** None.

#### Response

**200** The server description (`application/json`)

| Field | Type | | Description |
| --- | --- | --- | --- |
| `name` | `string` | required |  |
| `description` | `string` | required | What the server is for, in one line. |
| `icons` | `object[]` | required | The MachineMail mark, for clients and registries that show an icon. |
| `version` | `string` | required |  |
| `transport` | `"streamable-http"` | required |  |
| `url` | `string` | required | The canonical MCP endpoint, https://mcp.machinemail.dev/mcp. https://machinemail.dev/mcp also works (legacy alias). |
| `authentication` | `object` | required |  |
| `docs` | `string` | required |  |

#### Errors

| Status | Meaning                                          |
| ------ | ------------------------------------------------ |
| `401`  | Missing, invalid, expired or revoked credential. |
| `405`  | Stateless server: no standalone stream.          |
| `500`  | Unexpected server error.                         |

#### Example

```bash title="Request"
curl "https://mcp.machinemail.dev/mcp"
```

```json title="Response 200"
{
  "name": "Production",
  "description": "string",
  "icons": [
    {
      "src": "string",
      "mimeType": "string",
      "sizes": ["string"]
    }
  ],
  "version": "string",
  "transport": "streamable-http",
  "url": "https://example.com/webhooks/machinemail",
  "authentication": {
    "type": "bearer",
    "header": "string",
    "resource_metadata": "string",
    "oauth": {
      "authorization_server": "string",
      "resource": "string"
    }
  },
  "docs": "string"
}
```

## MCP JSON-RPC (Streamable HTTP)

```http
POST /mcp
```

MachineMail as a remote MCP server over Streamable HTTP, stateless: send one JSON-RPC message per request with `Authorization: Bearer` set to an API key, an OAuth access token for the MCP server (`aud` `https://mcp.machinemail.dev/mcp`, `https://machinemail.dev/mcp` or `https://machinemail.dev/`) or an auth.md access token (the session cookie is not accepted). Every request is served independently; there is no `Mcp-Session-Id`.

The canonical URL is `https://mcp.machinemail.dev/mcp`; `https://machinemail.dev/mcp` is the same server, kept as a legacy alias.

Without a valid token the answer is `401` with `WWW-Authenticate: Bearer resource_metadata="<origin>/.well-known/oauth-protected-resource/mcp", scope="..."` on the host the request came to (plus `error="invalid_token"` when a token was sent): MCP clients follow it to the authorization server and sign the person in with OAuth (authorization code with PKCE).

Protocol 2026-07-28 (per-request `_meta`, `server/discover`), with stateless fallback for 2025-11-25, 2025-06-18, 2025-03-26 and 2024-11-05 clients (`initialize`). The tools act with the credential’s scope and permissions. Bodies over 2 MiB are rejected.

Responses are JSON, or `text/event-stream` when the client accepts it; protocol-level errors are JSON-RPC error objects with an HTTP 4xx status. See the MCP specification for the methods.

**Authentication:** `Authorization: Bearer <api key>`.

#### Request body

Content type: `application/json`. Required.

Type: `unknown`

#### Response

**200** JSON-RPC response (`application/json`, `text/event-stream`)

Type: `Record<string, unknown>`

**202** Notification or response accepted (empty body)

#### Errors

| Status | Meaning                                                               |
| ------ | --------------------------------------------------------------------- |
| `400`  | Malformed JSON-RPC, unsupported protocol version or too large a body. |
| `401`  | Missing, invalid, expired or revoked credential.                      |
| `500`  | Internal error                                                        |

Error bodies use the [error envelope](https://machinemail.dev/docs/reference/errors).

#### Example

```bash title="Request"
curl -X POST "https://mcp.machinemail.dev/mcp" \
  -H "Authorization: Bearer $MACHINEMAIL_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{}'
```

```json title="Response 200"
{
  "key": "value"
}
```

## MCP Session Termination (Unsupported)

```http
DELETE /mcp
```

The server keeps no sessions, so there is nothing to delete: always `405` for an authenticated caller.

**Authentication:** `Authorization: Bearer <api key>`.

#### Response

#### Errors

| Status | Meaning                                          |
| ------ | ------------------------------------------------ |
| `401`  | Missing, invalid, expired or revoked credential. |
| `405`  | Stateless server.                                |
| `500`  | Unexpected server error.                         |

Error bodies use the [error envelope](https://machinemail.dev/docs/reference/errors).

#### Example

```bash title="Request"
curl -X DELETE "https://mcp.machinemail.dev/mcp" \
  -H "Authorization: Bearer $MACHINEMAIL_API_KEY"
```

## Download Attachment (Signed Link)

```http
GET /mcp/attachments/{token}
```

The `download_url` the `get_attachment` tool returns for an attachment it does not hand over inline (anything but small text files and small PNG, JPEG, GIF or WebP images). The link names one attachment, is signed by the server and works for 10 minutes, as often as needed, with no `Authorization` header: the link is the credential.

Every fetch checks the signature and expiry and re-reads the message: a deleted message, or one quarantined or rated high risk since the link was made, answers `404`. An expired link answers `403`; call `get_attachment` again for a new one.

The bytes are served as by the REST download: `Content-Disposition: attachment` (ASCII `filename` plus RFC 5987 `filename*`), `X-Content-Type-Options: nosniff` and a sandboxing Content-Security-Policy. Attachment content is untrusted third-party input.

**Authentication:** None.

#### Path parameters

| Field | Type | | Description |
| --- | --- | --- | --- |
| `token` | `string` | required | Signed token from download_url. |

#### Response

**200** The attachment bytes (`application/octet-stream`)

Headers:

| Field | Type | | Description |
| --- | --- | --- | --- |
| `Content-Disposition` | `string` |  | attachment; filename="<ascii name>"; filename*=UTF-8''<encoded name>. |

#### Errors

| Status | Meaning                                                                                                                                                                                                                                |
| ------ | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `403`  | The credential lacks the permission or scope for this request (error.type forbidden), or MachineMail suspended the organization or its sending (account\_suspended: error.message says what still works; do not retry or re-register). |
| `404`  | Not found. Also returned for resources outside the credential scope.                                                                                                                                                                   |
| `500`  | Unexpected server error.                                                                                                                                                                                                               |

#### Example

```bash title="Request"
curl "https://mcp.machinemail.dev/mcp/attachments/string"
```
