diff --git a/skills/iblai-agent-mcp/SKILL.md b/skills/iblai-agent-mcp/SKILL.md index a0b2c5d..314ad0e 100644 --- a/skills/iblai-agent-mcp/SKILL.md +++ b/skills/iblai-agent-mcp/SKILL.md @@ -83,6 +83,65 @@ curl -X POST \ }' ``` +## Connector model + +Three objects work together: + +- **MCP server** (`mcp-servers/`) — the connector record: `name`, `url`, + `transport` (`sse|websocket|streamable_http`), `auth_type` + (`none|token|oauth2`), and `auth_scope` (`user|mentor|tenant`). + `is_featured=true` lets admins in *other* orgs create their own connections to + the same server; disabled connectors are skipped at runtime. +- **MCP server connection** (`mcp-server-connections/`) — the auth binding that + supplies credentials for a server at a given `scope`. OAuth2 connections + reference a `connected_service`. +- **Connected service** (`connected-services/…`) — a user's stored OAuth grant + for a provider + service (e.g. `google` + `drive`), created by completing the + OAuth flow. One per user per service. + +`auth_type` and `auth_scope` answer two different questions: `auth_type` is +*how* the call is authenticated (`none`, a static `token`, or `oauth2`); +`auth_scope`/`scope` is *whose* credentials are used (`user`, `mentor`, or +`tenant`). Only `auth_type=oauth2` **and** `auth_scope=user` together trigger the +in-chat OAuth prompt below. + +## Runtime credential resolution + +When an agent calls an attached MCP server, the platform selects credentials in +priority order — first match wins: + +1. **user**-scoped connection for (server, current user) +2. **mentor**-scoped connection for (server, agent) +3. **tenant**-scoped connection for (server, org) +4. featured-server global fallback +5. otherwise fail (401 / no connection) — or, for a per-user oauth2 server with + no user connection, start the in-chat OAuth flow + +OAuth access tokens are refreshed automatically as they near expiry — no client +action required. + +## In-chat OAuth (per-user oauth2 connectors) + +A connector with `auth_type=oauth2` + `auth_scope=user` authenticates each user +individually. When an authenticated user chats with the agent and has no +connection yet, the chat pauses and the runtime emits JSON events on the +existing chat socket (WebSocket/SSE) — switch on the `type` field: + +- `oauth_required` — carries `server_name`, `server_id`, and `auth_url`; open + `auth_url` in a new tab/popup (providers block iframes) so the user can + authenticate. Backend then polls for the new connection. +- `oauth_connection_resolved` — the connection was created; dismiss the prompt, + the chat resumes automatically. +- `warning` (`code` 503) — MCP tools couldn't load for a non-OAuth reason + (server unreachable / misconfigured); chat continues without those tools. +- `error` (`status_code` 400) — OAuth timed out (default ~5 min), the auth URL + couldn't be built (missing `auth_{provider}` credential), or the connection + has no valid connected service; the user retries the message. + +The backend polls every ~10s and times out after ~300s. Completing OAuth *after* +a timeout still works — the next message succeeds because the connection now +exists. + ## Notes - The connector list is paged (`page_size=12`); use `search` and `transport` to