Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 5 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,10 @@ On first run, the CLI opens your browser for OAuth authorization. Credentials ar

Generate an API key at [bitrefill.com/account/developers](https://www.bitrefill.com/account/developers) and pass it via the `--api-key` option or the `BITREFILL_API_KEY` environment variable. This skips the OAuth flow entirely.

### Non-interactive / CI

In environments without a TTY (e.g. CI, Docker, scripts), or when `CI=true`, the CLI cannot complete browser-based OAuth. Pass `--no-interactive` to fail fast with a clear message, or use `--api-key` / `BITREFILL_API_KEY` instead.

```bash
# Option
bitrefill --api-key YOUR_API_KEY search-products --query "Netflix"
Expand All @@ -39,7 +43,7 @@ Node does not load `.env` files automatically. After editing `.env`, either expo
## Usage

```bash
bitrefill [--api-key <key>] [--json] <command> [options]
bitrefill [--api-key <key>] [--json] [--no-interactive] <command> [options]
```

### Human-readable output (default)
Expand Down
21 changes: 21 additions & 0 deletions src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -52,6 +52,13 @@ function resolveJsonMode(): boolean {
return process.argv.some((arg) => arg === '--json');
}

function resolveInteractive(): boolean {
if (process.argv.includes('--no-interactive')) return false;
if (process.env.CI === 'true') return false;
if (!process.stdin.isTTY) return false;
return true;
}

function createOutputFormatter(jsonMode: boolean): OutputFormatter {
return jsonMode ? createJsonFormatter() : createHumanFormatter();
}
Expand Down Expand Up @@ -262,6 +269,16 @@ async function main(): Promise<void> {
const mcpUrl = resolveMcpUrl(apiKey);
const useOAuth = !apiKey && !process.env.MCP_URL;

if (useOAuth && !resolveInteractive()) {
formatter.error(
new Error(
'Authorization required but running in non-interactive mode.\n' +
'Use --api-key or set BITREFILL_API_KEY to authenticate without a browser.'
)
);
process.exit(1);
}

// Phase 1: connect and discover tools
const { client, transport } = await createMcpClient(
mcpUrl,
Expand Down Expand Up @@ -289,6 +306,10 @@ async function main(): Promise<void> {
.option(
'--json',
'Output raw JSON (TOON decoded); use with jq. Non-result messages go to stderr.'
)
.option(
'--no-interactive',
'Disable browser-based auth and interactive prompts (auto-detected in CI / non-TTY)'
);

program
Expand Down
Loading