@goke/mcp 0.0.12 → 0.1.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/README.md +21 -52
- package/dist/__test__/add-mcp-commands-help.test.js +134 -35
- package/dist/__test__/http-multi-tenant.test.d.ts +4 -3
- package/dist/__test__/http-multi-tenant.test.d.ts.map +1 -1
- package/dist/__test__/http-multi-tenant.test.js +26 -55
- package/dist/auth.d.ts +4 -2
- package/dist/auth.d.ts.map +1 -1
- package/dist/auth.js +4 -2
- package/dist/index.d.ts +9 -9
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +29 -21
- package/package.json +3 -3
- package/src/__test__/add-mcp-commands-help.test.ts +139 -35
- package/src/__test__/http-multi-tenant.test.ts +29 -67
- package/src/auth.ts +4 -2
- package/src/index.ts +49 -35
package/src/auth.ts
CHANGED
|
@@ -29,8 +29,10 @@ async function openBrowser(url: string): Promise<void> {
|
|
|
29
29
|
|
|
30
30
|
/**
|
|
31
31
|
* Start the OAuth flow for an MCP server.
|
|
32
|
-
*
|
|
33
|
-
*
|
|
32
|
+
*
|
|
33
|
+
* Used internally by addMcpCommands on 401 errors, but also available
|
|
34
|
+
* for CLIs that need explicit control over the auth flow (e.g. a login
|
|
35
|
+
* command that runs the flow in a background daemon).
|
|
34
36
|
*
|
|
35
37
|
* This function:
|
|
36
38
|
* 1. Starts a local callback server on a random port
|
package/src/index.ts
CHANGED
|
@@ -9,7 +9,6 @@
|
|
|
9
9
|
*
|
|
10
10
|
* - **Auto-discovery**: Fetches all tools from the MCP server and creates CLI commands
|
|
11
11
|
* - **Caching**: Tools are cached for 1 hour to avoid reconnecting on every invocation
|
|
12
|
-
* - **Session reuse**: MCP session IDs are cached to skip initialization handshake
|
|
13
12
|
* - **Type-aware parsing**: Handles string, number, boolean, object, and array arguments
|
|
14
13
|
* - **JSON schema support**: Generates CLI options from tool input schemas
|
|
15
14
|
* - **OAuth support**: Automatic OAuth authentication on 401 errors (lazy auth)
|
|
@@ -48,13 +47,14 @@ import { wrapJsonSchema } from "goke";
|
|
|
48
47
|
import yaml from "js-yaml";
|
|
49
48
|
import { FileOAuthProvider } from "./oauth-provider.js";
|
|
50
49
|
import { startOAuthFlow, isAuthRequiredError } from "./auth.js";
|
|
50
|
+
export { startOAuthFlow } from "./auth.js";
|
|
51
51
|
import type { McpOAuthConfig, McpOAuthState } from "./types.js";
|
|
52
52
|
export { addCliToolsToMcp, createMcpAction } from "./cli-to-mcp.js";
|
|
53
53
|
export type { AddCliToolsToMcpOptions, CreateMcpActionOptions } from "./cli-to-mcp.js";
|
|
54
54
|
|
|
55
|
-
// Public exports
|
|
55
|
+
// Public exports
|
|
56
56
|
export type { Transport };
|
|
57
|
-
export type { McpOAuthConfig, McpOAuthState } from "./types.js";
|
|
57
|
+
export type { McpOAuthConfig, McpOAuthState, StartOAuthFlowOptions, OAuthFlowResult } from "./types.js";
|
|
58
58
|
|
|
59
59
|
export interface CachedMcpTools {
|
|
60
60
|
tools: Array<{
|
|
@@ -63,7 +63,6 @@ export interface CachedMcpTools {
|
|
|
63
63
|
inputSchema?: unknown;
|
|
64
64
|
}>;
|
|
65
65
|
timestamp: number;
|
|
66
|
-
sessionId?: string;
|
|
67
66
|
}
|
|
68
67
|
|
|
69
68
|
const CACHE_TTL_MS = 60 * 60 * 1000; // 1 hour
|
|
@@ -90,12 +89,15 @@ export interface AddMcpCommandsOptions {
|
|
|
90
89
|
|
|
91
90
|
/**
|
|
92
91
|
* Returns a transport to connect to the MCP server, or null if not configured.
|
|
93
|
-
*
|
|
94
|
-
* @param sessionId - Optional session ID from cache to reuse existing session
|
|
95
|
-
*
|
|
96
|
-
* @deprecated Use getMcpUrl + oauth instead for simpler setup
|
|
92
|
+
* Use this for stdio servers or any setup `getMcpUrl` cannot express.
|
|
97
93
|
*/
|
|
98
|
-
getMcpTransport?: (
|
|
94
|
+
getMcpTransport?: () => Transport | null | Promise<Transport | null>;
|
|
95
|
+
|
|
96
|
+
/**
|
|
97
|
+
* Argv used to decide whether to skip live discovery.
|
|
98
|
+
* Defaults to `process.argv.slice(2)`.
|
|
99
|
+
*/
|
|
100
|
+
argv?: string[];
|
|
99
101
|
|
|
100
102
|
/**
|
|
101
103
|
* Extra headers for MCP HTTP requests (for example `Authorization`).
|
|
@@ -236,13 +238,26 @@ function isHelpOrMetaArgv(argv: string[]) {
|
|
|
236
238
|
return argv.some((arg) => arg === "--help" || arg === "-h" || arg === "--version" || arg === "-v");
|
|
237
239
|
}
|
|
238
240
|
|
|
239
|
-
function
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
)
|
|
241
|
+
function matchesRegisteredCommand({ argv, cli }: { argv: string[]; cli: Goke }) {
|
|
242
|
+
const parts = argv.filter((arg) => !arg.startsWith("-"));
|
|
243
|
+
return cli.commands.some((cmd) => {
|
|
244
|
+
if (!cmd.name) return false;
|
|
245
|
+
const nameParts = cmd.name.split(" ");
|
|
246
|
+
return nameParts.every((part, i) => parts[i] === part);
|
|
247
|
+
});
|
|
248
|
+
}
|
|
249
|
+
|
|
250
|
+
function createTransportWithAuth({
|
|
251
|
+
url,
|
|
252
|
+
oauthState,
|
|
253
|
+
oauth,
|
|
254
|
+
headers,
|
|
255
|
+
}: {
|
|
256
|
+
url: URL
|
|
257
|
+
oauthState?: McpOAuthState
|
|
258
|
+
oauth?: McpOAuthConfig
|
|
259
|
+
headers?: Record<string, string>
|
|
260
|
+
}): StreamableHTTPClientTransport {
|
|
246
261
|
let authProvider: FileOAuthProvider | undefined;
|
|
247
262
|
|
|
248
263
|
if (oauth && oauthState?.tokens) {
|
|
@@ -261,7 +276,6 @@ function createTransportWithAuth(
|
|
|
261
276
|
|
|
262
277
|
const hasHeaders = headers && Object.keys(headers).length > 0;
|
|
263
278
|
return new StreamableHTTPClientTransport(url, {
|
|
264
|
-
sessionId,
|
|
265
279
|
authProvider,
|
|
266
280
|
requestInit: hasHeaders ? { headers } : undefined,
|
|
267
281
|
});
|
|
@@ -273,7 +287,6 @@ function createTransportWithAuth(
|
|
|
273
287
|
* Adds MCP tool commands to a goke CLI instance.
|
|
274
288
|
*
|
|
275
289
|
* Tools are cached for 1 hour to avoid connecting on every CLI invocation.
|
|
276
|
-
* Session ID is also cached to skip MCP initialization handshake.
|
|
277
290
|
*
|
|
278
291
|
* OAuth is lazy - authentication only happens when a 401 error occurs.
|
|
279
292
|
* After successful auth, the operation is automatically retried.
|
|
@@ -289,11 +302,10 @@ export async function addMcpCommands(options: AddMcpCommandsOptions): Promise<vo
|
|
|
289
302
|
oauth,
|
|
290
303
|
loadCache,
|
|
291
304
|
saveCache,
|
|
305
|
+
argv = process.argv.slice(2),
|
|
292
306
|
} = options;
|
|
293
307
|
|
|
294
|
-
|
|
295
|
-
const getTransport = async (sessionId?: string): Promise<Transport | null> => {
|
|
296
|
-
// New API: getMcpUrl + oauth
|
|
308
|
+
const getTransport = async (): Promise<Transport | null> => {
|
|
297
309
|
if (getMcpUrl) {
|
|
298
310
|
const mcpUrl = getMcpUrl();
|
|
299
311
|
if (!mcpUrl) {
|
|
@@ -303,12 +315,16 @@ export async function addMcpCommands(options: AddMcpCommandsOptions): Promise<vo
|
|
|
303
315
|
const url = new URL(mcpUrl);
|
|
304
316
|
const oauthState = oauth?.load();
|
|
305
317
|
|
|
306
|
-
return createTransportWithAuth(
|
|
318
|
+
return createTransportWithAuth({
|
|
319
|
+
url,
|
|
320
|
+
oauthState,
|
|
321
|
+
oauth,
|
|
322
|
+
headers: getHeaders?.(),
|
|
323
|
+
});
|
|
307
324
|
}
|
|
308
325
|
|
|
309
|
-
// Legacy API: getMcpTransport
|
|
310
326
|
if (getMcpTransport) {
|
|
311
|
-
return getMcpTransport(
|
|
327
|
+
return getMcpTransport();
|
|
312
328
|
}
|
|
313
329
|
|
|
314
330
|
return null;
|
|
@@ -346,14 +362,17 @@ export async function addMcpCommands(options: AddMcpCommandsOptions): Promise<vo
|
|
|
346
362
|
// Try to use cached tools first (fast path - no network)
|
|
347
363
|
const cachedTools = loadCache();
|
|
348
364
|
const isCacheValid = cachedTools && (Date.now() - cachedTools.timestamp) < CACHE_TTL_MS;
|
|
349
|
-
const
|
|
365
|
+
const skipLiveDiscovery =
|
|
366
|
+
isHelpOrMetaArgv(argv) || matchesRegisteredCommand({ argv, cli });
|
|
350
367
|
|
|
351
368
|
let tools: CachedMcpTools["tools"] | undefined;
|
|
352
|
-
let cachedSessionId: string | undefined;
|
|
353
369
|
|
|
354
370
|
if (isCacheValid && cachedTools) {
|
|
355
371
|
tools = cachedTools.tools;
|
|
356
|
-
|
|
372
|
+
} else if (skipLiveDiscovery) {
|
|
373
|
+
if (cachedTools) {
|
|
374
|
+
tools = cachedTools.tools;
|
|
375
|
+
}
|
|
357
376
|
} else {
|
|
358
377
|
const transport = await getTransport();
|
|
359
378
|
if (transport) {
|
|
@@ -363,8 +382,6 @@ export async function addMcpCommands(options: AddMcpCommandsOptions): Promise<vo
|
|
|
363
382
|
const result = await client.listTools();
|
|
364
383
|
tools = result.tools;
|
|
365
384
|
|
|
366
|
-
const sessionId = (transport as { sessionId?: string }).sessionId;
|
|
367
|
-
|
|
368
385
|
saveCache({
|
|
369
386
|
tools: tools.map((t) => ({
|
|
370
387
|
name: t.name,
|
|
@@ -372,11 +389,9 @@ export async function addMcpCommands(options: AddMcpCommandsOptions): Promise<vo
|
|
|
372
389
|
inputSchema: t.inputSchema,
|
|
373
390
|
})),
|
|
374
391
|
timestamp: Date.now(),
|
|
375
|
-
sessionId,
|
|
376
392
|
});
|
|
377
|
-
cachedSessionId = sessionId;
|
|
378
393
|
} catch (err) {
|
|
379
|
-
const shouldAuth = isAuthRequiredError(err) && oauth && getMcpUrl && !
|
|
394
|
+
const shouldAuth = isAuthRequiredError(err) && oauth && getMcpUrl && !skipLiveDiscovery;
|
|
380
395
|
if (shouldAuth) {
|
|
381
396
|
const mcpUrl = getMcpUrl();
|
|
382
397
|
if (mcpUrl) {
|
|
@@ -386,7 +401,7 @@ export async function addMcpCommands(options: AddMcpCommandsOptions): Promise<vo
|
|
|
386
401
|
}
|
|
387
402
|
}
|
|
388
403
|
}
|
|
389
|
-
if (!
|
|
404
|
+
if (!skipLiveDiscovery) {
|
|
390
405
|
console.error(`Failed to connect to MCP server: ${err instanceof Error ? err.message : err}`);
|
|
391
406
|
}
|
|
392
407
|
} finally {
|
|
@@ -396,7 +411,6 @@ export async function addMcpCommands(options: AddMcpCommandsOptions): Promise<vo
|
|
|
396
411
|
|
|
397
412
|
if (!tools && cachedTools) {
|
|
398
413
|
tools = cachedTools.tools;
|
|
399
|
-
cachedSessionId = cachedTools.sessionId;
|
|
400
414
|
}
|
|
401
415
|
}
|
|
402
416
|
|
|
@@ -450,7 +464,7 @@ export async function addMcpCommands(options: AddMcpCommandsOptions): Promise<vo
|
|
|
450
464
|
const parsedArgs = extractToolArguments(cliOptions, inputSchema);
|
|
451
465
|
|
|
452
466
|
const executeWithRetry = async (isRetry = false): Promise<void> => {
|
|
453
|
-
const transport = await getTransport(
|
|
467
|
+
const transport = await getTransport();
|
|
454
468
|
if (!transport) {
|
|
455
469
|
console.error("MCP transport not available. Run login command first.");
|
|
456
470
|
process.exit(1);
|