docs: document headless OAuth auth flow
This commit is contained in:
parent
b29854ebf2
commit
7ddb433479
@ -164,7 +164,8 @@ Helpful flags:
|
||||
- `--` (on `mcporter call`) -- stop flag parsing so the remaining tokens stay literal positional values, even when they start with `--`.
|
||||
- `--json` (on `mcporter list`) -- emit JSON summaries/counts instead of text. Multi-server runs report per-server statuses, counts, and connection issues; single-server runs include the full tool metadata.
|
||||
- `--output json/raw` (on `mcporter call`) -- when a connection fails, MCPorter prints the usual colorized hint and also emits a structured `{ server, tool, issue }` envelope so scripts can handle auth/offline/http errors programmatically.
|
||||
- `--json` (on `mcporter auth`) -- emit the same structured connection envelope whenever OAuth/transport setup fails, instead of throwing an error.
|
||||
- `--json` (on `mcporter auth`) -- emit the same structured connection envelope whenever OAuth/transport setup fails, instead of throwing an error. With `--no-browser`, it emits auth-start JSON containing `authorizationUrl` and `redirectUrl`.
|
||||
- `--no-browser` / `--browser none` (on `mcporter auth` or `mcporter config login`) -- suppress browser launch and print the OAuth authorization URL for headless workflows; `MCPORTER_OAUTH_NO_BROWSER=1` / `true` / `yes` enables the same behavior.
|
||||
- `--json` (on `mcporter emit-ts`) -- print a JSON summary describing the emitted files (mode + output paths) instead of text logs—handy when generating artifacts inside scripts.
|
||||
- `--all-parameters` -- show every schema field when listing a server (default output shows at least five parameters plus a summary of the rest).
|
||||
- `--http-url <https://…>` / `--stdio "command …"` -- describe an ad-hoc MCP server inline. STDIO transports now inherit your current shell environment automatically; add `--env KEY=value` only when you need to inject/override variables alongside `--cwd`, `--name`, or `--persist <config.json>`. These flags now work with `mcporter auth` too, so `mcporter auth https://mcp.example.com/mcp` just works.
|
||||
@ -415,6 +416,8 @@ npx mcporter config add notion https://mcp.notion.com/mcp --auth oauth
|
||||
npx mcporter auth notion
|
||||
```
|
||||
|
||||
On headless hosts, use `npx mcporter auth notion --no-browser` to print the authorization URL instead of launching the platform browser. Treat the printed URL as sensitive operational output. If you open it on another machine, make sure the printed `redirectUrl` callback port is reachable through a loopback-only tunnel or a configured `oauthRedirectUrl`.
|
||||
|
||||
Providers that do not support dynamic client registration can use a pre-registered app:
|
||||
|
||||
```jsonc
|
||||
|
||||
@ -53,7 +53,7 @@ This name becomes the cache key for OAuth tokens and log preferences, so repeate
|
||||
|
||||
Many hosted MCP servers (Supabase, Vercel, etc.) advertise OAuth capabilities but expect clients to discover this dynamically. When an ad-hoc HTTP server responds with `401/403` during the initial handshake, mcporter now:
|
||||
|
||||
1. **Promotes the definition to OAuth** and spins up the default browser flow—no need to edit config or supply `auth: "oauth"` manually.
|
||||
1. **Promotes the definition to OAuth** and spins up the default browser flow—no need to edit config or supply `auth: "oauth"` manually. On headless hosts, pass `--no-browser` (or `--browser none`) to print the authorization URL instead of launching the platform browser.
|
||||
2. **Persists the change** whenever you pass `--persist`, so future runs remember that the endpoint requires OAuth without repeating the detection step.
|
||||
|
||||
The CLI still avoids surprise prompts during `mcporter list`; the upgrade happens the first time you run `mcporter auth <url>` or any other command that allows OAuth (i.e., not in `--autoAuthorize=false` mode).
|
||||
@ -62,6 +62,8 @@ The CLI still avoids surprise prompts during `mcporter list`; the upgrade happen
|
||||
|
||||
- OAuth flows are allowed; successful tokens store under the inferred name just like regular definitions.
|
||||
- `mcporter auth` accepts the same `--http-url/--stdio` flags (and even bare URLs), so you can immediately re-run `mcporter auth https://…` after a 401 without touching a config file.
|
||||
- Use `mcporter auth <url> --no-browser` for human-in-the-loop headless OAuth. Text mode writes only the authorization URL to stdout; `--json --no-browser` writes `authorizationUrl` plus `redirectUrl` as JSON. Keep that URL out of durable CI logs and support bundles.
|
||||
- When opening the URL on a different machine, remember that loopback redirect URLs point at the browser machine unless an SSH tunnel forwards the callback port back to the mcporter process. Use `oauthRedirectUrl` when you need a predictable callback port.
|
||||
- Nothing is written to disk unless you pass `--persist /path/to/config.json`. When set, we merge the generated definition into that file (creating it if necessary) so future runs can rely on the standard config pipeline. Ad-hoc HTTP headers are persisted with the entry, so placeholders such as `--header 'Authorization=$env:MY_TOKEN'` keep working through the normal config header resolver.
|
||||
|
||||
## Safety Nets
|
||||
|
||||
@ -148,7 +148,8 @@ Use `--scope home|project` with `mcporter config add` to pick the write target e
|
||||
### `mcporter config login <name|url>` / `logout`
|
||||
|
||||
- Mirrors `mcporter auth`. `login` completes OAuth (or token provisioning) for either a named server or an ad-hoc URL. When a hosted MCP returns 401/403, mcporter automatically promotes that target to OAuth and re-runs the flow, matching the behavior documented in `docs/adhoc.md`.
|
||||
- `--browser none` suppresses automatic browser launch (useful for copying the URL into a remote browser).
|
||||
- `--no-browser` suppresses automatic browser launch and prints the authorization URL to stdout so it can be copied from a headless host. `--browser none` is accepted as a compatibility alias, and `MCPORTER_OAUTH_NO_BROWSER=1` / `true` / `yes` enables the same behavior by environment.
|
||||
- In `--json --no-browser` mode, stdout contains a JSON object with `authorizationUrl` and `redirectUrl`; diagnostics stay off stdout so scripts can parse the result. Treat emitted authorization URLs as sensitive operational output.
|
||||
- `logout` wipes the shared vault entry, legacy `~/.mcporter/<name>/` caches, and the custom `tokenCacheDir` when present. Pass `--all` to clear everything.
|
||||
|
||||
### `mcporter config doctor`
|
||||
|
||||
@ -74,6 +74,13 @@ Expectations:
|
||||
- If a token cache exists, log should mention the cleared directory.
|
||||
- Failed auths emit the unified message (`Failed to authorize 'SERVER': ...`).
|
||||
|
||||
For headless OAuth URL capture, run the same auth command with `--no-browser`:
|
||||
|
||||
- Text mode stdout should contain exactly one authorization URL line and no logger prefix.
|
||||
- `--json --no-browser` stdout should parse as JSON with `authorizationUrl` and `redirectUrl`.
|
||||
- If completing the flow from another machine over SSH, forward the printed callback port with a loopback-only tunnel; avoid exposing the callback listener publicly.
|
||||
- Treat copied authorization URLs as sensitive and avoid storing them in long-lived logs.
|
||||
|
||||
## Tips
|
||||
|
||||
- To exercise error paths, point at a placeholder endpoint and use `--timeout 1000` (e.g., `https://example.com/mcp.listStuff`).
|
||||
|
||||
@ -98,8 +98,21 @@ export const CONFIG_HELP_ENTRIES: Record<ConfigSubcommand, ConfigHelpEntry> = {
|
||||
name: 'login <name|url> [options]',
|
||||
summary: 'Run the OAuth/auth flow',
|
||||
usage: 'mcporter config login <name|url> [options]',
|
||||
description: 'Delegates to `mcporter auth`, so you can pass ephemeral flags like --http-url/--stdio/--reset.',
|
||||
examples: ['pnpm mcporter config login linear', 'pnpm mcporter config login https://example.com/mcp --reset'],
|
||||
description:
|
||||
'Delegates to `mcporter auth`, so you can pass ephemeral flags like --http-url/--stdio/--reset and browser-suppression flags for headless OAuth.',
|
||||
flags: [
|
||||
{ flag: '--no-browser', description: 'Print the OAuth authorization URL without launching a browser.' },
|
||||
{ flag: '--browser none', description: 'Alias for --no-browser.' },
|
||||
{
|
||||
flag: 'MCPORTER_OAUTH_NO_BROWSER=1|true|yes',
|
||||
description: 'Environment default for browser-suppressed OAuth.',
|
||||
},
|
||||
],
|
||||
examples: [
|
||||
'pnpm mcporter config login linear',
|
||||
'pnpm mcporter config login linear --no-browser',
|
||||
'pnpm mcporter config login https://example.com/mcp --reset',
|
||||
],
|
||||
},
|
||||
logout: {
|
||||
name: 'logout <name>',
|
||||
|
||||
@ -27,7 +27,11 @@ describe('mcporter auth help shortcut', () => {
|
||||
|
||||
await runCli(['auth', '--help']);
|
||||
|
||||
expect(errorSpy).toHaveBeenCalledWith(expect.stringContaining('Usage: mcporter auth'));
|
||||
const output = errorSpy.mock.calls.map(([message]) => String(message)).join('\n');
|
||||
expect(output).toContain('Usage: mcporter auth');
|
||||
expect(output).toContain('--no-browser');
|
||||
expect(output).toContain('--browser none');
|
||||
expect(output).toContain('MCPORTER_OAUTH_NO_BROWSER');
|
||||
expect(process.exitCode).toBe(0);
|
||||
});
|
||||
|
||||
@ -37,7 +41,11 @@ describe('mcporter auth help shortcut', () => {
|
||||
|
||||
await runCli(['auth', 'help']);
|
||||
|
||||
expect(errorSpy).toHaveBeenCalledWith(expect.stringContaining('Usage: mcporter auth'));
|
||||
const output = errorSpy.mock.calls.map(([message]) => String(message)).join('\n');
|
||||
expect(output).toContain('Usage: mcporter auth');
|
||||
expect(output).toContain('--no-browser');
|
||||
expect(output).toContain('--browser none');
|
||||
expect(output).toContain('MCPORTER_OAUTH_NO_BROWSER');
|
||||
expect(process.exitCode).toBe(0);
|
||||
});
|
||||
});
|
||||
|
||||
Loading…
Reference in New Issue
Block a user