Skip to content

MCP Server Part 10: OAuth discovery#3767

Open
KoolADE85 wants to merge 2 commits into
mcpfrom
feature/mcp-oauth
Open

MCP Server Part 10: OAuth discovery#3767
KoolADE85 wants to merge 2 commits into
mcpfrom
feature/mcp-oauth

Conversation

@KoolADE85
Copy link
Copy Markdown
Contributor

Summary

Support OAuth so MCP clients can discover how to authenticate against an authorization server when connecting to the Dash MCP endpoint. Implements the discovery half of the MCP Authorization spec.

  • New mcp_authorization_server constructor arg (and DASH_MCP_AUTHORIZATION_SERVER env var). When set, registers an RFC 9728 Protected Resource Metadata endpoint at /.well-known/oauth-protected-resource/<mcp-path> advertising the authorization server.
  • Dash serves discovery metadata only — it does not enforce auth. Token validation, 401 responses, and WWW-Authenticate headers are the responsibility of the hosting platform (middleware, reverse proxy, etc.).

@KoolADE85 KoolADE85 force-pushed the feature/mcp-background-callbacks branch from 3e146f8 to 0a82ca0 Compare May 8, 2026 22:11
@KoolADE85 KoolADE85 force-pushed the feature/mcp-oauth branch 3 times, most recently from 1d9eb46 to 7121548 Compare May 8, 2026 22:47
@KoolADE85 KoolADE85 force-pushed the feature/mcp-background-callbacks branch from fd13290 to 5c45baf Compare May 11, 2026 23:19
@KoolADE85 KoolADE85 force-pushed the feature/mcp-oauth branch from 7121548 to 2e87a4b Compare May 11, 2026 23:20
@KoolADE85 KoolADE85 force-pushed the feature/mcp-background-callbacks branch from 01e8744 to 1366bd4 Compare May 13, 2026 18:06
@KoolADE85 KoolADE85 force-pushed the feature/mcp-oauth branch from 2e87a4b to c2801af Compare May 13, 2026 18:08
@KoolADE85 KoolADE85 force-pushed the feature/mcp-background-callbacks branch 2 times, most recently from f4254e2 to 3ef3409 Compare May 19, 2026 15:18
@KoolADE85 KoolADE85 force-pushed the feature/mcp-oauth branch from cff5ebd to 41a5689 Compare May 19, 2026 15:23
Comment thread dash/mcp/_server.py
server. Auth enforcement is the responsibility of the hosting platform
(e.g. Plotly Cloud gateway, Dash Embedded, or a reverse proxy).
"""
well_known_path = urljoin("/.well-known/oauth-protected-resource/", mcp_path)
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Could you double check the URL construction? It looks like the final result might not be correct. Shouldn't the pathname prefix be included before the MCP path?

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

As discussed offline, I am now raising when mcp_authorization_server is used in conjunction with requests_pathname_prefix since we cannot accommodate both.

@KoolADE85 KoolADE85 changed the base branch from feature/mcp-background-callbacks to mcp May 20, 2026 20:38
@KoolADE85 KoolADE85 force-pushed the feature/mcp-oauth branch from d18681e to 8a24973 Compare May 20, 2026 20:39
@KoolADE85 KoolADE85 force-pushed the feature/mcp-oauth branch from 8a24973 to 2bbbc02 Compare May 20, 2026 21:19
Copy link
Copy Markdown
Contributor

@camdecoster camdecoster left a comment

Choose a reason for hiding this comment

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

I left some suggestions, but this should work as is.

Comment thread dash/mcp/_server.py
"`requests_pathname_prefix`. "
"Authorization must be implemented at the platform level "
"(see https://www.rfc-editor.org/rfc/rfc9728#section-3). "
"Remove the mcp_authorization_server parameter."
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

It might be worth it to guide the user a bit more on how to fix the issue with a URL template or something. At a minimum, I'd update the last sentence to be a little less of a command.

Suggested change
"Remove the mcp_authorization_server parameter."
"Remove the `mcp_authorization_server` or `requests_pathname_prefix` parameter to avoid this error."

Comment thread dash/mcp/_server.py
json.dumps(
{
"resource": _url_from_path(
app, app.config.requests_pathname_prefix, mcp_path
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

The prefix will only ever be "/" here, right?

Comment thread dash/mcp/_server.py
(e.g. Plotly Cloud gateway, Dash Embedded, or a reverse proxy).
"""
if app.config.requests_pathname_prefix != "/":
raise ValueError(
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Raising here means that the error will get caught in the try/except block in dash.py. Would it be better to raise earlier when first checking on config options?

Comment thread dash/mcp/_server.py
)
app.routes.append(mcp_url)

if mcp_authorization_server:
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Should this check happen before registering the routes? If the auth server has been configured, then the routes get registered but MCP can't be enabled. It might be better to fail earlier.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants