Vend a token
getAccessToken(). This is the legacy entry point used by the stdio runtime; the HTTP MCP transport calls resolveToken() directly (see below).
Success response (200):
resolveToken() — three-source resolution
Inside the HTTP MCP transport (apps/server/src/routes/mcp-remote.ts), every plugin handler’s ctx.auth.getToken("<provider>") runs through resolveToken(userId, provider) which checks three sources in order:
tool_connectionsrow for the user withtool_id = <provider>. If present, decrypt and return the stored secret. This is how dashboard-managed API keys (granola personal/enterprise) and any future per-user tokens work.- Better Auth
getAccessToken({ providerId, userId }). Returns the OAuth access token (auto-refreshing if expired). Covers the social providers (github/google/slack/linear) and Generic OAuth providers (quickbooks/gcp/docusign/carta). process.env["${UPPER(provider).replace(/-/g, "_")}_API_KEY"]. Falls back to a server-wide env var. This is how the built-in tools (attio, browserbase, firecrawl, perplexity) get their keys without per-user storage.
resolveToken() throws No credentials for "<provider>". Connect it in the Toolshed dashboard. — surfaced to the agent verbatim by call_tool.