Skip to main content

Documentation Index

Fetch the complete documentation index at: https://septemberai.mintlify.app/llms.txt

Use this file to discover all available pages before exploring further.

MCP (Model Context Protocol) is the standard the Engine uses to talk to external tool providers. Each “connector” is an MCP server — locally or remotely hosted — that exposes a set of actions to the agent. Slack, Gmail, Notion, Linear, GitHub: anything with an MCP server can be connected. This page covers what MCP looks like to your application, how to connect a server, and how the resulting tools behave.

The model’s view

Once connected, MCP actions appear in the agent’s tool catalog like any other tool:
  • slack.send_message
  • gmail.read_thread
  • linear.create_issue
  • github.create_pr
The agent doesn’t know they’re MCP. It calls them by name and gets results.

Lifecycle of a connection

For static-credential servers (API key instead of OAuth), step 3 returns “connected” immediately and you skip steps 4–6.

Listing servers

curl -fsS "$ENGINE_URL/assets/servers" \
  -H "X-Engine-Key: $KEY"
Returns the catalog of servers the Engine can connect to:
[
  {
    "server_name": "slack",
    "display_name": "Slack",
    "transport": "sse",
    "auth_method": "oauth",
    "status": "available"
  },
  ...
]
The catalog is configured in the engine repo. Adding a new server type involves a JSON entry plus (if it’s a custom server) the MCP server itself.

Initiating a connection

curl -X POST "$ENGINE_URL/assets/connect" \
  -H "X-Engine-Key: $KEY" \
  -H "Content-Type: application/json" \
  -d '{"server_name": "slack"}'
For OAuth servers:
{
  "ref_id": "conn-abc123",
  "status": "pending_oauth",
  "auth_url": "https://slack.com/oauth/v2/authorize?..."
}
Direct the user to auth_url. After they grant access, the provider redirects to <OAUTH_REDIRECT_BASE_URL>/assets/oauth/callback, which completes the flow. For static-credential servers:
{
  "ref_id": "conn-abc123",
  "status": "connected"
}
The Engine stores the credential, encrypted.

Listing connections

curl -fsS "$ENGINE_URL/assets/connections" \
  -H "X-Engine-Key: $KEY"
Returns the user’s active connections:
[
  {
    "ref_id": "conn-abc123",
    "server_name": "slack",
    "status": "connected",
    "scopes": ["channels:read", "chat:write"],
    "expires_at": "2026-05-27T..."
  }
]

Disconnecting

curl -X DELETE "$ENGINE_URL/assets/connections/conn-abc123" \
  -H "X-Engine-Key: $KEY"
Revokes the stored credentials and removes the connection. Subsequent agent calls to that server’s actions error with MCP_CONNECTION_FAILED.

What MCP actions look like to the model

Each action surfaces as a tool with the server’s prefix in the name:
{
  "name": "slack.send_message",
  "description": "Send a message to a Slack channel.",
  "input_schema": {
    "type": "object",
    "properties": {
      "channel": { "type": "string", "description": "Channel ID." },
      "text": { "type": "string", "description": "Message text." }
    },
    "required": ["channel", "text"]
  }
}
The description and schema come from the MCP server. If the description is bad, the agent uses the tool poorly — and you can’t easily fix it without modifying the server.

Credentials

MCP credentials live in connections.credentials, encrypted at rest with Fernet using AD_ENCRYPTION_KEY. They’re only decrypted when the Engine makes an outbound call to the MCP server. They never appear in:
  • The prompt to the LLM.
  • The SSE stream.
  • The Engine’s logs.
If you set ENGINE_LOG_LEVEL=DEBUG, you’ll see MCP request/response traces, but the credentials are still redacted.

Refresh and circuit breaker

OAuth tokens expire. The refresh scheduler (asset_directory/refresh_scheduler.py) refreshes them in the background before they expire. If refresh fails (the user revoked access, the provider’s API changed), the connection moves to expired and tool calls error with MCP_TOKEN_EXPIRED. The circuit breaker (asset_directory/circuit_breaker.py) tracks failure rates per connection. If a connection fails repeatedly, the breaker opens and rejects subsequent calls for a cooldown period. This prevents one broken connector from generating runaway error traffic.

Per-user vs. per-tenant

Each Engine instance is single-user, so its connections are per-user by definition. The MCP credentials in this Engine’s brain belong to this user. Multi-user setups run multiple Engines, each with its own brain and its own connection set.

Adding a new MCP server type

To add a server the Engine doesn’t know about yet:
  1. Add a JSON entry to the catalog with the server’s metadata (name, transport, auth method, OAuth config).
  2. If the server is custom (you wrote it), point the Engine at its transport endpoint.
  3. Hot-reload with POST /admin/reload-catalog.
  4. The new server appears in GET /assets/servers.
For OAuth servers, register the Engine’s callback URL (<OAUTH_REDIRECT_BASE_URL>/assets/oauth/callback) in the provider’s OAuth app settings.

Pitfalls

  • OAuth callback URL mismatch. If OAUTH_REDIRECT_BASE_URL doesn’t match what’s registered with the provider, the OAuth flow fails with a redirect_uri_mismatch error.
  • Encryption key rotation. Rotating AD_ENCRYPTION_KEY without a re-encrypt step invalidates every stored credential. Plan rotation with a migration.
  • Scope drift. A connection grants specific scopes. If the agent needs a scope the connection doesn’t have, the MCP call fails. Keep scopes in mind when defining the agent’s expected workflow.
  • Server-side rate limits. MCP servers (especially Slack, Gmail) have their own rate limits. The circuit breaker mitigates the worst cases but doesn’t eliminate them. Design for retry.

See also