dify - ✅(Solved) Fix MCP Dynamic Client Registration fails with 400 when server validates null fields [3 pull requests, 1 participants]

Official PRs (…)
ON THIS PAGE

Recommended Tools

×6

Utilities matched from this issue’s tags and category — try them while you read without losing context.

GitHub issue graph ai analysis

Paste a GitHub issue URL. We fetch that issue, discover linked issues from bodies/comments/timeline, collect linked pull requests, and produce a structured English report.

The report is written in English Markdown for sharing and archival.

Helpful · Quick feedback

Loading…
GitHub stats
langgenius/dify#34857Fetched 2026-04-10 03:45:41
View on GitHub
Comments
0
Participants
1
Timeline
2
Reactions
1
Timeline (top)
cross-referenced ×1labeled ×1

Error Message

HTTP Request: POST https://gitlab-mcp.koesio.io/register "HTTP/1.1 400 Bad Request"
ERROR - Exception on /console/api/workspaces/current/tool-provider/mcp/auth [POST]
httpx.HTTPStatusError: Client error '400 Bad Request' for url 'https://gitlab-mcp.koesio.io/register'

Root Cause

In api/core/mcp/auth/auth_flow.py, the register_client() function uses:

json=client_metadata.model_dump()

OAuthClientMetadata has several optional fields (scope, client_uri, etc.) that default to None. Pydantic's model_dump() serializes these as JSON null. MCP servers that perform strict validation on the registration payload (such as GitLab MCP) reject null values where a string type is expected.

Per RFC 7591, optional fields that are not provided should simply be absent from the request body, not sent as null.

Fix Action

Fix

Change model_dump() to model_dump(exclude_none=True) on line 530 of api/core/mcp/auth/auth_flow.py.

PR fix notes

PR #34856: fix(mcp): exclude null fields from Dynamic Client Registration payload

Description (problem / solution / changelog)

[!IMPORTANT]

  1. Make sure you have read our contribution guidelines
  2. Ensure there is an associated issue and you have been assigned to it
  3. Use the correct syntax to link this PR: Fixes #<issue number>.

Fixes #34857

Summary

OAuthClientMetadata.model_dump() serializes optional None fields (scope, client_uri, etc.) as JSON null in the Dynamic Client Registration request body (RFC 7591). MCP servers that perform strict validation (e.g. GitLab MCP) reject the request with 400 Bad Request:

{"error":"invalid_client_metadata","error_description":"expected string, received null (path: [\"scope\"])"}

The fix uses model_dump(exclude_none=True) to omit unset optional fields from the JSON body, conforming to RFC 7591 where absent fields should use server defaults.

File changed: api/core/mcp/auth/auth_flow.py line 530 in register_client()

# Before (sends {"scope": null, "client_uri": null, ...})
json=client_metadata.model_dump(),

# After (omits None fields entirely)
json=client_metadata.model_dump(exclude_none=True),

Screenshots

N/A — backend-only change, no UI impact.

Checklist

  • This change requires a documentation update, included: Dify Document — No documentation update needed
  • I understand that this PR may be closed in case there was no previous discussion or issues. (This doesn't apply to typos!)
  • I've added a test for each change that was introduced, and I tried as much as possible to make a single atomic change.
  • I've updated the documentation accordingly.
  • I ran make lint and make type-check (backend) and cd web && pnpm exec vp staged (frontend) to appease the lint gods

🤖 Generated with Claude Code

Changed files

  • api/core/mcp/auth/auth_flow.py (modified, +1/-1)

PR #34949: fix(mcp): omit None fields from OAuth Dynamic Client Registration payload

Description (problem / solution / changelog)

Fixes #34857. @uskaidev filed this with the full root-cause analysis and the exact one-line fix already identified, so I just applied it and added a regression test.

Short version: OAuthClientMetadata has a bunch of optional fields defaulting to None (scope, client_uri, grant_types, etc.). register_client() was serializing with plain model_dump(), so unset fields went out as JSON null. Per RFC 7591 §2 they're supposed to just be absent from the payload, and strict MCP registration servers (the reporter hit this against GitLab's gitlab-mcp) respond with invalid_client_metadata when they see the nulls.

Fix is model_dump(exclude_none=True). I left a comment above the call referencing the issue and the RFC so the next refactor of this file doesn't quietly undo it.

The existing test_register_client_success was asserting the serialized payload shape, so I updated that to match. I also added test_register_client_omits_none_fields: it constructs an OAuthClientMetadata with only the two required fields, calls register_client, and checks that mock_post received exactly {"client_name", "redirect_uris"} with none of the optional fields leaking through as null.

49 tests in test_auth_flow.py pass, ruff and format clean. I don't have a GitLab MCP instance to verify the end-to-end OAuth flow against the real server, but the regression test pins the exact payload shape that was being rejected.

Changed files

  • api/core/mcp/auth/auth_flow.py (modified, +8/-1)
  • api/tests/unit_tests/core/mcp/auth/test_auth_flow.py (modified, +36/-1)

