mcp-google-multi 6.0.0-alpha.37 → 6.0.0-alpha.38

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.
package/dist/doctor.js CHANGED
@@ -7,6 +7,7 @@ import { peekMasterKeyProvenance, deleteMasterKeyMaterial } from './master-key.j
7
7
  import { hasToken } from './token-store.js';
8
8
  import { configDir, loadConfigFile } from './config-file.js';
9
9
  import { envValueSource } from './env-load.js';
10
+ import { reauthHint } from './reauth-hint.js';
10
11
  import { describeMetricsDir, resolveUsageMetrics, sourceLabel } from './usage-metrics.js';
11
12
  import { probeApiEnablement } from './api-probe.js';
12
13
  import { safeMessage, stringifyEnvelope } from './tools/_errors.js';
@@ -181,7 +182,7 @@ function sectionsTokensAndScopes(deps, aliases) {
181
182
  if (scopeVerdict === 'ok')
182
183
  scopeVerdict = 'warn';
183
184
  scopeLines.push(`${alias}: ${r.callable.length} callable, ${r.requestable.length} requested-not-granted`);
184
- scopeHint = `Re-auth to grant missing scopes: \`npx mcp-google-multi auth --account ${alias}\`.`;
185
+ scopeHint = `Re-auth to grant missing scopes. ${reauthHint(alias)}`;
185
186
  }
