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
8 changes: 4 additions & 4 deletions src/coding-agent.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6327,12 +6327,12 @@ 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. `/agents` (no trailing
// segment) doesn't match `app.all("/agents/*")` and returns 404 when
// the OAuth provider redirects there.
// 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.
await this.addMcpServer(name, url, {
callbackHost: this.env.WORKER_URL,
callbackPath: "/agents/oauth/callback",
callbackPath: `/agents/coding-agent/${this.name}/callback`,
});
}

Expand Down
20 changes: 14 additions & 6 deletions src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -1634,14 +1634,22 @@ app.post("/api/mcp/start-auth", async (c) => {
const callbackHost = c.env.WORKER_URL && c.env.WORKER_URL !== "http://localhost:8787"
? c.env.WORKER_URL
: inferredHost;
// callbackPath must point at a real route, not just the prefix. We
// mount `app.all("/agents/*")` (one path segment minimum). Registering
// `/agents` as the redirect_uri makes the OAuth provider redirect to a
// path that doesn't match the wildcard, and Dodo returns 404. Use a
// dedicated, stable subpath under `/agents/`.
// 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.
//
// 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`;
const result = await stub.addMcpServer(displayName, mcpUrl, {
callbackHost,
callbackPath: "/agents/oauth/callback",
callbackPath,
});
if (result.state === "authenticating") {
return c.json({ authUrl: result.authUrl });
Expand Down
Loading