PR #35002: fix: exclude None fields in MCP Dynamic Client Registration request

Description (problem / solution / changelog)

Summary

Use model_dump(exclude_none=True) instead of model_dump() when serializing client_metadata for OAuth Dynamic Client Registration. Strict MCP servers (e.g., GitLab) return HTTP 400 when optional fields are sent as JSON null. One-line change in api/core/mcp/auth/auth_flow.py.

Fixes #34857

Screenshots

N/A — backend-only change.

Checklist

  • This change requires a documentation update, included: Dify Document
  • I understand that this PR may be closed in case there was no previous discussion or issues. (This doesn't apply to typos!)
  • I've added a test for each change that was introduced, and I tried as much as possible to make a single atomic change.
  • I've updated the documentation accordingly.
  • I ran make lint and make type-check (backend) and cd web && pnpm exec vp staged (frontend) to appease the lint gods

From Claude Code

Changed files

  • api/core/mcp/auth/auth_flow.py (modified, +1/-1)

Code Example

{
  "error": "invalid_client_metadata",
  "error_description": "[{\"expected\":\"string\",\"code\":\"invalid_type\",\"path\":[\"scope\"],\"message\":\"Invalid input: expected string, received null\"}]"
}

---

json=client_metadata.model_dump()

---

HTTP Request: POST https://gitlab-mcp.koesio.io/register "HTTP/1.1 400 Bad Request"
ERROR - Exception on /console/api/workspaces/current/tool-provider/mcp/auth [POST]
httpx.HTTPStatusError: Client error '400 Bad Request' for url 'https://gitlab-mcp.koesio.io/register'
RAW_BUFFERClick to expand / collapse

Self Checks

  • This is only a request for a single feature or a bug report, not a question.
  • I have searched the existing issues, and there is no existing issue for this bug.

Dify version

1.13.3

Cloud or Self-Hosted

Self-Hosted (Kubernetes / Helm)

Steps to reproduce

  1. Add an MCP tool in Dify pointing to a GitLab MCP server (e.g. gitlab-mcp from @anthropic/gitlab-mcp-server)
  2. Click Authorize to start the OAuth flow
  3. Dify attempts Dynamic Client Registration (RFC 7591) via POST /register
  4. The MCP server responds with 400 Bad Request

✔️ Expected Behavior

Dynamic Client Registration should succeed and redirect the user to the OAuth authorization page.

❌ Actual Behavior

The registration fails with:

{
  "error": "invalid_client_metadata",
  "error_description": "[{\"expected\":\"string\",\"code\":\"invalid_type\",\"path\":[\"scope\"],\"message\":\"Invalid input: expected string, received null\"}]"
}

Root cause

In api/core/mcp/auth/auth_flow.py, the register_client() function uses:

json=client_metadata.model_dump()

OAuthClientMetadata has several optional fields (scope, client_uri, etc.) that default to None. Pydantic's model_dump() serializes these as JSON null. MCP servers that perform strict validation on the registration payload (such as GitLab MCP) reject null values where a string type is expected.

Per RFC 7591, optional fields that are not provided should simply be absent from the request body, not sent as null.

Fix

Change model_dump() to model_dump(exclude_none=True) on line 530 of api/core/mcp/auth/auth_flow.py.

Logs

HTTP Request: POST https://gitlab-mcp.koesio.io/register "HTTP/1.1 400 Bad Request"
ERROR - Exception on /console/api/workspaces/current/tool-provider/mcp/auth [POST]
httpx.HTTPStatusError: Client error '400 Bad Request' for url 'https://gitlab-mcp.koesio.io/register'

extent analysis

TL;DR

Change the model_dump() function to model_dump(exclude_none=True) in api/core/mcp/auth/auth_flow.py to fix the Dynamic Client Registration issue.

Guidance

  • Identify the line of code causing the issue: json=client_metadata.model_dump() in api/core/mcp/auth/auth_flow.py.
  • Update the model_dump() function to exclude None values by setting exclude_none=True.
  • Verify the fix by attempting the OAuth flow again and checking for a successful redirect to the authorization page.
  • Review the logs for any remaining errors related to the registration process.

Example

json = client_metadata.model_dump(exclude_none=True)

Notes

This fix assumes that the issue is solely caused by the serialization of optional fields as null in the registration payload. If other issues are present, additional debugging may be necessary.

Recommendation

Apply the workaround by changing the model_dump() function to exclude None values, as this directly addresses the identified root cause of the issue.

Vote matrix · Quick signals

Works
Did the solution work? Tap to confirm.
Easy Fix
Was it a quick fix?
Time Saver
Did it save you time?
Blocking
Was it severely blocking?
Common Issue
Are others likely hitting this too?
Flaky / Intermittent
Is it intermittent?
Verified / Reproducible
Can you reproduce it reliably?
Loading…

Still need to ship something?

×6

Another batch ranked right after the header list — different links, same matching logic.

Back to top recommendations

TRENDING