diff --git a/src/client.ts b/src/client.ts index 451325c..c76a538 100644 --- a/src/client.ts +++ b/src/client.ts @@ -18,7 +18,7 @@ import { SSEClientTransport } from '@modelcontextprotocol/sdk/client/sse.js' import { ListResourcesResultSchema, ListToolsResultSchema } from '@modelcontextprotocol/sdk/types.js' import { UnauthorizedError } from '@modelcontextprotocol/sdk/client/auth.js' import { NodeOAuthClientProvider } from './lib/node-oauth-client-provider' -import { parseCommandLineArgs, setupOAuthCallbackServer, setupSignalHandlers } from './lib/utils' +import { parseCommandLineArgs, setupOAuthCallbackServer, setupSignalHandlers, MCP_REMOTE_VERSION } from './lib/utils' /** * Main function to run the client @@ -39,7 +39,7 @@ async function runClient(serverUrl: string, callbackPort: number, clean: boolean const client = new Client( { name: 'mcp-remote', - version: require('../package.json').version, + version: MCP_REMOTE_VERSION, }, { capabilities: {}, diff --git a/src/lib/mcp-auth-config.ts b/src/lib/mcp-auth-config.ts index f52fc64..e35badc 100644 --- a/src/lib/mcp-auth-config.ts +++ b/src/lib/mcp-auth-config.ts @@ -2,16 +2,17 @@ import crypto from 'crypto' import path from 'path' import os from 'os' import fs from 'fs/promises' +import { MCP_REMOTE_VERSION } from './utils' /** * MCP Remote Authentication Configuration - * + * * This module handles the storage and retrieval of authentication-related data for MCP Remote. - * + * * Configuration directory structure: * - The config directory is determined by MCP_REMOTE_CONFIG_DIR env var or defaults to ~/.mcp-auth * - Each file is prefixed with a hash of the server URL to separate configurations for different servers - * + * * Files stored in the config directory: * - {server_hash}_client_info.json: Contains OAuth client registration information * - Format: OAuthClientInformation object with client_id and other registration details @@ -19,18 +20,14 @@ import fs from 'fs/promises' * - Format: OAuthTokens object with access_token, refresh_token, and expiration information * - {server_hash}_code_verifier.txt: Contains the PKCE code verifier for the current OAuth flow * - Format: Plain text string used for PKCE verification - * + * * All JSON files are stored with 2-space indentation for readability. */ /** * Known configuration file names that might need to be cleaned */ -export const knownConfigFiles = [ - 'client_info.json', - 'tokens.json', - 'code_verifier.txt', -]; +export const knownConfigFiles = ['client_info.json', 'tokens.json', 'code_verifier.txt'] /** * Deletes all known configuration files for a specific server @@ -48,7 +45,9 @@ export async function cleanServerConfig(serverUrlHash: string): Promise { * @returns The path to the configuration directory */ export function getConfigDir(): string { - return process.env.MCP_REMOTE_CONFIG_DIR || path.join(os.homedir(), '.mcp-auth') + const baseConfigDir = process.env.MCP_REMOTE_CONFIG_DIR || path.join(os.homedir(), '.mcp-auth') + // Add a version subdirectory so we don't need to worry about backwards/forwards compatibility yet + return path.join(baseConfigDir, `mcp-remote-${MCP_REMOTE_VERSION}`) } /** @@ -110,20 +109,20 @@ export async function deleteConfigFile(serverUrlHash: string, filename: string): * @returns The parsed file content or undefined if the file doesn't exist */ export async function readJsonFile( - serverUrlHash: string, - filename: string, + serverUrlHash: string, + filename: string, schema: any, - clean: boolean = false + clean: boolean = false, ): Promise { try { await ensureConfigDir() - + // If clean flag is set, delete the file before trying to read it if (clean) { await deleteConfigFile(serverUrlHash, filename) return undefined } - + const filePath = getConfigFilePath(serverUrlHash, filename) const content = await fs.readFile(filePath, 'utf-8') return await schema.parseAsync(JSON.parse(content)) @@ -141,11 +140,7 @@ export async function readJsonFile( * @param filename The name of the file to write * @param data The data to write */ -export async function writeJsonFile( - serverUrlHash: string, - filename: string, - data: any -): Promise { +export async function writeJsonFile(serverUrlHash: string, filename: string, data: any): Promise { try { await ensureConfigDir() const filePath = getConfigFilePath(serverUrlHash, filename) @@ -165,20 +160,20 @@ export async function writeJsonFile( * @returns The file content as a string */ export async function readTextFile( - serverUrlHash: string, + serverUrlHash: string, filename: string, errorMessage?: string, - clean: boolean = false + clean: boolean = false, ): Promise { try { await ensureConfigDir() - + // If clean flag is set, delete the file before trying to read it if (clean) { await deleteConfigFile(serverUrlHash, filename) throw new Error('File deleted due to clean flag') } - + const filePath = getConfigFilePath(serverUrlHash, filename) return await fs.readFile(filePath, 'utf-8') } catch (error) { @@ -192,11 +187,7 @@ export async function readTextFile( * @param filename The name of the file to write * @param text The text to write */ -export async function writeTextFile( - serverUrlHash: string, - filename: string, - text: string -): Promise { +export async function writeTextFile(serverUrlHash: string, filename: string, text: string): Promise { try { await ensureConfigDir() const filePath = getConfigFilePath(serverUrlHash, filename) @@ -205,4 +196,4 @@ export async function writeTextFile( console.error(`Error writing ${filename}:`, error) throw error } -} \ No newline at end of file +} diff --git a/src/lib/utils.ts b/src/lib/utils.ts index e9b4bf3..3cbb1f6 100644 --- a/src/lib/utils.ts +++ b/src/lib/utils.ts @@ -191,12 +191,12 @@ export async function parseCommandLineArgs(args: string[], defaultPort: number, // Check for --clean flag const cleanIndex = args.indexOf('--clean') const clean = cleanIndex !== -1 - + // Remove the flag from args if it exists if (clean) { args.splice(cleanIndex, 1) } - + const serverUrl = args[0] const specifiedPort = args[1] ? parseInt(args[1]) : undefined @@ -221,7 +221,7 @@ export async function parseCommandLineArgs(args: string[], defaultPort: number, } else { console.error(`Using automatically selected callback port: ${callbackPort}`) } - + if (clean) { console.error('Clean mode enabled: config files will be reset before reading') } @@ -243,3 +243,5 @@ export function setupSignalHandlers(cleanup: () => Promise) { // Keep the process alive process.stdin.resume() } + +export const MCP_REMOTE_VERSION = require('../../package.json').version