/**
 * Generic OAuth client provider for hosted (HTTP) MCP servers.
 *
 * Implements the MCP SDK's `OAuthClientProvider` against a terminal app:
 * tokens, the dynamically-registered client, and the PKCE code verifier are
 * persisted to `~/.blockrun/mcp-auth/<server>.json` (0600). Authorization uses
 * the OS browser plus a loopback redirect listener to capture the auth code.
 *
 * Nothing here is Base-specific — any hosted MCP doing Dynamic Client
 * Registration + PKCE + authorization-code (e.g. https://mcp.base.org) works.
 * The SDK performs discovery, registration, token exchange and refresh; this
 * class only supplies the storage + browser/loopback plumbing a CLI needs.
 *
 * Startup safety: when constructed non-interactively (the path used by
 * `connectMcpServers` at `franklin start`), `redirectToAuthorization` throws
 * instead of opening a browser, so a not-yet-authorized server can never pop a
 * browser tab mid-launch. The interactive flow only runs from `franklin mcp`.
 */
import type { OAuthClientProvider } from '@modelcontextprotocol/sdk/client/auth.js';
import type { OAuthClientMetadata, OAuthTokens, OAuthClientInformationMixed } from '@modelcontextprotocol/sdk/shared/auth.js';
export interface OAuthProviderOptions {
    /** Interactive flows (franklin mcp) may open a browser; startup must not. */
    interactive?: boolean;
    /** Called with the authorization URL in interactive mode (open a browser). */
    onAuthorizationUrl?: (url: URL) => void;
}
/** Path to the persisted auth blob for a given server name. */
export declare function authFilePath(serverName: string): string;
/**
 * Does a usable access token exist for this server? Used as the startup gate
 * in loadMcpConfig — a token-less http server is auto-disabled so it is
 * silently skipped (never pops a browser, never hangs the agent boot).
 */
export declare function hasStoredToken(serverName: string): boolean;
export declare class McpOAuthProvider implements OAuthClientProvider {
    private readonly serverName;
    private readonly serverUrl;
    readonly interactive: boolean;
    onAuthorizationUrl?: (url: URL) => void;
    private readonly file;
    private _port;
    private _state?;
    private server?;
    private callback?;
    constructor(serverName: string, serverUrl: string, opts?: OAuthProviderOptions);
    private read;
    private persist;
    get redirectUrl(): string;
    get clientMetadata(): OAuthClientMetadata;
    state(): string;
    clientInformation(): OAuthClientInformationMixed | undefined;
    saveClientInformation(info: OAuthClientInformationMixed): void;
    tokens(): OAuthTokens | undefined;
    saveTokens(tokens: OAuthTokens): void;
    saveCodeVerifier(verifier: string): void;
    codeVerifier(): string;
    redirectToAuthorization(url: URL): void;
    /** Clear stored credentials so the next login starts clean. */
    invalidateCredentials(scope: 'all' | 'client' | 'tokens' | 'verifier'): void;
    /**
     * Bind the loopback redirect listener and fix `redirectUrl`'s port BEFORE the
     * connect attempt, so Dynamic Client Registration registers the right URI.
     * Tries a stable port first, then an ephemeral one if it's taken.
     */
    startLoopback(): Promise<void>;
    /** Await the captured authorization code (after the browser redirect). */
    waitForCallback(): Promise<{
        code: string;
        state?: string;
    }>;
    stopLoopback(): void;
}
/** Open a URL in the system browser. Returns false if it couldn't be launched. */
export declare function openUrl(url: string): boolean;
