# MCP Server Description

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

## 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 | 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

Request

```
curl "https://mcp.machinemail.dev/.well-known/mcp.json"
```

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`)

#### Errors

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

#### Example

Request

```
curl "https://mcp.machinemail.dev/mcp"
```

Response 200

## 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](/content/docs/reference/errors/index.html).

#### Example

Request

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

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](/content/docs/reference/errors/index.html).

#### Example

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 | Description
--- | ---
`token` | `string` Required
Signed token from download_url.

#### Response

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

Headers:

Field | 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

Request

```
curl "https://mcp.machinemail.dev/mcp/attachments/string"
```
