@kadoa/mcp 0.3.2 → 0.3.3-rc.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (2) hide show
  1. package/dist/index.js +455 -23
  2. package/package.json +1 -1
package/dist/index.js CHANGED
@@ -49167,6 +49167,20 @@ function errorResult(message) {
49167
49167
  isError: true
49168
49168
  };
49169
49169
  }
49170
+ function extractApiMessage(responseBody) {
49171
+ const body = responseBody;
49172
+ if (!body || typeof body !== "object")
49173
+ return;
49174
+ const msg = typeof body.error === "string" && body.error || typeof body.message === "string" && body.message || undefined;
49175
+ if (!msg)
49176
+ return;
49177
+ if (body.validationErrors && typeof body.validationErrors === "object" && body.validationErrors !== null) {
49178
+ const details = Object.entries(body.validationErrors).map(([field, err]) => `${field}: "${err}"`).join(", ");
49179
+ if (details)
49180
+ return `${msg} — Details: ${details}`;
49181
+ }
49182
+ return msg;
49183
+ }
49170
49184
  function classifyError(error48) {
49171
49185
  if (KadoaSdkException.isInstance(error48)) {
49172
49186
  const code = error48.code;
@@ -49186,9 +49200,9 @@ function classifyError(error48) {
49186
49200
  return `Request timed out${status}. Please try again.`;
49187
49201
  case "VALIDATION_ERROR":
49188
49202
  case "BAD_REQUEST":
49189
- return httpError.message;
49203
+ return extractApiMessage(httpError.responseBody) || httpError.message;
49190
49204
  default:
49191
- return `Kadoa API error${status}. Please try again later.`;
49205
+ return extractApiMessage(httpError.responseBody) || `Kadoa API error${status}. Please try again later.`;
49192
49206
  }
49193
49207
  }
49194
49208
  switch (code) {
@@ -53676,14 +53690,139 @@ class KadoaOAuthProvider {
53676
53690
  params,
53677
53691
  supabaseCodeVerifier: verifier
53678
53692
  });
53693
+ res.type("html").send(renderLoginPage(state));
53694
+ }
53695
+ async handleGoogleLogin(req, res) {
53696
+ const { state } = req.body;
53697
+ const pending = pendingAuths.get(state);
53698
+ if (!pending) {
53699
+ res.status(400).send("Unknown or expired state parameter");
53700
+ return;
53701
+ }
53702
+ const supabaseUrl = process.env.SUPABASE_URL;
53703
+ const serverUrl = process.env.MCP_SERVER_URL;
53704
+ if (!supabaseUrl || !serverUrl) {
53705
+ res.status(500).send("Server misconfigured");
53706
+ return;
53707
+ }
53679
53708
  const redirectTo = `${serverUrl}/auth/callback?mcp_state=${state}`;
53680
53709
  const authUrl = new URL(`${supabaseUrl}/auth/v1/authorize`);
53681
53710
  authUrl.searchParams.set("provider", "google");
53682
53711
  authUrl.searchParams.set("redirect_to", redirectTo);
53683
- authUrl.searchParams.set("code_challenge", challenge);
53712
+ authUrl.searchParams.set("code_challenge", pending.supabaseCodeVerifier ? createHash2("sha256").update(pending.supabaseCodeVerifier).digest("base64url") : "");
53684
53713
  authUrl.searchParams.set("code_challenge_method", "S256");
53685
53714
  res.redirect(authUrl.toString());
53686
53715
  }
