@haikit/mcp 0.32.0 → 0.34.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 (52) hide show
  1. package/README.md +60 -1
  2. package/dist/auth.d.ts +151 -0
  3. package/dist/auth.d.ts.map +1 -0
  4. package/dist/auth.js +334 -0
  5. package/dist/auth.js.map +1 -0
  6. package/dist/credential.d.ts +55 -0
  7. package/dist/credential.d.ts.map +1 -0
  8. package/dist/credential.js +62 -0
  9. package/dist/credential.js.map +1 -0
  10. package/dist/errors.d.ts +24 -1
  11. package/dist/errors.d.ts.map +1 -1
  12. package/dist/errors.js +3 -0
  13. package/dist/errors.js.map +1 -1
  14. package/dist/index.d.ts +44 -11
  15. package/dist/index.d.ts.map +1 -1
  16. package/dist/index.js +511 -144
  17. package/dist/index.js.map +1 -1
  18. package/dist/oauth.d.ts +193 -0
  19. package/dist/oauth.d.ts.map +1 -0
  20. package/dist/oauth.js +558 -0
  21. package/dist/oauth.js.map +1 -0
  22. package/dist/postgres.d.ts +25 -0
  23. package/dist/postgres.d.ts.map +1 -0
  24. package/dist/postgres.js +97 -0
  25. package/dist/postgres.js.map +1 -0
  26. package/dist/routes.d.ts +17 -0
  27. package/dist/routes.d.ts.map +1 -0
  28. package/dist/routes.js +228 -0
  29. package/dist/routes.js.map +1 -0
  30. package/dist/seal.d.ts +25 -0
  31. package/dist/seal.d.ts.map +1 -0
  32. package/dist/seal.js +60 -0
  33. package/dist/seal.js.map +1 -0
  34. package/dist/store.d.ts +50 -0
  35. package/dist/store.d.ts.map +1 -0
  36. package/dist/store.js +83 -0
  37. package/dist/store.js.map +1 -0
  38. package/dist/transports.d.ts +17 -3
  39. package/dist/transports.d.ts.map +1 -1
  40. package/dist/transports.js +13 -3
  41. package/dist/transports.js.map +1 -1
  42. package/package.json +6 -2
  43. package/src/auth.ts +466 -0
  44. package/src/credential.ts +78 -0
  45. package/src/errors.ts +26 -2
  46. package/src/index.ts +555 -158
  47. package/src/oauth.ts +659 -0
  48. package/src/postgres.ts +127 -0
  49. package/src/routes.ts +243 -0
  50. package/src/seal.ts +62 -0
  51. package/src/store.ts +118 -0
  52. package/src/transports.ts +34 -4
package/README.md CHANGED
@@ -53,10 +53,69 @@ await github.connect(); // at startup: stops here if a declared tool isn't on th
53
53
  - `textOf(result)` turns a result into text, for a tool that decides to pass
54
54
  some of it on. A cut is always marked in the text.
55
55
 
