@haikit/mcp 0.32.0 → 0.33.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 +20 -0
- package/dist/auth.d.ts +80 -0
- package/dist/auth.d.ts.map +1 -0
- package/dist/auth.js +119 -0
- package/dist/auth.js.map +1 -0
- package/dist/errors.d.ts +17 -1
- package/dist/errors.d.ts.map +1 -1
- package/dist/errors.js +3 -0
- package/dist/errors.js.map +1 -1
- package/dist/index.d.ts +42 -11
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +456 -146
- package/dist/index.js.map +1 -1
- package/dist/transports.d.ts +13 -3
- package/dist/transports.d.ts.map +1 -1
- package/dist/transports.js +11 -3
- package/dist/transports.js.map +1 -1
- package/package.json +2 -2
- package/src/auth.ts +160 -0
- package/src/errors.ts +19 -2
- package/src/index.ts +493 -159
- package/src/transports.ts +27 -4
package/README.md
CHANGED
|
@@ -53,6 +53,26 @@ 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
|
+
|
|
62
|
+
const mcpAuth = createMcpAuth({ userOf: (id) => auth.ownerOf(id) }); // auth from @haikit/auth
|
|
63
|
+
const tracker = mcpServer({
|
|
64
|
+
name: "tracker",
|
|
65
|
+
transport: http("https://mcp.tracker.example/mcp"),
|
|
66
|
+
auth: mcpAuth.bearer((userId) => keys.find(userId)), // their token, or null
|
|
67
|
+
});
|
|
68
|
+
```
|
|
69
|
+
|
|
70
|
+
A call with no one to run as is refused with reason `user`, and one for a user
|
|
71
|
+
with no token with reason `auth`, before anything is sent: it never falls
|
|
72
|
+
back to the app's identity. `err.auth.kind` says what the user must do:
|
|
73
|
+
`connect`, `reconnect`, or grant more `scope`. A job outside any conversation
|
|
74
|
+
passes `{ userId }`.
|
|
75
|
+
|
|
56
76
|
`McpTool` isn't a HaiKIT `Tool`, so it can't be passed to
|
|
57
77
|
`createHai({ tools })`: `npm run typetest` checks that.
|
|
58
78
|
|
package/dist/auth.d.ts
ADDED
|
@@ -0,0 +1,80 @@
|
|
|
1
|
+
import type { AuthProvider } from "@modelcontextprotocol/client";
|
|
2
|
+
export interface McpAuthOptions {
|
|
3
|
+
/**
|
|
4
|
+
* Who a conversation belongs to: the user a call made in it runs as. With
|
|
5
|
+
* @haikit/auth, `(id) => auth.ownerOf(id)`. `null` for no one.
|
|
6
|
+
*/
|
|
7
|
+
userOf(conversationId: string): string | null | Promise<string | null>;
|
|
8
|
+
}
|
|
9
|
+
/** Makes the `auth` of servers whose calls are made as each user. */
|
|
10
|
+
export interface McpAuth {
|
|
11
|
+
/**
|
|
12
|
+
* Each user's own token, which the app already has: `token(userId)` gives
|
|
13
|
+
* it, or `null` when the user has none. Sent as `Authorization: Bearer`.
|
|
14
|
+
*/
|
|
15
|
+
bearer(token: (userId: string) => string | null | Promise<string | null>): McpServerAuth;
|
|
16
|
+
}
|
|
17
|
+
/** How a server's calls are made as each user: made by an `McpAuth`, and given to `mcpServer({ auth })`. */
|
|
18
|
+
export interface McpServerAuth {
|
|
19
|
+
readonly kind: "bearer";
|
|
20
|
+
}
|
|
21
|
+
/** What an `McpServerAuth` stands for. */
|
|
22
|
+
export interface AuthConfig {
|
|
23
|
+
readonly kind: "bearer";
|
|
24
|
+
userOf(conversationId: string): string | null | Promise<string | null>;
|
|
25
|
+
token(userId: string): string | null | Promise<string | null>;
|
|
26
|
+
/** Server names in use with this `McpAuth`: each is a key for its users' credentials. */
|
|
27
|
+
readonly names: Set<string>;
|
|
28
|
+
}
|
|
29
|
+
/** The config an `McpServerAuth` stands for, or undefined if `createMcpAuth` didn't make it. */
|
|
30
|
+
export declare const configOf: (auth: unknown) => AuthConfig | undefined;
|
|
31
|
+
/**
|
|
32
|
+
* For servers whose calls are made as each user, with that user's own
|
|
33
|
+
* credential: `mcpServer({ auth: mcpAuth.bearer(token) })`.
|
|
34
|
+
*/
|
|
35
|
+
export declare function createMcpAuth(options: McpAuthOptions): McpAuth;
|
|
36
|
+
/**
|
|
37
|
+
* The user has no credential, or the server refused theirs: thrown inside a
|
|
38
|
+
* connection, where the transport passes it on unchanged, and made an
|
|
39
|
+
* `McpError` with reason `auth`.
|
|
40
|
+
*/
|
|
41
|
+
export declare class NeedsAuth extends Error {
|
|
42
|
+
readonly kind: "connect" | "reconnect";
|
|
43
|
+
readonly name = "NeedsAuth";
|
|
44
|
+
constructor(kind: "connect" | "reconnect");
|
|
45
|
+
}
|
|
46
|
+
/** The app's lookup of a credential failed: made an `McpError` with reason `connection`. */
|
|
47
|
+
export declare class LookupFailed extends Error {
|
|
48
|
+
readonly name = "LookupFailed";
|
|
49
|
+
constructor(cause: unknown);
|
|
50
|
+
}
|
|
51
|
+
/** One user's credential for one server, and the `AuthProvider` that sends it. */
|
|
52
|
+
export interface Credential {
|
|
53
|
+
/** Before a connection or call: finds the credential, or throws `NeedsAuth("connect")`, so nothing is sent without one. */
|
|
54
|
+
ensure(): Promise<void>;
|
|
55
|
+
/** For a connection being closed: stops a lookup on its way, and its timer. */
|
|
56
|
+
close(): void;
|
|
57
|
+
readonly provider: AuthProvider;
|
|
58
|
+
}
|
|
59
|
+
/** A token from `bearer`'s function, kept until a lookup on a 401 finds another, or none. */
|
|
60
|
+
export declare class BearerCredential implements Credential {
|
|
61
|
+
private readonly read;
|
|
62
|
+
private readonly user;
|
|
63
|
+
/** How long `read` may take: a lookup that never answers would hold up every call after it. */
|
|
64
|
+
private readonly timeoutMs;
|
|
65
|
+
private token;
|
|
66
|
+
/** The lookup on its way, which every caller shares: only it sets `token`. */
|
|
67
|
+
private looking;
|
|
68
|
+
/** Stops the lookup on its way, for `close()`. */
|
|
69
|
+
private stop;
|
|
70
|
+
constructor(read: (userId: string) => string | null | Promise<string | null>, user: string,
|
|
71
|
+
/** How long `read` may take: a lookup that never answers would hold up every call after it. */
|
|
72
|
+
timeoutMs: number);
|
|
73
|
+
ensure(): Promise<void>;
|
|
74
|
+
close(): void;
|
|
75
|
+
readonly provider: AuthProvider;
|
|
76
|
+
/** One lookup at a time, for first calls and 401s that come together, so none overwrites another's token. */
|
|
77
|
+
private look;
|
|
78
|
+
private lookup;
|
|
79
|
+
}
|
|
80
|
+
//# sourceMappingURL=auth.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"auth.d.ts","sourceRoot":"","sources":["../src/auth.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,8BAA8B,CAAC;AAEjE,MAAM,WAAW,cAAc;IAC7B;;;OAGG;IACH,MAAM,CAAC,cAAc,EAAE,MAAM,GAAG,MAAM,GAAG,IAAI,GAAG,OAAO,CAAC,MAAM,GAAG,IAAI,CAAC,CAAC;CACxE;AAED,qEAAqE;AACrE,MAAM,WAAW,OAAO;IACtB;;;OAGG;IACH,MAAM,CAAC,KAAK,EAAE,CAAC,MAAM,EAAE,MAAM,KAAK,MAAM,GAAG,IAAI,GAAG,OAAO,CAAC,MAAM,GAAG,IAAI,CAAC,GAAG,aAAa,CAAC;CAC1F;AAED,4GAA4G;AAC5G,MAAM,WAAW,aAAa;IAC5B,QAAQ,CAAC,IAAI,EAAE,QAAQ,CAAC;CACzB;AAED,0CAA0C;AAC1C,MAAM,WAAW,UAAU;IACzB,QAAQ,CAAC,IAAI,EAAE,QAAQ,CAAC;IACxB,MAAM,CAAC,cAAc,EAAE,MAAM,GAAG,MAAM,GAAG,IAAI,GAAG,OAAO,CAAC,MAAM,GAAG,IAAI,CAAC,CAAC;IACvE,KAAK,CAAC,MAAM,EAAE,MAAM,GAAG,MAAM,GAAG,IAAI,GAAG,OAAO,CAAC,MAAM,GAAG,IAAI,CAAC,CAAC;IAC9D,yFAAyF;IACzF,QAAQ,CAAC,KAAK,EAAE,GAAG,CAAC,MAAM,CAAC,CAAC;CAC7B;AAID,gGAAgG;AAChG,eAAO,MAAM,QAAQ,GAAI,MAAM,OAAO,KAAG,UAAU,GAAG,SACqB,CAAC;AAE5E;;;GAGG;AACH,wBAAgB,aAAa,CAAC,OAAO,EAAE,cAAc,GAAG,OAAO,CAgB9D;AAED;;;;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,4FAA4F;AAC5F,qBAAa,YAAa,SAAQ,KAAK;IACrC,QAAQ,CAAC,IAAI,kBAAkB;gBACnB,KAAK,EAAE,OAAO;CAG3B;AAED,kFAAkF;AAClF,MAAM,WAAW,UAAU;IACzB,2HAA2H;IAC3H,MAAM,IAAI,OAAO,CAAC,IAAI,CAAC,CAAC;IACxB,+EAA+E;IAC/E,KAAK,IAAI,IAAI,CAAC;IACd,QAAQ,CAAC,QAAQ,EAAE,YAAY,CAAC;CACjC;AAED,6FAA6F;AAC7F,qBAAa,gBAAiB,YAAW,UAAU;IAQ/C,OAAO,CAAC,QAAQ,CAAC,IAAI;IACrB,OAAO,CAAC,QAAQ,CAAC,IAAI;IACrB,+FAA+F;IAC/F,OAAO,CAAC,QAAQ,CAAC,SAAS;IAV5B,OAAO,CAAC,KAAK,CAAuB;IACpC,8EAA8E;IAC9E,OAAO,CAAC,OAAO,CAAuC;IACtD,kDAAkD;IAClD,OAAO,CAAC,IAAI,CAA6B;gBAGtB,IAAI,EAAE,CAAC,MAAM,EAAE,MAAM,KAAK,MAAM,GAAG,IAAI,GAAG,OAAO,CAAC,MAAM,GAAG,IAAI,CAAC,EAChE,IAAI,EAAE,MAAM;IAC7B,+FAA+F;IAC9E,SAAS,EAAE,MAAM;IAG9B,MAAM,IAAI,OAAO,CAAC,IAAI,CAAC;IAK7B,KAAK,IAAI,IAAI;IAMb,QAAQ,CAAC,QAAQ,EAAE,YAAY,CAc7B;IAEF,6GAA6G;IAC7G,OAAO,CAAC,IAAI;YASE,MAAM;CAiBrB"}
|
package/dist/auth.js
ADDED
|
@@ -0,0 +1,119 @@
|
|
|
1
|
+
const configs = new WeakMap();
|
|
2
|
+
/** The config an `McpServerAuth` stands for, or undefined if `createMcpAuth` didn't make it. */
|
|
3
|
+
export const configOf = (auth) => typeof auth === "object" && auth !== null ? configs.get(auth) : undefined;
|
|
4
|
+
/**
|
|
5
|
+
* For servers whose calls are made as each user, with that user's own
|
|
6
|
+
* credential: `mcpServer({ auth: mcpAuth.bearer(token) })`.
|
|
7
|
+
*/
|
|
8
|
+
export function createMcpAuth(options) {
|
|
9
|
+
if (typeof options?.userOf !== "function") {
|
|
10
|
+
throw new TypeError("createMcpAuth: userOf must be a function, such as (id) => auth.ownerOf(id)");
|
|
11
|
+
}
|
|
12
|
+
const names = new Set();
|
|
13
|
+
const userOf = (conversationId) => options.userOf(conversationId);
|
|
14
|
+
return Object.freeze({
|
|
15
|
+
bearer(token) {
|
|
16
|
+
if (typeof token !== "function") {
|
|
17
|
+
throw new TypeError("bearer: token must be a function that takes a user id and returns their token, or null");
|
|
18
|
+
}
|
|
19
|
+
const auth = Object.freeze({ kind: "bearer" });
|
|
20
|
+
configs.set(auth, { kind: "bearer", userOf, token, names });
|
|
21
|
+
return auth;
|
|
22
|
+
},
|
|
23
|
+
});
|
|
24
|
+
}
|
|
25
|
+
/**
|
|
26
|
+
* The user has no credential, or the server refused theirs: thrown inside a
|
|
27
|
+
* connection, where the transport passes it on unchanged, and made an
|
|
28
|
+
* `McpError` with reason `auth`.
|
|
29
|
+
*/
|
|
30
|
+
export class NeedsAuth extends Error {
|
|
31
|
+
kind;
|
|
32
|
+
name = "NeedsAuth";
|
|
33
|
+
constructor(kind) {
|
|
34
|
+
super(kind === "connect" ? "the user has no credential" : "the server refused the user's credential");
|
|
35
|
+
this.kind = kind;
|
|
36
|
+
}
|
|
37
|
+
}
|
|
38
|
+
/** The app's lookup of a credential failed: made an `McpError` with reason `connection`. */
|
|
39
|
+
export class LookupFailed extends Error {
|
|
40
|
+
name = "LookupFailed";
|
|
41
|
+
constructor(cause) {
|
|
42
|
+
super("the user's credential could not be looked up", { cause });
|
|
43
|
+
}
|
|
44
|
+
}
|
|
45
|
+
/** A token from `bearer`'s function, kept until a lookup on a 401 finds another, or none. */
|
|
46
|
+
export class BearerCredential {
|
|
47
|
+
read;
|
|
48
|
+
user;
|
|
49
|
+
timeoutMs;
|
|
50
|
+
token = null;
|
|
51
|
+
/** The lookup on its way, which every caller shares: only it sets `token`. */
|
|
52
|
+
looking = null;
|
|
53
|
+
/** Stops the lookup on its way, for `close()`. */
|
|
54
|
+
stop = null;
|
|
55
|
+
constructor(read, user,
|
|
56
|
+
/** How long `read` may take: a lookup that never answers would hold up every call after it. */
|
|
57
|
+
timeoutMs) {
|
|
58
|
+
this.read = read;
|
|
59
|
+
this.user = user;
|
|
60
|
+
this.timeoutMs = timeoutMs;
|
|
61
|
+
}
|
|
62
|
+
async ensure() {
|
|
63
|
+
if (this.token === null)
|
|
64
|
+
await this.look();
|
|
65
|
+
if (this.token === null)
|
|
66
|
+
throw new NeedsAuth("connect");
|
|
67
|
+
}
|
|
68
|
+
close() {
|
|
69
|
+
this.stop?.();
|
|
70
|
+
}
|
|
71
|
+
// The transport asks for the token before every request, and on a 401
|
|
72
|
+
// calls onUnauthorized, then tries once more with what it finds.
|
|
73
|
+
provider = {
|
|
74
|
+
// A request is never sent without the user's token: the transport would
|
|
75
|
+
// send it with no Authorization at all. Gone since its call began, as
|
|
76
|
+
// when another call's 401 found none, it stops the request here.
|
|
77
|
+
token: async () => {
|
|
78
|
+
if (this.token === null)
|
|
79
|
+
throw new NeedsAuth("reconnect");
|
|
80
|
+
return this.token;
|
|
81
|
+
},
|
|
82
|
+
onUnauthorized: async () => {
|
|
83
|
+
// A token the server still refuses gets its 401 on the retry, and is
|
|
84
|
+
// kept: the next 401 looks again. Forgetting it would throw away a
|
|
85
|
+
// newer one that another call's 401 found meanwhile.
|
|
86
|
+
if ((await this.look()) === null)
|
|
87
|
+
throw new NeedsAuth("reconnect");
|
|
88
|
+
},
|
|
89
|
+
};
|
|
90
|
+
/** One lookup at a time, for first calls and 401s that come together, so none overwrites another's token. */
|
|
91
|
+
look() {
|
|
92
|
+
this.looking ??= this.lookup()
|
|
93
|
+
.then((token) => (this.token = token))
|
|
94
|
+
.finally(() => {
|
|
95
|
+
this.looking = null;
|
|
96
|
+
});
|
|
97
|
+
return this.looking;
|
|
98
|
+
}
|
|
99
|
+
async lookup() {
|
|
100
|
+
let timer;
|
|
101
|
+
const cut = new Promise((_, reject) => {
|
|
102
|
+
timer = setTimeout(() => reject(new Error(`no token within ${this.timeoutMs} ms`)), this.timeoutMs);
|
|
103
|
+
this.stop = () => reject(new Error("closed while the token was being looked up"));
|
|
104
|
+
});
|
|
105
|
+
let token;
|
|
106
|
+
try {
|
|
107
|
+
token = await Promise.race([Promise.resolve().then(() => this.read(this.user)), cut]);
|
|
108
|
+
}
|
|
109
|
+
catch (err) {
|
|
110
|
+
throw new LookupFailed(err);
|
|
111
|
+
}
|
|
112
|
+
finally {
|
|
113
|
+
clearTimeout(timer);
|
|
114
|
+
this.stop = null;
|
|
115
|
+
}
|
|
116
|
+
return typeof token === "string" && token !== "" ? token : null;
|
|
117
|
+
}
|
|
118
|
+
}
|
|
119
|
+
//# sourceMappingURL=auth.js.map
|
package/dist/auth.js.map
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"auth.js","sourceRoot":"","sources":["../src/auth.ts"],"names":[],"mappings":"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"}
|
package/dist/errors.d.ts
CHANGED
|
@@ -9,8 +9,21 @@ import type { ContentBlock } from "@modelcontextprotocol/client";
|
|
|
9
9
|
* - `protocol`: the server refused the call, such as for a tool it doesn't
|
|
10
10
|
* have, or asked for something this client doesn't do.
|
|
11
11
|
* - `closed`: `close()` was called.
|
|
12
|
+
* - `user`: a server with `auth` had no user to call as, so nothing was sent.
|
|
13
|
+
* - `auth`: the user's credential for the server is missing, was refused, or
|
|
14
|
+
* needs more access. `auth` on the error says which.
|
|
12
15
|
*/
|
|
13
|
-
export type McpErrorReason = "args" | "result" | "timeout" | "connection" | "protocol" | "closed";
|
|
16
|
+
export type McpErrorReason = "args" | "result" | "timeout" | "connection" | "protocol" | "closed" | "user" | "auth";
|
|
17
|
+
/** What a call with reason `auth` needs from the user. */
|
|
18
|
+
export interface McpAuthNeed {
|
|
19
|
+
/**
|
|
20
|
+
* `connect`: the user has no credential for the server, so nothing was sent.
|
|
21
|
+
* `reconnect`: the server refused theirs. `scope`: theirs needs more access.
|
|
22
|
+
*/
|
|
23
|
+
readonly kind: "connect" | "reconnect" | "scope";
|
|
24
|
+
/** On `scope`: the scope the server asked for, as its challenge put it. */
|
|
25
|
+
readonly scope?: string;
|
|
26
|
+
}
|
|
14
27
|
/**
|
|
15
28
|
* A call that didn't get a result. The message names only the server and the
|
|
16
29
|
* tool, never what the server said: a HaiKIT tool that lets this go reaches the
|
|
@@ -32,12 +45,15 @@ export declare class McpError extends Error {
|
|
|
32
45
|
readonly text: string | undefined;
|
|
33
46
|
/** A JSON-RPC error's code. */
|
|
34
47
|
readonly code: number | undefined;
|
|
48
|
+
/** With reason `auth`: what the user's credential needs. */
|
|
49
|
+
readonly auth: McpAuthNeed | undefined;
|
|
35
50
|
constructor(reason: McpErrorReason, message: string, detail: {
|
|
36
51
|
server: string;
|
|
37
52
|
tool?: string;
|
|
38
53
|
text?: string;
|
|
39
54
|
code?: number;
|
|
40
55
|
cause?: unknown;
|
|
56
|
+
auth?: McpAuthNeed;
|
|
41
57
|
});
|
|
42
58
|
}
|
|
43
59
|
/**
|
package/dist/errors.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"errors.d.ts","sourceRoot":"","sources":["../src/errors.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,8BAA8B,CAAC;AAEjE
|
|
1
|
+
{"version":3,"file":"errors.d.ts","sourceRoot":"","sources":["../src/errors.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,8BAA8B,CAAC;AAEjE;;;;;;;;;;;;;GAaG;AACH,MAAM,MAAM,cAAc,GAAG,MAAM,GAAG,QAAQ,GAAG,SAAS,GAAG,YAAY,GAAG,UAAU,GAAG,QAAQ,GAAG,MAAM,GAAG,MAAM,CAAC;AAEpH,0DAA0D;AAC1D,MAAM,WAAW,WAAW;IAC1B;;;OAGG;IACH,QAAQ,CAAC,IAAI,EAAE,SAAS,GAAG,WAAW,GAAG,OAAO,CAAC;IACjD,2EAA2E;IAC3E,QAAQ,CAAC,KAAK,CAAC,EAAE,MAAM,CAAC;CACzB;AAED;;;;;;;;;GASG;AACH,qBAAa,QAAS,SAAQ,KAAK;IACjC,QAAQ,CAAC,IAAI,cAAc;IAC3B,2BAA2B;IAC3B,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAC;IACxB,uDAAuD;IACvD,QAAQ,CAAC,IAAI,EAAE,MAAM,GAAG,SAAS,CAAC;IAClC,QAAQ,CAAC,MAAM,EAAE,cAAc,CAAC;IAChC,wFAAwF;IACxF,QAAQ,CAAC,IAAI,EAAE,MAAM,GAAG,SAAS,CAAC;IAClC,+BAA+B;IAC/B,QAAQ,CAAC,IAAI,EAAE,MAAM,GAAG,SAAS,CAAC;IAClC,4DAA4D;IAC5D,QAAQ,CAAC,IAAI,EAAE,WAAW,GAAG,SAAS,CAAC;gBAGrC,MAAM,EAAE,cAAc,EACtB,OAAO,EAAE,MAAM,EACf,MAAM,EAAE;QAAE,MAAM,EAAE,MAAM,CAAC;QAAC,IAAI,CAAC,EAAE,MAAM,CAAC;QAAC,IAAI,CAAC,EAAE,MAAM,CAAC;QAAC,IAAI,CAAC,EAAE,MAAM,CAAC;QAAC,KAAK,CAAC,EAAE,OAAO,CAAC;QAAC,IAAI,CAAC,EAAE,WAAW,CAAA;KAAE;CAU/G;AAED;;;;GAIG;AACH,qBAAa,YAAa,SAAQ,KAAK;IACrC,QAAQ,CAAC,IAAI,kBAAkB;IAC/B,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAC;IACxB,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;IACtB,oDAAoD;IACpD,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;IACtB,4DAA4D;IAC5D,QAAQ,CAAC,OAAO,EAAE,YAAY,EAAE,CAAC;gBAErB,MAAM,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,EAAE,OAAO,EAAE,YAAY,EAAE;CAOlE;AAED,eAAO,MAAM,UAAU,GAAI,KAAK,OAAO,KAAG,GAAG,IAAI,QAA2D,CAAC;AAE7G,eAAO,MAAM,cAAc,GAAI,KAAK,OAAO,KAAG,GAAG,IAAI,YACA,CAAC"}
|
package/dist/errors.js
CHANGED
|
@@ -19,6 +19,8 @@ export class McpError extends Error {
|
|
|
19
19
|
text;
|
|
20
20
|
/** A JSON-RPC error's code. */
|
|
21
21
|
code;
|
|
22
|
+
/** With reason `auth`: what the user's credential needs. */
|
|
23
|
+
auth;
|
|
22
24
|
constructor(reason, message, detail) {
|
|
23
25
|
super(message, detail.cause === undefined ? undefined : { cause: detail.cause });
|
|
24
26
|
this.reason = reason;
|
|
@@ -26,6 +28,7 @@ export class McpError extends Error {
|
|
|
26
28
|
this.tool = detail.tool;
|
|
27
29
|
this.text = detail.text;
|
|
28
30
|
this.code = detail.code;
|
|
31
|
+
this.auth = detail.auth === undefined ? undefined : Object.freeze({ ...detail.auth });
|
|
29
32
|
}
|
|
30
33
|
}
|
|
31
34
|
/**
|
package/dist/errors.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"errors.js","sourceRoot":"","sources":["../src/errors.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"errors.js","sourceRoot":"","sources":["../src/errors.ts"],"names":[],"mappings":"AA6BA;;;;;;;;;GASG;AACH,MAAM,OAAO,QAAS,SAAQ,KAAK;IACxB,IAAI,GAAG,UAAU,CAAC;IAC3B,2BAA2B;IAClB,MAAM,CAAS;IACxB,uDAAuD;IAC9C,IAAI,CAAqB;IACzB,MAAM,CAAiB;IAChC,wFAAwF;IAC/E,IAAI,CAAqB;IAClC,+BAA+B;IACtB,IAAI,CAAqB;IAClC,4DAA4D;IACnD,IAAI,CAA0B;IAEvC,YACE,MAAsB,EACtB,OAAe,EACf,MAA4G;QAE5G,KAAK,CAAC,OAAO,EAAE,MAAM,CAAC,KAAK,KAAK,SAAS,CAAC,CAAC,CAAC,SAAS,CAAC,CAAC,CAAC,EAAE,KAAK,EAAE,MAAM,CAAC,KAAK,EAAE,CAAC,CAAC;QACjF,IAAI,CAAC,MAAM,GAAG,MAAM,CAAC;QACrB,IAAI,CAAC,MAAM,GAAG,MAAM,CAAC,MAAM,CAAC;QAC5B,IAAI,CAAC,IAAI,GAAG,MAAM,CAAC,IAAI,CAAC;QACxB,IAAI,CAAC,IAAI,GAAG,MAAM,CAAC,IAAI,CAAC;QACxB,IAAI,CAAC,IAAI,GAAG,MAAM,CAAC,IAAI,CAAC;QACxB,IAAI,CAAC,IAAI,GAAG,MAAM,CAAC,IAAI,KAAK,SAAS,CAAC,CAAC,CAAC,SAAS,CAAC,CAAC,CAAC,MAAM,CAAC,MAAM,CAAC,EAAE,GAAG,MAAM,CAAC,IAAI,EAAE,CAAC,CAAC;IACxF,CAAC;CACF;AAED;;;;GAIG;AACH,MAAM,OAAO,YAAa,SAAQ,KAAK;IAC5B,IAAI,GAAG,cAAc,CAAC;IACtB,MAAM,CAAS;IACf,IAAI,CAAS;IACtB,oDAAoD;IAC3C,IAAI,CAAS;IACtB,4DAA4D;IACnD,OAAO,CAAiB;IAEjC,YAAY,MAAc,EAAE,IAAY,EAAE,OAAuB;QAC/D,KAAK,CAAC,GAAG,MAAM,IAAI,IAAI,oBAAoB,CAAC,CAAC;QAC7C,IAAI,CAAC,MAAM,GAAG,MAAM,CAAC;QACrB,IAAI,CAAC,IAAI,GAAG,IAAI,CAAC;QACjB,IAAI,CAAC,OAAO,GAAG,OAAO,CAAC;QACvB,IAAI,CAAC,IAAI,GAAG,OAAO,CAAC,OAAO,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,CAAC,IAAI,KAAK,MAAM,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;IACrF,CAAC;CACF;AAED,MAAM,CAAC,MAAM,UAAU,GAAG,CAAC,GAAY,EAAmB,EAAE,CAAC,GAAG,YAAY,KAAK,IAAI,GAAG,CAAC,IAAI,KAAK,UAAU,CAAC;AAE7G,MAAM,CAAC,MAAM,cAAc,GAAG,CAAC,GAAY,EAAuB,EAAE,CAClE,GAAG,YAAY,KAAK,IAAI,GAAG,CAAC,IAAI,KAAK,cAAc,CAAC"}
|
package/dist/index.d.ts
CHANGED
|
@@ -14,23 +14,40 @@
|
|
|
14
14
|
* Imports only @haikit/core, like the model adapters.
|
|
15
15
|
*/
|
|
16
16
|
import type { Progress, Schema } from "@haikit/core";
|
|
17
|
-
import { type ContentBlock, type Transport, type VersionNegotiationMode } from "@modelcontextprotocol/client";
|
|
18
|
-
|
|
17
|
+
import { type AuthProvider, type ContentBlock, type Transport, type VersionNegotiationMode } from "@modelcontextprotocol/client";
|
|
18
|
+
import { type McpServerAuth } from "./auth.js";
|
|
19
|
+
export { createMcpAuth, type McpAuth, type McpAuthOptions, type McpServerAuth } from "./auth.js";
|
|
20
|
+
export { McpError, McpToolError, isMcpError, isMcpToolError, type McpAuthNeed, type McpErrorReason } from "./errors.js";
|
|
19
21
|
export { textOf, type TextOptions } from "./text.js";
|
|
20
22
|
export { http, stdio, type HttpOptions } from "./transports.js";
|
|
21
|
-
export type { ContentBlock, Transport } from "@modelcontextprotocol/client";
|
|
23
|
+
export type { AuthProvider, ContentBlock, Transport } from "@modelcontextprotocol/client";
|
|
22
24
|
export interface McpServerOptions {
|
|
23
25
|
/** Names the server in errors and warnings, as in `github/search_issues`. */
|
|
24
26
|
name: string;
|
|
25
27
|
/**
|
|
26
28
|
* Makes a connection: called by the first `connect()` or call, and again
|
|
27
|
-
* for each reconnect. `http(url)` and `stdio({ command })` make one.
|
|
29
|
+
* for each reconnect. `http(url)` and `stdio({ command })` make one. For a
|
|
30
|
+
* server with `auth`, it's given the user's `AuthProvider`, and must be
|
|
31
|
+
* `http()`'s.
|
|
28
32
|
*/
|
|
29
|
-
transport: () => Transport | Promise<Transport>;
|
|
33
|
+
transport: (authProvider?: AuthProvider) => Transport | Promise<Transport>;
|
|
34
|
+
/**
|
|
35
|
+
* Makes each call as the user it runs for, with their own credential, over
|
|
36
|
+
* a connection of their own: `createMcpAuth({ userOf }).bearer(token)`.
|
|
37
|
+
* Without it, every call shares one connection and one identity.
|
|
38
|
+
*/
|
|
39
|
+
auth?: McpServerAuth;
|
|
40
|
+
/**
|
|
41
|
+
* With `auth`: the most users connected at once. Past it, the least recently
|
|
42
|
+
* used connection with no call in flight is closed. Default 100.
|
|
43
|
+
*/
|
|
44
|
+
maxConnections?: number;
|
|
45
|
+
/** With `auth`: a user's connection is closed after this long with no call, in milliseconds. Default 300,000. */
|
|
46
|
+
idleMs?: number;
|
|
30
47
|
/**
|
|
31
48
|
* How long the server may go without answering a call or reporting progress
|
|
32
|
-
* on it, in milliseconds. Also bounds making the transport, connecting
|
|
33
|
-
* listing tools. Default 30,000.
|
|
49
|
+
* on it, in milliseconds. Also bounds making the transport, connecting,
|
|
50
|
+
* listing tools and, with `auth`, looking up a user's token. Default 30,000.
|
|
34
51
|
*/
|
|
35
52
|
timeoutMs?: number;
|
|
36
53
|
/**
|
|
@@ -50,6 +67,8 @@ export interface McpServerOptions {
|
|
|
50
67
|
}
|
|
51
68
|
export interface McpToolChange {
|
|
52
69
|
server: string;
|
|
70
|
+
/** With `auth`: the user whose connection saw the change. Each user's tools are compared apart. */
|
|
71
|
+
user?: string;
|
|
53
72
|
/** Declared tools the server no longer has. */
|
|
54
73
|
removed: string[];
|
|
55
74
|
/** Declared tools whose input or output schema, or task support, changed. */
|
|
@@ -82,10 +101,16 @@ export interface McpResult {
|
|
|
82
101
|
*/
|
|
83
102
|
export interface McpCallCtx {
|
|
84
103
|
/**
|
|
85
|
-
* The conversation the call is for.
|
|
86
|
-
*
|
|
104
|
+
* The conversation the call is for. A server with `auth` calls as its
|
|
105
|
+
* owner, from `userOf`.
|
|
87
106
|
*/
|
|
88
107
|
readonly conversationId?: string;
|
|
108
|
+
/**
|
|
109
|
+
* For a server with `auth`: the user to call as, for a call made outside any
|
|
110
|
+
* conversation, such as a job. With a `conversationId` too, it must be the
|
|
111
|
+
* conversation's owner.
|
|
112
|
+
*/
|
|
113
|
+
readonly userId?: string;
|
|
89
114
|
/** Hears the server's progress notifications, as `ToolCtx.progress` does. */
|
|
90
115
|
progress?(progress: Progress): void;
|
|
91
116
|
}
|
|
@@ -116,9 +141,15 @@ export interface McpConnection {
|
|
|
116
141
|
* Connects, and checks every declared tool: it throws if the server has no
|
|
117
142
|
* tool of that name, or one that can only run as an MCP task. Call it at
|
|
118
143
|
* startup, so a mistake stops the app there; the first call connects
|
|
119
|
-
* otherwise, and fails with the same error.
|
|
144
|
+
* otherwise, and fails with the same error. A server with `auth` needs
|
|
145
|
+
* the user to connect as, and checks the tools that user sees.
|
|
146
|
+
*/
|
|
147
|
+
connect(userId?: string): Promise<void>;
|
|
148
|
+
/**
|
|
149
|
+
* For a server with `auth`: closes the user's connection, if they have
|
|
150
|
+
* one. Their next call makes a new one, and looks up their credential again.
|
|
120
151
|
*/
|
|
121
|
-
|
|
152
|
+
forget(userId: string): Promise<void>;
|
|
122
153
|
/** Closes the connection, and stops a `stdio` server. Final: a later call fails with reason `closed`. */
|
|
123
154
|
close(): Promise<void>;
|
|
124
155
|
}
|
package/dist/index.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;GAcG;AAGH,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,EAAE,MAAM,cAAc,CAAC;AACrD,OAAO,
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;GAcG;AAGH,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,EAAE,MAAM,cAAc,CAAC;AACrD,OAAO,EASL,KAAK,YAAY,EAEjB,KAAK,YAAY,EAEjB,KAAK,SAAS,EACd,KAAK,sBAAsB,EAC5B,MAAM,8BAA8B,CAAC;AACtC,OAAO,EAAyF,KAAK,aAAa,EAAE,MAAM,WAAW,CAAC;AAItI,OAAO,EAAE,aAAa,EAAE,KAAK,OAAO,EAAE,KAAK,cAAc,EAAE,KAAK,aAAa,EAAE,MAAM,WAAW,CAAC;AACjG,OAAO,EAAE,QAAQ,EAAE,YAAY,EAAE,UAAU,EAAE,cAAc,EAAE,KAAK,WAAW,EAAE,KAAK,cAAc,EAAE,MAAM,aAAa,CAAC;AACxH,OAAO,EAAE,MAAM,EAAE,KAAK,WAAW,EAAE,MAAM,WAAW,CAAC;AACrD,OAAO,EAAE,IAAI,EAAE,KAAK,EAAE,KAAK,WAAW,EAAE,MAAM,iBAAiB,CAAC;AAChE,YAAY,EAAE,YAAY,EAAE,YAAY,EAAE,SAAS,EAAE,MAAM,8BAA8B,CAAC;AAuB1F,MAAM,WAAW,gBAAgB;IAC/B,6EAA6E;IAC7E,IAAI,EAAE,MAAM,CAAC;IACb;;;;;OAKG;IACH,SAAS,EAAE,CAAC,YAAY,CAAC,EAAE,YAAY,KAAK,SAAS,GAAG,OAAO,CAAC,SAAS,CAAC,CAAC;IAC3E;;;;OAIG;IACH,IAAI,CAAC,EAAE,aAAa,CAAC;IACrB;;;OAGG;IACH,cAAc,CAAC,EAAE,MAAM,CAAC;IACxB,iHAAiH;IACjH,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB;;;;OAIG;IACH,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB;;;OAGG;IACH,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB;;;;;OAKG;IACH,QAAQ,CAAC,EAAE,CAAC,MAAM,EAAE,aAAa,KAAK,IAAI,CAAC;IAC3C,qGAAqG;IACrG,kBAAkB,CAAC,EAAE,sBAAsB,CAAC;CAC7C;AAED,MAAM,WAAW,aAAa;IAC5B,MAAM,EAAE,MAAM,CAAC;IACf,mGAAmG;IACnG,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,+CAA+C;IAC/C,OAAO,EAAE,MAAM,EAAE,CAAC;IAClB,6EAA6E;IAC7E,OAAO,EAAE,MAAM,EAAE,CAAC;CACnB;AAED,MAAM,WAAW,UAAU,CAAC,CAAC,EAAE,CAAC;IAC9B,6EAA6E;IAC7E,IAAI,EAAE,MAAM,CAAC,CAAC,CAAC,CAAC;IAChB;;;;OAIG;IACH,MAAM,CAAC,EAAE,MAAM,CAAC,CAAC,CAAC,CAAC;IACnB,wDAAwD;IACxD,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,yDAAyD;IACzD,UAAU,CAAC,EAAE,MAAM,CAAC;CACrB;AAED,yEAAyE;AACzE,MAAM,WAAW,SAAS;IACxB,mDAAmD;IACnD,OAAO,EAAE,YAAY,EAAE,CAAC;IACxB,wDAAwD;IACxD,iBAAiB,CAAC,EAAE,OAAO,CAAC;CAC7B;AAED;;;GAGG;AACH,MAAM,WAAW,UAAU;IACzB;;;OAGG;IACH,QAAQ,CAAC,cAAc,CAAC,EAAE,MAAM,CAAC;IACjC;;;;OAIG;IACH,QAAQ,CAAC,MAAM,CAAC,EAAE,MAAM,CAAC;IACzB,6EAA6E;IAC7E,QAAQ,CAAC,CAAC,QAAQ,EAAE,QAAQ,GAAG,IAAI,CAAC;CACrC;AAED,uGAAuG;AACvG,MAAM,WAAW,OAAO,CAAC,CAAC,EAAE,CAAC;IAC3B,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAC;IACxB,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;IACtB;;;OAGG;IACH,IAAI,CAAC,IAAI,EAAE,CAAC,EAAE,GAAG,CAAC,EAAE,UAAU,GAAG,OAAO,CAAC,CAAC,CAAC,CAAC;CAC7C;AAED,8EAA8E;AAC9E,MAAM,WAAW,aAAa;IAC5B,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;IACtB;;;OAGG;IACH,IAAI,CAAC,CAAC,EAAE,CAAC,EAAE,IAAI,EAAE,MAAM,EAAE,GAAG,EAAE,UAAU,CAAC,CAAC,EAAE,CAAC,CAAC,GAAG;QAAE,MAAM,EAAE,MAAM,CAAC,CAAC,CAAC,CAAA;KAAE,GAAG,OAAO,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC;IACvF,IAAI,CAAC,CAAC,EAAE,IAAI,EAAE,MAAM,EAAE,GAAG,EAAE,UAAU,CAAC,CAAC,EAAE,OAAO,CAAC,GAAG;QAAE,MAAM,CAAC,EAAE,SAAS,CAAA;KAAE,GAAG,OAAO,CAAC,CAAC,EAAE,SAAS,CAAC,CAAC;IACnG;;;;;;OAMG;IACH,OAAO,CAAC,MAAM,CAAC,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;IACxC;;;OAGG;IACH,MAAM,CAAC,MAAM,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;IACtC,yGAAyG;IACzG,KAAK,IAAI,OAAO,CAAC,IAAI,CAAC,CAAC;CACxB;AAED,6FAA6F;AAC7F,wBAAgB,SAAS,CAAC,OAAO,EAAE,gBAAgB,GAAG,aAAa,CAElE"}
|