Suped

MCP server

Connect MCP clients to Suped with OAuth to inspect email authentication data and manage domains and MSP clients.

Get started

Connect an MCP client to Suped to inspect organizations, domains, email authentication issues, and DMARC data, download report XML, add domains, and create MSP client organizations. Use this server URL with the Streamable HTTP transport:

https://www.suped.com/api/mcp

MCP uses OAuth authorization through your Suped account. REST API keys do not authenticate MCP requests.

Authentication

Clients discover OAuth settings from these endpoints. The issuer is https://www.suped.com/api/mcp/oauth.

PurposeEndpoint
Protected resource metadataGET https://www.suped.com/.well-known/oauth-protected-resource/api/mcp
Authorization server metadataGET https://www.suped.com/.well-known/oauth-authorization-server/api/mcp/oauth
Dynamic client registrationPOST https://www.suped.com/api/mcp/oauth/register
User authorizationGET https://www.suped.com/api/mcp/oauth/authorize
Token exchange and refreshPOST https://www.suped.com/api/mcp/oauth/token
  1. Register a public client by sending JSON with a required redirect_uris array of 1–10 URLs and optional client_name. Set token_endpoint_auth_method to none; no client secret is issued. Redirect URIs must use HTTPS, or HTTP on localhost, 127.0.0.1, or [::1], without credentials or fragments. Registration returns HTTP 201 with a client_id.
  2. Open the authorization endpoint with client_id, the registered redirect_uri, response_type=code, scope=suped:write, resource=https://www.suped.com/api/mcp, and PKCE parameters code_challenge_method=S256 and code_challenge. Include a state value to verify the callback. The user signs in and approves access; the callback includes the authorization code, issuer, and the supplied state.
  3. Exchange the code within five minutes using a form-encoded token request with grant_type=authorization_code, client_id, code, redirect_uri, the original code_verifier, and the same resource. The response includes access_token, token_type=Bearer, expires_in=3600, refresh_token, and scope=suped:write.
  4. Refresh with a form-encoded request containing grant_type=refresh_token, client_id, refresh_token, and resource=https://www.suped.com/api/mcp. Store both replacement tokens. Refresh tokens expire after 30 days and rotate on use; reusing a consumed code or refresh token revokes the grant and requires reconnecting.

suped:write is the only supported scope and covers both reading and creating data. Authorization follows the connected user's current organization permissions.

Requests

Send one JSON-RPC 2.0 message per POST with these headers:

Authorization: Bearer <access_token>
Content-Type: application/json
Accept: application/json, text/event-stream
MCP-Protocol-Version: 2025-11-25

Supported protocol versions are 2025-11-25 and 2025-06-18. The endpoint is stateless: it returns JSON without an SSE stream or session ID. GET and DELETE return HTTP 405. Initialize your MCP client, then use tools/list to discover current tool schemas and tools/call to run a tool. For example:

{
  "jsonrpc": "2.0",
  "id": 1,
  "method": "tools/call",
  "params": {
    "name": "list_organizations",
    "arguments": {}
  }
}

Successful calls return a JSON-RPC result with content. JSON tool data is serialized in a text content item; most tools also return the same data as structuredContent. get_domains returns its array in text content only, and download_dmarc_report returns an embedded XML resource.

Organization permissions

Start with list_organizations and use the returned organization IDs. IDs are 24 hexadecimal characters. The list includes direct memberships and client organizations under MSPs where you have a user or admin role. Billing-only memberships can appear in the list but cannot read issues, domains, or reports, or add domains. Those tools require a user or admin role, directly or through the parent MSP. Creating a client organization requires administrator access to its parent MSP; the tool is advertised only when an accessible MSP has that permission.

Tools

All parameters below are required unless the tool has none. Outputs describe tool data inside the MCP result, rather than the outer JSON-RPC envelope. Optional properties are omitted when unavailable.

