Phase 1: Add configuration for integrated/separate auth modes

- Updated config.ts with AUTH_MODE, AUTH_SERVER_URL, AUTH_SERVER_PORT
- Added validation for port consistency between URL and PORT variables
- Added comprehensive JSDoc comments for all config variables
- Created .env.integrated and .env.separate config files
- Updated redis.ts to use REDIS_URL from config
- Added .claude/ to .gitignore
This commit is contained in:
Basil Hosmer 2025-09-03 22:54:27 -04:00
commit 1bcb85bb4f
No known key found for this signature in database
5 changed files with 62 additions and 4 deletions

4
.env.integrated Normal file
View file

@ -0,0 +1,4 @@
AUTH_MODE=integrated
BASE_URI=http://localhost:3232
PORT=3232
REDIS_URL=redis://localhost:6379

6
.env.separate Normal file
View file

@ -0,0 +1,6 @@
AUTH_MODE=separate
BASE_URI=http://localhost:3232
PORT=3232
REDIS_URL=redis://localhost:6379
AUTH_SERVER_URL=http://localhost:3001
AUTH_SERVER_PORT=3001

3
.gitignore vendored
View file

@ -129,3 +129,6 @@ dist
.yarn/build-state.yml
.yarn/install-state.gz
.pnp.*
# Claude config directory
.claude/

View file

@ -1,6 +1,50 @@
import "dotenv/config";
/**
* Port for the MCP server to listen on
*/
export const PORT = Number(process.env.PORT) || 3232;
export const BASE_URI =
process.env.BASE_URI || "https://localhost:3232";
/**
* Base URI for the MCP server. Used for OAuth callbacks and metadata.
* Should match the port if specified separately.
*/
export const BASE_URI = process.env.BASE_URI || `http://localhost:${PORT}`;
// Validate PORT and BASE_URI consistency
const baseUrl = new URL(BASE_URI);
if (baseUrl.port && parseInt(baseUrl.port) !== PORT) {
console.warn(`Warning: BASE_URI port (${baseUrl.port}) doesn't match PORT (${PORT})`);
}
/**
* Redis connection URL
*/
export const REDIS_URL = process.env.REDIS_URL || 'redis://localhost:6379';
/**
* Authentication mode:
* - 'integrated': MCP server acts as its own OAuth server (default)
* - 'separate': MCP server delegates to external auth server
*/
export const AUTH_MODE = (process.env.AUTH_MODE as 'integrated' | 'separate') || 'integrated';
/**
* Port for the standalone auth server (only used in separate mode)
* Used when running the auth-server component
*/
export const AUTH_SERVER_PORT = parseInt(process.env.AUTH_SERVER_PORT || '3001');
/**
* URL of the external authorization server (only used when AUTH_MODE='separate')
* This is where the MCP server will redirect clients for authentication
*/
export const AUTH_SERVER_URL = process.env.AUTH_SERVER_URL || `http://localhost:${AUTH_SERVER_PORT}`;
// Validate AUTH_SERVER configuration
if (AUTH_MODE === 'separate') {
const authUrl = new URL(AUTH_SERVER_URL);
if (authUrl.port && parseInt(authUrl.port) !== AUTH_SERVER_PORT) {
throw new Error(`Configuration error: AUTH_SERVER_URL port (${authUrl.port}) doesn't match AUTH_SERVER_PORT (${AUTH_SERVER_PORT})`);
}
}

View file

@ -1,5 +1,6 @@
import { createClient, SetOptions } from "@redis/client";
import { logger } from "./utils/logger.js";
import { REDIS_URL } from "./config.js";
/**
* Describes the Redis primitives we use in this application, to be able to mock
@ -37,7 +38,7 @@ export interface RedisClient {
export class RedisClientImpl implements RedisClient {
private redis = createClient({
url: process.env.REDIS_URL || "redis://localhost:6379",
url: REDIS_URL,
password: process.env.REDIS_PASSWORD,
socket: {
tls: process.env.REDIS_TLS === "1",
@ -97,7 +98,7 @@ export class RedisClientImpl implements RedisClient {
}
get options() {
return { url: process.env.REDIS_URL || "redis://localhost:6379" };
return { url: REDIS_URL };
}
async createSubscription(