53716
+ async handleEmailPasswordLogin(req, res) {
53717
+ const { state, email: email3, password } = req.body;
53718
+ if (!state || !email3 || !password) {
53719
+ res.status(400).send("Missing required fields");
53720
+ return;
53721
+ }
53722
+ const pending = pendingAuths.get(state);
53723
+ if (!pending) {
53724
+ res.status(400).type("html").send(renderLoginPage(state, "Session expired — please try again"));
53725
+ return;
53726
+ }
53727
+ const supabaseUrl = process.env.SUPABASE_URL;
53728
+ if (!supabaseUrl) {
53729
+ res.status(500).send("Server misconfigured");
53730
+ return;
53731
+ }
53732
+ try {
53733
+ const tokenRes = await fetch(`${supabaseUrl}/auth/v1/token?grant_type=password`, {
53734
+ method: "POST",
53735
+ headers: {
53736
+ "Content-Type": "application/json",
53737
+ apikey: process.env.SUPABASE_ANON_KEY
53738
+ },
53739
+ body: JSON.stringify({ email: email3, password })
53740
+ });
53741
+ if (!tokenRes.ok) {
53742
+ const body = await tokenRes.json().catch(() => ({ error_description: "Authentication failed" }));
53743
+ const message = body.error_description || body.msg || "Invalid email or password";
53744
+ res.type("html").send(renderLoginPage(state, message));
53745
+ return;
53746
+ }
53747
+ const data = await tokenRes.json();
53748
+ pendingAuths.delete(state);
53749
+ await this.completeAuthWithTokens(pending, res, data.access_token, data.refresh_token);
53750
+ } catch (error48) {
53751
+ console.error("Email/password login error:", error48);
53752
+ res.type("html").send(renderLoginPage(state, "An unexpected error occurred"));
53753
+ }
53754
+ }
53755
+ async handleSSOLogin(req, res) {
53756
+ const { state, email: email3 } = req.body;
53757
+ if (!state || !email3) {
53758
+ res.status(400).send("Missing required fields");
53759
+ return;
53760
+ }
53761
+ const pending = pendingAuths.get(state);
53762
+ if (!pending) {
53763
+ res.status(400).type("html").send(renderLoginPage(state, "Session expired — please try again"));
53764
+ return;
53765
+ }
53766
+ const supabaseUrl = process.env.SUPABASE_URL;
53767
+ const serverUrl = process.env.MCP_SERVER_URL;
53768
+ if (!supabaseUrl || !serverUrl) {
53769
+ res.status(500).send("Server misconfigured");
53770
+ return;
53771
+ }
53772
+ const domain2 = email3.includes("@") ? email3.split("@").pop() : email3;
53773
+ try {
53774
+ const ssoRes = await fetch(`${supabaseUrl}/auth/v1/sso`, {
53775
+ method: "POST",
53776
+ headers: {
53777
+ "Content-Type": "application/json",
53778
+ apikey: process.env.SUPABASE_ANON_KEY
53779
+ },
53780
+ body: JSON.stringify({
53781
+ domain: domain2,
53782
+ redirect_to: `${serverUrl}/auth/callback?mcp_state=${state}`,
53783
+ skip_http_redirect: true,
53784
+ code_challenge: createHash2("sha256").update(pending.supabaseCodeVerifier).digest("base64url"),
53785
+ code_challenge_method: "s256"
53786
+ })
53787
+ });
53788
+ if (!ssoRes.ok) {
53789
+ const body = await ssoRes.json().catch(() => ({}));
53790
+ const message = body.error_description || body.msg || body.message || "No SSO provider configured for this domain";
53791
+ res.type("html").send(renderLoginPage(state, message));
53792
+ return;
53793
+ }
53794
+ const data = await ssoRes.json();
53795
+ if (!data.url) {
53796
+ res.type("html").send(renderLoginPage(state, "No SSO provider configured for this domain"));
53797
+ return;
53798
+ }
53799
+ res.redirect(data.url);
53800
+ } catch (error48) {
53801
+ console.error("SSO login error:", error48);
53802
+ res.type("html").send(renderLoginPage(state, "An unexpected error occurred"));
53803
+ }
53804
+ }
53805
+ async completeAuthWithTokens(pending, res, supabaseJwt, supabaseRefreshToken) {
53806
+ const teams = await fetchUserTeams(supabaseJwt);
53807
+ if (teams.length === 1) {
53808
+ const refreshed = await setActiveTeamAndRefresh(supabaseJwt, supabaseRefreshToken, teams[0].id);
53809
+ this.completeAuthFlow(pending, res, {
53810
+ jwt: refreshed.jwt,
53811
+ refreshToken: refreshed.refreshToken,
53812
+ teamId: teams[0].id
53813
+ });
53814
+ return;
53815
+ }
53816
+ const selectionToken = randomToken();
53817
+ pendingTeamSelections.set(selectionToken, {
53818
+ supabaseJwt,
53819
+ supabaseRefreshToken,
53820
+ teams,
53821
+ pending,
53822
+ expiresAt: Date.now() + TEAM_SELECTION_TTL
53823
+ });
53824
+ res.type("html").send(renderTeamSelectionPage(teams, selectionToken));
53825
+ }
53687
53826
  async challengeForAuthorizationCode(_client, authorizationCode) {
53688
53827
  const entry = authCodes.get(authorizationCode);
53689
53828
  if (!entry)
@@ -53815,26 +53954,7 @@ class KadoaOAuthProvider {
53815
53954
  pendingAuths.delete(state);
53816
53955
  try {
53817
53956
  const supabaseTokens = await exchangeSupabaseCode(code, pending.supabaseCodeVerifier);
53818
- const supabaseJwt = supabaseTokens.accessToken;
53819
- const teams = await fetchUserTeams(supabaseJwt);
53820
- if (teams.length === 1) {
53821
- const refreshed = await setActiveTeamAndRefresh(supabaseJwt, supabaseTokens.refreshToken, teams[0].id);
53822
- this.completeAuthFlow(pending, res, {
53823
- jwt: refreshed.jwt,
53824
- refreshToken: refreshed.refreshToken,
53825
- teamId: teams[0].id
53826
- });
53827
- return;
53828
- }
53829
- const selectionToken = randomToken();
53830
- pendingTeamSelections.set(selectionToken, {
53831
- supabaseJwt,
53832
- supabaseRefreshToken: supabaseTokens.refreshToken,
53833
- teams,
53834
- pending,
53835
- expiresAt: Date.now() + TEAM_SELECTION_TTL
53836
- });
53837
- res.type("html").send(renderTeamSelectionPage(teams, selectionToken));
53957
+ await this.completeAuthWithTokens(pending, res, supabaseTokens.accessToken, supabaseTokens.refreshToken);
53838
53958
  } catch (error48) {
53839
53959
  console.error("Auth callback error:", error48);
53840
53960
  const redirectUrl = new URL(pending.params.redirectUri);
@@ -54017,6 +54137,309 @@ function renderTeamSelectionPage(teams, selectionToken) {
54017
54137
  </body>
54018
54138
  </html>`;
54019
54139
  }
54140
+ function renderLoginPage(state, error48) {
54141
+ const errorHtml = error48 ? `<div class="error">${escapeHtml(error48)}</div>` : "";
54142
+ return `<!DOCTYPE html>
54143
+ <html lang="en">
54144
+ <head>
54145
+ <meta charset="utf-8" />
54146
+ <meta name="viewport" content="width=device-width, initial-scale=1" />
54147
+ <title>Sign In - Kadoa</title>
54148
+ <style>
54149
+ * { margin: 0; padding: 0; box-sizing: border-box; }
54150
+
54151
+ body {
54152
+ font-family: ui-sans-serif, system-ui, -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, sans-serif;
54153
+ background: hsl(0 0% 98%);
54154
+ color: #18181b;
54155
+ min-height: 100dvh;
54156
+ display: flex;
54157
+ align-items: center;
54158
+ justify-content: center;
54159
+ background-image: radial-gradient(circle, #d4d4d8 1px, transparent 1px);
54160
+ background-size: 24px 24px;
54161
+ background-position: center top;
54162
+ }
54163
+
54164
+ .card {
54165
+ width: 100%;
54166
+ max-width: 460px;
54167
+ background: #fff;
54168
+ padding: 1rem;
54169
+ display: flex;
54170
+ flex-direction: column;
54171
+ gap: 1rem;
54172
+ min-height: 100dvh;
54173
+ }
54174
+
54175
+ @media (min-width: 768px) {
54176
+ .card { padding: 3rem; min-height: auto; border-left: 1px solid #e0e1e5; border-right: 1px solid #e0e1e5; }
54177
+ }
54178
+
54179
+ .logo { display: grid; place-content: center; }
54180
+
54181
+ h1 {
54182
+ font-size: 20px;
54183
+ font-weight: 600;
54184
+ text-align: center;
54185
+ color: #18181b;
54186
+ }
54187
+
54188
+ .spacer { height: 0; }
54189
+ @media (min-width: 768px) { .spacer { height: 3rem; } }
54190
+
54191
+ .error {
54192
+ background: #fef2f2;
54193
+ color: #991b1b;
54194
+ border: 1px solid #fecaca;
54195
+ border-radius: 4px;
54196
+ padding: 0.6rem 0.875rem;
54197
+ font-size: 15px;
54198
+ }
54199
+
54200
+ /* Buttons — matching KUI default + primary looks */
54201
+ .btn {
54202
+ width: 100%;
54203
+ padding: 0.6em 1em;
54204
+ border-radius: 4px;
54205
+ font-size: 16px;
54206
+ font-weight: 500;
54207
+ cursor: pointer;
54208
+ display: flex;
54209
+ align-items: center;
54210
+ justify-content: center;
54211
+ gap: 0.5rem;
54212
+ transition: background 0.15s, border-color 0.15s;
54213
+ text-decoration: none;
54214
+ }
54215
+
54216
+ .btn-default {
54217
+ background: #fff;
54218
+ color: #18181b;
54219
+ border: 1px solid #d4d4d8;
54220
+ box-shadow: inset 0 -3px 0 0 rgba(0,0,0,0.03), 0 1px 0px 1px rgba(255,255,255,0.5), 0 -1px 0px 1px rgba(0,0,0,0.02);
54221
+ }
54222
+
54223
+ .btn-default:hover {
54224
+ background: rgba(113,113,122,0.1);
54225
+ }
54226
+
54227
+ .btn-primary {
54228
+ background: hsl(212 70% 27%);
54229
+ color: #fff;
54230
+ border: 1px solid hsl(214 70% 23%);
54231
+ box-shadow: inset 0 2px 0 0 rgba(56,189,248,0.2), 0 -1px 0px 1px rgba(0,0,0,0.02);
54232
+ }
54233
+
54234
+ .btn-primary:hover {
54235
+ background: hsl(212 70% 33%);
54236
+ }
54237
+
54238
+ /* OR divider */
54239
+ .line-or {
54240
+ display: flex;
54241
+ align-items: center;
54242
+ gap: 0.5rem;
54243
+ font-weight: 500;
54244
+ color: rgba(24,24,27,0.6);
54245
+ font-size: 14px;
54246
+ margin: 0.5rem 0;
54247
+ }
54248
+
54249
+ .line-or hr {
54250
+ flex: 1;
54251
+ border: none;
54252
+ border-top: 1px solid rgba(113,113,122,0.15);
54253
+ }
54254
+
54255
+ /* Form inputs — matching KUI input style */
54256
+ label {
54257
+ display: block;
54258
+ font-size: 16px;
54259
+ font-weight: 500;
54260
+ margin-bottom: 0.25rem;
54261
+ color: #18181b;
54262
+ }
54263
+
54264
+ input[type="email"], input[type="password"] {
54265
+ width: 100%;
54266
+ padding: 0.35em 0.5em;
54267
+ border: 1px solid #d4d4d8;
54268
+ border-radius: 4px;
54269
+ font-size: 18px;
54270
+ font-family: inherit;
54271
+ color: #18181b;
54272
+ background: #fff;
54273
+ outline: none;
54274
+ box-shadow: inset 0 3px 0 0 rgba(0,0,0,0.025);
54275
+ transition: border-color 0.15s;
54276
+ caret-color: hsl(25 98% 53%);
54277
+ }
54278
+
54279
+ input[type="email"]:hover, input[type="password"]:hover {
54280
+ border-color: hsl(31 99% 72%);
54281
+ }
54282
+
54283
+ input[type="email"]:focus, input[type="password"]:focus {
54284
+ border-color: hsl(25 98% 53%);
54285
+ box-shadow: inset 0 3px 0 0 rgba(0,0,0,0.025), 0 0 0 2px rgba(249,115,22,0.2);
54286
+ }
54287
+
54288
+ .field { margin-bottom: 0.75rem; }
54289
+
54290
+ hr.separator {
54291
+ border: none;
54292
+ border-top: 1px solid rgba(113,113,122,0.15);
54293
+ margin: 0.5rem 0;
54294
+ }
54295
+
54296
+ .google-icon { width: 18px; height: 18px; }
54297
+ .key-icon { width: 16px; height: 16px; }
54298
+
54299
+ /* Tabs for email/SSO — keep simple, same visual weight */
54300
+ .tabs {
54301
+ display: none;
54302
+ }
54303
+
54304
+ .tab-content { display: none; }
54305
+ .tab-content.active { display: block; }
54306
+
54307
+ .tab-switch {
54308
+ text-align: center;
54309
+ margin-top: 0.25rem;
54310
+ }
54311
+
54312
+ .tab-switch a {
54313
+ font-size: 15px;
54314
+ color: #18181b;
54315
+ text-decoration: underline;
54316
+ text-decoration-color: rgba(251,146,60,0.5);
54317
+ text-underline-offset: 2px;
54318
+ cursor: pointer;
54319
+ }
54320
+
54321
+ .tab-switch a:hover {
54322
+ background: rgba(251,146,60,0.1);
54323
+ border-radius: 2px;
54324
+ }
54325
+ </style>
54326
+ </head>
54327
+ <body>
54328
+ <div class="card">
54329
+ <!-- Logo {k} -->
54330
+ <div class="logo">
54331
+ <svg width="40" height="40" viewBox="0 0 40 40" fill="none" xmlns="http://www.w3.org/2000/svg">
54332
+ <path opacity="0.15" d="M25.3196 6.25H14.6804C14.6804 7.49264 13.6596 8.5 12.4005 8.5C11.3808 8.5 10.8312 8.67478 10.5466 8.82497C10.3001 8.95506 10.147 9.11941 10.0189 9.38005C9.85482 9.7141 9.74438 10.1712 9.68281 10.8152C9.62136 11.458 9.61405 12.2133 9.61405 13.125L9.61416 13.3731C9.61532 14.9118 9.61694 17.0733 8.75235 18.8332C8.55109 19.2428 8.30266 19.6357 8 20C8.30266 20.3643 8.55109 20.7572 8.75235 21.1668C9.61694 22.9267 9.61532 25.0882 9.61416 26.6269L9.61405 26.875C9.61405 27.7867 9.62136 28.542 9.68281 29.1848C9.74438 29.8288 9.85482 30.2859 10.0189 30.6199C10.147 30.8806 10.3001 31.0449 10.5466 31.175C10.8312 31.3252 11.3808 31.5 12.4005 31.5C13.6596 31.5 14.6804 32.5074 14.6804 33.75H25.3196C25.3196 32.5074 26.3404 31.5 27.5995 31.5C28.6192 31.5 29.1688 31.3252 29.4534 31.175C29.6999 31.0449 29.853 30.8806 29.9811 30.6199C30.1452 30.2859 30.2556 29.8288 30.3172 29.1848C30.3786 28.542 30.386 27.7867 30.386 26.875L30.3858 26.6269C30.3847 25.0882 30.3831 22.9267 31.2477 21.1668C31.4489 20.7572 31.6973 20.3643 32 20C31.6973 19.6357 31.4489 19.2428 31.2477 18.8332C30.3831 17.0733 30.3847 14.9118 30.3858 13.3731L30.386 13.125C30.386 12.2133 30.3786 11.458 30.3172 10.8152C30.2556 10.1712 30.1452 9.7141 29.9811 9.38005C29.853 9.11941 29.6999 8.95506 29.4534 8.82497C29.1688 8.67478 28.6192 8.5 27.5995 8.5C26.3404 8.5 25.3196 7.49264 25.3196 6.25Z" fill="#fd7412"/>
54333
+ <path d="M12.5 6.25C2.5 6.25 12.5 20 2.5 20C12.5 20 2.5 33.75 12.5 33.75" stroke="#fd7412" stroke-linecap="round" stroke-linejoin="round" stroke-width="1.8"/>
54334
+ <path d="M16 10V29" stroke="#18181B" stroke-linecap="round" stroke-linejoin="round" stroke-width="1.8"/>
54335
+ <path d="M27.5 6.25C37.5 6.25 27.5 20 37.5 20C27.5 20 37.5 33.75 27.5 33.75" stroke="#fd7412" stroke-linecap="round" stroke-linejoin="round" stroke-width="1.8"/>
54336
+ <path d="M16 23L25 18" stroke="#18181B" stroke-linecap="round" stroke-linejoin="round" stroke-width="1.8"/>
54337
+ <path d="M25 29L16 23" stroke="#18181B" stroke-linecap="round" stroke-linejoin="round" stroke-width="1.8"/>
54338
+ </svg>
54339
+ </div>
54340
+
54341
+ <!-- Heading -->
54342
+ <h1>Sign in to Kadoa</h1>
54343
+
54344
+ <div class="spacer"></div>
54345
+
54346
+ ${errorHtml}
54347
+
54348
+ <!-- Continue with Google -->
54349
+ <form method="POST" action="/auth/google">
54350
+ <input type="hidden" name="state" value="${escapeHtml(state)}" />
54351
+ <button type="submit" class="btn btn-default">
54352
+ <svg class="google-icon" viewBox="0 0 24 24" xmlns="http://www.w3.org/2000/svg">
54353
+ <path d="M22.56 12.25c0-.78-.07-1.53-.2-2.25H12v4.26h5.92a5.06 5.06 0 0 1-2.2 3.32v2.77h3.57c2.08-1.92 3.28-4.74 3.28-8.1z" fill="#4285F4"/>
54354
+ <path d="M12 23c2.97 0 5.46-.98 7.28-2.66l-3.57-2.77c-.98.66-2.23 1.06-3.71 1.06-2.86 0-5.29-1.93-6.16-4.53H2.18v2.84C3.99 20.53 7.7 23 12 23z" fill="#34A853"/>
54355
+ <path d="M5.84 14.09c-.22-.66-.35-1.36-.35-2.09s.13-1.43.35-2.09V7.07H2.18C1.43 8.55 1 10.22 1 12s.43 3.45 1.18 4.93l2.85-2.22.81-.62z" fill="#FBBC05"/>
54356
+ <path d="M12 5.38c1.62 0 3.06.56 4.21 1.64l3.15-3.15C17.45 2.09 14.97 1 12 1 7.7 1 3.99 3.47 2.18 7.07l3.66 2.84c.87-2.6 3.3-4.53 6.16-4.53z" fill="#EA4335"/>
54357
+ </svg>
54358
+ Continue with Google
54359
+ </button>
54360
+ </form>
54361
+
54362
+ <!-- Continue with SSO -->
54363
+ <div id="sso-button-wrapper">
54364
+ <form method="POST" action="/auth/sso" id="sso-direct-form" style="display:none">
54365
+ <input type="hidden" name="state" value="${escapeHtml(state)}" />
54366
+ <input type="hidden" name="email" id="sso-email-hidden" />
54367
+ </form>
54368
+ <button type="button" class="btn btn-default" id="sso-toggle-btn">
54369
+ <svg class="key-icon" viewBox="0 0 16 16" fill="none" xmlns="http://www.w3.org/2000/svg">
54370
+ <path d="M10 1a5 5 0 0 0-4.546 7.066l-4.161 4.16a.5.5 0 0 0-.146.354V14.5a.5.5 0 0 0 .5.5h2a.5.5 0 0 0 .5-.5V14h1a.5.5 0 0 0 .5-.5v-1h1a.5.5 0 0 0 .354-.146l.94-.94A5 5 0 1 0 10 1zm1.5 4a1.5 1.5 0 1 1 0-3 1.5 1.5 0 0 1 0 3z" fill="currentColor"/>
54371
+ </svg>
54372
+ Continue with SSO
54373
+ </button>
54374
+ </div>
54375
+
54376
+ <!-- OR divider -->
54377
+ <div class="line-or">
54378
+ <hr />
54379
+ OR
54380
+ <hr />
54381
+ </div>
54382
+
54383
+ <!-- Email + Password form -->
54384
+ <div class="tab-content active" id="tab-email">
54385
+ <form method="POST" action="/auth/login">
54386
+ <input type="hidden" name="state" value="${escapeHtml(state)}" />
54387
+ <div class="field">
54388
+ <label for="email">Sign in with email:</label>
54389
+ <input type="email" id="email" name="email" required autocomplete="email" />
54390
+ </div>
54391
+ <div class="field">
54392
+ <label for="password">Your password:</label>
54393
+ <input type="password" id="password" name="password" required autocomplete="current-password" />
54394
+ </div>
54395
+ <button type="submit" class="btn btn-primary">Continue</button>
54396
+ </form>
54397
+ </div>
54398
+
54399
+ <!-- SSO form (shown when "Continue with SSO" is clicked) -->
54400
+ <div class="tab-content" id="tab-sso">
54401
+ <form method="POST" action="/auth/sso">
54402
+ <input type="hidden" name="state" value="${escapeHtml(state)}" />
54403
+ <div class="field">
54404
+ <label for="sso-email">Work email:</label>
54405
+ <input type="email" id="sso-email" name="email" required autocomplete="email" />
54406
+ </div>
54407
+ <button type="submit" class="btn btn-primary">Continue with SSO</button>
54408
+ </form>
54409
+ <div class="tab-switch">
54410
+ <a id="back-to-email">Sign in with email instead</a>
54411
+ </div>
54412
+ </div>
54413
+
54414
+ <div style="flex:1"></div>
54415
+
54416
+ <script>
54417
+ var ssoBtn = document.getElementById('sso-toggle-btn');
54418
+ var tabEmail = document.getElementById('tab-email');
54419
+ var tabSso = document.getElementById('tab-sso');
54420
+ var ssoWrapper = document.getElementById('sso-button-wrapper');
54421
+ var lineOr = document.querySelector('.line-or');
54422
+ var backLink = document.getElementById('back-to-email');
54423
+
54424
+ ssoBtn.addEventListener('click', function() {
54425
+ tabEmail.classList.remove('active');
54426
+ tabSso.classList.add('active');
54427
+ ssoWrapper.style.display = 'none';
54428
+ lineOr.style.display = 'none';
54429
+ document.getElementById('sso-email').focus();
54430
+ });
54431
+
54432
+ backLink.addEventListener('click', function() {
54433
+ tabSso.classList.remove('active');
54434
+ tabEmail.classList.add('active');
54435
+ ssoWrapper.style.display = '';
54436
+ lineOr.style.display = '';
54437
+ });
54438
+ </script>
54439
+ </div>
54440
+ </body>
54441
+ </html>`;
54442
+ }
54020
54443
  function escapeHtml(str) {
54021
54444
  return str.replace(/&/g, "&amp;").replace(/</g, "&lt;").replace(/>/g, "&gt;").replace(/"/g, "&quot;").replace(/'/g, "&#39;");
54022
54445
  }
@@ -54098,6 +54521,15 @@ async function startHttpServer() {
54098
54521
  app.get("/auth/callback", (req, res) => {
54099
54522
  provider.handleAuthCallback(req, res);
54100
54523
  });
54524
+ app.post("/auth/google", express8.urlencoded({ extended: false }), (req, res) => {
54525
+ provider.handleGoogleLogin(req, res);
54526
+ });
54527
+ app.post("/auth/login", express8.urlencoded({ extended: false }), (req, res) => {
54528
+ provider.handleEmailPasswordLogin(req, res);
54529
+ });
54530
+ app.post("/auth/sso", express8.urlencoded({ extended: false }), (req, res) => {
54531
+ provider.handleSSOLogin(req, res);
54532
+ });
54101
54533
  app.post("/team-select", express8.urlencoded({ extended: false }), (req, res) => {
54102
54534
  provider.handleTeamSelection(req, res);
54103
54535
  });
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@kadoa/mcp",
3
- "version": "0.3.2",
3
+ "version": "0.3.3-rc.1",
4
4
  "description": "Kadoa MCP Server — manage workflows from Claude Desktop, Cursor, and other MCP clients",
5
5
  "type": "module",
6
6
  "main": "dist/index.js",