# How to Create Custom LLM API Configurations in Chat MCP: A Complete Guide

> Learn to create custom LLM API configurations in Chat MCP by adding your API key and URL to config.json. This guide details the process for seamless integration.

- Repository: [AIQL/chat-mcp](https://github.com/ai-ql/chat-mcp)
- Tags: how-to-guide
- Published: 2026-02-23

---

**To create custom LLM API configurations in Chat MCP, add an `env` object containing your API key and URL to the server entry in [`src/main/config.json`](https://github.com/ai-ql/chat-mcp/blob/main/src/main/config.json), which the Electron main process injects into the MCP server's environment variables at runtime.**

The **ai-ql/chat-mcp** repository provides an Electron-based frontend for Model Context Protocol (MCP) servers. Because the application delegates LLM interactions to external MCP servers rather than implementing them directly, you configure custom API endpoints and authentication keys via environment variables defined in the server's JSON configuration.

## Understanding the Configuration Architecture

The configuration flow follows a strict pipeline from JSON definition to process execution. When the Electron application starts, [`src/main/main.ts`](https://github.com/ai-ql/chat-mcp/blob/main/src/main/main.ts) reads [`src/main/config.json`](https://github.com/ai-ql/chat-mcp/blob/main/src/main/config.json) and constructs **ServerConfig** objects for each entry. These configurations pass to [`src/main/client.ts`](https://github.com/ai-ql/chat-mcp/blob/main/src/main/client.ts), where `initializeClient` creates a `StdioClientTransport` instance that spawns the MCP server as a child process. The transport merges the `env` object from your configuration into the child process environment, making variables like `LLM_API_URL` and `LLM_API_KEY` available to the server implementation.

## Step-by-Step Configuration Guide

### Step 1: Define Environment Variables in config.json

Locate [`src/main/config.json`](https://github.com/ai-ql/chat-mcp/blob/main/src/main/config.json) and add an `env` object under your target server entry. This object must contain the URL and API key variables expected by your specific MCP server implementation.

```json
{
  "mcpServers": {
    "custom-llm": {
      "command": "npx",
      "args": [
        "-y",
        "@modelcontextprotocol/server-everything"
      ],
      "env": {
        "LLM_API_URL": "https://api.custom-model.com/v1",
        "LLM_API_KEY": "sk-your-secret-key-here"
      }
    }
  }
}

```

The Electron main process passes these values to `child_process.spawn` via the `StdioClientTransport` constructor, ensuring the variables exist in the server's process environment before it initializes.

### Step 2: Match Variable Names to Server Requirements

Different MCP server implementations expect different environment variable names. If your server requires `CUSTOM_ENDPOINT` instead of `LLM_API_URL`, adjust the `env` keys accordingly:

```json
{
  "mcpServers": {
    "myModel": {
      "command": "npx",
      "args": ["-y", "@myorg/custom-mcp-server"],
      "env": {
        "CUSTOM_ENDPOINT": "https://my-custom-model.com/v1",
        "CUSTOM_TOKEN": "sk-your-token-here"
      }
    }
  }
}

```

### Step 3: (Optional) Expose Configuration to the UI

If you want the renderer process to dynamically specify model parameters, modify the request handler in [`src/main/client.ts`](https://github.com/ai-ql/chat-mcp/blob/main/src/main/client.ts). The `setRequestHandler` method for `CreateMessageRequestSchema` can read environment variables or request parameters to determine which endpoint to target:

```typescript
// src/main/client.ts
client.setRequestHandler(CreateMessageRequestSchema, async (request) => {
  // Use model from request or fall back to environment variable
  const model = request?.model ?? process.env.LLM_API_URL;
  
  return {
    model,
    stopReason: "endTurn",
    role: "assistant",
    content: {
      type: "text",
      text: "Custom LLM response placeholder"
    }
  };
});

```

## Accessing Custom LLMs from the Renderer

Once configured, the renderer process accesses the custom LLM through the preload bridge defined in [`src/preload/preload.ts`](https://github.com/ai-ql/chat-mcp/blob/main/src/preload/preload.ts). The `window.mcpServers` object exposes methods to call tools, prompts, and resources from the configured server:

```typescript
// Renderer process (e.g., React component or vanilla JS)
window.mcpServers['custom-llm'].tools.call('myTool', { query: "Hello" })
  .then(result => console.log('Response:', result))
  .catch(err => console.error('Error:', err));

```

## Key Implementation Files

Understanding these source files helps troubleshoot configuration issues:

- **[`src/main/config.json`](https://github.com/ai-ql/chat-mcp/blob/main/src/main/config.json)**: Defines MCP server commands, arguments, and environment variables. This is the only file you must edit to configure a custom API endpoint.
- **[`src/main/main.ts`](https://github.com/ai-ql/chat-mcp/blob/main/src/main/main.ts)**: Reads the configuration and initializes the Electron window. Calls `readConfig` to parse the JSON into `ServerConfig` objects.
- **[`src/main/client.ts`](https://github.com/ai-ql/chat-mcp/blob/main/src/main/client.ts)**: Creates `StdioClientTransport` instances and manages the `Client` lifecycle. Contains `initializeClient` where you can modify request handlers.
- **[`src/preload/preload.ts`](https://github.com/ai-ql/chat-mcp/blob/main/src/preload/preload.ts)**: Exposes the MCP API to the renderer via `contextBridge`, creating the `window.mcpServers` interface.

## Summary

- **Chat MCP** configures custom LLM endpoints via environment variables in [`src/main/config.json`](https://github.com/ai-ql/chat-mcp/blob/main/src/main/config.json), not hardcoded frontend values.
- Add an `env` object to your server configuration containing `LLM_API_URL` and `LLM_API_KEY` (or server-specific equivalents).
- The **Electron main process** injects these variables when spawning the MCP server through `StdioClientTransport`.
- For dynamic model selection, extend the `CreateMessageRequestSchema` handler in [`src/main/client.ts`](https://github.com/ai-ql/chat-mcp/blob/main/src/main/client.ts).
- Access configured servers from the renderer using `window.mcpServers.<name>.tools.call()`.

## Frequently Asked Questions

### Where do I store the API key securely?

Store the API key in the `env` object within [`src/main/config.json`](https://github.com/ai-ql/chat-mcp/blob/main/src/main/config.json). Because this file resides in the main process and is read at runtime, the key never ships in the renderer bundle. For production, consider loading sensitive values from the host environment or a secrets manager rather than committing them to version control.

### Can I use multiple custom LLM providers simultaneously?

Yes. Define multiple entries in the `mcpServers` object, each with distinct `env` configurations. For example, configure one server with OpenAI credentials and another with Azure OpenAI credentials. Each runs as a separate process with isolated environment variables.

### Why does my server not recognize the environment variables?

Verify that your MCP server implementation actually reads the variable names you configured. The Chat MCP repository passes variables exactly as defined in the JSON `env` object, but the server code must explicitly access them via `process.env.LLM_API_URL` (Node.js) or equivalent. Check your server's documentation for the expected variable names.

### Do I need to rebuild the Electron app after changing config.json?

No. Because [`src/main/config.json`](https://github.com/ai-ql/chat-mcp/blob/main/src/main/config.json) is read at runtime by [`src/main/main.ts`](https://github.com/ai-ql/chat-mcp/blob/main/src/main/main.ts), you only need to restart the Electron application. Changes take effect immediately on the next launch without recompiling the TypeScript or rebuilding the bundle.