@axtary/cli 0.1.0 → 0.2.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.
Files changed (48) hide show
  1. package/README.md +122 -12
  2. package/dist/bin.js +10 -0
  3. package/dist/bin.js.map +1 -1
  4. package/dist/claude-code-hook.d.ts +20 -0
  5. package/dist/claude-code-hook.d.ts.map +1 -1
  6. package/dist/claude-code-hook.js +114 -34
  7. package/dist/claude-code-hook.js.map +1 -1
  8. package/dist/codex-hook.d.ts +48 -0
  9. package/dist/codex-hook.d.ts.map +1 -0
  10. package/dist/codex-hook.js +259 -0
  11. package/dist/codex-hook.js.map +1 -0
  12. package/dist/credentials.d.ts +101 -0
  13. package/dist/credentials.d.ts.map +1 -0
  14. package/dist/credentials.js +277 -0
  15. package/dist/credentials.js.map +1 -0
  16. package/dist/cursor-hook.d.ts +51 -0
  17. package/dist/cursor-hook.d.ts.map +1 -0
  18. package/dist/cursor-hook.js +214 -0
  19. package/dist/cursor-hook.js.map +1 -0
  20. package/dist/hook-install.d.ts +21 -0
  21. package/dist/hook-install.d.ts.map +1 -0
  22. package/dist/hook-install.js +179 -0
  23. package/dist/hook-install.js.map +1 -0
  24. package/dist/index.d.ts +768 -7
  25. package/dist/index.d.ts.map +1 -1
  26. package/dist/index.js +6132 -1050
  27. package/dist/index.js.map +1 -1
  28. package/dist/mcp-fs-normalize.d.ts +18 -0
  29. package/dist/mcp-fs-normalize.d.ts.map +1 -0
  30. package/dist/mcp-fs-normalize.js +39 -0
  31. package/dist/mcp-fs-normalize.js.map +1 -0
  32. package/dist/mcp-oauth.d.ts +67 -0
  33. package/dist/mcp-oauth.d.ts.map +1 -0
  34. package/dist/mcp-oauth.js +242 -0
  35. package/dist/mcp-oauth.js.map +1 -0
  36. package/dist/oauth.d.ts +90 -0
  37. package/dist/oauth.d.ts.map +1 -0
  38. package/dist/oauth.js +339 -0
  39. package/dist/oauth.js.map +1 -0
  40. package/dist/render.d.ts +103 -0
  41. package/dist/render.d.ts.map +1 -0
  42. package/dist/render.js +172 -0
  43. package/dist/render.js.map +1 -0
  44. package/dist/shell-file-normalize.d.ts +21 -0
  45. package/dist/shell-file-normalize.d.ts.map +1 -0
  46. package/dist/shell-file-normalize.js +269 -0
  47. package/dist/shell-file-normalize.js.map +1 -0
  48. package/package.json +14 -9
