@evantahler/mcpcli 0.2.4 → 0.3.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@evantahler/mcpcli",
3
- "version": "0.2.4",
3
+ "version": "0.3.0",
4
4
  "description": "A command-line interface for MCP servers. curl for MCP.",
5
5
  "type": "module",
6
6
  "bin": {
@@ -1,6 +1,10 @@
1
1
  import { exec } from "child_process";
2
2
  import type { OAuthClientProvider } from "@modelcontextprotocol/sdk/client/auth.js";
3
- import { auth, refreshAuthorization } from "@modelcontextprotocol/sdk/client/auth.js";
3
+ import {
4
+ auth,
5
+ discoverOAuthServerInfo,
6
+ refreshAuthorization,
7
+ } from "@modelcontextprotocol/sdk/client/auth.js";
4
8
  import type {
5
9
  OAuthClientMetadata,
6
10
  OAuthClientInformationMixed,
@@ -8,6 +12,8 @@ import type {
8
12
  } from "@modelcontextprotocol/sdk/shared/auth.js";
9
13
  import type { AuthFile } from "../config/schemas.ts";
10
14
  import { saveAuth } from "../config/loader.ts";
15
+ import type { FormatOptions } from "../output/formatter.ts";
16
+ import { startSpinner } from "../output/spinner.ts";
11
17
 
12
18
  export class McpOAuthProvider implements OAuthClientProvider {
13
19
  private serverName: string;
@@ -243,6 +249,37 @@ export function startCallbackServer(): {
243
249
  return { server, authCodePromise };
244
250
  }
245
251
 
252
+ /** Probe for OAuth support and run the auth flow if the server supports it.
253
+ * Returns true if auth ran, false if server doesn't support OAuth (silent skip). */
254
+ export async function tryOAuthIfSupported(
255
+ serverName: string,
256
+ serverUrl: string,
257
+ configDir: string,
258
+ auth: AuthFile,
259
+ formatOptions: FormatOptions,
260
+ ): Promise<boolean> {
261
+ let oauthSupported: boolean;
262
+ try {
263
+ const info = await discoverOAuthServerInfo(serverUrl);
264
+ oauthSupported = info.authorizationServerMetadata !== undefined;
265
+ } catch {
266
+ return false;
267
+ }
268
+
269
+ if (!oauthSupported) return false;
270
+
271
+ const provider = new McpOAuthProvider({ serverName, configDir, auth });
272
+ const spinner = startSpinner(`Authenticating with "${serverName}"…`, formatOptions);
273
+ try {
274
+ await runOAuthFlow(serverUrl, provider);
275
+ spinner.success(`Authenticated with "${serverName}"`);
276
+ return true;
277
+ } catch (err) {
278
+ spinner.error(`Authentication failed: ${err instanceof Error ? err.message : err}`);
279
+ throw err;
280
+ }
281
+ }
282
+
246
283
  /** Run a full OAuth authorization flow for an HTTP MCP server */
247
284
  export async function runOAuthFlow(serverUrl: string, provider: McpOAuthProvider): Promise<void> {
248
285
  // Clear any leftover state from a previously cancelled auth flow
@@ -1,6 +1,7 @@
1
1
  import type { Command } from "commander";
2
2
  import type { ServerConfig } from "../config/schemas.ts";
3
- import { loadRawServers, saveServers } from "../config/loader.ts";
3
+ import { loadRawAuth, loadRawServers, saveServers } from "../config/loader.ts";
4
+ import { tryOAuthIfSupported } from "../client/oauth.ts";
4
5
  import { runIndex } from "./index.ts";
5
6
 
6
7
  export function registerAddCommand(program: Command) {
@@ -16,6 +17,7 @@ export function registerAddCommand(program: Command) {
16
17
  .option("--allowed-tools <tools>", "comma-separated list of allowed tools")
17
18
  .option("--disabled-tools <tools>", "comma-separated list of disabled tools")
18
19
  .option("-f, --force", "overwrite if server already exists")
20
+ .option("--no-auth", "skip automatic OAuth authentication after adding an HTTP server")
19
21
  .option("--no-index", "skip rebuilding the search index after adding")
20
22
  .action(
21
23
  async (
@@ -30,6 +32,7 @@ export function registerAddCommand(program: Command) {
30
32
  allowedTools?: string;
31
33
  disabledTools?: string;
32
34
  force?: boolean;
35
+ auth?: boolean;
33
36
  index?: boolean;
34
37
  },
35
38
  ) => {
@@ -73,6 +76,21 @@ export function registerAddCommand(program: Command) {
73
76
  await saveServers(configDir, servers);
74
77
  console.log(`Added server "${name}" to ${configDir}/servers.json`);
75
78
 
79
+ // Auto-auth: probe for OAuth support and run the flow if supported
80
+ if (hasUrl && options.auth !== false) {
81
+ const auth = await loadRawAuth(configDir);
82
+ const formatOptions = {
83
+ json: !!program.opts().json,
84
+ verbose: !!program.opts().verbose,
85
+ showSecrets: false,
86
+ };
87
+ try {
88
+ await tryOAuthIfSupported(name, options.url!, configDir, auth, formatOptions);
89
+ } catch {
90
+ console.error(`Warning: OAuth authentication failed. Run: mcpcli auth ${name}`);
91
+ }
92
+ }
93
+
76
94
  // Commander treats --no-index as index=false (default true)
77
95
  if (options.index !== false) {
78
96
  await runIndex(program);