186
187
  else {
187
188
  scopeLines.push(`${alias}: ${r.callable.length} callable, all profile scopes granted`);
@@ -4,6 +4,7 @@ import type { HttpConfig } from './http-config.js';
4
4
  import { type ArgShape, type StrictArgOptions, type ValidationEnvelopeOptions } from './arg-normalize.js';
5
5
  export type AuthOutcome = {
6
6
  ok: true;
7
+ sub?: string;
7
8
  } | {
8
9
  ok: false;
9
10
  status: number;
@@ -149,6 +149,15 @@ export class HttpTransportHost {
149
149
  this.log(`${auth.status} auth_failed path=/mcp`);
150
150
  return;
151
151
  }
152
+ // Thread the verified subject to tool handlers: the Node transport forwards
153
+ // req.auth verbatim as ctx.http.authInfo. Token/clientId stay empty — the
154
+ // bearer value must not re-enter the dispatch path via handler context.
155
+ req.auth = {
156
+ token: '',
157
+ clientId: '',
158
+ scopes: ['mcp:use'],
159
+ extra: { sub: auth.sub ?? 'owner' },
160
+ };
152
161
  let body;
153
162
  try {
154
163
  body = await this.readJson(req);
package/dist/oauth-as.js CHANGED
@@ -385,8 +385,8 @@ export function buildAuthServer(config, deps = {}) {
385
385
  if (!form.code_verifier || pkceS256(form.code_verifier) !== code.code_challenge) {
386
386
  return json(res, 400, { error: 'invalid_grant', message: 'PKCE verification failed' });
387
387
  }
388
- const access = await signAccessToken({ base, secret, iat: nowSec(), ttlSec: accessTtl, sub: 'owner' });
389
- const refreshToken = refresh.issue(now(), 'owner');
388
+ const access = await signAccessToken({ base, secret, iat: nowSec(), ttlSec: accessTtl, sub: code.sub });
389
+ const refreshToken = refresh.issue(now(), code.sub);
390
390
  log('token issued grant=authorization_code');
391
391
  return json(res, 200, { access_token: access, token_type: 'Bearer', expires_in: accessTtl, refresh_token: refreshToken, scope: 'mcp:use' });
392
392
  }
@@ -394,7 +394,7 @@ export function buildAuthServer(config, deps = {}) {
394
394
  const next = refresh.rotate(form.refresh_token ?? '', now());
395
395
  if (!next)
396
396
  return json(res, 400, { error: 'invalid_grant', message: 'unknown or rotated refresh token' });
397
- const access = await signAccessToken({ base, secret, iat: nowSec(), ttlSec: accessTtl, sub: 'owner' });
397
+ const access = await signAccessToken({ base, secret, iat: nowSec(), ttlSec: accessTtl, sub: next.sub });
398
398
  log('token issued grant=refresh_token');
399
399
  return json(res, 200, { access_token: access, token_type: 'Bearer', expires_in: accessTtl, refresh_token: next.token, scope: 'mcp:use' });
400
400
  }
@@ -446,8 +446,8 @@ export function buildAuthServer(config, deps = {}) {
446
446
  return { ok: false, status: 401, headers: { 'WWW-Authenticate': wwwAuth }, body: JSON.stringify({ error: 'E_MCP_TOKEN_INVALID', message: 'missing bearer token' }) };
447
447
  }
448
448
  try {
449
- await verifyAccessToken(header.slice(7), base, secret);
450
- return { ok: true };
449
+ const claims = await verifyAccessToken(header.slice(7), base, secret);
450
+ return { ok: true, sub: claims.sub };
451
451
  }
452
452
  catch {
453
453
  return { ok: false, status: 401, headers: { 'WWW-Authenticate': wwwAuth }, body: JSON.stringify({ error: 'E_MCP_TOKEN_INVALID', message: 'invalid or expired token' }) };
@@ -1,6 +1,7 @@
1
1
  import { ADMIN_SCOPES, BUNDLE_CATALOG } from './scope-catalog.js';
2
2
  import { BASE_SCOPES, resolveScopesForAccount } from './auth.js';
3
3
  import { readToken } from './token-store.js';
4
+ import { reauthHint } from './reauth-hint.js';
4
5
  // Reverse index scope -> bundles offering it, narrowest bundle first (fewest
5
6
  // scopes) so the remediation names the smallest grant. BASE_SCOPES map to the
6
7
  // pseudo-bundle "base" (outside a profile only via includesBase:false).
@@ -74,7 +75,7 @@ export function scopeHint(scope, c, alias) {
74
75
  case 'requestable_not_granted':
75
76
  return {
76
77
  hint: `Scope ${scope} is in ${alias}'s profile but not granted (you unchecked it at consent). ` +
77
- `Re-grant: npx mcp-google-multi auth --account ${alias}`,
78
+ reauthHint(alias),
78
79
  retriable: true,
79
80
  };
80
81
  case 'not_requestable':
@@ -1,3 +1,4 @@
1
+ import { reauthHint } from '../reauth-hint.js';
1
2
  import * as fs from 'node:fs';
2
3
  import { getAccountSet, refreshAccountSetIfStale } from '../accounts.js';
3
4
  import { buildScopesReport } from '../scope-observability.js';
@@ -35,7 +36,7 @@ export function deriveAccountHealth(alias, deps = DEFAULT_DEPS) {
35
36
  status: 'missing',
36
37
  hint: legacy
37
38
  ? 'Plaintext token.json found — run: npx mcp-google-multi migrate-tokens'
38
- : `Run: npx mcp-google-multi auth --account ${alias}`,
39
+ : reauthHint(alias),
39
40
  },
40
41
  scopes: noScopes,
41
42
  };
@@ -69,7 +70,7 @@ export function deriveAccountHealth(alias, deps = DEFAULT_DEPS) {
69
70
  status,
70
71
  expiryDate: expiry !== undefined ? new Date(expiry).toISOString() : undefined,
71
72
  hint: status === 'needs_reauth'
72
- ? `Run: npx mcp-google-multi auth --account ${alias}`
73
+ ? reauthHint(alias)
73
74
  : missing.length > 0
74
75
  ? 'Re-auth to grant the missing scopes'
75
76
  : undefined,
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "mcp-google-multi",
3
- "version": "6.0.0-alpha.37",
3
+ "version": "6.0.0-alpha.38",
4
4
  "mcpName": "io.github.bakissation/mcp-google-multi",
5
5
  "description": "Local MCP server for Google Workspace (Gmail, Drive, Calendar, Sheets, Docs, Contacts, Tasks, Meet, Search Console, +Forms/Chat/Admin) across multiple accounts — OAuth-only, encrypted token storage, deny-by-default writes.",
6
6
  "type": "module",