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
fix(mcp): make hookdeck_login non-blocking so browser URL is shown immediately
Previously, handleLogin blocked for up to 4 minutes while polling for
the user to complete browser auth. The browser URL was only returned
in the tool result after polling finished, meaning the user never saw
it — they just saw a spinner with no way to authenticate.
Now the handler returns the browser URL immediately and polls in a
background goroutine. Subsequent calls to hookdeck_login report
"in progress" (with the URL) or the final result. Once auth completes,
the background goroutine updates the shared client and removes the
login tool.
https://claude.ai/code/session_01Y2eJZgKG78nDyN6Uw2tWQx
returnTextResult("Already authenticated. All Hookdeck tools are available."), nil
27
41
}
28
42
43
+
// If a login flow is already in progress, check its status.
44
+
ifstate!=nil {
45
+
select {
46
+
case<-state.done:
47
+
// Polling finished — check result.
48
+
ifstate.err!=nil {
49
+
errMsg:=state.err.Error()
50
+
browserURL:=state.browserURL
51
+
state=nil// allow a fresh retry
52
+
returnErrorResult(fmt.Sprintf(
53
+
"Authentication failed: %s\n\nPlease call hookdeck_login again to retry.\nThe user needs to open this URL in their browser:\n\n%s",
54
+
errMsg, browserURL,
55
+
)), nil
56
+
}
57
+
// Success was already handled by the goroutine (client.APIKey set).
58
+
returnTextResult("Already authenticated. All Hookdeck tools are available."), nil
59
+
default:
60
+
// Still polling — remind the agent about the URL.
61
+
returnTextResult(fmt.Sprintf(
62
+
"Login is already in progress. Waiting for the user to complete authentication.\n\nThe user needs to open this URL in their browser:\n\n%s\n\nCall hookdeck_login again to check status.",
63
+
state.browserURL,
64
+
)), nil
65
+
}
66
+
}
67
+
29
68
parsedBaseURL, err:=url.Parse(cfg.APIBaseURL)
30
69
iferr!=nil {
31
70
returnErrorResult(fmt.Sprintf("Invalid API base URL: %s", err)), nil
"Authentication timed out or failed: %s\n\nPlease try again by calling hookdeck_login.\nTo authenticate, the user needs to open this URL in their browser:\n\n%s",
s.err=fmt.Errorf("received invalid API key: %s", err)
104
+
s.mu.Unlock()
105
+
return
106
+
}
107
+
108
+
// Persist credentials so future MCP sessions start authenticated.
109
+
cfg.Profile.APIKey=response.APIKey
110
+
cfg.Profile.ProjectId=response.ProjectID
111
+
cfg.Profile.ProjectMode=response.ProjectMode
112
+
cfg.Profile.GuestURL=""
113
+
114
+
iferr:=cfg.Profile.SaveProfile(); err!=nil {
115
+
log.WithError(err).Error("Login succeeded but failed to save profile")
116
+
}
117
+
iferr:=cfg.Profile.UseProfile(); err!=nil {
118
+
log.WithError(err).Error("Login succeeded but failed to activate profile")
119
+
}
120
+
121
+
// Update the shared client so all resource tools start working.
122
+
client.APIKey=response.APIKey
123
+
client.ProjectID=response.ProjectID
73
124
74
-
// Update the shared client so all resource tools start working.
75
-
client.APIKey=response.APIKey
76
-
client.ProjectID=response.ProjectID
125
+
// Remove the login tool now that auth is complete.
126
+
mcpServer.RemoveTools("hookdeck_login")
77
127
78
-
// Remove the login tool now that auth is complete. This sends
79
-
// notifications/tools/list_changed to clients that support it.
80
-
mcpServer.RemoveTools("hookdeck_login")
128
+
log.WithFields(log.Fields{
129
+
"user": response.UserName,
130
+
"project": response.ProjectName,
131
+
}).Info("MCP login completed successfully")
132
+
}(state)
81
133
134
+
// Return the URL immediately so the agent can show it to the user.
82
135
returnTextResult(fmt.Sprintf(
83
-
"Successfully authenticated as %s (%s).\nActive project: %s in organization %s.\nAll Hookdeck tools are now available.",
84
-
response.UserName, response.UserEmail,
85
-
response.ProjectName, response.OrganizationName,
136
+
"Login initiated. The user must open the following URL in their browser to authenticate:\n\n%s\n\nOnce the user completes authentication in the browser, all Hookdeck tools will become available.\nCall hookdeck_login again to check if authentication has completed.",
0 commit comments