56
+ A server can take each user's own credential instead of the app's. Then each
57
+ call runs as the conversation's owner, over a connection of their own:
58
+
59
+ ```ts
60
+ import { createMcpAuth } from "@haikit/mcp";
61
+ import { pgCredentialStore } from "@haikit/mcp/postgres";
62
+
63
+ const mcpAuth = createMcpAuth({
64
+ userOf: (id) => auth.ownerOf(id), // auth from @haikit/auth
65
+ // for oauth(): where each user's tokens are kept, sealed, and who's signed in
66
+ store: pgCredentialStore(pool), // or memoryCredentialStore()
67
+ secret: process.env.MCP_SECRET!, // 32 bytes or more; a list to rotate
68
+ redirectUri: "https://app.example.com/mcp/callback",
69
+ requestUser: async (req) => (await auth.user(req))?.id ?? null,
70
+ onConnected: ({ userId, server, conversationId }) => { /* wake the conversation */ },
71
+ });
72
+
73
+ // a token the app already has for each user, or null
74
+ const tracker = mcpServer({
75
+ name: "tracker",
76
+ transport: http("https://mcp.tracker.example/mcp"),
77
+ auth: mcpAuth.bearer((userId) => keys.find(userId)),
78
+ });
79
+
80
+ // each user connects their own account, with the server's authorization server
81
+ const linear = mcpServer({
82
+ name: "linear",
83
+ transport: http("https://mcp.linear.example/mcp"),
84
+ auth: mcpAuth.oauth({ issuer: "https://linear.example" }), // pin a third party's
85
+ });
86
+
87
+ // the connect, callback and disconnect routes, beside your own
88
+ const mcpRoutes = mcpAuth.handler();
89
+ createServer(async (req, res) => {
90
+ if (await mcpRoutes(req, res)) return;
91
+ // ...
92
+ });
93
+ ```
94
+
95
+ A call with no one to run as is refused with reason `user`, and one for a user
96
+ with no credential with reason `auth`, before anything is sent: it never
97
+ falls back to the app's identity. `err.auth.kind` says what the user must
98
+ do: `connect`, `reconnect`, or grant more `scope`. For an `oauth()` server,
99
+ `err.auth.connect` is the app's link for it, such as
100
+ `/mcp/connect/linear?conversation=c_123`, to show the user in a surface,
101
+ never to give the model. A job outside any conversation passes `{ userId }`.
102
+
103
+ With `oauth()`, the connect route sends the user to the authorization server
104
+ with PKCE, and the callback stores their tokens sealed with `secret`, bound
105
+ to the user and the server. A 401 refreshes them once, however many calls
106
+ get one. Across app processes sharing the store, one at a time takes the
107
+ store's refresh lease and spends the refresh token, and the others use what
108
+ it stores. Each call reads the store first, so a refresh, a connect or a
109
+ disconnect in another process is seen on the next call. `connections(userId)` lists what a user connected, and
110
+ `disconnect(userId, server?)` revokes and deletes.
111
+ `mcpAuth.sdk(make)` takes one of the SDK's own providers for each user
112
+ instead.
113
+
56
114
  `McpTool` isn't a HaiKIT `Tool`, so it can't be passed to
57
115
  `createHai({ tools })`: `npm run typetest` checks that.
58
116
 
