Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
10 changes: 6 additions & 4 deletions src/coding-agent.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6327,12 +6327,14 @@ export class CodingAgent extends Think<Env, DodoConfig> {
const url = server.server_url;
const name = server.name ?? new URL(url).host;
await this.removeMcpServer(mcpId);
// Mirror the /api/mcp/start-auth callback path shape (Seal pattern):
// /agents/<kebab-class>/<instance-name>/callback. cf-portal rejects
// redirect URIs that don't follow this OAuth-callback shape.
// Mirror the /api/mcp/start-auth callback path shape.
// Use the UserControl DO ID hex (not email) to avoid URL-encoding
// mismatches when the OAuth client sends the redirect_uri as a query
// parameter — see the long comment in /api/mcp/start-auth.
const userId = this.env.USER_CONTROL.idFromName(this.name).toString();
await this.addMcpServer(name, url, {
callbackHost: this.env.WORKER_URL,
callbackPath: `/agents/coding-agent/${this.name}/callback`,
callbackPath: `/agents/coding-agent/${userId}/callback`,
});
}

Expand Down
24 changes: 14 additions & 10 deletions src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -1636,17 +1636,21 @@ app.post("/api/mcp/start-auth", async (c) => {
: inferredHost;
// callbackPath follows the Agents-SDK convention used by Seal et al:
// `/agents/<kebab-class-name>/<instance-name>/callback`. The trailing
// /callback segment matters — some OAuth providers (cf-portal in
// particular) reject redirect URIs that don't end in a recognised
// OAuth-callback suffix with "Redirect URI not allowed by application
// configuration". Using the SDK's canonical shape also keeps us
// compatible with `/agents/*` routing on the way back.
// /callback segment matters — some OAuth providers reject redirect
// URIs that don't end in a recognised OAuth-callback suffix.
//
// userEmail is already canonicalized (lowercased + trimmed) by the
// auth middleware so it's safe to embed in a URL path. Edge case:
// emails contain `@` and `.` which are valid in URL path segments
// per RFC 3986 — no encoding needed and no provider rejects them.
const callbackPath = `/agents/coding-agent/${userEmail}/callback`;
// Use the user's UserControl DO ID hex (not the email) as the
// instance segment. The `@` and `.` in an email — even though they
// are valid URL path characters per RFC 3986 — get URL-encoded by
// the OAuth client (`@` → `%40`) when included in the authorize
// request's redirect_uri query param. cf-portal's authorize endpoint
// appears to do a strict string comparison against the as-registered
// URI, so the encoded vs decoded forms don't match and the request
// is rejected with "Redirect URI not allowed by application
// configuration". Using a hex-only segment side-steps the encoding
// mismatch entirely.
const userId = c.env.USER_CONTROL.idFromName(userEmail).toString();
const callbackPath = `/agents/coding-agent/${userId}/callback`;
const result = await stub.addMcpServer(displayName, mcpUrl, {
callbackHost,
callbackPath,
Expand Down
Loading