drio
Technical Overview

MCP Authentication In drio

How MCP auth works in drio, which requests stay public, how the OAuth bridge works, and what to verify when protected tools fail.

This page explains the auth model for MCP apps hosted by drio.

Use it when you need to understand:

  • which MCP requests are public
  • when drio challenges an MCP client for sign-in
  • how drio's OAuth bridge works
  • what a published app must satisfy before MCP auth will work reliably

This is the MCP auth model for drio-hosted apps. It is separate from the management API auth flow described in Authentication.

The Model In One View

drio uses one server-wide OAuth configuration per published MCP app.

That means:

  • initialize is public
  • tools/list is public
  • public tools can run without auth
  • protected tools challenge on tools/call
  • the OAuth metadata and OAuth endpoints are shared for the whole MCP server

What drio does not do anymore:

  • it does not expose a different OAuth registration flow per tool
  • it does not expect MCP clients to invent custom adapter_id calls
  • it does not require auth before a client can discover tools

So the distinction is:

  • authorization is per tool
  • authentication configuration is per server

Public Versus Protected Behavior

For a drio MCP server, the request behavior is:

RequestAuth required?Notes
initializeNoAlways available so clients can connect and inspect the server
tools/listNoClients can discover public and protected tools before sign-in
tools/call for a public toolNoThe tool executes immediately
tools/call for a protected toolYesdrio returns an MCP auth challenge when no bearer token is present

This gives clients a usable discovery experience while still protecting business actions.

Host And Route Layout

Each published app has an MCP host. That can be:

https://{mcpId}.mcp.getdrio.com/mcp
https://customer.example.com/mcp

The same tenant host serves the auth discovery and bridge routes:

  • GET /.well-known/oauth-protected-resource
  • GET /.well-known/oauth-authorization-server
  • GET /.well-known/openid-configuration
  • POST /mcp/oauth/register
  • GET /mcp/oauth/authorize
  • POST /mcp/oauth/token

The upstream provider callback is brokered through drio's control-plane host:

  • https://www.getdrio.com/api/mcp/oauth/callback

What drio Publishes At Runtime

When an app is published, drio compiles the authoring model into runtime MCP config.

For auth, the important runtime rule is:

  • a published MCP app can expose one effective delegated OAuth strategy

drio derives that from the published tools. If the app would require multiple non-equivalent delegated OAuth strategies, publish fails. That is intentional: the MCP server should present one consistent OAuth configuration to clients.

This applies to:

  • tools that inherit delegated OAuth through their integration
  • direct API tools configured with delegated OAuth

How The Challenge Works

If a client calls a protected tool without a bearer token, drio returns a 401 with standard MCP auth metadata.

The important part is the WWW-Authenticate value:

Bearer resource_metadata="https://{host}/.well-known/oauth-protected-resource"

The same value is also included in the MCP error _meta.

Example response shape:

{
  "jsonrpc": "2.0",
  "id": 1,
  "error": {
    "code": -32001,
    "message": "Authentication required",
    "data": {
      "_meta": {
        "mcp/www_authenticate": "Bearer resource_metadata=\"https://example.mcp.getdrio.com/.well-known/oauth-protected-resource\""
      }
    }
  }
}

The key point is that this challenge is server-wide. It is not tool-specific metadata.

The Discovery Flow

Once challenged, the MCP client should follow the advertised endpoints in the usual order:

  1. fetch /.well-known/oauth-protected-resource
  2. read the authorization_servers entry
  3. fetch /.well-known/oauth-authorization-server
  4. use the returned registration_endpoint
  5. use the returned authorization_endpoint
  6. exchange the returned code at the returned token_endpoint

The client should use those endpoints as-is. It should not construct drio- specific variants.

The OAuth Bridge Flow

drio acts as an OAuth bridge between the MCP client and the configured upstream OAuth provider.

High-level flow:

Mermaid diagram source:
sequenceDiagram
  autonumber
  participant Client as MCP client
  participant Drio as drio MCP host
  participant OAuth as Upstream OAuth provider
  participant API as Protected upstream API

  Client->>Drio: tools/call protected tool without token
  Drio-->>Client: 401 + resource_metadata
  Client->>Drio: GET /.well-known/oauth-protected-resource
  Client->>Drio: GET /.well-known/oauth-authorization-server
  Client->>Drio: POST /mcp/oauth/register
  Client->>Drio: GET /mcp/oauth/authorize
  Drio->>OAuth: Redirect user to authorize
  OAuth-->>Drio: GET https://www.getdrio.com/api/mcp/oauth/callback
  Drio-->>Client: Redirect back with authorization code
  Client->>Drio: POST /mcp/oauth/token
  Client->>Drio: Retry protected tools/call with Bearer token
  Drio->>API: Forward authenticated request
  API-->>Drio: Protected response
  Drio-->>Client: Tool result

What Each Route Does

GET /.well-known/oauth-protected-resource

This identifies the MCP server as the protected resource and tells the client which authorization server to use.