59
- Imports only `@haikit/core`, never `@haikit/server`. Built on
117
+ Imports only `@haikit/core`, never `@haikit/server`. `@haikit/mcp/postgres`
118
+ takes any driver with `query(text, params)`, such as a `pg.Pool`. Built on
60
119
  [`@modelcontextprotocol/client`](https://www.npmjs.com/package/@modelcontextprotocol/client),
61
120
  the official TypeScript SDK's client.
62
121
 
package/dist/auth.d.ts ADDED
@@ -0,0 +1,151 @@
1
+ import type { IncomingMessage, ServerResponse } from "node:http";
2
+ import type { AuthProvider, FetchLike, OAuthClientProvider } from "@modelcontextprotocol/client";
3
+ import { type Credential } from "./credential.js";
4
+ import { type OAuthServerOptions } from "./oauth.js";
5
+ import { type CredentialStore } from "./store.js";
6
+ export { LookupFailed, Mismatch, NeedsAuth, type Credential } from "./credential.js";
7
+ export type { OAuthServerOptions } from "./oauth.js";
8
+ export interface McpAuthOptions {
9
+ /**
10
+ * Who a conversation belongs to: the user a call made in it runs as. With
11
+ * @haikit/auth, `(id) => auth.ownerOf(id)`. `null` for no one.
12
+ */
13
+ userOf(conversationId: string): string | null | Promise<string | null>;
14
+ /**
15
+ * Where each user's OAuth credentials are kept, sealed:
16
+ * `memoryCredentialStore()`, or `pgCredentialStore(db)` from
17
+ * `@haikit/mcp/postgres`. With `secret` and `redirectUri`, for `oauth()`.
18
+ */
19
+ store?: CredentialStore;
20
+ /**
21
+ * Seals every credential at rest. Several: the first seals, and every one
22
+ * opens, so a secret can be rotated out. Each at least 32 bytes.
23
+ */
24
+ secret?: string | string[];
25
+ /**
26
+ * Where an authorization server sends the browser back, exactly as
27
+ * registered with it: its path is the callback route. https, except on
28
+ * localhost.
29
+ */
30
+ redirectUri?: string;
31
+ /**
32
+ * The signed-in user a request to the routes comes from, or `null`. With
33
+ * @haikit/auth, `async (req) => (await auth.user(req))?.id ?? null`. For
34
+ * `handler()`.
35
+ */
36
+ requestUser?(req: IncomingMessage): string | null | Promise<string | null>;
37
+ /**
38
+ * A user has connected an account, at the callback route. With the
39
+ * conversation the connect link was for, if they own it. What it throws is
40
+ * logged: the user is connected all the same.
41
+ */
42
+ onConnected?(connected: McpConnected): void | Promise<void>;
43
+ /** Where `handler()`'s routes are, and the connect links point. Default `"/mcp"`. */
44
+ basePath?: string;
45
+ /** The app's name, which an authorization server shows when the user connects. Default: the redirect URI's host. */
46
+ clientName?: string;
47
+ }
48
+ /** What `onConnected` is told. */
49
+ export interface McpConnected {
50
+ userId: string;
51
+ server: string;
52
+ /** The conversation the connect link was for: only one the user owns. */
53
+ conversationId?: string;
54
+ }
55
+ /** A server a user has connected an account for, from `connections()`. */
56
+ export interface McpAccount {
57
+ /** The server's `name`. */
58
+ name: string;
59
+ /** The scope granted, or asked for when the authorization server didn't say. */
60
+ scope: string | null;
61
+ /** When the user connected, epoch ms. */
62
+ connectedAt: number;
63
+ }
64
+ /** Makes the `auth` of servers whose calls are made as each user. */
65
+ export interface McpAuth {
66
+ /**
67
+ * Each user's own token, which the app already has: `token(userId)` gives
68
+ * it, or `null` when the user has none. Sent as `Authorization: Bearer`.
69
+ */
70
+ bearer(token: (userId: string) => string | null | Promise<string | null>): McpServerAuth;
71
+ /**
72
+ * Each user connects their account through the connect route, and the
73
+ * store keeps their tokens. Needs `store`, `secret` and `redirectUri`.
74
+ */
75
+ oauth(options?: OAuthServerOptions): McpServerAuth;
76
+ /**
77
+ * One of the SDK's own providers, made for each user: `make(userId)` gives
78
+ * it, or `null` when the user has none. The app owns the whole provider:
79
+ * nothing is stored, and there's no connect route.
80
+ */
81
+ sdk(make: (userId: string) => AuthProvider | OAuthClientProvider | null | Promise<AuthProvider | OAuthClientProvider | null>): McpServerAuth;
82
+ /**
83
+ * The routes, under `basePath`: connect, the callback at the redirect URI's
84
+ * path, disconnect, the user's connections, and the client metadata
85
+ * document. Resolves false for anything else. Needs `requestUser`.
86
+ */
87
+ handler(): (req: IncomingMessage, res: ServerResponse) => Promise<boolean>;
88
+ /** The `oauth()` servers a user has connected an account for. */
89
+ connections(userId: string): Promise<McpAccount[]>;
90
+ /**
91
+ * Revokes a user's tokens for a server where its authorization server takes
92
+ * it, deletes them, and closes the user's connection; with no `server`, for
93
+ * every server they connected.
94
+ */
95
+ disconnect(userId: string, server?: string): Promise<void>;
96
+ }
97
+ /** How a server's calls are made as each user: made by an `McpAuth`, and given to `mcpServer({ auth })`. */
98
+ export interface McpServerAuth {
99
+ readonly kind: "bearer" | "oauth" | "sdk";
100
+ }
101
+ /** What a server tells its `McpAuth` of itself. */
102
+ export interface Attached {
103
+ name: string;
104
+ timeoutMs: number;
105
+ url: URL;
106
+ fetch: FetchLike | undefined;
107
+ forget(userId: string): Promise<void>;
108
+ }
109
+ /** A server's place on its `McpAuth`. */
110
+ export interface Binding {
111
+ /** The user's credential, for a new connection of theirs. */
112
+ credential(userId: string): Credential;
113
+ /** The connect route's path, for an `oauth()` server: for this conversation, and asking for `scope`. */
114
+ readonly connect: ((conversationId: string | undefined, scope: string | undefined) => string) | null;
115
+ /** Frees the name, for a closed server. */
116
+ detach(): void;
117
+ }
118
+ /** What an `McpServerAuth` stands for. */
119
+ export interface AuthConfig {
120
+ readonly kind: McpServerAuth["kind"];
121
+ userOf(conversationId: string): string | null | Promise<string | null>;
122
+ /** Takes the server's name on this `McpAuth`, or throws if another server has it: the name keys its users' credentials. */
123
+ attach(server: Attached): Binding;
124
+ }
125
+ /** The config an `McpServerAuth` stands for, or undefined if `createMcpAuth` didn't make it. */
126
+ export declare const configOf: (auth: unknown) => AuthConfig | undefined;
127
+ /**
128
+ * For servers whose calls are made as each user, with that user's own
129
+ * credential: `mcpServer({ auth: mcpAuth.oauth() })`.
130
+ */
131
+ export declare function createMcpAuth(options: McpAuthOptions): McpAuth;
132
+ /** A token from `bearer`'s function, kept until a lookup on a 401 finds another, or none. */
133
+ export declare class BearerCredential implements Credential {
134
+ private readonly read;
135
+ private readonly user;
136
+ private token;
137
+ /** The lookup on its way, which every caller shares: only it sets `token`. */
138
+ private looking;
139
+ /** Bounds `read`: a lookup that never answers would hold up every call after it. */
140
+ private readonly lookups;
141
+ constructor(read: (userId: string) => string | null | Promise<string | null>, user: string,
142
+ /** How long `read` may take. */
143
+ timeoutMs: number);
144
+ ensure(): Promise<boolean>;
145
+ close(): void;
146
+ readonly provider: AuthProvider;
147
+ /** One lookup at a time, for first calls and 401s that come together, so none overwrites another's token. */
148
+ private look;
149
+ private lookup;
150
+ }
151
+ //# sourceMappingURL=auth.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"auth.d.ts","sourceRoot":"","sources":["../src/auth.ts"],"names":[],"mappings":"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"}
package/dist/auth.js ADDED
@@ -0,0 +1,334 @@
1
+ import { LookupFailed, Lookup, NeedsAuth } from "./credential.js";
2
+ import { OAuthServer, isSecure } from "./oauth.js";
3
+ import { routes } from "./routes.js";
4
+ import { SECRET_BYTES, Sealer } from "./seal.js";
5
+ import { STORE_METHODS } from "./store.js";
6
+ export { LookupFailed, Mismatch, NeedsAuth } from "./credential.js";
7
+ const configs = new WeakMap();
8
+ /** The config an `McpServerAuth` stands for, or undefined if `createMcpAuth` didn't make it. */
9
+ export const configOf = (auth) => typeof auth === "object" && auth !== null ? configs.get(auth) : undefined;
10
+ const BASE_PATH = /^(\/[A-Za-z0-9\-._~!$&'()*+,;=:@%]+)+$/;
11
+ /** What `handler()` answers under `basePath` itself. */
12
+ const ROUTES = ["connect", "disconnect", "connections", "client.json"];
13
+ /**
14
+ * For servers whose calls are made as each user, with that user's own
15
+ * credential: `mcpServer({ auth: mcpAuth.oauth() })`.
16
+ */
17
+ export function createMcpAuth(options) {
18
+ if (typeof options?.userOf !== "function") {
19
+ throw new TypeError("createMcpAuth: userOf must be a function, such as (id) => auth.ownerOf(id)");
20
+ }
21
+ for (const name of ["requestUser", "onConnected"]) {
22
+ if (options[name] !== undefined && typeof options[name] !== "function")
23
+ throw new TypeError(`createMcpAuth: ${name} must be a function`);
24
+ }
25
+ const basePath = options.basePath ?? "/mcp";
26
+ if (typeof basePath !== "string" || !BASE_PATH.test(basePath)) {
27
+ throw new TypeError(`createMcpAuth: basePath must be a path such as "/mcp", with no trailing slash (got ${JSON.stringify(basePath)})`);
28
+ }
29
+ // a request's path is read as a URL, which takes out dot segments: one there would match no route
30
+ if (new URL(basePath, "http://localhost").pathname !== basePath) {
31
+ throw new TypeError(`createMcpAuth: basePath can't have a "." or ".." segment (got ${JSON.stringify(basePath)})`);
32
+ }
33
+ const core = oauthCore(options, basePath);
34
+ /** Every server attached, by name: its kind, and its OAuth if it has one. */
35
+ const servers = new Map();
36
+ const userOf = (conversationId) => options.userOf(conversationId);
37
+ function make(kind, bind) {
38
+ const auth = Object.freeze({ kind });
39
+ configs.set(auth, {
40
+ kind,
41
+ userOf,
42
+ attach(server) {
43
+ if (servers.has(server.name))
44
+ throw new TypeError(`another server from the same createMcpAuth is named "${server.name}"`);
45
+ const bound = bind(server);
46
+ const entry = { forget: server.forget, oauth: bound instanceof OAuthBinding ? bound.oauth : null };
47
+ servers.set(server.name, entry);
48
+ return {
49
+ credential: (user) => bound.credential(user),
50
+ connect: bound.connect,
51
+ detach: () => {
52
+ if (servers.get(server.name) === entry)
53
+ servers.delete(server.name);
54
+ },
55
+ };
56
+ },
57
+ });
58
+ return auth;
59
+ }
60
+ const needsStore = (what) => {
61
+ if (!core)
62
+ throw new TypeError(`${what} needs createMcpAuth({ store, secret, redirectUri })`);
63
+ return core;
64
+ };
65
+ return Object.freeze({
66
+ bearer(token) {
67
+ if (typeof token !== "function") {
68
+ throw new TypeError("bearer: token must be a function that takes a user id and returns their token, or null");
69
+ }
70
+ return make("bearer", (server) => ({
71
+ credential: (user) => new BearerCredential(token, user, server.timeoutMs),
72
+ connect: null,
73
+ }));
74
+ },
75
+ oauth(oauthOptions = {}) {
76
+ const ready = needsStore("oauth()");
77
+ const checked = checkOAuth(oauthOptions);
78
+ return make("oauth", (server) => new OAuthBinding(new OAuthServer(ready, checked, server.name, server.url, server.fetch ?? fetch, server.timeoutMs, server.forget), basePath));
79
+ },
80
+ sdk(makeProvider) {
81
+ if (typeof makeProvider !== "function") {
82
+ throw new TypeError("sdk: make must be a function that takes a user id and returns their AuthProvider, or null");
83
+ }
84
+ return make("sdk", (server) => ({
85
+ credential: (user) => new SdkCredential(makeProvider, user, server.timeoutMs),
86
+ connect: null,
87
+ }));
88
+ },
89
+ handler() {
90
+ const ready = needsStore("handler()");
91
+ if (!options.requestUser)
92
+ throw new TypeError("handler() needs createMcpAuth's requestUser: its routes act for the user signed in");
93
+ const requestUser = options.requestUser;
94
+ return routes({
95
+ core: ready,
96
+ basePath,
97
+ requestUser: async (req) => nonEmpty(await requestUser(req)),
98
+ userOf: async (id) => nonEmpty(await options.userOf(id)),
99
+ onConnected: options.onConnected,
100
+ oauth: (name) => servers.get(name)?.oauth ?? undefined,
101
+ connections,
102
+ disconnect,
103
+ });
104
+ },
105
+ connections,
106
+ disconnect,
107
+ });
108
+ async function connections(userId) {
109
+ const ready = needsStore("connections()");
110
+ if (typeof userId !== "string" || userId === "")
111
+ throw new TypeError("connections() needs a userId");
112
+ const accounts = [];
113
+ for (const name of await ready.store.list(userId)) {
114
+ const held = await servers.get(name)?.oauth?.read(userId);
115
+ if (held)
116
+ accounts.push({ name, scope: held.kept.scope, connectedAt: held.kept.connectedAt });
117
+ }
118
+ return accounts;
119
+ }
120
+ async function disconnect(userId, server) {
121
+ const ready = needsStore("disconnect()");
122
+ if (typeof userId !== "string" || userId === "")
123
+ throw new TypeError("disconnect() needs a userId");
124
+ if (server !== undefined && (typeof server !== "string" || server === ""))
125
+ throw new TypeError("disconnect(): server must be a server's name");
126
+ for (const name of server === undefined ? await ready.store.list(userId) : [server]) {
127
+ const oauth = servers.get(name)?.oauth;
128
+ if (oauth)
129
+ await oauth.disconnect(userId);
130
+ // a server no longer configured: nothing to revoke with, or close
131
+ else
132
+ await ready.store.delete(userId, name);
133
+ }
134
+ }
135
+ }
136
+ /** An `oauth()` server's place on its `McpAuth`. */
137
+ class OAuthBinding {
138
+ oauth;
139
+ basePath;
140
+ constructor(oauth, basePath) {
141
+ this.oauth = oauth;
142
+ this.basePath = basePath;
143
+ }
144
+ credential(user) {
145
+ return this.oauth.credential(user);
146
+ }
147
+ connect = (conversationId, scope) => {
148
+ const query = new URLSearchParams();
149
+ if (conversationId !== undefined)
150
+ query.set("conversation", conversationId);
151
+ if (scope !== undefined)
152
+ query.set("scope", scope);
153
+ const search = query.toString();
154
+ return `${this.basePath}/connect/${encodeURIComponent(this.oauth.name)}${search ? `?${search}` : ""}`;
155
+ };
156
+ }
157
+ /** What `oauth()` needs of `createMcpAuth`'s options, checked: null if none of it is given. */
158
+ function oauthCore(options, basePath) {
159
+ const { store, secret, redirectUri } = options;
160
+ if (store === undefined && secret === undefined && redirectUri === undefined)
161
+ return null;
162
+ if (store === undefined || secret === undefined || redirectUri === undefined) {
163
+ throw new TypeError("createMcpAuth: store, secret and redirectUri go together: oauth() needs all three");
164
+ }
165
+ if (typeof store !== "object" || store === null || STORE_METHODS.some((m) => typeof store[m] !== "function")) {
166
+ throw new TypeError("createMcpAuth: store must be a CredentialStore, such as memoryCredentialStore()");
167
+ }
168
+ const secrets = [secret].flat();
169
+ if (!secrets.length || secrets.some((s) => typeof s !== "string"))
170
+ throw new TypeError("createMcpAuth: secret must be a string, or a list of them");
171
+ if (secrets.some((s) => Buffer.byteLength(s) < SECRET_BYTES))
172
+ throw new TypeError(`createMcpAuth: each secret must be at least ${SECRET_BYTES} bytes`);
173
+ let callback;
174
+ try {
175
+ callback = new URL(redirectUri);
176
+ }
177
+ catch {
178
+ throw new TypeError("createMcpAuth: redirectUri must be a URL, such as https://app.example.com/mcp/callback");
179
+ }
180
+ if (!isSecure(callback))
181
+ throw new TypeError("createMcpAuth: redirectUri must be https, except on localhost");
182
+ if (callback.hash || callback.search)
183
+ throw new TypeError("createMcpAuth: redirectUri can't have a query or a fragment");
184
+ const path = callback.pathname;
185
+ if (ROUTES.some((route) => path === `${basePath}/${route}` || path.startsWith(`${basePath}/${route}/`))) {
186
+ throw new TypeError(`createMcpAuth: redirectUri comes back to ${path}, a route handler() answers already`);
187
+ }
188
+ const clientName = options.clientName ?? callback.host;
189
+ if (typeof clientName !== "string" || clientName === "")
190
+ throw new TypeError("createMcpAuth: clientName must be a non-empty string");
191
+ return {
192
+ store,
193
+ sealer: new Sealer(secrets),
194
+ redirectUri: callback.href,
195
+ clientMetadata: {
196
+ client_name: clientName,
197
+ redirect_uris: [callback.href],
198
+ grant_types: ["authorization_code", "refresh_token"],
199
+ response_types: ["code"],
200
+ token_endpoint_auth_method: "none",
201
+ },
202
+ // the SDK refuses a client identified by a URL that isn't https: on localhost, it registers one
203
+ clientMetadataUrl: callback.protocol === "https:" ? new URL(`${basePath}/client.json`, callback).href : undefined,
204
+ };
205
+ }
206
+ function checkOAuth(options) {
207
+ if (typeof options !== "object" || options === null)
208
+ throw new TypeError("oauth: options must be an object");
209
+ const { issuer, scopes, client } = options;
210
+ if (issuer !== undefined) {
211
+ if (typeof issuer !== "string" || !URL.canParse(issuer))
212
+ throw new TypeError("oauth: issuer must be the authorization server's issuer URL");
213
+ if (!isSecure(issuer))
214
+ throw new TypeError("oauth: issuer must be https, except on localhost");
215
+ }
216
+ if (scopes !== undefined && (!Array.isArray(scopes) || scopes.some((s) => typeof s !== "string" || !/^[\x21\x23-\x5b\x5d-\x7e]+$/.test(s)))) {
217
+ throw new TypeError("oauth: scopes must be a list of OAuth scopes, such as [\"repo\"], each without spaces");
218
+ }
219
+ if (client !== undefined) {
220
+ if (typeof client?.id !== "string" || client.id === "" || (client.secret !== undefined && typeof client.secret !== "string")) {
221
+ throw new TypeError("oauth: client must be { id, secret? }, as registered with the authorization server");
222
+ }
223
+ if (issuer === undefined)
224
+ throw new TypeError("oauth: a client needs the issuer it was registered with");
225
+ }
226
+ return Object.freeze({ ...options, ...(scopes ? { scopes: [...scopes] } : {}), ...(client ? { client: { ...client } } : {}) });
227
+ }
228
+ const nonEmpty = (value) => (typeof value === "string" && value !== "" ? value : null);
229
+ /** A token from `bearer`'s function, kept until a lookup on a 401 finds another, or none. */
230
+ export class BearerCredential {
231
+ read;
232
+ user;
233
+ token = null;
234
+ /** The lookup on its way, which every caller shares: only it sets `token`. */
235
+ looking = null;
236
+ /** Bounds `read`: a lookup that never answers would hold up every call after it. */
237
+ lookups;
238
+ constructor(read, user,
239
+ /** How long `read` may take. */
240
+ timeoutMs) {
241
+ this.read = read;
242
+ this.user = user;
243
+ this.lookups = new Lookup(timeoutMs, "token");
244
+ }
245
+ async ensure() {
246
+ if (this.token === null)
247
+ await this.look();
248
+ if (this.token === null)
249
+ throw new NeedsAuth("connect");
250
+ return false;
251
+ }
252
+ close() {
253
+ this.lookups.stop();
254
+ }
255
+ // The transport asks for the token before every request, and on a 401
256
+ // calls onUnauthorized, then tries once more with what it finds.
257
+ provider = {
258
+ // A request is never sent without the user's token: the transport would
259
+ // send it with no Authorization at all. Gone since its call began, as
260
+ // when another call's 401 found none, it stops the request here.
261
+ token: async () => {
262
+ if (this.token === null)
263
+ throw new NeedsAuth("reconnect");
264
+ return this.token;
265
+ },
266
+ onUnauthorized: async () => {
267
+ // A token the server still refuses gets its 401 on the retry, and is
268
+ // kept: the next 401 looks again. Forgetting it would throw away a
269
+ // newer one that another call's 401 found meanwhile.
270
+ if ((await this.look()) === null)
271
+ throw new NeedsAuth("reconnect");
272
+ },
273
+ };
274
+ /** One lookup at a time, for first calls and 401s that come together, so none overwrites another's token. */
275
+ look() {
276
+ this.looking ??= this.lookup()
277
+ .then((token) => (this.token = token))
278
+ .finally(() => {
279
+ this.looking = null;
280
+ });
281
+ return this.looking;
282
+ }
283
+ async lookup() {
284
+ let token;
285
+ try {
286
+ token = await this.lookups.run(() => this.read(this.user));
287
+ }
288
+ catch (err) {
289
+ throw new LookupFailed(err);
290
+ }
291
+ return typeof token === "string" && token !== "" ? token : null;
292
+ }
293
+ }
294
+ /** A provider from `sdk()`'s function, made once for each connection: the app's provider does the rest. */
295
+ class SdkCredential {
296
+ make;
297
+ user;
298
+ made = null;
299
+ looking = null;
300
+ lookups;
301
+ constructor(make, user, timeoutMs) {
302
+ this.make = make;
303
+ this.user = user;
304
+ this.lookups = new Lookup(timeoutMs, "provider");
305
+ }
306
+ async ensure() {
307
+ if (this.made === null) {
308
+ this.looking ??= this.lookups
309
+ .run(() => this.make(this.user))
310
+ .then((made) => {
311
+ this.made = typeof made === "object" && made !== null ? made : null;
312
+ }, (err) => {
313
+ throw new LookupFailed(err);
314
+ })
315
+ .finally(() => {
316
+ this.looking = null;
317
+ });
318
+ await this.looking;
319
+ }
320
+ if (this.made === null)
321
+ throw new NeedsAuth("connect");
322
+ return false;
323
+ }
324
+ close() {
325
+ this.lookups.stop();
326
+ }
327
+ get provider() {
328
+ // never asked for before ensure() has made it: a connection dials only after
329
+ if (this.made === null)
330
+ throw new NeedsAuth("connect");
331
+ return this.made;
332
+ }
333
+ }
334
+ //# sourceMappingURL=auth.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"auth.js","sourceRoot":"","sources":["../src/auth.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,55 @@
1
+ import type { AuthProvider, OAuthClientProvider } from "@modelcontextprotocol/client";
2
+ /**
3
+ * The user has no credential, or the server refused theirs: thrown inside a
4
+ * connection, where the transport passes it on unchanged, and made an
5
+ * `McpError` with reason `auth`.
6
+ */
7
+ export declare class NeedsAuth extends Error {
8
+ readonly kind: "connect" | "reconnect";
9
+ readonly name = "NeedsAuth";
10
+ constructor(kind: "connect" | "reconnect");
11
+ }
12
+ /** The app's lookup of a credential failed, or a refresh couldn't be made: made an `McpError` with reason `connection`. */
13
+ export declare class LookupFailed extends Error {
14
+ readonly name = "LookupFailed";
15
+ constructor(cause: unknown);
16
+ }
17
+ /**
18
+ * The server names another authorization server than the one its `issuer`
19
+ * pins, or than the one that issued a credential: made an `McpError` with
20
+ * reason `protocol`. The pin decides, not the user, so it's never `auth`.
21
+ */
22
+ export declare class Mismatch extends Error {
23
+ readonly name = "Mismatch";
24
+ }
25
+ /** One user's credential for one server, and the `AuthProvider` that sends it. */
26
+ export interface Credential {
27
+ /**
28
+ * Before a connection or call: finds the credential, or throws
29
+ * `NeedsAuth("connect")`, so nothing is sent without one. True when it's
30
+ * now another account than before: the connection made with the old one
31
+ * is made again.
32
+ */
33
+ ensure(): Promise<boolean>;
34
+ /** For a connection being closed: stops a lookup on its way, and its timer. */
35
+ close(): void;
36
+ /** What each connection's transport is given, read as it's made, once `ensure()` has found the credential. */
37
+ readonly provider: AuthProvider | OAuthClientProvider;
38
+ }
39
+ /**
40
+ * A lookup that takes at most `ms`, and that `stop()` ends at once: one that
41
+ * never answered would hold up every call after it, and its timer would keep
42
+ * the process going.
43
+ */
44
+ export declare class Lookup {
45
+ private readonly ms;
46
+ /** Names what's looked up, in the errors. */
47
+ private readonly what;
48
+ private stopping;
49
+ constructor(ms: number,
50
+ /** Names what's looked up, in the errors. */
51
+ what: string);
52
+ run<T>(look: () => T | Promise<T>): Promise<T>;
53
+ stop(): void;
54
+ }
55
+ //# sourceMappingURL=credential.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"credential.d.ts","sourceRoot":"","sources":["../src/credential.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,YAAY,EAAE,mBAAmB,EAAE,MAAM,8BAA8B,CAAC;AAEtF;;;;GAIG;AACH,qBAAa,SAAU,SAAQ,KAAK;IAEtB,QAAQ,CAAC,IAAI,EAAE,SAAS,GAAG,WAAW;IADlD,QAAQ,CAAC,IAAI,eAAe;gBACP,IAAI,EAAE,SAAS,GAAG,WAAW;CAGnD;AAED,2HAA2H;AAC3H,qBAAa,YAAa,SAAQ,KAAK;IACrC,QAAQ,CAAC,IAAI,kBAAkB;gBACnB,KAAK,EAAE,OAAO;CAG3B;AAED;;;;GAIG;AACH,qBAAa,QAAS,SAAQ,KAAK;IACjC,QAAQ,CAAC,IAAI,cAAc;CAC5B;AAED,kFAAkF;AAClF,MAAM,WAAW,UAAU;IACzB;;;;;OAKG;IACH,MAAM,IAAI,OAAO,CAAC,OAAO,CAAC,CAAC;IAC3B,+EAA+E;IAC/E,KAAK,IAAI,IAAI,CAAC;IACd,8GAA8G;IAC9G,QAAQ,CAAC,QAAQ,EAAE,YAAY,GAAG,mBAAmB,CAAC;CACvD;AAED;;;;GAIG;AACH,qBAAa,MAAM;IAIf,OAAO,CAAC,QAAQ,CAAC,EAAE;IACnB,6CAA6C;IAC7C,OAAO,CAAC,QAAQ,CAAC,IAAI;IALvB,OAAO,CAAC,QAAQ,CAA6B;gBAG1B,EAAE,EAAE,MAAM;IAC3B,6CAA6C;IAC5B,IAAI,EAAE,MAAM;IAGzB,GAAG,CAAC,CAAC,EAAE,IAAI,EAAE,MAAM,CAAC,GAAG,OAAO,CAAC,CAAC,CAAC,GAAG,OAAO,CAAC,CAAC,CAAC;IAcpD,IAAI,IAAI,IAAI;CAGb"}