Skip to content

Conversation

@Aisha630
Copy link

Description

Add a Discord OAuth provider to the FastMCP server auth stack, mirroring the existing GitHub/Google-style providers.

Contributors Checklist

  • My change closes Add support for Discord auth #2346
  • I have followed the repository's development workflow
  • I have tested my changes manually and by adding relevant tests
  • I have performed all required documentation updates

Review Checklist

  • I have self-reviewed my changes
  • My Pull Request is ready for review

@coderabbitai
Copy link
Contributor

coderabbitai bot commented Nov 16, 2025

Walkthrough

This change introduces a complete Discord OAuth provider implementation for FastMCP. It adds three new classes to src/fastmcp/server/auth/providers/discord.py: DiscordProviderSettings for configuration management with environment-based loading, DiscordTokenVerifier for HTTP-based token validation against Discord's API endpoints, and DiscordProvider extending OAuthProxy to integrate Discord's authorization flow. The implementation includes token verification with scope enforcement, user data enrichment, expiration handling, and comprehensive initialization configuration using NotSet-based parameter handling.

Pre-merge checks and finishing touches

✅ Passed checks (5 passed)
Check name Status Explanation
Title check ✅ Passed The title accurately summarizes the main change: adding a Discord OAuth provider with tests, which is clearly supported by the file changes.
Description check ✅ Passed The PR description addresses the main objective, closes issue #2346, and includes all completed checklist items for contributors and reviewers.
Linked Issues check ✅ Passed The PR implements Discord OAuth support as required by issue #2346, adding a complete Discord provider with token verification and configuration management.
Out of Scope Changes check ✅ Passed All changes in discord.py are directly related to implementing Discord OAuth support per issue #2346; no unrelated modifications detected.
Docstring Coverage ✅ Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.
✨ Finishing touches
  • 📝 Generate docstrings
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Post copyable unit tests in a comment

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

@Aisha630
Copy link
Author

@coderabbitai review

@coderabbitai
Copy link
Contributor

coderabbitai bot commented Nov 16, 2025

✅ Actions performed

Review triggered.

Note: CodeRabbit is an incremental review system and does not re-review already reviewed commits. This command is applicable only when automatic reviews are paused.

Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 1

🧹 Nitpick comments (1)
src/fastmcp/server/auth/providers/discord.py (1)

67-183: Tighten exception handling in DiscordTokenVerifier to avoid masking bugs

The overall verification flow (calling /api/oauth2/@me, enforcing scopes, optional /users/@me, and building AccessToken) looks good, but the broad except Exception blocks can hide real programming errors and are flagged by Ruff (BLE001).

You can keep behavior (treat network/JSON issues as invalid token) while narrowing the catches to expected failures:

@@
-                user_data = {}
-                if "identify" in token_scopes:
-                    try:
-                        userinfo_response = await client.get(
-                            "https://discord.com/api/users/@me",
-                            headers=headers,
-                        )
-                        if userinfo_response.status_code == 200:
-                            user_data = userinfo_response.json()
-                    except Exception as e:
-                        logger.debug("Failed to fetch Discord user info: %s", e)
+                user_data = {}
+                if "identify" in token_scopes:
+                    try:
+                        userinfo_response = await client.get(
+                            "https://discord.com/api/users/@me",
+                            headers=headers,
+                        )
+                        if userinfo_response.status_code == 200:
+                            user_data = userinfo_response.json()
+                    except httpx.RequestError as e:
+                        logger.debug("Failed to fetch Discord user info: %s", e)
+                    except ValueError as e:
+                        logger.debug("Failed to decode Discord user info JSON: %s", e)
@@
-        except httpx.RequestError as e:
-            logger.debug("Failed to verify Discord token: %s", e)
-            return None
-        except Exception as e:
-            logger.debug("Discord token verification error: %s", e)
-            return None
+        except httpx.RequestError as e:
+            logger.debug("Failed to verify Discord token: %s", e)
+            return None
+        except ValueError as e:
+            logger.debug("Failed to decode Discord tokeninfo JSON: %s", e)
+            return None

Optionally, you might also treat 5xx responses from Discord differently from 4xx (e.g., log as upstream failure vs. invalid token), but that’s secondary to fixing the broad catches. Based on static analysis hints.

Please verify the exact exception types httpx can raise in your version and adjust the narrowed except clauses accordingly.

📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between b5f88bf and 2dc0803.

⛔ Files ignored due to path filters (2)
  • README.md is excluded by none and included by none
  • tests/server/auth/providers/test_discord.py is excluded by none and included by none
📒 Files selected for processing (1)
  • src/fastmcp/server/auth/providers/discord.py (1 hunks)
🧰 Additional context used
🧬 Code graph analysis (1)
src/fastmcp/server/auth/providers/discord.py (2)
src/fastmcp/server/auth/auth.py (2)
  • TokenVerifier (170-193)
  • AccessToken (36-39)
src/fastmcp/server/auth/oauth_proxy.py (1)
  • OAuthProxy (536-2172)
🪛 Ruff (0.14.4)
src/fastmcp/server/auth/providers/discord.py

146-146: Do not catch blind exception: Exception

(BLE001)


181-181: Do not catch blind exception: Exception

(BLE001)


277-279: Avoid specifying long messages outside the exception class

(TRY003)


281-283: Avoid specifying long messages outside the exception class

(TRY003)


304-304: Possible hardcoded password assigned to argument: "upstream_token_endpoint"

(S106)

⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (1)
  • GitHub Check: Run tests: Python 3.10 on windows-latest
🔇 Additional comments (1)
src/fastmcp/server/auth/providers/discord.py (1)

42-65: DiscordProviderSettings env wiring and scope parsing look consistent

The settings model (env prefix, ENV_FILE usage, ignore-extra, and _parse_scopes delegating to parse_scopes) is clean and matches the expected pattern for other providers; I don’t see required changes here.

Please just confirm parse_scopes already handles None and both string / list inputs the same way for other providers.

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.

Add support for Discord auth

1 participant