You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
feat(mcp): support custom OAuth callbackRedirectURL for remote toolsets
Add an optional `callbackRedirectURL` field to the remote MCP OAuth config.
When set, it is advertised to the authorization server as the OAuth
`redirect_uri` instead of the default `http://127.0.0.1:{callbackPort}/callback`.
The literal placeholder `${callbackPort}` is substituted with the actual
port the local callback server is listening on.
This lets users put a public-facing proxy (HTTPS or pre-registered static
redirect) in front of the local loopback callback, working around auth
servers that refuse http://localhost redirect URIs. The local callback
server still listens on 127.0.0.1:{callbackPort}; only the advertised
redirect URI changes.
Validation:
- URL must be absolute (scheme + host) once ${callbackPort} is substituted.
- Scheme must be http or https; other schemes (javascript:, file:, ftp:, …) are rejected.
- http is only allowed on loopback hosts (127.0.0.1, ::1, localhost); non-loopback http would expose the authorization code on the wire (RFC 8252 §7.3).
Includes JSON schema + docs update, a runnable example, and unit tests for
validation and the pure buildRedirectURI substitution helper.
Assisted-By: docker-agent
Copy file name to clipboardExpand all lines: agent-schema.json
+4Lines changed: 4 additions & 0 deletions
Original file line number
Diff line number
Diff line change
@@ -1803,6 +1803,10 @@
1803
1803
"items": {
1804
1804
"type": "string"
1805
1805
}
1806
+
},
1807
+
"callbackRedirectURL": {
1808
+
"type": "string",
1809
+
"description": "Optional OAuth redirect URI used in place of http://127.0.0.1:{callbackPort}/callback. The literal placeholder ${callbackPort} is replaced with the actual local callback port at runtime. The external URL is expected to redirect the browser back to the local callback server."
Copy file name to clipboardExpand all lines: docs/features/remote-mcp/index.md
+31Lines changed: 31 additions & 0 deletions
Display the source diff
Display the rich diff
Original file line number
Diff line number
Diff line change
@@ -68,9 +68,40 @@ toolsets:
68
68
| `clientSecret` | string | ✗ | OAuth client secret. Omit for public clients using PKCE. |
69
69
| `callbackPort` | integer | ✗ | Local port to receive the OAuth redirect. If omitted, docker-agent picks a random free port. |
70
70
| `scopes` | array[string] | ✗ | Scopes to request during the authorization step. Values are server-specific. |
71
+
| `callbackRedirectURL` | string | ✗ | Custom OAuth redirect URI. Useful when the auth server requires HTTPS or a pre-registered URL. The literal placeholder `${callbackPort}` is replaced with the actual local callback port. See below. |
71
72
72
73
Secrets should be stored in a credential helper or environment variable rather than committed — see [Secrets]({{ '/guides/secrets/' | relative_url }}) for interpolation patterns.
73
74
75
+
### Custom redirect URI (`callbackRedirectURL`)
76
+
77
+
Some authorization servers require the OAuth `redirect_uri` to be HTTPS or to match a URL that was pre-registered during app creation — neither of which plays nicely with a locally-bound loopback address such as `http://127.0.0.1:8765/callback`.
78
+
79
+
To work around this, set `callbackRedirectURL` to a public URL that redirects back to the local callback server. The literal placeholder `${callbackPort}` is substituted with the actual port the local callback server is listening on (either `callbackPort` when set, or the randomly-assigned port otherwise).
80
+
81
+
```yaml
82
+
toolsets:
83
+
- type: mcp
84
+
remote:
85
+
url: "https://mcp.example.com/mcp"
86
+
transport_type: "streamable"
87
+
oauth:
88
+
clientId: "my-app-client-id"
89
+
callbackPort: 8765
90
+
# Advertise this URL to the authorization server. The external
91
+
# service at redirect.example.com is expected to 302-redirect the
92
+
# browser to http://127.0.0.1:8765/callback preserving the query
The local callback server still listens on the loopback interface on `callbackPort`; only the `redirect_uri` advertised to the authorization server changes.
98
+
99
+
**Validation rules:**
100
+
101
+
- The URL must be absolute (scheme + host) once `${callbackPort}` has been substituted.
102
+
- Only `http` and `https` schemes are accepted.
103
+
- `http`is only allowed when the host is a loopback address (`127.0.0.1`, `::1`, `localhost`); any other host must use `https` to avoid exposing the authorization `code` on the wire (RFC 8252 §7.3).
0 commit comments