Typical response:

{
  "resource": "https://example.mcp.getdrio.com/mcp",
  "authorization_servers": ["https://example.mcp.getdrio.com"],
  "bearer_methods_supported": ["header"],
  "scopes_supported": ["openid", "profile", "email"]
}

GET /.well-known/oauth-authorization-server

This advertises the OAuth endpoints for the MCP host.

Typical response:

{
  "issuer": "https://example.mcp.getdrio.com",
  "authorization_endpoint": "https://example.mcp.getdrio.com/mcp/oauth/authorize",
  "token_endpoint": "https://example.mcp.getdrio.com/mcp/oauth/token",
  "registration_endpoint": "https://example.mcp.getdrio.com/mcp/oauth/register",
  "response_types_supported": ["code"],
  "grant_types_supported": ["authorization_code", "refresh_token"],
  "code_challenge_methods_supported": ["S256"],
  "token_endpoint_auth_methods_supported": ["none"],
  "scopes_supported": ["openid", "profile", "email"]
}

/.well-known/openid-configuration is also exposed as a compatibility alias.

POST /mcp/oauth/register

This creates a local client registration for the MCP client and, when needed, registers an upstream public client with the delegated OAuth provider.

drio currently expects a public OAuth client flow:

  • authorization_code
  • refresh_token
  • token_endpoint_auth_method: none
  • PKCE

Example:

curl -X POST https://example.mcp.getdrio.com/mcp/oauth/register \
  -H "Content-Type: application/json" \
  -d '{
    "client_name": "My MCP Client",
    "redirect_uris": ["http://127.0.0.1:3333/callback"],
    "grant_types": ["authorization_code", "refresh_token"],
    "response_types": ["code"],
    "token_endpoint_auth_method": "none",
    "scope": "openid profile email"
  }'

GET /mcp/oauth/authorize

This starts the OAuth authorization flow for the already-registered MCP client.

drio validates the local client registration, then redirects the user to the configured upstream provider authorization endpoint.

POST /mcp/oauth/token

This exchanges the authorization code or refresh token against the upstream provider and proxies the token response back to the MCP client.

Supported grant types:

  • authorization_code
  • refresh_token

How Tokens Are Used

After token exchange, the MCP client retries the protected tools/call request with:

Authorization: Bearer ACCESS_TOKEN

drio then forwards that bearer token to the protected downstream path for the tool.

For the drio management API tools, that means the token is forwarded into the drio platform stack. For custom API tools, it is forwarded to the configured upstream API call.

What This Means For App Authors

If your app has both public and protected tools:

  • the public tools still work before sign-in
  • the protected tools all rely on the same server OAuth configuration

If your app needs multiple different delegated OAuth providers for different protected tools, that is not a good fit for one published MCP server in drio. You should simplify to one delegated OAuth strategy or split the surface into separate apps.

Verify The Flow With curl

1. Confirm discovery routes

curl -i https://{mcpId}.mcp.getdrio.com/.well-known/oauth-protected-resource
curl -i https://{mcpId}.mcp.getdrio.com/.well-known/oauth-authorization-server

Expected:

  • both return 200
  • the metadata points back to the same MCP host

2. Confirm public MCP discovery

curl -i https://{mcpId}.mcp.getdrio.com/mcp \
  -H "Accept: application/json, text/event-stream" \
  -H "Content-Type: application/json" \
  --data '{
    "jsonrpc":"2.0",
    "id":1,
    "method":"tools/list"
  }'

Expected:

  • 200
  • no auth challenge

3. Confirm protected tool challenge

curl -i https://{mcpId}.mcp.getdrio.com/mcp \
  -H "Accept: application/json, text/event-stream" \
  -H "Content-Type: application/json" \
  --data '{
    "jsonrpc":"2.0",
    "id":1,
    "method":"tools/call",
    "params":{
      "name":"List apps",
      "arguments":{"limit":5}
    }
  }'

Expected:

  • 401
  • WWW-Authenticate: Bearer resource_metadata=".../.well-known/oauth-protected-resource"

Common Failure Modes

initialize or tools/list returns 401

That means the MCP server is still behaving like whole-server auth. In drio's intended model, those requests stay public.

Register succeeds, authorize fails immediately

That usually means the local client registration is invalid, expired, or no longer matches the published server auth config.

Tool challenge appears, but the protected tool still fails after sign-in

That usually means the bearer token is reaching the protected path, but a downstream service does not trust it. In drio-hosted tools, that often means a platform auth mismatch between the token issuer and the service validating the token.

Metadata works, but /mcp returns 406

The client is missing the required accept header. drio's MCP transport expects:

Accept: application/json, text/event-stream

Design Constraints To Keep In Mind

  • one published MCP app exposes one effective delegated OAuth configuration
  • public discovery stays available even when some tools are protected
  • protected tool auth is triggered by tools/call, not by initialize
  • MCP clients should follow the advertised metadata endpoints directly
  • drio's OAuth bridge is stateless from the MCP client's point of view