/** * Where the Coolify API token comes from, and how it is re-read (#398). * * ## Why this exists * * A stdio MCP server is spawned once per client session and lives for the whole * of it. `COOLIFY_ACCESS_TOKEN` was read at startup and captured for the life of * the process, so rotating the token meant restarting the client session. * * That was named in writing as a reason for retiring this server in favour of * the official CLI, which reads its context on every invocation * (pedrorezendefig/hospital-reunioes#312). It matters more than it looks: * rotation is the remediation step for a leaked token, so the moment somebody * most needs a new token to take effect is the moment we made them restart * everything. * * ## Why a file, and not just the environment * * A spawned subprocess does not see later changes to its parent's environment. * Exporting a new value in a shell cannot reach a server that is already * running, so an env-only design cannot support rotation no matter how often it * re-reads. `COOLIFY_ACCESS_TOKEN_FILE` points at a path, and the value is * re-read when the file's mtime changes — the same shape as a Kubernetes or * Docker secret mount, and what makes `coolify context set-token` style * rotation possible for us. * * The environment variable keeps working unchanged and stays the default. */ export interface TokenSourceInfo { /** Where the current value came from. */ origin: 'env' | 'file'; /** The path, when the origin is a file. */ path?: string; /** When the value was last read from disk, epoch ms. Undefined for `env`. */ lastReadAt?: number; } /** * Resolves the token on demand. * * `current()` is called on every request, so the file case stats before reading * and only re-reads when the mtime moved. A stat per API call is a local * syscall against a file the OS has cached; re-reading unconditionally would be * wasteful, and caching without the stat would be the bug this module exists to * fix. */ export declare class TokenSource { private readonly path?; private value; private mtimeMs; private lastReadAt?; constructor(config: { accessToken?: string; accessTokenFile?: string; }); current(): string; /** * Force a re-read, ignoring the mtime cache, and say whether the value moved. * * Used on a 401: an editor that writes in place can leave mtime granularity * ambiguity, and more importantly a rotation that lands mid-request should * recover rather than surface an error the user cannot act on. */ refresh(): { changed: boolean; }; info(): TokenSourceInfo; private readFile; }