@@ -0,0 +1,18 @@
1
+ /** Read-only filesystem tools → the input field holding the path. */
2
+ export declare const MCP_FS_READ_TOOLS: Record<string, string>;
3
+ /** Mutating filesystem tools → the input field holding the path. */
4
+ export declare const MCP_FS_WRITE_TOOLS: Record<string, string>;
5
+ /**
6
+ * An MCP tool may be presented bare (`read_text_file`) or namespaced by the
7
+ * server (`filesystem.read_text_file`, `mcp__fs__read_text_file`); match on the
8
+ * trailing segment so a recognized tool is governed either way.
9
+ */
10
+ export declare function baseMcpToolName(toolName: string): string;
11
+ export type McpFilesystemToolClass = {
12
+ kind: "read" | "write";
13
+ /** Input field holding the path argument. */
14
+ pathField: string;
15
+ };
16
+ /** Classify an MCP tool name as a filesystem read/write, or null if unknown. */
17
+ export declare function classifyMcpFilesystemTool(toolName: string): McpFilesystemToolClass | null;
18
+ //# sourceMappingURL=mcp-fs-normalize.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"mcp-fs-normalize.d.ts","sourceRoot":"","sources":["../src/mcp-fs-normalize.ts"],"names":[],"mappings":"AAMA,qEAAqE;AACrE,eAAO,MAAM,iBAAiB,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAKpD,CAAC;AAEF,oEAAoE;AACpE,eAAO,MAAM,kBAAkB,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAIrD,CAAC;AAEF;;;;GAIG;AACH,wBAAgB,eAAe,CAAC,QAAQ,EAAE,MAAM,GAAG,MAAM,CAGxD;AAED,MAAM,MAAM,sBAAsB,GAAG;IACnC,IAAI,EAAE,MAAM,GAAG,OAAO,CAAC;IACvB,6CAA6C;IAC7C,SAAS,EAAE,MAAM,CAAC;CACnB,CAAC;AAEF,gFAAgF;AAChF,wBAAgB,yBAAyB,CACvC,QAAQ,EAAE,MAAM,GACf,sBAAsB,GAAG,IAAI,CAS/B"}
@@ -0,0 +1,39 @@
1
+ // Shared classification of MCP filesystem-server tool calls, used by the Cursor
2
+ // and Codex runtime-hook adapters so the recognized (security-relevant) tool
3
+ // list lives in exactly one place. Tool names verified against the official
4
+ // @modelcontextprotocol/server-filesystem README (2026-06-26): the old
5
+ // `read_file` was renamed to `read_text_file`; the path argument is `"path"`.
6
+ /** Read-only filesystem tools → the input field holding the path. */
7
+ export const MCP_FS_READ_TOOLS = {
8
+ read_text_file: "path",
9
+ read_media_file: "path",
10
+ read_file: "path",
11
+ get_file_info: "path",
12
+ };
13
+ /** Mutating filesystem tools → the input field holding the path. */
14
+ export const MCP_FS_WRITE_TOOLS = {
15
+ write_file: "path",
16
+ edit_file: "path",
17
+ create_directory: "path",
18
+ };
19
+ /**
20
+ * An MCP tool may be presented bare (`read_text_file`) or namespaced by the
21
+ * server (`filesystem.read_text_file`, `mcp__fs__read_text_file`); match on the
22
+ * trailing segment so a recognized tool is governed either way.
23
+ */
24
+ export function baseMcpToolName(toolName) {
25
+ const segments = toolName.split(/__|[./]/);
26
+ return segments[segments.length - 1] ?? toolName;
27
+ }
28
+ /** Classify an MCP tool name as a filesystem read/write, or null if unknown. */
29
+ export function classifyMcpFilesystemTool(toolName) {
30
+ const base = baseMcpToolName(toolName);
31
+ if (MCP_FS_READ_TOOLS[base]) {
32
+ return { kind: "read", pathField: MCP_FS_READ_TOOLS[base] };
33
+ }
34
+ if (MCP_FS_WRITE_TOOLS[base]) {
35
+ return { kind: "write", pathField: MCP_FS_WRITE_TOOLS[base] };
36
+ }
37
+ return null;
38
+ }
39
+ //# sourceMappingURL=mcp-fs-normalize.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"mcp-fs-normalize.js","sourceRoot":"","sources":["../src/mcp-fs-normalize.ts"],"names":[],"mappings":"AAAA,gFAAgF;AAChF,6EAA6E;AAC7E,4EAA4E;AAC5E,uEAAuE;AACvE,8EAA8E;AAE9E,qEAAqE;AACrE,MAAM,CAAC,MAAM,iBAAiB,GAA2B;IACvD,cAAc,EAAE,MAAM;IACtB,eAAe,EAAE,MAAM;IACvB,SAAS,EAAE,MAAM;IACjB,aAAa,EAAE,MAAM;CACtB,CAAC;AAEF,oEAAoE;AACpE,MAAM,CAAC,MAAM,kBAAkB,GAA2B;IACxD,UAAU,EAAE,MAAM;IAClB,SAAS,EAAE,MAAM;IACjB,gBAAgB,EAAE,MAAM;CACzB,CAAC;AAEF;;;;GAIG;AACH,MAAM,UAAU,eAAe,CAAC,QAAgB;IAC9C,MAAM,QAAQ,GAAG,QAAQ,CAAC,KAAK,CAAC,SAAS,CAAC,CAAC;IAC3C,OAAO,QAAQ,CAAC,QAAQ,CAAC,MAAM,GAAG,CAAC,CAAC,IAAI,QAAQ,CAAC;AACnD,CAAC;AAQD,gFAAgF;AAChF,MAAM,UAAU,yBAAyB,CACvC,QAAgB;IAEhB,MAAM,IAAI,GAAG,eAAe,CAAC,QAAQ,CAAC,CAAC;IACvC,IAAI,iBAAiB,CAAC,IAAI,CAAC,EAAE,CAAC;QAC5B,OAAO,EAAE,IAAI,EAAE,MAAM,EAAE,SAAS,EAAE,iBAAiB,CAAC,IAAI,CAAE,EAAE,CAAC;IAC/D,CAAC;IACD,IAAI,kBAAkB,CAAC,IAAI,CAAC,EAAE,CAAC;QAC7B,OAAO,EAAE,IAAI,EAAE,OAAO,EAAE,SAAS,EAAE,kBAAkB,CAAC,IAAI,CAAE,EAAE,CAAC;IACjE,CAAC;IACD,OAAO,IAAI,CAAC;AACd,CAAC"}
@@ -0,0 +1,67 @@
1
+ import { type CredentialStore, type StoredCredential } from "./credentials.js";
2
+ export declare const MCP_OAUTH_CLIENT_NAME = "axtary-mcp-wrapper";
3
+ /** Stable credential-broker key for a remote MCP server, by canonical resource URI. */
4
+ export declare function mcpOAuthProviderKey(wrapUrl: string): string;
5
+ export type McpOAuthLoginInput = {
6
+ wrapUrl: string;
7
+ scopes?: string[];
8
+ /** A pre-registered client id; skips Dynamic Client Registration. */
9
+ clientId?: string;
10
+ clientSecret?: string;
11
+ redirectPort?: number;
12
+ store?: CredentialStore;
13
+ fetch?: typeof fetch;
14
+ openBrowser?: (url: string) => void | Promise<void>;
15
+ stdout?: (text: string) => void;
16
+ now?: () => number;
17
+ randomState?: () => string;
18
+ pkceVerifier?: () => string;
19
+ timeoutMs?: number;
20
+ onListening?: (port: number) => void;
21
+ };
22
+ export type McpOAuthLoginResult = {
23
+ resource: string;
24
+ issuer: string;
25
+ authMethod: "dynamic_registration" | "preregistered_client";
26
+ scopes: string[];
27
+ expiresAt: string | null;
28
+ account: string | null;
29
+ secretBackend: StoredCredential["secretBackend"];
30
+ };
31
+ export declare function runMcpLogin(input: McpOAuthLoginInput): Promise<McpOAuthLoginResult>;
32
+ export declare function runMcpLogout(input: {
33
+ wrapUrl: string;
34
+ store?: CredentialStore;
35
+ }): Promise<{
36
+ resource: string;
37
+ removed: boolean;
38
+ }>;
39
+ export type McpOAuthSession = {
40
+ resource: string;
41
+ issuer: string | null;
42
+ scopes: string[];
43
+ expiresAt: string | null;
44
+ status: "live" | "stale";
45
+ account: string | null;
46
+ };
47
+ /** List remote-MCP OAuth sessions from the broker — metadata only, never tokens. */
48
+ export declare function runMcpSessions(input?: {
49
+ store?: CredentialStore;
50
+ now?: number;
51
+ }): Promise<McpOAuthSession[]>;
52
+ /**
53
+ * Resolve the `Authorization: Bearer` header for a remote MCP server from the
54
+ * broker, refreshing a lapsed token when a refresh token and token endpoint are
55
+ * available. Fails closed with an actionable error when no session exists or a
56
+ * stale session cannot be refreshed — the bearer is never invented.
57
+ */
58
+ export declare function resolveMcpOAuthAuthorization(input: {
59
+ wrapUrl: string;
60
+ store?: CredentialStore;
61
+ fetch?: typeof fetch;
62
+ now?: () => number;
63
+ }): Promise<{
64
+ authorization: string;
65
+ resource: string;
66
+ }>;
67
+ //# sourceMappingURL=mcp-oauth.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"mcp-oauth.d.ts","sourceRoot":"","sources":["../src/mcp-oauth.ts"],"names":[],"mappings":"AAcA,OAAO,EAGL,KAAK,eAAe,EACpB,KAAK,gBAAgB,EACtB,MAAM,kBAAkB,CAAC;AAoB1B,eAAO,MAAM,qBAAqB,uBAAuB,CAAC;AAE1D,uFAAuF;AACvF,wBAAgB,mBAAmB,CAAC,OAAO,EAAE,MAAM,GAAG,MAAM,CAE3D;AAED,MAAM,MAAM,kBAAkB,GAAG;IAC/B,OAAO,EAAE,MAAM,CAAC;IAChB,MAAM,CAAC,EAAE,MAAM,EAAE,CAAC;IAClB,qEAAqE;IACrE,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,KAAK,CAAC,EAAE,eAAe,CAAC;IACxB,KAAK,CAAC,EAAE,OAAO,KAAK,CAAC;IACrB,WAAW,CAAC,EAAE,CAAC,GAAG,EAAE,MAAM,KAAK,IAAI,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;IACpD,MAAM,CAAC,EAAE,CAAC,IAAI,EAAE,MAAM,KAAK,IAAI,CAAC;IAChC,GAAG,CAAC,EAAE,MAAM,MAAM,CAAC;IACnB,WAAW,CAAC,EAAE,MAAM,MAAM,CAAC;IAC3B,YAAY,CAAC,EAAE,MAAM,MAAM,CAAC;IAC5B,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,WAAW,CAAC,EAAE,CAAC,IAAI,EAAE,MAAM,KAAK,IAAI,CAAC;CACtC,CAAC;AAEF,MAAM,MAAM,mBAAmB,GAAG;IAChC,QAAQ,EAAE,MAAM,CAAC;IACjB,MAAM,EAAE,MAAM,CAAC;IACf,UAAU,EAAE,sBAAsB,GAAG,sBAAsB,CAAC;IAC5D,MAAM,EAAE,MAAM,EAAE,CAAC;IACjB,SAAS,EAAE,MAAM,GAAG,IAAI,CAAC;IACzB,OAAO,EAAE,MAAM,GAAG,IAAI,CAAC;IACvB,aAAa,EAAE,gBAAgB,CAAC,eAAe,CAAC,CAAC;CAClD,CAAC;AAgCF,wBAAsB,WAAW,CAC/B,KAAK,EAAE,kBAAkB,GACxB,OAAO,CAAC,mBAAmB,CAAC,CAgJ9B;AAED,wBAAsB,YAAY,CAAC,KAAK,EAAE;IACxC,OAAO,EAAE,MAAM,CAAC;IAChB,KAAK,CAAC,EAAE,eAAe,CAAC;CACzB,GAAG,OAAO,CAAC;IAAE,QAAQ,EAAE,MAAM,CAAC;IAAC,OAAO,EAAE,OAAO,CAAA;CAAE,CAAC,CAIlD;AAED,MAAM,MAAM,eAAe,GAAG;IAC5B,QAAQ,EAAE,MAAM,CAAC;IACjB,MAAM,EAAE,MAAM,GAAG,IAAI,CAAC;IACtB,MAAM,EAAE,MAAM,EAAE,CAAC;IACjB,SAAS,EAAE,MAAM,GAAG,IAAI,CAAC;IACzB,MAAM,EAAE,MAAM,GAAG,OAAO,CAAC;IACzB,OAAO,EAAE,MAAM,GAAG,IAAI,CAAC;CACxB,CAAC;AAEF,oFAAoF;AACpF,wBAAsB,cAAc,CAAC,KAAK,GAAE;IAC1C,KAAK,CAAC,EAAE,eAAe,CAAC;IACxB,GAAG,CAAC,EAAE,MAAM,CAAC;CACT,GAAG,OAAO,CAAC,eAAe,EAAE,CAAC,CAiBlC;AAED;;;;;GAKG;AACH,wBAAsB,4BAA4B,CAAC,KAAK,EAAE;IACxD,OAAO,EAAE,MAAM,CAAC;IAChB,KAAK,CAAC,EAAE,eAAe,CAAC;IACxB,KAAK,CAAC,EAAE,OAAO,KAAK,CAAC;IACrB,GAAG,CAAC,EAAE,MAAM,MAAM,CAAC;CACpB,GAAG,OAAO,CAAC;IAAE,aAAa,EAAE,MAAM,CAAC;IAAC,QAAQ,EAAE,MAAM,CAAA;CAAE,CAAC,CAuDvD"}
@@ -0,0 +1,242 @@
1
+ import { buildAuthorizationUrl, canonicalResourceUri, createOAuthState, createPkcePair, discoverAuthorizationServerMetadata, discoverProtectedResourceMetadata, exchangeAuthorizationCode, refreshAccessToken, registerOAuthClient, } from "@axtary/mcp";
2
+ import { credentialExpired, loadCredentialStore, } from "./credentials.js";
3
+ import { captureAuthorizationCode, defaultOpenBrowser, listen, DEFAULT_OAUTH_REDIRECT_PATH, DEFAULT_OAUTH_REDIRECT_PORT, } from "./oauth.js";
4
+ // Remote-MCP OAuth, wired to the local credential broker.
5
+ //
6
+ // `axtary mcp login --wrap-url <https url>` discovers the server's authorization
7
+ // server (RFC 9728 → RFC 8414), registers a public PKCE client when the server
8
+ // supports Dynamic Client Registration (RFC 7591), runs the loopback consent
9
+ // flow, and stores the resulting bearer + refresh token in the same 0600/keychain
10
+ // broker as native connectors. The token never leaves the enforcement plane: it
11
+ // lives only in the broker and the upstream request header — never in pins, the
12
+ // ledger, status output, or the dashboard. `axtary mcp serve --oauth` then
13
+ // resolves (and refreshes) that bearer when connecting upstream.
14
+ export const MCP_OAUTH_CLIENT_NAME = "axtary-mcp-wrapper";
15
+ /** Stable credential-broker key for a remote MCP server, by canonical resource URI. */
16
+ export function mcpOAuthProviderKey(wrapUrl) {
17
+ return `mcp-remote:${canonicalResourceUri(wrapUrl)}`;
18
+ }
19
+ /**
20
+ * Probe the MCP endpoint to recover the `WWW-Authenticate` header from a 401, so
21
+ * discovery can prefer the advertised `resource_metadata` URL. Best-effort: a
22
+ * server that does not 401 (or any transport error) simply yields no header and
23
+ * discovery falls back to the well-known path.
24
+ */
25
+ async function probeWwwAuthenticate(wrapUrl, fetchImpl, timeoutMs) {
26
+ try {
27
+ const response = await fetchImpl(wrapUrl, {
28
+ method: "POST",
29
+ headers: { "content-type": "application/json", accept: "application/json" },
30
+ body: JSON.stringify({
31
+ jsonrpc: "2.0",
32
+ id: "axtary_oauth_probe",
33
+ method: "ping",
34
+ params: {},
35
+ }),
36
+ signal: AbortSignal.timeout(timeoutMs),
37
+ });
38
+ void response.body?.cancel();
39
+ return response.headers.get("www-authenticate") ?? undefined;
40
+ }
41
+ catch {
42
+ return undefined;
43
+ }
44
+ }
45
+ export async function runMcpLogin(input) {
46
+ const fetchImpl = input.fetch ?? globalThis.fetch;
47
+ const stdout = input.stdout ?? ((text) => process.stdout.write(text));
48
+ const now = input.now ?? (() => Date.now());
49
+ const timeoutMs = input.timeoutMs ?? 300_000;
50
+ const discoveryTimeoutMs = 15_000;
51
+ const resource = canonicalResourceUri(input.wrapUrl);
52
+ const wwwAuthenticate = await probeWwwAuthenticate(input.wrapUrl, fetchImpl, discoveryTimeoutMs);
53
+ const prm = await discoverProtectedResourceMetadata({
54
+ mcpUrl: input.wrapUrl,
55
+ fetch: fetchImpl,
56
+ wwwAuthenticate,
57
+ timeoutMs: discoveryTimeoutMs,
58
+ });
59
+ const asMeta = await discoverAuthorizationServerMetadata({
60
+ issuer: prm.authorizationServers[0],
61
+ fetch: fetchImpl,
62
+ timeoutMs: discoveryTimeoutMs,
63
+ });
64
+ const scopes = input.scopes && input.scopes.length > 0
65
+ ? input.scopes
66
+ : prm.scopesSupported.length > 0
67
+ ? prm.scopesSupported
68
+ : asMeta.scopesSupported;
69
+ // Dynamic Client Registration registers whatever redirect we bound, so default
70
+ // to an ephemeral port (0) for the DCR path — there is no fixed, predictable
71
+ // port for another local process to pre-bind and race for the callback. A
72
+ // pre-registered client (explicit --client-id) keeps the conventional 7878,
73
+ // since its redirect URI was registered out of band.
74
+ const redirectPort = input.redirectPort ?? (input.clientId ? DEFAULT_OAUTH_REDIRECT_PORT : 0);
75
+ const { server, port } = await listen(redirectPort);
76
+ input.onListening?.(port);
77
+ const redirectUri = `http://127.0.0.1:${port}${DEFAULT_OAUTH_REDIRECT_PATH}`;
78
+ let authMethod = "preregistered_client";
79
+ let clientId = input.clientId;
80
+ let clientSecret = input.clientSecret;
81
+ try {
82
+ if (!clientId) {
83
+ if (!asMeta.registrationEndpoint) {
84
+ throw new Error(`mcp_oauth_no_client_id:${asMeta.issuer} does not support dynamic registration — pass --client-id`);
85
+ }
86
+ const registered = await registerOAuthClient({
87
+ registrationEndpoint: asMeta.registrationEndpoint,
88
+ redirectUris: [redirectUri],
89
+ clientName: MCP_OAUTH_CLIENT_NAME,
90
+ scopes,
91
+ fetch: fetchImpl,
92
+ timeoutMs: discoveryTimeoutMs,
93
+ });
94
+ clientId = registered.clientId;
95
+ clientSecret = registered.clientSecret ?? undefined;
96
+ authMethod = "dynamic_registration";
97
+ }
98
+ const pkce = createPkcePair(input.pkceVerifier);
99
+ const state = createOAuthState(input.randomState);
100
+ const authorization = await captureAuthorizationCode({
101
+ server,
102
+ redirectPath: DEFAULT_OAUTH_REDIRECT_PATH,
103
+ state,
104
+ timeoutMs,
105
+ start: async () => {
106
+ const authorizeUrl = buildAuthorizationUrl({
107
+ authorizationEndpoint: asMeta.authorizationEndpoint,
108
+ clientId: clientId,
109
+ redirectUri,
110
+ resource,
111
+ scopes,
112
+ state,
113
+ codeChallenge: pkce.challenge,
114
+ });
115
+ stdout(`Opening your browser to authorize ${resource}.\n`);
116
+ stdout(`If it does not open, visit:\n ${authorizeUrl}\n`);
117
+ await (input.openBrowser ?? defaultOpenBrowser)(authorizeUrl);
118
+ },
119
+ });
120
+ const tokens = await exchangeAuthorizationCode({
121
+ tokenEndpoint: asMeta.tokenEndpoint,
122
+ clientId: clientId,
123
+ clientSecret,
124
+ code: authorization.code,
125
+ redirectUri,
126
+ codeVerifier: pkce.verifier,
127
+ resource,
128
+ fetch: fetchImpl,
129
+ timeoutMs: discoveryTimeoutMs,
130
+ });
131
+ const grantedScopes = tokens.scope.length > 0 ? tokens.scope : scopes;
132
+ const expiresAt = tokens.expiresIn
133
+ ? new Date(now() + tokens.expiresIn * 1000).toISOString()
134
+ : null;
135
+ const store = input.store ?? loadCredentialStore();
136
+ const metadata = await store.set({
137
+ provider: mcpOAuthProviderKey(input.wrapUrl),
138
+ type: "oauth",
139
+ source: "oauth",
140
+ accessToken: tokens.accessToken,
141
+ refreshToken: tokens.refreshToken,
142
+ scopes: grantedScopes,
143
+ expiresAt,
144
+ account: prm.resourceName,
145
+ context: {
146
+ resource,
147
+ issuer: asMeta.issuer,
148
+ tokenEndpoint: asMeta.tokenEndpoint,
149
+ authorizationEndpoint: asMeta.authorizationEndpoint,
150
+ clientId: clientId,
151
+ transport: "streamable-http",
152
+ authMethod,
153
+ },
154
+ });
155
+ return {
156
+ resource,
157
+ issuer: asMeta.issuer,
158
+ authMethod,
159
+ scopes: metadata.scopes,
160
+ expiresAt: metadata.expiresAt,
161
+ account: metadata.account,
162
+ secretBackend: metadata.secretBackend,
163
+ };
164
+ }
165
+ finally {
166
+ server.close();
167
+ }
168
+ }
169
+ export async function runMcpLogout(input) {
170
+ const store = input.store ?? loadCredentialStore();
171
+ const removed = await store.delete(mcpOAuthProviderKey(input.wrapUrl));
172
+ return { resource: canonicalResourceUri(input.wrapUrl), removed };
173
+ }
174
+ /** List remote-MCP OAuth sessions from the broker — metadata only, never tokens. */
175
+ export async function runMcpSessions(input = {}) {
176
+ const store = input.store ?? loadCredentialStore();
177
+ const metadata = await store.list();
178
+ return metadata
179
+ .filter((entry) => entry.provider.startsWith("mcp-remote:"))
180
+ .map((entry) => ({
181
+ resource: entry.context?.resource ?? entry.provider.slice("mcp-remote:".length),
182
+ issuer: entry.context?.issuer ?? null,
183
+ scopes: entry.scopes,
184
+ expiresAt: entry.expiresAt,
185
+ status: credentialExpired({ expiresAt: entry.expiresAt }, input.now)
186
+ ? "stale"
187
+ : "live",
188
+ account: entry.account,
189
+ }))
190
+ .sort((a, b) => a.resource.localeCompare(b.resource));
191
+ }
192
+ /**
193
+ * Resolve the `Authorization: Bearer` header for a remote MCP server from the
194
+ * broker, refreshing a lapsed token when a refresh token and token endpoint are
195
+ * available. Fails closed with an actionable error when no session exists or a
196
+ * stale session cannot be refreshed — the bearer is never invented.
197
+ */
198
+ export async function resolveMcpOAuthAuthorization(input) {
199
+ const store = input.store ?? loadCredentialStore();
200
+ const now = input.now ?? (() => Date.now());
201
+ const resource = canonicalResourceUri(input.wrapUrl);
202
+ const key = mcpOAuthProviderKey(input.wrapUrl);
203
+ const credential = await store.get(key);
204
+ if (!credential) {
205
+ throw new Error(`mcp_oauth_not_authorized:${resource} — run 'axtary mcp login --wrap-url ${input.wrapUrl}'`);
206
+ }
207
+ if (!credentialExpired(credential, now())) {
208
+ return { authorization: `Bearer ${credential.accessToken}`, resource };
209
+ }
210
+ const tokenEndpoint = credential.context?.tokenEndpoint;
211
+ const clientId = credential.context?.clientId;
212
+ if (!credential.refreshToken || !tokenEndpoint || !clientId) {
213
+ throw new Error(`mcp_oauth_session_expired:${resource} — run 'axtary mcp login --wrap-url ${input.wrapUrl}'`);
214
+ }
215
+ const refreshed = await refreshAccessToken({
216
+ tokenEndpoint,
217
+ clientId,
218
+ refreshToken: credential.refreshToken,
219
+ resource,
220
+ scopes: credential.scopes,
221
+ fetch: input.fetch ?? globalThis.fetch,
222
+ });
223
+ const grantedScopes = refreshed.scope.length > 0 ? refreshed.scope : credential.scopes;
224
+ const expiresAt = refreshed.expiresIn
225
+ ? new Date(now() + refreshed.expiresIn * 1000).toISOString()
226
+ : null;
227
+ await store.set({
228
+ provider: key,
229
+ type: "oauth",
230
+ source: "oauth",
231
+ accessToken: refreshed.accessToken,
232
+ // OAuth 2.1 rotates public-client refresh tokens; keep the prior one if the
233
+ // server did not return a new one.
234
+ refreshToken: refreshed.refreshToken ?? credential.refreshToken,
235
+ scopes: grantedScopes,
236
+ expiresAt,
237
+ account: credential.account,
238
+ context: credential.context,
239
+ });
240
+ return { authorization: `Bearer ${refreshed.accessToken}`, resource };
241
+ }
242
+ //# sourceMappingURL=mcp-oauth.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"mcp-oauth.js","sourceRoot":"","sources":["../src/mcp-oauth.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,90 @@
1
+ import { type Server } from "node:http";
2
+ export declare const DEFAULT_OAUTH_REDIRECT_PORT = 7878;
3
+ export declare const DEFAULT_OAUTH_REDIRECT_PATH = "/callback";
4
+ export type OAuthProviderDescriptor = {
5
+ provider: string;
6
+ authorizeUrl: string;
7
+ tokenUrl: string;
8
+ scopes: string[];
9
+ /** Separator used in the `scope` param. Slack uses ",", most use " ". */
10
+ scopeSeparator: string;
11
+ /** Whether to use PKCE (S256). Slack/Linear v2 require a client secret instead. */
12
+ pkce: boolean;
13
+ /** Whether the token exchange needs the client secret. */
14
+ requiresClientSecret: boolean;
15
+ tokenRequestFormat?: "form" | "json";
16
+ /**
17
+ * Whether the provider rejects a plain-http loopback redirect and requires an
18
+ * HTTPS redirect URI. Slack does (verified: Slack OAuth rejects http://
19
+ * redirects), so a bare `127.0.0.1` loopback cannot be used — the caller must
20
+ * supply an HTTPS redirect (e.g. a tunnel) or use a different credential path.
21
+ * Linear accepts http://localhost.
22
+ */
23
+ requiresHttpsRedirect: boolean;
24
+ extraAuthParams?: Record<string, string>;
25
+ };
26
+ export declare const OAUTH_PROVIDERS: Record<string, OAuthProviderDescriptor>;
27
+ export type OAuthTokenResult = {
28
+ accessToken: string;
29
+ refreshToken: string | null;
30
+ tokenType: string | null;
31
+ scope: string[];
32
+ expiresAt: string | null;
33
+ account: string | null;
34
+ selectedResourceIds: string[];
35
+ };
36
+ export type LoopbackOAuthInput = {
37
+ descriptor: OAuthProviderDescriptor;
38
+ clientId: string;
39
+ clientSecret?: string;
40
+ redirectPort?: number;
41
+ redirectPath?: string;
42
+ /**
43
+ * The redirect URI advertised to the provider. Defaults to the local loopback
44
+ * (`http://127.0.0.1:<port><path>`). Override with a tunnel's HTTPS URL when a
45
+ * provider requires HTTPS (e.g. Slack); the local server still listens on
46
+ * redirectPort and the tunnel forwards to it.
47
+ */
48
+ redirectUri?: string;
49
+ openBrowser: (url: string) => void | Promise<void>;
50
+ fetch?: typeof fetch;
51
+ now?: () => number;
52
+ randomState?: () => string;
53
+ pkceVerifier?: () => string;
54
+ timeoutMs?: number;
55
+ /** Called with the bound local port once listening (useful for tunnels/tests). */
56
+ onListening?: (port: number) => void;
57
+ };
58
+ export declare function runLoopbackOAuth(input: LoopbackOAuthInput): Promise<OAuthTokenResult>;
59
+ export type AtlassianAccessibleResource = {
60
+ id: string;
61
+ url: string;
62
+ name: string;
63
+ scopes: string[];
64
+ avatarUrl?: string;
65
+ };
66
+ export declare function discoverAtlassianAccessibleResources(accessToken: string, fetchImpl?: typeof fetch): Promise<AtlassianAccessibleResource[]>;
67
+ export declare function refreshOAuthAccessToken(input: {
68
+ descriptor: OAuthProviderDescriptor;
69
+ clientId: string;
70
+ clientSecret?: string;
71
+ refreshToken: string;
72
+ fetch?: typeof fetch;
73
+ now?: () => number;
74
+ }): Promise<OAuthTokenResult>;
75
+ export declare function listen(port: number): Promise<{
76
+ server: Server;
77
+ port: number;
78
+ }>;
79
+ export declare function captureAuthorizationCode(input: {
80
+ server: Server;
81
+ redirectPath: string;
82
+ state: string;
83
+ timeoutMs: number;
84
+ start: () => Promise<void>;
85
+ }): Promise<{
86
+ code: string;
87
+ selectedResourceIds: string[];
88
+ }>;
89
+ export declare function defaultOpenBrowser(url: string): void;
90
+ //# sourceMappingURL=oauth.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"oauth.d.ts","sourceRoot":"","sources":["../src/oauth.ts"],"names":[],"mappings":"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"}