How Environment Configuration Is Loaded and Used in castrozan/tcc
Environment configuration in the castrozan/tcc repository is loaded via dotenv for dummy applications and through a merged CLI-arguments-and-environment-variables approach using yargs for the MCP OpenAPI server, then propagated through typed config objects to server components.
The castrozan/tcc repository implements a dual-strategy approach to environment configuration management, separating simple dotenv-based loading for mock services from a sophisticated command-line-and-environment merger for the core MCP OpenAPI server. Understanding how these configuration patterns initialize runtime behavior is essential for deploying and extending the system.
Configuration Loading Architectures
The repository employs two distinct patterns for loading environment configuration based on the component's complexity requirements.
Dummy Applications: Direct dotenv Initialization
For the professionals-dummy-app and equipments-dummy-app services, configuration loading follows a straightforward pattern. The src/config/index.ts file invokes dotenv.config() at the module level to parse local .env files, then exports a Config object selected by process.env.NODE_ENV.
Individual values such as process.env.PORT are read directly when the configuration map is built. The resulting configuration object is then imported by the HTTP server in src/infrastructure/web/open-api/server.ts, which passes the port value to the Hono server instance.
MCP OpenAPI Server: Merged CLI and Environment Variables
The mcp-openapi-server package employs a more complex resolution strategy defined in src/config.ts. The loadConfig() function parses command-line arguments using yargs, then merges these with process.env fallbacks to construct an OpenAPIMCPServerConfig object.
This configuration resolution handles:
- Transport type (
TRANSPORT_TYPEor--transport): Determines whether to use HTTP or stdio transport - HTTP settings (
HTTP_PORT,HTTP_HOST,ENDPOINT_PATH): Server binding parameters - OpenAPI spec source: Exactly one of
OPENAPI_SPEC_PATH,OPENAPI_SPEC_FROM_STDIN, orOPENAPI_SPEC_INLINEmust be provided - API connectivity (
API_BASE_URL,API_HEADERS): Downstream service endpoints and authentication - Feature flags (
DISABLE_ABBREVIATION,TOOLS_MODE): Optional behavioral toggles
Configuration Resolution Flow
The MCP OpenAPI server follows a strict initialization sequence when loading environment configuration:
- Process initialization —
src/index.tsinvokesloadConfig() - Argument parsing —
yargsbuilds theargvobject from process arguments - Environment fallback — For each configuration option, the code applies
argv.xxx ?? process.env.XXXprecedence - Transport determination — If
argv.transport === "http"orprocess.env.TRANSPORT_TYPE === "http", the transport type is set to"http"; otherwise defaults to"stdio" - Spec source validation — The function ensures exactly one of
--openapi-spec,--spec-from-stdin, or--spec-inlineis provided, recording the method asurl,file,stdin, orinline - Header parsing — The
parseHeaders()function transforms the string"Key:Value,Another:Value"into aRecord<string,string> - Object assembly — All derived values are assembled into the immutable
OpenAPIMCPServerConfigobject
Propagation to Runtime Components
Once loaded, the configuration object propagates through the application stack according to a strict dependency injection pattern.
The src/index.ts entry point passes the config to new OpenAPIServer(config), which stores the configuration internally. Inside the OpenAPIServer constructor located in src/server.ts, the configuration drives:
- Server metadata:
nameandversionfields exposed to clients - ToolsManager construction: Receives the config to determine which OpenAPI tools to load, which tools to filter, and whether abbreviation is disabled via
disableAbbreviation - ApiClient creation: Uses
config.apiBaseUrlandconfig.headersto enable downstream API calls with correct base URLs and authentication headers - Transport selection: The
src/index.tsfile selects betweenStreamableHttpServerTransport(for HTTP) orStdioServerTransport(for stdio) based onconfig.transportType
Code Implementation Examples
Loading Configuration with CLI and Environment Merge
// mcp-openapi-server/src/config.ts
export function loadConfig(): OpenAPIMCPServerConfig {
const argv = yargs(hideBin(process.argv))
.option("transport", { choices: ["stdio", "http"] })
.option("port", { type: "number" })
// …other options…
.parseSync();
// Transport resolution with environment fallback
const transportType =
argv.transport === "http" || process.env.TRANSPORT_TYPE === "http"
? "http"
: "stdio";
// HTTP settings fallback to env vars
const httpPort = argv.port ?? (process.env.HTTP_PORT ? parseInt(process.env.HTTP_PORT, 10) : 3000);
const httpHost = argv.host || process.env.HTTP_HOST || "127.0.0.1";
const endpointPath = argv.path || process.env.ENDPOINT_PATH || "/mcp";
// Spec source handling (exactly one required)
const specFromStdin = argv["spec-from-stdin"] || process.env.OPENAPI_SPEC_FROM_STDIN === "true";
const specInline = argv["spec-inline"] || process.env.OPENAPI_SPEC_INLINE;
const openApiSpec = argv["openapi-spec"] || process.env.OPENAPI_SPEC_PATH;
const apiBaseUrl = argv["api-base-url"] || process.env.API_BASE_URL;
const headers = parseHeaders(argv.headers || process.env.API_HEADERS);
return {
name: argv.name || process.env.SERVER_NAME || "mcp-openapi-server",
version: argv["server-version"] || process.env.SERVER_VERSION || "1.0.0",
apiBaseUrl,
openApiSpec,
specInputMethod,
inlineSpecContent: specInline,
headers,
transportType,
httpPort,
httpHost,
endpointPath,
toolsMode: (argv.tools as "all" | "dynamic") || process.env.TOOLS_MODE || "all",
disableAbbreviation: argv["disable-abbreviation"] ?? (process.env.DISABLE_ABBREVIATION === "true"),
};
}
Consuming Configuration to Initialize the Server
// mcp-openapi-server/src/index.ts
import { loadConfig } from "./config";
import { OpenAPIServer } from "./server";
import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio.js";
import { StreamableHttpServerTransport } from "./transport/StreamableHttpServerTransport";
async function main() {
const config = loadConfig(); // ← pulls from CLI & env
const server = new OpenAPIServer(config); // ← config drives server setup
let transport;
if (config.transportType === "http") {
transport = new StreamableHttpServerTransport(
config.httpPort!,
config.httpHost,
config.endpointPath,
);
} else {
transport = new StdioServerTransport();
}
await server.start(transport); // ← server uses config internally
}
main();
Dummy Application Configuration Pattern
// professionals-dummy-app/src/config/index.ts
import dotenv from "dotenv";
import { Config } from "./types.js";
dotenv.config(); // ← reads .env file
const configs: Record<string, Config> = {
development: { port: Number(process.env.PORT) || 3003 },
test: { port: Number(process.env.PORT) || 3003 },
production: { port: Number(process.env.PORT) || 3003 },
};
const environment = process.env.NODE_ENV ?? "development";
export default configs[environment] ?? configs.development;
Summary
- Dual strategies: Dummy apps use simple
dotenvloading insrc/config/index.ts, while the MCP server usesyargs+process.envmerging insrc/config.ts - Precedence rules: CLI arguments take priority over environment variables using the
argv.xxx ?? process.env.XXXpattern - Typed propagation: The
OpenAPIMCPServerConfigobject provides a single source of truth passed fromloadConfig()throughOpenAPIServertoToolsManagerandApiClient - Transport selection: The
TRANSPORT_TYPEenvironment variable or--transportCLI flag determines whether the server usesStreamableHttpServerTransportorStdioServerTransport - Validation requirements: The MCP server requires exactly one OpenAPI spec source to be specified among file path, stdin, or inline options
Frequently Asked Questions
How does the MCP OpenAPI server prioritize CLI arguments over environment variables?
The loadConfig() function in mcp-openapi-server/src/config.ts uses the nullish coalescing operator (??) and logical OR (||) to implement precedence. For most options, the pattern argv.xxx ?? process.env.XXX ensures that explicitly provided CLI arguments override environment variables, while environment variables provide defaults when CLI arguments are absent. For boolean flags like disableAbbreviation, the code checks both the argv property and the environment variable separately.
What configuration options control the OpenAPI specification source?
The server accepts exactly one of three mutually exclusive options: OPENAPI_SPEC_PATH (or --openapi-spec) for file/URL paths, OPENAPI_SPEC_FROM_STDIN (or --spec-from-stdin) for piping specs via standard input, or OPENAPI_SPEC_INLINE (or --spec-inline) for direct string embedding. The loadConfig() function validates that only one method is specified and records this choice in the specInputMethod field of the configuration object.
How are HTTP server parameters configured in the dummy applications?
The dummy applications read process.env.PORT after dotenv.config() initializes the environment. The src/config/index.ts file maps NODE_ENV values to specific configuration objects, defaulting to port 3003 if PORT is undefined. This configuration is then consumed by src/infrastructure/web/open-api/server.ts to bind the Hono server to the specified port.
Which file is responsible for transport type selection?
Transport type selection occurs in two locations. The loadConfig() function in mcp-openapi-server/src/config.ts determines the transport type by checking argv.transport and process.env.TRANSPORT_TYPE, defaulting to "stdio" if neither specifies "http". Subsequently, src/index.ts instantiates the appropriate transport class—either StreamableHttpServerTransport for HTTP mode or StdioServerTransport for stdio mode—based on the config.transportType value.
Have a question about this repo?
These articles cover the highlights, but your codebase questions are specific. Give your agent direct access to the source. Share this with your agent to get started:
curl -s "https://instagit.com/install.md" Maintain an open-source project? Get it listed too →