ToolParametersOutput
list_organizationsNone.{ organizations: { id, name, isMsp, mspOrganizationId? }[] }
list_issuesorganizationId (string).{ organizationId, issues: Issue[] }; includes open, resolved, and dismissed issues, newest first.
get_domainsorganizationId (string).{ domain: string, archived: boolean }[]; includes archived domains.
get_dmarc_recordsorganizationId, startDate, and endDate (strings).{ status: "success", dmarcRecords: DmarcRecord[] }.
download_dmarc_reportorganizationId and reportId (strings).An embedded application/xml resource containing the original report XML.
create_domainorganizationId and domain (strings).{ organizationId, domain: { id, domain, alias } }. Adds a domain, returns an existing active domain, or restores an archived domain. Does not change DNS records.
create_organizationmspOrganizationId and name (strings).{ organization: { id, name, isMsp: false, mspOrganizationId } }. Creates a new client under the MSP on every successful call.

For create_domain, use an email sending domain such as example.com. Suped normalizes the domain, removes a leading www., and rejects wildcards and underscores. For create_organization, select a parent with isMsp: true and provide a nonempty client name. Retrying that tool can create duplicate organizations.

Issue output

type Issue = {
  id: string;
  slug: string;
  organizationId: string;
  status: "open" | "resolved" | "dismissed";
  issue: { type: string; /* Fields depend on the issue type. */ };
  createdAt: string; // ISO 8601
  updatedAt: string; // ISO 8601
  resolvedAt?: string; // ISO 8601
  resolvedReason?: string;
  dismissedAt?: string; // ISO 8601
  dismissedReason?: string;
  verifyFixErrorMessage?: string;
};

The nested issue payload identifies its variant with type. Its fields depend on that variant:

  • Strings: domain, source, dmarcDomain, visibleFrom, record, extraInformation, returnPath, returnPathSample, dkimDomain, and status.
  • String arrays: sources, records, and failingIps.
  • Alignment fields aspf and adkim are s or r when present. isFixableByRelaxingAlignment is an optional boolean on the dkimNoAlignedSignature variant.

These tools do not resolve or dismiss issues. See Resolving issues for the application workflow.

DMARC records and report XML

startDate and endDate select reports by their reported end date, inclusively. Use ISO 8601 timestamps with a timezone; the end must be on or after the start. Each row includes the report ID needed to download its original XML. Use a narrow date range for organizations with many records.

type DmarcRecord = {
  reportId: string;
  source: string;
  reporter: string;
  visibleFrom: string;
  from: string; // Same value as visibleFrom.
  returnPath: string;
  to?: string;
  ipAddress: string;
  ipCountryCode?: string;
  rdns: string[];
  emails: number;
  category: "authorized" | "rejected" | "quarantined" | "partially-authorized";
  date: string; // Report end date, ISO 8601.
  dmarc: "none" | "quarantine" | "reject";
  alignedSpf: AuthResult;
  alignedDkim: AuthResult;
  spf: AuthResult;
  dkims: { selector: string; domain: string; result: AuthResult }[];
};

type AuthResult = "permerror" | "fail" | "temperror" | "temperr" |
  "softfail" | "hardfail" | "unknown" | "none" | "neutral" |
  "policy" | "pass" | "skipped" | "";

Call download_dmarc_report with a reportId returned for the same organization. Read the XML from resource.text in the embedded resource; resource.uri identifies the report. Its MCP result has this shape:

{
  "content": [{
    "type": "resource",
    "resource": {
      "uri": "https://www.suped.com/api/dmarc/reports/<reportId>",
      "mimeType": "application/xml",
      "text": "<feedback>...</feedback>"
    }
  }]
}

Errors

Check both the HTTP status and the JSON-RPC body. Invalid or expired access tokens return HTTP 401 with a WWW-Authenticate header pointing to protected resource metadata. Refresh the token or reconnect if the grant is no longer valid. OAuth endpoint errors return HTTP 400 with error and error_description.

  • HTTP 400: malformed JSON or JSON-RPC, or an unsupported protocol version header. HTTP 406: the Accept header is missing one of the required types. HTTP 415: the Content-Type is not application/json.
  • HTTP 403: a supplied Origin is not the Suped origin or https://chatgpt.com.
  • JSON-RPC error.code: -32700 for a parse error, -32600 for an invalid request, -32601 for an unknown method, and -32602 for an unknown tool or invalid parameters.
  • Tool validation and permission failures can return HTTP 200 with result.isError: true. Read the message from text content. DMARC record errors also include structuredContent with status and message.