@prefecthq/fastmcp-ts 0.0.2-alpha.0 → 0.0.4
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 +11 -11
- package/dist/cli/index.cjs +3879 -9436
- package/dist/cli/index.cjs.map +1 -1
- package/dist/client.d.ts +101 -11
- package/dist/client.js +252 -61
- package/dist/client.js.map +1 -1
- package/dist/server.d.ts +27 -20
- package/dist/server.js +7 -7
- package/dist/server.js.map +1 -1
- package/dist/{zod-P5QUYVPB.js → zod-JRPBLP6C.js} +1171 -423
- package/dist/zod-JRPBLP6C.js.map +1 -0
- package/package.json +43 -7
- package/dist/zod-P5QUYVPB.js.map +0 -1
package/dist/client.d.ts
CHANGED
|
@@ -1,8 +1,8 @@
|
|
|
1
|
-
import { CreateMessageResult, CreateMessageResultWithTools, ContentBlock, CreateMessageRequestParams, LoggingLevel, ElicitRequestParams, ElicitResult, Tool, Resource, Prompt, ResourceTemplate,
|
|
2
|
-
export { ContentBlock, CreateMessageRequestParams, CreateMessageResult, CreateMessageResultWithTools, ElicitRequestParams, ElicitResult, GetPromptResult, LoggingLevel, ModelPreferences, Prompt, PromptArgument, PromptMessage, Resource, ResourceContents, ResourceTemplate, Root, SamplingMessage, Tool, ToolChoice, ToolResultContent, ToolUseContent } from '@modelcontextprotocol/sdk/types';
|
|
1
|
+
import { CreateMessageResult, CreateMessageResultWithTools, ContentBlock, CreateMessageRequestParams, LoggingLevel, ElicitRequestParams, ElicitResult, Tool, Resource, Prompt, ResourceTemplate, TextResourceContents, BlobResourceContents, GetPromptResult, Root, ModelPreferences, SamplingMessage, ToolChoice } from '@modelcontextprotocol/sdk/types.js';
|
|
2
|
+
export { BlobResourceContents, ContentBlock, CreateMessageRequestParams, CreateMessageResult, CreateMessageResultWithTools, ElicitRequestParams, ElicitResult, GetPromptResult, LoggingLevel, ModelPreferences, Prompt, PromptArgument, PromptMessage, Resource, ResourceContents, ResourceTemplate, Root, SamplingMessage, TextResourceContents, Tool, ToolChoice, ToolResultContent, ToolUseContent } from '@modelcontextprotocol/sdk/types.js';
|
|
3
3
|
import { OAuthClientProvider, OAuthDiscoveryState } from '@modelcontextprotocol/sdk/client/auth.js';
|
|
4
4
|
import { OAuthClientMetadata, OAuthClientInformationMixed, OAuthTokens } from '@modelcontextprotocol/sdk/shared/auth.js';
|
|
5
|
-
import { Transport } from '@modelcontextprotocol/sdk/shared/transport';
|
|
5
|
+
import { Transport } from '@modelcontextprotocol/sdk/shared/transport.js';
|
|
6
6
|
import Anthropic from '@anthropic-ai/sdk';
|
|
7
7
|
import OpenAI from 'openai';
|
|
8
8
|
import { GoogleGenAI } from '@google/genai';
|
|
@@ -75,7 +75,7 @@ interface IToolsClient {
|
|
|
75
75
|
interface IResourcesClient {
|
|
76
76
|
listResources(options?: RequestOptions): Promise<Resource[]>;
|
|
77
77
|
listResourceTemplates(options?: RequestOptions): Promise<ResourceTemplate[]>;
|
|
78
|
-
readResource(uri: string, options?: RequestOptions): Promise<
|
|
78
|
+
readResource(uri: string, options?: RequestOptions): Promise<Array<TextResourceContents | BlobResourceContents>>;
|
|
79
79
|
subscribeResource(uri: string, handler: ResourceUpdateHandler, options?: RequestOptions): Promise<void>;
|
|
80
80
|
unsubscribeResource(uri: string, options?: RequestOptions): Promise<void>;
|
|
81
81
|
}
|
|
@@ -126,8 +126,10 @@ declare class InMemoryStore implements KeyValueStore {
|
|
|
126
126
|
delete(key: string): Promise<void>;
|
|
127
127
|
}
|
|
128
128
|
declare class FileTokenStorage implements KeyValueStore {
|
|
129
|
-
private readonly
|
|
129
|
+
private readonly _explicitPath?;
|
|
130
|
+
private _resolvedPath?;
|
|
130
131
|
constructor(path?: string);
|
|
132
|
+
private _path;
|
|
131
133
|
private _readAll;
|
|
132
134
|
private _writeAll;
|
|
133
135
|
get(key: string): Promise<string | null>;
|
|
@@ -167,9 +169,9 @@ declare class OAuth implements OAuthClientProvider {
|
|
|
167
169
|
private readonly _callbackPort;
|
|
168
170
|
private readonly _onRedirect?;
|
|
169
171
|
private _codeVerifier;
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
172
|
+
protected _callbackPromise: Promise<string> | null;
|
|
173
|
+
protected _callbackResolve: ((code: string) => void) | null;
|
|
174
|
+
protected _callbackReject: ((err: Error) => void) | null;
|
|
173
175
|
private _callbackServer;
|
|
174
176
|
private _actualCallbackPort;
|
|
175
177
|
constructor(options?: OAuthOptions);
|
|
@@ -185,6 +187,20 @@ declare class OAuth implements OAuthClientProvider {
|
|
|
185
187
|
tokens(): Promise<OAuthTokens | undefined>;
|
|
186
188
|
saveTokens(tokens: OAuthTokens): Promise<void>;
|
|
187
189
|
redirectToAuthorization(authorizationUrl: URL): Promise<void>;
|
|
190
|
+
/**
|
|
191
|
+
* Creates the pending-callback promise that {@link waitForCallback} awaits.
|
|
192
|
+
* Subclasses (e.g. BrowserOAuth) call this before opening their own redirect.
|
|
193
|
+
*/
|
|
194
|
+
protected _armCallbackPromise(): void;
|
|
195
|
+
/** Resolves the pending callback with an authorization code. */
|
|
196
|
+
protected _resolveCallback(code: string): void;
|
|
197
|
+
/** Rejects the pending callback with an error. */
|
|
198
|
+
protected _rejectCallback(err: Error): void;
|
|
199
|
+
/**
|
|
200
|
+
* Races the pending callback promise against a timeout and clears the
|
|
201
|
+
* promise state. Subclasses reuse this and add their own teardown.
|
|
202
|
+
*/
|
|
203
|
+
protected _awaitCallback(timeoutMs: number): Promise<string>;
|
|
188
204
|
saveCodeVerifier(codeVerifier: string): void;
|
|
189
205
|
codeVerifier(): string;
|
|
190
206
|
invalidateCredentials(scope: 'all' | 'client' | 'tokens' | 'verifier' | 'discovery'): Promise<void>;
|
|
@@ -236,6 +252,80 @@ declare class ClientCredentials {
|
|
|
236
252
|
private _doFetch;
|
|
237
253
|
}
|
|
238
254
|
|
|
255
|
+
/**
|
|
256
|
+
* KeyValueStore backed by `localStorage`. Synchronous and simple; suitable for
|
|
257
|
+
* OAuth tokens and client registration state in single-page apps. Keys are
|
|
258
|
+
* namespaced by a prefix to avoid collisions with other app state.
|
|
259
|
+
*/
|
|
260
|
+
declare class LocalStorageStore implements KeyValueStore {
|
|
261
|
+
private readonly _prefix;
|
|
262
|
+
constructor(prefix?: string);
|
|
263
|
+
get(key: string): Promise<string | null>;
|
|
264
|
+
set(key: string, value: string): Promise<void>;
|
|
265
|
+
delete(key: string): Promise<void>;
|
|
266
|
+
}
|
|
267
|
+
/**
|
|
268
|
+
* KeyValueStore backed by IndexedDB. Preferred when tokens should survive
|
|
269
|
+
* outside the synchronous, size-limited localStorage (e.g. larger payloads or
|
|
270
|
+
* stricter persistence). Opens the database per operation and closes it again.
|
|
271
|
+
*/
|
|
272
|
+
declare class IndexedDBStore implements KeyValueStore {
|
|
273
|
+
private readonly _dbName;
|
|
274
|
+
private readonly _storeName;
|
|
275
|
+
constructor(opts?: {
|
|
276
|
+
dbName?: string;
|
|
277
|
+
storeName?: string;
|
|
278
|
+
});
|
|
279
|
+
private _open;
|
|
280
|
+
private _tx;
|
|
281
|
+
get(key: string): Promise<string | null>;
|
|
282
|
+
set(key: string, value: string): Promise<void>;
|
|
283
|
+
delete(key: string): Promise<void>;
|
|
284
|
+
}
|
|
285
|
+
|
|
286
|
+
interface BrowserOAuthOptions extends Omit<OAuthOptions, 'callbackPort' | 'onRedirect'> {
|
|
287
|
+
/**
|
|
288
|
+
* Redirect URI registered with the provider. Must serve a page that calls
|
|
289
|
+
* {@link handleOAuthCallback} (popup mode) or is your app route that reads the
|
|
290
|
+
* returned `?code=` (redirect mode).
|
|
291
|
+
*/
|
|
292
|
+
redirectUri: string;
|
|
293
|
+
/**
|
|
294
|
+
* 'popup' (default) opens the authorization URL in a popup window and listens
|
|
295
|
+
* for a postMessage from the callback page. 'redirect' navigates the whole
|
|
296
|
+
* tab; resume with {@link BrowserOAuth.resumeFromRedirect} on return.
|
|
297
|
+
*/
|
|
298
|
+
mode?: 'popup' | 'redirect';
|
|
299
|
+
/** `window.open` features string for popup mode. */
|
|
300
|
+
popupFeatures?: string;
|
|
301
|
+
}
|
|
302
|
+
declare class BrowserOAuth extends OAuth {
|
|
303
|
+
private readonly _redirectUri;
|
|
304
|
+
private readonly _mode;
|
|
305
|
+
private readonly _popupFeatures;
|
|
306
|
+
private _popup;
|
|
307
|
+
private _messageHandler;
|
|
308
|
+
constructor(options: BrowserOAuthOptions);
|
|
309
|
+
get redirectUrl(): string;
|
|
310
|
+
get clientMetadata(): OAuthClientMetadata;
|
|
311
|
+
redirectToAuthorization(authorizationUrl: URL): Promise<void>;
|
|
312
|
+
waitForCallback(timeoutMs?: number): Promise<string>;
|
|
313
|
+
/**
|
|
314
|
+
* Redirect-mode resume: parse the authorization code from a returned URL
|
|
315
|
+
* (defaults to the current location). Returns the code, or null if absent.
|
|
316
|
+
* Throws if the provider returned an error.
|
|
317
|
+
*/
|
|
318
|
+
resumeFromRedirect(href?: string): string | null;
|
|
319
|
+
private _teardown;
|
|
320
|
+
}
|
|
321
|
+
/**
|
|
322
|
+
* Call from the redirect_uri page (popup mode) to deliver the authorization
|
|
323
|
+
* code back to the opener window and close the popup.
|
|
324
|
+
*/
|
|
325
|
+
declare function handleOAuthCallback(opts?: {
|
|
326
|
+
targetOrigin?: string;
|
|
327
|
+
}): void;
|
|
328
|
+
|
|
239
329
|
interface McpServerLike {
|
|
240
330
|
connect(transport: Transport): Promise<void>;
|
|
241
331
|
}
|
|
@@ -296,7 +386,7 @@ declare class MultiServerClient implements IClient {
|
|
|
296
386
|
callToolRaw<TData = unknown>(name: string, args?: Record<string, unknown>, options?: CallToolOptions): Promise<CallToolResult<TData>>;
|
|
297
387
|
listResources(options?: RequestOptions): Promise<Resource[]>;
|
|
298
388
|
listResourceTemplates(options?: RequestOptions): Promise<ResourceTemplate[]>;
|
|
299
|
-
readResource(uri: string, options?: RequestOptions): Promise<
|
|
389
|
+
readResource(uri: string, options?: RequestOptions): Promise<Array<TextResourceContents | BlobResourceContents>>;
|
|
300
390
|
listPrompts(options?: RequestOptions): Promise<Prompt[]>;
|
|
301
391
|
getPrompt(name: string, args?: Record<string, string>, options?: RequestOptions): Promise<GetPromptResult>;
|
|
302
392
|
subscribeResource(uri: string, handler: ResourceUpdateHandler, options?: RequestOptions): Promise<void>;
|
|
@@ -397,7 +487,7 @@ declare class Client implements IClient {
|
|
|
397
487
|
callToolRaw<TData = unknown>(name: string, args?: Record<string, unknown>, options?: CallToolOptions): Promise<CallToolResult<TData>>;
|
|
398
488
|
listResources(options?: RequestOptions): Promise<Resource[]>;
|
|
399
489
|
listResourceTemplates(options?: RequestOptions): Promise<ResourceTemplate[]>;
|
|
400
|
-
readResource(uri: string, options?: RequestOptions): Promise<
|
|
490
|
+
readResource(uri: string, options?: RequestOptions): Promise<Array<TextResourceContents | BlobResourceContents>>;
|
|
401
491
|
/** Returns the raw SDK ReadResourceResult without unwrapping. */
|
|
402
492
|
readResourceRaw(uri: string, options?: RequestOptions): Promise<{
|
|
403
493
|
[x: string]: unknown;
|
|
@@ -540,4 +630,4 @@ declare class GoogleSamplingAdapter implements SamplingAdapter {
|
|
|
540
630
|
asHandler(): SamplingHandler;
|
|
541
631
|
}
|
|
542
632
|
|
|
543
|
-
export { AnthropicSamplingAdapter, type AnySamplingResult, BearerAuth, type CallToolOptions, type CallToolResult, Client, ClientCredentials, type ClientCredentialsOptions, type ClientDefaultOptions, type ClientHandlers, type ClientOptions, type ClientTransportInput, type CompletionResult, type ElicitationHandler, FileTokenStorage, type GenericCompletionFn, type GenericCompletionParams, GenericSamplingAdapter, GoogleSamplingAdapter, type IClient, type IPromptsClient, type IResourcesClient, type IToolsClient, InMemoryStore, type KeyValueStore, type ListChangedHandler, type LogHandler, type LogMessage, type McpConfig, type McpServerEntry, type McpServerLike, type McpServerValue, type ModelSelector, MultiServerClient, type MultiServerOptions, OAuth, type OAuthOptions, type OAuthToken, type OnTokenCallback, OpenAISamplingAdapter, type ProgressHandler, type RequestOptions, type ResourceUpdateHandler, type Result, type RootInput, type RootsValue, type SamplingAdapter, type SamplingAdapterOptions, type SamplingHandler, StdioTransport, ToolCallError, defaultLogHandler, defaultProgressHandler, toResult };
|
|
633
|
+
export { AnthropicSamplingAdapter, type AnySamplingResult, BearerAuth, BrowserOAuth, type BrowserOAuthOptions, type CallToolOptions, type CallToolResult, Client, ClientCredentials, type ClientCredentialsOptions, type ClientDefaultOptions, type ClientHandlers, type ClientOptions, type ClientTransportInput, type CompletionResult, type ElicitationHandler, FileTokenStorage, type GenericCompletionFn, type GenericCompletionParams, GenericSamplingAdapter, GoogleSamplingAdapter, type IClient, type IPromptsClient, type IResourcesClient, type IToolsClient, InMemoryStore, IndexedDBStore, type KeyValueStore, type ListChangedHandler, LocalStorageStore, type LogHandler, type LogMessage, type McpConfig, type McpServerEntry, type McpServerLike, type McpServerValue, type ModelSelector, MultiServerClient, type MultiServerOptions, OAuth, type OAuthOptions, type OAuthToken, type OnTokenCallback, OpenAISamplingAdapter, type ProgressHandler, type RequestOptions, type ResourceUpdateHandler, type Result, type RootInput, type RootsValue, type SamplingAdapter, type SamplingAdapterOptions, type SamplingHandler, StdioTransport, ToolCallError, defaultLogHandler, defaultProgressHandler, handleOAuthCallback, toResult };
|
package/dist/client.js
CHANGED
|
@@ -25,11 +25,6 @@ function defaultProgressHandler(progress, total, message) {
|
|
|
25
25
|
}
|
|
26
26
|
|
|
27
27
|
// src/client/auth.ts
|
|
28
|
-
import { spawn } from "child_process";
|
|
29
|
-
import * as fs from "fs/promises";
|
|
30
|
-
import * as http from "http";
|
|
31
|
-
import { homedir } from "os";
|
|
32
|
-
import { dirname, join } from "path";
|
|
33
28
|
var InMemoryStore = class {
|
|
34
29
|
_map = /* @__PURE__ */ new Map();
|
|
35
30
|
async get(key) {
|
|
@@ -43,13 +38,22 @@ var InMemoryStore = class {
|
|
|
43
38
|
}
|
|
44
39
|
};
|
|
45
40
|
var FileTokenStorage = class {
|
|
46
|
-
|
|
41
|
+
_explicitPath;
|
|
42
|
+
_resolvedPath;
|
|
47
43
|
constructor(path) {
|
|
48
|
-
this.
|
|
44
|
+
this._explicitPath = path;
|
|
45
|
+
}
|
|
46
|
+
async _path() {
|
|
47
|
+
if (this._resolvedPath) return this._resolvedPath;
|
|
48
|
+
if (this._explicitPath) return this._resolvedPath = this._explicitPath;
|
|
49
|
+
const { homedir } = await import("os");
|
|
50
|
+
const { join } = await import("path");
|
|
51
|
+
return this._resolvedPath = join(homedir(), ".fastmcp", "tokens.json");
|
|
49
52
|
}
|
|
50
53
|
async _readAll() {
|
|
54
|
+
const fs = await import("fs/promises");
|
|
51
55
|
try {
|
|
52
|
-
const raw = await fs.readFile(this._path, "utf8");
|
|
56
|
+
const raw = await fs.readFile(await this._path(), "utf8");
|
|
53
57
|
const parsed = JSON.parse(raw);
|
|
54
58
|
if (typeof parsed === "object" && parsed !== null && !Array.isArray(parsed)) {
|
|
55
59
|
return parsed;
|
|
@@ -60,10 +64,13 @@ var FileTokenStorage = class {
|
|
|
60
64
|
}
|
|
61
65
|
}
|
|
62
66
|
async _writeAll(data) {
|
|
63
|
-
|
|
64
|
-
const
|
|
67
|
+
const fs = await import("fs/promises");
|
|
68
|
+
const { dirname } = await import("path");
|
|
69
|
+
const path = await this._path();
|
|
70
|
+
await fs.mkdir(dirname(path), { recursive: true });
|
|
71
|
+
const tmp = `${path}.tmp`;
|
|
65
72
|
await fs.writeFile(tmp, JSON.stringify(data, null, 2), "utf8");
|
|
66
|
-
await fs.rename(tmp,
|
|
73
|
+
await fs.rename(tmp, path);
|
|
67
74
|
}
|
|
68
75
|
async get(key) {
|
|
69
76
|
const data = await this._readAll();
|
|
@@ -152,17 +159,54 @@ var OAuth = class {
|
|
|
152
159
|
await this._store.set(this._key("tokens"), JSON.stringify(tokens));
|
|
153
160
|
}
|
|
154
161
|
async redirectToAuthorization(authorizationUrl) {
|
|
155
|
-
this.
|
|
156
|
-
this._callbackResolve = resolve2;
|
|
157
|
-
this._callbackReject = reject;
|
|
158
|
-
});
|
|
159
|
-
this._callbackPromise.catch(() => {
|
|
160
|
-
});
|
|
162
|
+
this._armCallbackPromise();
|
|
161
163
|
await this._startCallbackServer();
|
|
162
164
|
if (this._onRedirect) {
|
|
163
165
|
await this._onRedirect(authorizationUrl);
|
|
164
166
|
} else {
|
|
165
|
-
openBrowser(authorizationUrl.toString());
|
|
167
|
+
await openBrowser(authorizationUrl.toString());
|
|
168
|
+
}
|
|
169
|
+
}
|
|
170
|
+
/**
|
|
171
|
+
* Creates the pending-callback promise that {@link waitForCallback} awaits.
|
|
172
|
+
* Subclasses (e.g. BrowserOAuth) call this before opening their own redirect.
|
|
173
|
+
*/
|
|
174
|
+
_armCallbackPromise() {
|
|
175
|
+
this._callbackPromise = new Promise((resolve, reject) => {
|
|
176
|
+
this._callbackResolve = resolve;
|
|
177
|
+
this._callbackReject = reject;
|
|
178
|
+
});
|
|
179
|
+
this._callbackPromise.catch(() => {
|
|
180
|
+
});
|
|
181
|
+
}
|
|
182
|
+
/** Resolves the pending callback with an authorization code. */
|
|
183
|
+
_resolveCallback(code) {
|
|
184
|
+
this._callbackResolve?.(code);
|
|
185
|
+
}
|
|
186
|
+
/** Rejects the pending callback with an error. */
|
|
187
|
+
_rejectCallback(err) {
|
|
188
|
+
this._callbackReject?.(err);
|
|
189
|
+
}
|
|
190
|
+
/**
|
|
191
|
+
* Races the pending callback promise against a timeout and clears the
|
|
192
|
+
* promise state. Subclasses reuse this and add their own teardown.
|
|
193
|
+
*/
|
|
194
|
+
async _awaitCallback(timeoutMs) {
|
|
195
|
+
if (!this._callbackPromise) {
|
|
196
|
+
throw new Error("No pending OAuth callback \u2014 call redirectToAuthorization() first");
|
|
197
|
+
}
|
|
198
|
+
const timeout = new Promise(
|
|
199
|
+
(_, reject) => setTimeout(
|
|
200
|
+
() => reject(new Error("OAuth callback timed out waiting for authorization")),
|
|
201
|
+
timeoutMs
|
|
202
|
+
)
|
|
203
|
+
);
|
|
204
|
+
try {
|
|
205
|
+
return await Promise.race([this._callbackPromise, timeout]);
|
|
206
|
+
} finally {
|
|
207
|
+
this._callbackPromise = null;
|
|
208
|
+
this._callbackResolve = null;
|
|
209
|
+
this._callbackReject = null;
|
|
166
210
|
}
|
|
167
211
|
}
|
|
168
212
|
saveCodeVerifier(codeVerifier) {
|
|
@@ -211,30 +255,19 @@ var OAuth = class {
|
|
|
211
255
|
* Must be called after the UnauthorizedError thrown by connect() is caught.
|
|
212
256
|
*/
|
|
213
257
|
async waitForCallback(timeoutMs = 5 * 60 * 1e3) {
|
|
214
|
-
if (!this._callbackPromise) {
|
|
215
|
-
throw new Error("No pending OAuth callback \u2014 call redirectToAuthorization() first");
|
|
216
|
-
}
|
|
217
|
-
const timeout = new Promise(
|
|
218
|
-
(_, reject) => setTimeout(
|
|
219
|
-
() => reject(new Error("OAuth callback timed out waiting for authorization")),
|
|
220
|
-
timeoutMs
|
|
221
|
-
)
|
|
222
|
-
);
|
|
223
258
|
try {
|
|
224
|
-
return await
|
|
259
|
+
return await this._awaitCallback(timeoutMs);
|
|
225
260
|
} finally {
|
|
226
|
-
this._callbackPromise = null;
|
|
227
|
-
this._callbackResolve = null;
|
|
228
|
-
this._callbackReject = null;
|
|
229
261
|
this._stopCallbackServer();
|
|
230
262
|
}
|
|
231
263
|
}
|
|
232
264
|
_key(type) {
|
|
233
265
|
return `${this._serverUrl}/${type}`;
|
|
234
266
|
}
|
|
235
|
-
_startCallbackServer() {
|
|
236
|
-
if (this._callbackServer) return
|
|
237
|
-
|
|
267
|
+
async _startCallbackServer() {
|
|
268
|
+
if (this._callbackServer) return;
|
|
269
|
+
const http = await import("http");
|
|
270
|
+
await new Promise((resolve, reject) => {
|
|
238
271
|
const server = http.createServer((req, res) => {
|
|
239
272
|
const url = new URL(req.url ?? "/", `http://localhost`);
|
|
240
273
|
const error = url.searchParams.get("error");
|
|
@@ -266,7 +299,7 @@ var OAuth = class {
|
|
|
266
299
|
this._actualCallbackPort = addr.port;
|
|
267
300
|
}
|
|
268
301
|
this._callbackServer = server;
|
|
269
|
-
|
|
302
|
+
resolve();
|
|
270
303
|
});
|
|
271
304
|
});
|
|
272
305
|
}
|
|
@@ -367,7 +400,8 @@ var ClientCredentials = class {
|
|
|
367
400
|
return this._fetchPromise;
|
|
368
401
|
}
|
|
369
402
|
};
|
|
370
|
-
function openBrowser(url) {
|
|
403
|
+
async function openBrowser(url) {
|
|
404
|
+
const { spawn } = await import("child_process");
|
|
371
405
|
if (process.platform === "win32") {
|
|
372
406
|
spawn("cmd", ["/c", "start", "", url], { detached: true, stdio: "ignore" });
|
|
373
407
|
} else if (process.platform === "darwin") {
|
|
@@ -377,12 +411,153 @@ function openBrowser(url) {
|
|
|
377
411
|
}
|
|
378
412
|
}
|
|
379
413
|
|
|
414
|
+
// src/client/browser-stores.ts
|
|
415
|
+
var LocalStorageStore = class {
|
|
416
|
+
_prefix;
|
|
417
|
+
constructor(prefix = "fastmcp:") {
|
|
418
|
+
this._prefix = prefix;
|
|
419
|
+
}
|
|
420
|
+
async get(key) {
|
|
421
|
+
return localStorage.getItem(this._prefix + key);
|
|
422
|
+
}
|
|
423
|
+
async set(key, value) {
|
|
424
|
+
localStorage.setItem(this._prefix + key, value);
|
|
425
|
+
}
|
|
426
|
+
async delete(key) {
|
|
427
|
+
localStorage.removeItem(this._prefix + key);
|
|
428
|
+
}
|
|
429
|
+
};
|
|
430
|
+
var IndexedDBStore = class {
|
|
431
|
+
_dbName;
|
|
432
|
+
_storeName;
|
|
433
|
+
constructor(opts = {}) {
|
|
434
|
+
this._dbName = opts.dbName ?? "fastmcp";
|
|
435
|
+
this._storeName = opts.storeName ?? "auth";
|
|
436
|
+
}
|
|
437
|
+
_open() {
|
|
438
|
+
return new Promise((resolve, reject) => {
|
|
439
|
+
const req = indexedDB.open(this._dbName, 1);
|
|
440
|
+
req.onupgradeneeded = () => {
|
|
441
|
+
if (!req.result.objectStoreNames.contains(this._storeName)) {
|
|
442
|
+
req.result.createObjectStore(this._storeName);
|
|
443
|
+
}
|
|
444
|
+
};
|
|
445
|
+
req.onsuccess = () => resolve(req.result);
|
|
446
|
+
req.onerror = () => reject(req.error ?? new Error("indexedDB.open failed"));
|
|
447
|
+
});
|
|
448
|
+
}
|
|
449
|
+
async _tx(mode, fn) {
|
|
450
|
+
const db = await this._open();
|
|
451
|
+
try {
|
|
452
|
+
return await new Promise((resolve, reject) => {
|
|
453
|
+
const req = fn(db.transaction(this._storeName, mode).objectStore(this._storeName));
|
|
454
|
+
req.onsuccess = () => resolve(req.result);
|
|
455
|
+
req.onerror = () => reject(req.error ?? new Error("indexedDB request failed"));
|
|
456
|
+
});
|
|
457
|
+
} finally {
|
|
458
|
+
db.close();
|
|
459
|
+
}
|
|
460
|
+
}
|
|
461
|
+
async get(key) {
|
|
462
|
+
const value = await this._tx("readonly", (s) => s.get(key));
|
|
463
|
+
return value ?? null;
|
|
464
|
+
}
|
|
465
|
+
async set(key, value) {
|
|
466
|
+
await this._tx("readwrite", (s) => s.put(value, key));
|
|
467
|
+
}
|
|
468
|
+
async delete(key) {
|
|
469
|
+
await this._tx("readwrite", (s) => s.delete(key));
|
|
470
|
+
}
|
|
471
|
+
};
|
|
472
|
+
|
|
473
|
+
// src/client/browser-oauth.ts
|
|
474
|
+
var MESSAGE_TYPE = "fastmcp:oauth";
|
|
475
|
+
var BrowserOAuth = class extends OAuth {
|
|
476
|
+
_redirectUri;
|
|
477
|
+
_mode;
|
|
478
|
+
_popupFeatures;
|
|
479
|
+
_popup = null;
|
|
480
|
+
_messageHandler = null;
|
|
481
|
+
constructor(options) {
|
|
482
|
+
super(options);
|
|
483
|
+
this._redirectUri = options.redirectUri;
|
|
484
|
+
this._mode = options.mode ?? "popup";
|
|
485
|
+
this._popupFeatures = options.popupFeatures ?? "width=600,height=720";
|
|
486
|
+
}
|
|
487
|
+
get redirectUrl() {
|
|
488
|
+
return this._redirectUri;
|
|
489
|
+
}
|
|
490
|
+
get clientMetadata() {
|
|
491
|
+
return { ...super.clientMetadata, redirect_uris: [this._redirectUri] };
|
|
492
|
+
}
|
|
493
|
+
async redirectToAuthorization(authorizationUrl) {
|
|
494
|
+
if (this._mode === "redirect") {
|
|
495
|
+
window.location.assign(authorizationUrl.toString());
|
|
496
|
+
return;
|
|
497
|
+
}
|
|
498
|
+
const expectedOrigin = new URL(this._redirectUri).origin;
|
|
499
|
+
this._messageHandler = (e) => {
|
|
500
|
+
if (e.origin !== expectedOrigin) return;
|
|
501
|
+
const data = e.data;
|
|
502
|
+
if (data?.type !== MESSAGE_TYPE) return;
|
|
503
|
+
if (data.error) this._rejectCallback(new Error(`OAuth authorization denied: ${data.error}`));
|
|
504
|
+
else if (data.code) this._resolveCallback(data.code);
|
|
505
|
+
};
|
|
506
|
+
window.addEventListener("message", this._messageHandler);
|
|
507
|
+
this._armCallbackPromise();
|
|
508
|
+
this._popup = window.open(authorizationUrl.toString(), "fastmcp-oauth", this._popupFeatures);
|
|
509
|
+
if (!this._popup) {
|
|
510
|
+
this._teardown();
|
|
511
|
+
throw new Error(
|
|
512
|
+
'Failed to open OAuth popup \u2014 it was likely blocked. Trigger connect from a user gesture or use mode: "redirect".'
|
|
513
|
+
);
|
|
514
|
+
}
|
|
515
|
+
}
|
|
516
|
+
async waitForCallback(timeoutMs = 5 * 60 * 1e3) {
|
|
517
|
+
try {
|
|
518
|
+
return await this._awaitCallback(timeoutMs);
|
|
519
|
+
} finally {
|
|
520
|
+
this._teardown();
|
|
521
|
+
}
|
|
522
|
+
}
|
|
523
|
+
/**
|
|
524
|
+
* Redirect-mode resume: parse the authorization code from a returned URL
|
|
525
|
+
* (defaults to the current location). Returns the code, or null if absent.
|
|
526
|
+
* Throws if the provider returned an error.
|
|
527
|
+
*/
|
|
528
|
+
resumeFromRedirect(href = window.location.href) {
|
|
529
|
+
const params = new URL(href).searchParams;
|
|
530
|
+
const error = params.get("error_description") ?? params.get("error");
|
|
531
|
+
if (error) throw new Error(`OAuth authorization denied: ${error}`);
|
|
532
|
+
return params.get("code");
|
|
533
|
+
}
|
|
534
|
+
_teardown() {
|
|
535
|
+
if (this._messageHandler) window.removeEventListener("message", this._messageHandler);
|
|
536
|
+
this._messageHandler = null;
|
|
537
|
+
try {
|
|
538
|
+
this._popup?.close();
|
|
539
|
+
} catch {
|
|
540
|
+
}
|
|
541
|
+
this._popup = null;
|
|
542
|
+
}
|
|
543
|
+
};
|
|
544
|
+
function handleOAuthCallback(opts = {}) {
|
|
545
|
+
const params = new URLSearchParams(window.location.search);
|
|
546
|
+
const code = params.get("code") ?? void 0;
|
|
547
|
+
const error = params.get("error_description") ?? params.get("error") ?? void 0;
|
|
548
|
+
const target = opts.targetOrigin ?? window.location.origin;
|
|
549
|
+
window.opener?.postMessage({ type: MESSAGE_TYPE, code, error }, target);
|
|
550
|
+
window.close();
|
|
551
|
+
}
|
|
552
|
+
|
|
380
553
|
// src/client/transports.ts
|
|
381
|
-
import {
|
|
382
|
-
import {
|
|
383
|
-
import {
|
|
384
|
-
|
|
385
|
-
|
|
554
|
+
import { InMemoryTransport } from "@modelcontextprotocol/sdk/inMemory.js";
|
|
555
|
+
import { StreamableHTTPClientTransport } from "@modelcontextprotocol/sdk/client/streamableHttp.js";
|
|
556
|
+
import { SSEClientTransport } from "@modelcontextprotocol/sdk/client/sse.js";
|
|
557
|
+
async function createStdioTransport(opts) {
|
|
558
|
+
const { StdioClientTransport } = await import("@modelcontextprotocol/sdk/client/stdio.js");
|
|
559
|
+
return new StdioClientTransport(opts);
|
|
560
|
+
}
|
|
386
561
|
function isMcpServerLike(value) {
|
|
387
562
|
return typeof value === "object" && value !== null && "connect" in value && typeof value.connect === "function";
|
|
388
563
|
}
|
|
@@ -401,6 +576,12 @@ var StdioTransport = class {
|
|
|
401
576
|
this.cwd = options?.cwd;
|
|
402
577
|
}
|
|
403
578
|
};
|
|
579
|
+
function normalizeHeaders(headers) {
|
|
580
|
+
if (!headers) return {};
|
|
581
|
+
if (headers instanceof Headers) return Object.fromEntries(headers.entries());
|
|
582
|
+
if (Array.isArray(headers)) return Object.fromEntries(headers);
|
|
583
|
+
return { ...headers };
|
|
584
|
+
}
|
|
404
585
|
function isAsyncAuth(auth) {
|
|
405
586
|
return "kind" in auth;
|
|
406
587
|
}
|
|
@@ -455,7 +636,7 @@ function urlToTransport(url, auth, extraHeaders = {}) {
|
|
|
455
636
|
...customFetch ? { fetch: customFetch } : {}
|
|
456
637
|
});
|
|
457
638
|
}
|
|
458
|
-
function resolveEntryTransport(entry, auth) {
|
|
639
|
+
async function resolveEntryTransport(entry, auth) {
|
|
459
640
|
if (isMcpServerLike(entry)) {
|
|
460
641
|
const [serverSide, clientSide] = InMemoryTransport.createLinkedPair();
|
|
461
642
|
return {
|
|
@@ -471,7 +652,7 @@ function resolveEntryTransport(entry, auth) {
|
|
|
471
652
|
}
|
|
472
653
|
const cmd = entry;
|
|
473
654
|
return {
|
|
474
|
-
transport:
|
|
655
|
+
transport: await createStdioTransport({
|
|
475
656
|
command: cmd.command,
|
|
476
657
|
args: cmd.args,
|
|
477
658
|
env: cmd.env
|
|
@@ -483,10 +664,10 @@ function resolveEntryAuth(auth) {
|
|
|
483
664
|
if (typeof auth === "string") return new BearerAuth(auth);
|
|
484
665
|
return auth;
|
|
485
666
|
}
|
|
486
|
-
function resolveTransport(input, auth) {
|
|
667
|
+
async function resolveTransport(input, auth) {
|
|
487
668
|
if (input instanceof StdioTransport) {
|
|
488
669
|
return {
|
|
489
|
-
transport:
|
|
670
|
+
transport: await createStdioTransport({
|
|
490
671
|
command: input.command,
|
|
491
672
|
args: input.args,
|
|
492
673
|
env: input.env,
|
|
@@ -505,7 +686,7 @@ function resolveTransport(input, auth) {
|
|
|
505
686
|
const entries = Object.entries(input.mcpServers);
|
|
506
687
|
if (entries.length === 0) throw new Error("mcpServers config is empty");
|
|
507
688
|
const [, entry] = entries[0];
|
|
508
|
-
return resolveEntryTransport(entry, auth);
|
|
689
|
+
return await resolveEntryTransport(entry, auth);
|
|
509
690
|
}
|
|
510
691
|
if (isMcpServerLike(input)) {
|
|
511
692
|
const [serverSide, clientSide] = InMemoryTransport.createLinkedPair();
|
|
@@ -520,8 +701,6 @@ function resolveTransport(input, auth) {
|
|
|
520
701
|
}
|
|
521
702
|
|
|
522
703
|
// src/client/client.ts
|
|
523
|
-
import { resolve } from "path";
|
|
524
|
-
import { pathToFileURL } from "url";
|
|
525
704
|
import { Client as SdkClient2 } from "@modelcontextprotocol/sdk/client";
|
|
526
705
|
import { UnauthorizedError } from "@modelcontextprotocol/sdk/client/auth.js";
|
|
527
706
|
import {
|
|
@@ -531,7 +710,7 @@ import {
|
|
|
531
710
|
ListRootsRequestSchema as ListRootsRequestSchema2,
|
|
532
711
|
LoggingMessageNotificationSchema as LoggingMessageNotificationSchema2,
|
|
533
712
|
ResourceUpdatedNotificationSchema as ResourceUpdatedNotificationSchema2
|
|
534
|
-
} from "@modelcontextprotocol/sdk/types";
|
|
713
|
+
} from "@modelcontextprotocol/sdk/types.js";
|
|
535
714
|
|
|
536
715
|
// src/client/multi-server.ts
|
|
537
716
|
import { Client as SdkClient } from "@modelcontextprotocol/sdk/client";
|
|
@@ -542,7 +721,7 @@ import {
|
|
|
542
721
|
CreateMessageRequestSchema,
|
|
543
722
|
ElicitRequestSchema,
|
|
544
723
|
ListRootsRequestSchema
|
|
545
|
-
} from "@modelcontextprotocol/sdk/types";
|
|
724
|
+
} from "@modelcontextprotocol/sdk/types.js";
|
|
546
725
|
var MultiServerClient = class _MultiServerClient {
|
|
547
726
|
_clients = /* @__PURE__ */ new Map();
|
|
548
727
|
_connectPromise = null;
|
|
@@ -588,7 +767,7 @@ var MultiServerClient = class _MultiServerClient {
|
|
|
588
767
|
entries.map(async ([name, entry]) => {
|
|
589
768
|
const sdk = this._buildSdkClient();
|
|
590
769
|
this._registerHandlers(sdk);
|
|
591
|
-
const { transport, beforeConnect } = resolveEntryTransport(
|
|
770
|
+
const { transport, beforeConnect } = await resolveEntryTransport(
|
|
592
771
|
entry
|
|
593
772
|
);
|
|
594
773
|
if (beforeConnect) await beforeConnect();
|
|
@@ -1020,7 +1199,7 @@ var Client = class _Client {
|
|
|
1020
1199
|
}
|
|
1021
1200
|
);
|
|
1022
1201
|
this._registerHandlers(sdkClient);
|
|
1023
|
-
const { transport, beforeConnect } = resolveTransport(this._input, this._auth);
|
|
1202
|
+
const { transport, beforeConnect } = await resolveTransport(this._input, this._auth);
|
|
1024
1203
|
if (this._auth instanceof OAuth) {
|
|
1025
1204
|
const serverUrl = this._extractServerUrl();
|
|
1026
1205
|
if (serverUrl) this._auth._bind(serverUrl);
|
|
@@ -1036,7 +1215,9 @@ var Client = class _Client {
|
|
|
1036
1215
|
code
|
|
1037
1216
|
);
|
|
1038
1217
|
}
|
|
1039
|
-
await
|
|
1218
|
+
const retry = await resolveTransport(this._input, this._auth);
|
|
1219
|
+
if (retry.beforeConnect) await retry.beforeConnect();
|
|
1220
|
+
await sdkClient.connect(retry.transport);
|
|
1040
1221
|
} else {
|
|
1041
1222
|
throw err;
|
|
1042
1223
|
}
|
|
@@ -1295,17 +1476,23 @@ function resolveAuth(auth) {
|
|
|
1295
1476
|
}
|
|
1296
1477
|
function normalizeRootsOption(roots) {
|
|
1297
1478
|
if (typeof roots === "function") {
|
|
1298
|
-
return async () => (await roots()).map(normalizeRootInput);
|
|
1479
|
+
return async () => Promise.all((await roots()).map(normalizeRootInput));
|
|
1299
1480
|
}
|
|
1300
|
-
|
|
1301
|
-
return () => Promise.resolve(normalized);
|
|
1481
|
+
return async () => Promise.all(roots.map(normalizeRootInput));
|
|
1302
1482
|
}
|
|
1303
|
-
function normalizeRootInput(input) {
|
|
1304
|
-
if (typeof input === "string") return { uri: normalizeRootUri(input) };
|
|
1305
|
-
return { ...input, uri: normalizeRootUri(input.uri) };
|
|
1483
|
+
async function normalizeRootInput(input) {
|
|
1484
|
+
if (typeof input === "string") return { uri: await normalizeRootUri(input) };
|
|
1485
|
+
return { ...input, uri: await normalizeRootUri(input.uri) };
|
|
1306
1486
|
}
|
|
1307
|
-
function normalizeRootUri(input) {
|
|
1308
|
-
if (
|
|
1487
|
+
async function normalizeRootUri(input) {
|
|
1488
|
+
if (/^[a-z][a-z0-9+.-]*:\/\//i.test(input)) return input;
|
|
1489
|
+
if (typeof process === "undefined" || !process.versions?.node) {
|
|
1490
|
+
throw new Error(
|
|
1491
|
+
`Cannot normalize filesystem root "${input}" in a browser. Pass a file:// URI instead.`
|
|
1492
|
+
);
|
|
1493
|
+
}
|
|
1494
|
+
const { resolve } = await import("path");
|
|
1495
|
+
const { pathToFileURL } = await import("url");
|
|
1309
1496
|
return pathToFileURL(resolve(input)).href;
|
|
1310
1497
|
}
|
|
1311
1498
|
|
|
@@ -1740,12 +1927,15 @@ var GoogleSamplingAdapter = class {
|
|
|
1740
1927
|
export {
|
|
1741
1928
|
AnthropicSamplingAdapter,
|
|
1742
1929
|
BearerAuth,
|
|
1930
|
+
BrowserOAuth,
|
|
1743
1931
|
Client,
|
|
1744
1932
|
ClientCredentials,
|
|
1745
1933
|
FileTokenStorage,
|
|
1746
1934
|
GenericSamplingAdapter,
|
|
1747
1935
|
GoogleSamplingAdapter,
|
|
1748
1936
|
InMemoryStore,
|
|
1937
|
+
IndexedDBStore,
|
|
1938
|
+
LocalStorageStore,
|
|
1749
1939
|
MultiServerClient,
|
|
1750
1940
|
OAuth,
|
|
1751
1941
|
OpenAISamplingAdapter,
|
|
@@ -1753,6 +1943,7 @@ export {
|
|
|
1753
1943
|
ToolCallError,
|
|
1754
1944
|
defaultLogHandler,
|
|
1755
1945
|
defaultProgressHandler,
|
|
1946
|
+
handleOAuthCallback,
|
|
1756
1947
|
toResult
|
|
1757
1948
|
};
|
|
1758
1949
|
//# sourceMappingURL=client.js.map
|