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_TYPE or --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, or OPENAPI_SPEC_INLINE must 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:

  1. Process initializationsrc/index.ts invokes loadConfig()
  2. Argument parsingyargs builds the argv object from process arguments
  3. Environment fallback — For each configuration option, the code applies argv.xxx ?? process.env.XXX precedence
  4. Transport determination — If argv.transport === "http" or process.env.TRANSPORT_TYPE === "http", the transport type is set to "http"; otherwise defaults to "stdio"
  5. Spec source validation — The function ensures exactly one of --openapi-spec, --spec-from-stdin, or --spec-inline is provided, recording the method as url, file, stdin, or inline
  6. Header parsing — The parseHeaders() function transforms the string "Key:Value,Another:Value" into a Record<string,string>
  7. Object assembly — All derived values are assembled into the immutable OpenAPIMCPServerConfig object

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: name and version fields 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.apiBaseUrl and config.headers to enable downstream API calls with correct base URLs and authentication headers
  • Transport selection: The src/index.ts file selects between StreamableHttpServerTransport (for HTTP) or StdioServerTransport (for stdio) based on config.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 dotenv loading in src/config/index.ts, while the MCP server uses yargs + process.env merging in src/config.ts
  • Precedence rules: CLI arguments take priority over environment variables using the argv.xxx ?? process.env.XXX pattern
  • Typed propagation: The OpenAPIMCPServerConfig object provides a single source of truth passed from loadConfig() through OpenAPIServer to ToolsManager and ApiClient
  • Transport selection: The TRANSPORT_TYPE environment variable or --transport CLI flag determines whether the server uses StreamableHttpServerTransport or StdioServerTransport
  • 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:

Share the following with your agent to get started:
curl -s "https://instagit.com/install.md"

Works with
Claude Codex Cursor VS Code OpenClaw Any MCP Client

Maintain an open-source project? Get it listed too →