Skip to content

Add external MCP servers as mcp connectors with per-user OAuth - #10009

Merged
k-anshul merged 14 commits into
mainfrom
mcp_connector
Oct 21, 2026
Merged

k-anshul merged 14 commits into
mainfrom
mcp_connector

Conversation

@nishantmonu51

@nishantmonu51 nishantmonu51 commented Oct 12, 2026 •

Copy link
Copy Markdown
Collaborator

Adds external MCP servers as a driver: mcp connector so AI agents can use their tools alongside the built-in Rill tools.

  • New runtime/drivers/mcp driver: streamable HTTP client, project-scoped headers with {{ .env.* }} and {{ .user.* }} templating, per-user OAuth 2.1 (auth: oauth) with discovery, dynamic client registration, PKCE and refresh. Hosted runtimes refuse private networks and cross-origin redirects.
  • Connector security block with metrics-view semantics (access, include, exclude) evaluated by the existing security engine with tool names as fields, plus agents to scope a server to specific agents.
  • runtime/ai: per-user tool discovery, tools exposed as mcp__<connector>__<tool>, a per-message call cap, and a JSON "authorization required" error the chat UI turns into a Connect card. External tools are never re-exported through Rill's own MCP server.
  • Rill Cloud: the admin service keeps each user's token encrypted (migration 0098.sql, tables mcp_oauth_clients and mcp_oauth_tokens), serves /mcp/oauth/connect and /mcp/oauth/callback, and hands runtimes short-lived access tokens via GetMCPOAuthToken. Rill Developer persists the local user's token under the project tmp directory.
  • Chat UI: an External tools popover to connect and disconnect servers, an inline Connect card when a tool needs authorization, and a read-only side panel for driver: mcp connector files.
  • Docs: docs/docs/guide/ai/external-mcp.md and the connector reference.

Checklist:

  • Covered by tests
  • Ran it and it works as intended
  • Reviewed the diff before requesting a review
  • Checked for unhandled edge cases
  • Linked the issues it closes
  • Checked if the docs need to be updated. If so, create a separate Linear DOCS issue
  • Intend to cherry-pick into the release branch
  • I'm proud of this work!

…nuation, per-user tool catalog, shared prompt fragment
… configuration, check tool access against the current connector
…uperseded OAuth clients, expose authorization separately from availability

- A tool call now refuses to send the session's hosted token to a handle whose server URL differs from the one the token was granted for, and discovery takes the URL from the handle it lists tools with.
- OAuth clients are never modified in place: a configuration change registers a new client next to the old one, so tokens and pending flows bound to the old client keep working. Unused clients older than the flow TTL are deleted.
- MCPServer gains an authorized flag that does not depend on reachability; the External tools popover offers Disconnect whenever an authorization is stored, so a server that is down can still be disconnected.

@nishantmonu51 nishantmonu51 left a comment

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Reviewed 61d9542. Three inline comments; the first one is the one to fix.

Comment thread admin/server/connector_oauth.go Outdated
if err != nil {
return nil, err
}
clientRow, err := s.admin.DB.FindConnectorOAuthClient(ctx, depl.ProjectID, req.Connector, req.ConfigHash)

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Disconnect only removes the token for the current config_hash. Tokens granted before a URL, scope or client change stay stored, unrevoked and refreshable, and nothing sweeps them now that the unused-client job is gone, so a user who disconnects after such a change still has a live grant held by Rill. Delete and revoke the user's tokens for every client of (project, connector) here (the runtime passes only the current hash from runtime/server/mcp_servers.go:87), and consider dropping clients that hold no tokens and are no longer current.

if err := json.Unmarshal(clientRow.Client, oauthClient); err != nil {
return fmt.Errorf("stored OAuth client is invalid: %w", err)
}
newTok, err := oauthClient.Refresh(ctx, tok, safehttp.NewHTTPClient(false, connectorOAuthHTTPTimeout))

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The refresh request to the authorization server (up to 15 s) runs while the advisory lock and its transaction are held, which the client-registration comment deliberately avoids for the same reason. With many tokens expiring at once this ties up database connections. If the lock scope is intentional, a comment saying so would help.

Comment thread runtime/ai/external_tools.go Outdated
tok, err := admin.GetConnectorOAuthToken(ctx, srv.Connector, srv.oauthConfigHash, userID, forceRefresh)
if err != nil {
if errors.Is(err, drivers.ErrNotImplemented) {
return "", errOAuthRequiresCloud

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

In Rill Developer this error lands in ExternalServer.Err, so the popover shows every auth: oauth connector with the red Error status and this message, as if it were misconfigured, while the docs describe such servers as listed but not connectable. A plain unauthorized state (no error) with the existing "Open this project in Rill Cloud" wording would match the docs.

k-anshul and others added 2 commits October 20, 2026 15:48
…CP session

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
@k-anshul
k-anshul merged commit 181e53f into main Oct 21, 2026
17 of 18 checks passed
@k-anshul
k-anshul deleted the mcp_connector branch October 21, 2026 06:05
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

Area:AI AI assistant, chat and agents Area:Connectors Size:XL Very large change: 2,000+ lines Type:Feature New feature request

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants