Skip to content

Commit 09e5cf2

Browse files
waleedlatif1claude
andcommitted
fix(mcp): preserve authType on URL-unchanged upserts; fallback serverId on tool reauth errors
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
1 parent 3ea52c9 commit 09e5cf2

2 files changed

Lines changed: 34 additions & 21 deletions

File tree

apps/sim/app/api/mcp/servers/route.ts

Lines changed: 27 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -112,21 +112,6 @@ export const POST = withRouteHandler(
112112

113113
const serverId = body.url ? generateMcpServerId(workspaceId, body.url) : generateId()
114114

115-
let resolvedAuthType: 'none' | 'headers' | 'oauth' = body.authType ?? 'headers'
116-
const hasHeaders = body.headers && Object.keys(body.headers).length > 0
117-
if (!body.authType && body.url && !hasHeaders) {
118-
try {
119-
resolvedAuthType = await detectMcpAuthType(body.url)
120-
logger.info(`[${requestId}] Probed ${body.url}: authType=${resolvedAuthType}`)
121-
} catch (e) {
122-
logger.warn(`[${requestId}] Probe failed for ${body.url}, defaulting to headers`, e)
123-
resolvedAuthType = 'headers'
124-
}
125-
}
126-
127-
// User-supplied client credentials imply OAuth; pin authType regardless of probe.
128-
if (body.oauthClientId) resolvedAuthType = 'oauth'
129-
130115
const oauthClientSecretProvided = body.oauthClientSecret !== undefined
131116
const oauthClientSecretEncrypted = body.oauthClientSecret
132117
? (await encryptSecret(body.oauthClientSecret)).encrypted
@@ -139,19 +124,45 @@ export const POST = withRouteHandler(
139124
id: mcpServers.id,
140125
deletedAt: mcpServers.deletedAt,
141126
url: mcpServers.url,
127+
authType: mcpServers.authType,
142128
oauthClientId: mcpServers.oauthClientId,
143129
oauthClientSecret: mcpServers.oauthClientSecret,
144130
})
145131
.from(mcpServers)
146132
.where(and(eq(mcpServers.id, serverId), eq(mcpServers.workspaceId, workspaceId)))
147133
.limit(1)
148134

135+
const urlChanged = existingServer ? existingServer.url !== body.url : true
136+
const hasHeaders = body.headers && Object.keys(body.headers).length > 0
137+
138+
let resolvedAuthType: 'none' | 'headers' | 'oauth' = body.authType ?? 'headers'
139+
if (!body.authType) {
140+
if (existingServer && !urlChanged) {
141+
// Preserve existing authType on edits that don't change the URL — re-probing
142+
// can flip a working OAuth+DCR server to 'headers' on a transient 401/timeout.
143+
resolvedAuthType = (existingServer.authType ?? 'headers') as
144+
| 'none'
145+
| 'headers'
146+
| 'oauth'
147+
} else if (body.url && !hasHeaders) {
148+
try {
149+
resolvedAuthType = await detectMcpAuthType(body.url)
150+
logger.info(`[${requestId}] Probed ${body.url}: authType=${resolvedAuthType}`)
151+
} catch (e) {
152+
logger.warn(`[${requestId}] Probe failed for ${body.url}, defaulting to headers`, e)
153+
resolvedAuthType = 'headers'
154+
}
155+
}
156+
}
157+
158+
// User-supplied client credentials imply OAuth; pin authType regardless of probe.
159+
if (body.oauthClientId) resolvedAuthType = 'oauth'
160+
149161
if (existingServer) {
150162
logger.info(
151163
`[${requestId}] Server with ID ${serverId} already exists, updating instead of creating`
152164
)
153165

154-
const urlChanged = existingServer.url !== body.url
155166
const clientIdChanged =
156167
oauthClientIdProvided &&
157168
(oauthClientId || null) !== (existingServer.oauthClientId ?? null)

apps/sim/app/api/mcp/tools/execute/route.ts

Lines changed: 7 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -51,6 +51,7 @@ function hasType(prop: unknown): prop is SchemaProperty {
5151
*/
5252
export const POST = withRouteHandler(
5353
withMcpAuth('read')(async (request: NextRequest, { userId, workspaceId, requestId }) => {
54+
let serverId: string | undefined
5455
try {
5556
const rawBody = getParsedBody(request) ?? (await request.json())
5657
const parsedBody = mcpToolExecutionBodySchema.safeParse(rawBody)
@@ -71,7 +72,8 @@ export const POST = withRouteHandler(
7172
userId: userId,
7273
})
7374

74-
const { serverId, toolName, arguments: rawArgs } = body
75+
const { toolName, arguments: rawArgs } = body
76+
serverId = body.serverId
7577
const args = rawArgs || {}
7678

7779
try {
@@ -237,17 +239,17 @@ export const POST = withRouteHandler(
237239
error instanceof McpOauthRedirectRequired ||
238240
error instanceof UnauthorizedError
239241
) {
240-
const serverId =
241-
error instanceof McpOauthAuthorizationRequiredError ? error.serverId : undefined
242+
const errorServerId =
243+
error instanceof McpOauthAuthorizationRequiredError ? error.serverId : serverId
242244
logger.warn(`[${requestId}] OAuth re-authorization required for MCP tool execution`, {
243-
serverId,
245+
serverId: errorServerId,
244246
})
245247
return NextResponse.json(
246248
{
247249
success: false,
248250
error: 'OAuth re-authorization required',
249251
code: 'reauth_required',
250-
serverId,
252+
serverId: errorServerId,
251253
},
252254
{ status: 401 }
253255
)

0 commit comments

Comments
 (0)