Add .denoignore file and update implementation plan with additional tasks for type safety, dependency management, testing, documentation, and build configuration.
This commit is contained in:
parent
00b1d15cfd
commit
4394c0773d
10 changed files with 1815 additions and 1096 deletions
|
@ -1,84 +1,108 @@
|
|||
import open from 'npm:open'
|
||||
import { OAuthClientProvider } from 'npm:@modelcontextprotocol/sdk/client/auth.js'
|
||||
import open from "npm:open";
|
||||
import type { OAuthClientProvider } from "npm:@modelcontextprotocol/sdk/client/auth.js";
|
||||
import "npm:@modelcontextprotocol/sdk/client/auth.js";
|
||||
import {
|
||||
OAuthClientInformationSchema,
|
||||
OAuthTokensSchema,
|
||||
} from "npm:@modelcontextprotocol/sdk/shared/auth.js";
|
||||
import type {
|
||||
OAuthClientInformation,
|
||||
OAuthClientInformationFull,
|
||||
OAuthClientInformationSchema,
|
||||
OAuthTokens,
|
||||
OAuthTokensSchema,
|
||||
} from 'npm:@modelcontextprotocol/sdk/shared/auth.js'
|
||||
import type { OAuthProviderOptions } from './types.ts'
|
||||
import { readJsonFile, writeJsonFile, readTextFile, writeTextFile } from './mcp-auth-config.ts'
|
||||
import { getServerUrlHash, log, MCP_REMOTE_VERSION } from './utils.ts'
|
||||
} from "npm:@modelcontextprotocol/sdk/shared/auth.js";
|
||||
import type { OAuthProviderOptions } from "./types.ts";
|
||||
import {
|
||||
readJsonFile,
|
||||
readTextFile,
|
||||
writeJsonFile,
|
||||
writeTextFile,
|
||||
} from "./mcp-auth-config.ts";
|
||||
import { getServerUrlHash, log, MCP_REMOTE_VERSION } from "./utils.ts";
|
||||
|
||||
/**
|
||||
* Implements the OAuthClientProvider interface for Node.js environments.
|
||||
* Handles OAuth flow and token storage for MCP clients.
|
||||
*/
|
||||
export class NodeOAuthClientProvider implements OAuthClientProvider {
|
||||
private serverUrlHash: string
|
||||
private callbackPath: string
|
||||
private clientName: string
|
||||
private clientUri: string
|
||||
private softwareId: string
|
||||
private softwareVersion: string
|
||||
private serverUrlHash: string;
|
||||
private callbackPath: string;
|
||||
private clientName: string;
|
||||
private clientUri: string;
|
||||
private softwareId: string;
|
||||
private softwareVersion: string;
|
||||
|
||||
/**
|
||||
* Creates a new NodeOAuthClientProvider
|
||||
* @param options Configuration options for the provider
|
||||
*/
|
||||
constructor(readonly options: OAuthProviderOptions) {
|
||||
this.serverUrlHash = getServerUrlHash(options.serverUrl)
|
||||
this.callbackPath = options.callbackPath || '/oauth/callback'
|
||||
this.clientName = options.clientName || 'MCP CLI Client'
|
||||
this.clientUri = options.clientUri || 'https://github.com/modelcontextprotocol/mcp-cli'
|
||||
this.softwareId = options.softwareId || '2e6dc280-f3c3-4e01-99a7-8181dbd1d23d'
|
||||
this.softwareVersion = options.softwareVersion || MCP_REMOTE_VERSION
|
||||
this.serverUrlHash = getServerUrlHash(options.serverUrl);
|
||||
this.callbackPath = options.callbackPath || "/oauth/callback";
|
||||
this.clientName = options.clientName || "MCP CLI Client";
|
||||
this.clientUri = options.clientUri ||
|
||||
"https://github.com/modelcontextprotocol/mcp-cli";
|
||||
this.softwareId = options.softwareId ||
|
||||
"2e6dc280-f3c3-4e01-99a7-8181dbd1d23d";
|
||||
this.softwareVersion = options.softwareVersion || MCP_REMOTE_VERSION;
|
||||
}
|
||||
|
||||
get redirectUrl(): string {
|
||||
return `http://127.0.0.1:${this.options.callbackPort}${this.callbackPath}`
|
||||
return `http://127.0.0.1:${this.options.callbackPort}${this.callbackPath}`;
|
||||
}
|
||||
|
||||
get clientMetadata() {
|
||||
return {
|
||||
redirect_uris: [this.redirectUrl],
|
||||
token_endpoint_auth_method: 'none',
|
||||
grant_types: ['authorization_code', 'refresh_token'],
|
||||
response_types: ['code'],
|
||||
token_endpoint_auth_method: "none",
|
||||
grant_types: ["authorization_code", "refresh_token"],
|
||||
response_types: ["code"],
|
||||
client_name: this.clientName,
|
||||
client_uri: this.clientUri,
|
||||
software_id: this.softwareId,
|
||||
software_version: this.softwareVersion,
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the client information if it exists
|
||||
* @returns The client information or undefined
|
||||
*/
|
||||
async clientInformation(): Promise<OAuthClientInformation | undefined> {
|
||||
clientInformation(): Promise<OAuthClientInformation | undefined> {
|
||||
// log('Reading client info')
|
||||
return readJsonFile<OAuthClientInformation>(this.serverUrlHash, 'client_info.json', OAuthClientInformationSchema)
|
||||
return readJsonFile<OAuthClientInformation>(
|
||||
this.serverUrlHash,
|
||||
"client_info.json",
|
||||
OAuthClientInformationSchema,
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Saves client information
|
||||
* @param clientInformation The client information to save
|
||||
*/
|
||||
async saveClientInformation(clientInformation: OAuthClientInformationFull): Promise<void> {
|
||||
async saveClientInformation(
|
||||
clientInformation: OAuthClientInformationFull,
|
||||
): Promise<void> {
|
||||
// log('Saving client info')
|
||||
await writeJsonFile(this.serverUrlHash, 'client_info.json', clientInformation)
|
||||
await writeJsonFile(
|
||||
this.serverUrlHash,
|
||||
"client_info.json",
|
||||
clientInformation,
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the OAuth tokens if they exist
|
||||
* @returns The OAuth tokens or undefined
|
||||
*/
|
||||
async tokens(): Promise<OAuthTokens | undefined> {
|
||||
tokens(): Promise<OAuthTokens | undefined> {
|
||||
// log('Reading tokens')
|
||||
// console.log(new Error().stack)
|
||||
return readJsonFile<OAuthTokens>(this.serverUrlHash, 'tokens.json', OAuthTokensSchema)
|
||||
return readJsonFile<OAuthTokens>(
|
||||
this.serverUrlHash,
|
||||
"tokens.json",
|
||||
OAuthTokensSchema,
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -87,7 +111,7 @@ export class NodeOAuthClientProvider implements OAuthClientProvider {
|
|||
*/
|
||||
async saveTokens(tokens: OAuthTokens): Promise<void> {
|
||||
// log('Saving tokens')
|
||||
await writeJsonFile(this.serverUrlHash, 'tokens.json', tokens)
|
||||
await writeJsonFile(this.serverUrlHash, "tokens.json", tokens);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -95,12 +119,16 @@ export class NodeOAuthClientProvider implements OAuthClientProvider {
|
|||
* @param authorizationUrl The URL to redirect to
|
||||
*/
|
||||
async redirectToAuthorization(authorizationUrl: URL): Promise<void> {
|
||||
log(`\nPlease authorize this client by visiting:\n${authorizationUrl.toString()}\n`)
|
||||
log(
|
||||
`\nPlease authorize this client by visiting:\n${authorizationUrl.toString()}\n`,
|
||||
);
|
||||
try {
|
||||
await open(authorizationUrl.toString())
|
||||
log('Browser opened automatically.')
|
||||
} catch (error) {
|
||||
log('Could not open browser automatically. Please copy and paste the URL above into your browser.')
|
||||
await open(authorizationUrl.toString());
|
||||
log("Browser opened automatically.");
|
||||
} catch (_error) {
|
||||
log(
|
||||
"Could not open browser automatically. Please copy and paste the URL above into your browser.",
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -110,7 +138,7 @@ export class NodeOAuthClientProvider implements OAuthClientProvider {
|
|||
*/
|
||||
async saveCodeVerifier(codeVerifier: string): Promise<void> {
|
||||
// log('Saving code verifier')
|
||||
await writeTextFile(this.serverUrlHash, 'code_verifier.txt', codeVerifier)
|
||||
await writeTextFile(this.serverUrlHash, "code_verifier.txt", codeVerifier);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -119,6 +147,10 @@ export class NodeOAuthClientProvider implements OAuthClientProvider {
|
|||
*/
|
||||
async codeVerifier(): Promise<string> {
|
||||
// log('Reading code verifier')
|
||||
return await readTextFile(this.serverUrlHash, 'code_verifier.txt', 'No code verifier saved for session')
|
||||
return await readTextFile(
|
||||
this.serverUrlHash,
|
||||
"code_verifier.txt",
|
||||
"No code verifier saved for session",
|
||||
);
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue