/* * Copyright (C) 2025 TomTom Navigation B.V. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ import { buildClientMetadataUrl } from "./auth/clientMetadata"; export interface AppConfig { port: number; baseUrl: string; baseUrlPath: string; allowedOrigins: string | undefined; logLevel: string; ciamTenantId: string | undefined; ciamDomain: string | undefined; workforceTenantId: string | undefined; authorizationServerUrl: string; ulsTokenEndpoint: string; ulsClientId: string; ulsResource: string; accountApiBaseUrl: string; accountApiAudience: string; accountApiScope: string; tomtomApiBaseUrl: string; tomtomApiKey: string | undefined; mcpTransportMode: string | undefined; testAuthorizeClientEnabled: boolean; } export function getAppConfig(env: NodeJS.ProcessEnv = process.env): AppConfig { // Both normalized slash-free at the end: they concatenate into identifiers // (resource, ulsClientId) that ULS compares byte-for-byte with fetch URLs. const baseUrl = (env.MCP_BASE_URL || `http://localhost:${env.PORT || 3000}`).replace(/\/$/, ""); const baseUrlPath = (env.MCP_BASE_URL_PATH || "").replace(/\/$/, ""); return { /** HTTP server port */ port: Number(env.PORT) || 3000, /** Base URL for the MCP API */ baseUrl, baseUrlPath, /** Comma-separated list of allowed CORS origins */ allowedOrigins: env.ALLOWED_ORIGINS, /** Log level */ logLevel: env.LOG_LEVEL || "info", /** CIAM tenant ID for JWT verification */ ciamTenantId: env.CIAM_TENANT_ID, /** CIAM domain subdomain (e.g. "tomtomext" for tomtomext.ciamlogin.com) */ ciamDomain: env.CIAM_DOMAIN, /** * Workforce (B2B) Entra tenant ID — optional. When set, the MCP server * also accepts JWTs issued by `https://login.microsoftonline.com/{id}/v2.0`, * in addition to the CIAM (External ID / B2C) issuer above. */ workforceTenantId: env.WORKFORCE_TENANT_ID, /** Authorization server base URL (e.g. https://oauth.my.tomtom.com) */ authorizationServerUrl: env.AUTHORIZATION_SERVER_URL || "https://oauth.my.tomtom.com", /** ULS token exchange endpoint URL */ ulsTokenEndpoint: env.ULS_TOKEN_ENDPOINT || "https://oauth.my.tomtom.com/token", /** * ULS token exchange client_id. Per CIMD, defaults to this deployment's * client metadata document URL, which ULS dereferences to identify the * client. ULS_CLIENT_ID overrides it as an operational rollback lever. */ ulsClientId: env.ULS_CLIENT_ID || buildClientMetadataUrl(baseUrl, baseUrlPath), /** ULS token exchange resource — the API the resolved key is for */ ulsResource: env.ULS_RESOURCE || "https://api.tomtom.com", /** Base URL for account/contract API calls */ accountApiBaseUrl: env.ACCOUNT_API_BASE_URL || "https://account.cx.tomtom.com", /** Audience of the token exchanged for account management API calls */ accountApiAudience: env.ACCOUNT_API_AUDIENCE || "https://account.cx.tomtom.com", /** Scope requested for the account management API token */ accountApiScope: env.ACCOUNT_API_SCOPE || "authorize", /** TomTom API base URL */ tomtomApiBaseUrl: env.TOMTOM_API_BASE_URL || "https://api.tomtom.com", /** Static TomTom API key (used when no per-session key is provided) */ tomtomApiKey: env.TOMTOM_API_KEY, /** HTTP server user-agent identity override, validated in utils/userAgent.ts */ mcpTransportMode: env.MCP_TRANSPORT_MODE, /** * Serve the CIMD document for the test authorize client (MCP Inspector, * mint scripts) — see auth/testClientMetadata.ts. Dev deployments only; * off unless the env var is exactly "true". */ testAuthorizeClientEnabled: env.TEST_AUTHORIZE_CLIENT_ENABLED === "true", }; } /** * Central configuration singleton for the TomTom MCP server. * All static values and environment-derived defaults live here. */ export const appConfig = getAppConfig();