Podcast Title

Author Name

0:00
0:00
Album Art

MCP Connection Management in TypeScript Explained

By 10xdev team August 16, 2025

This article explores building Model Context Protocol (MCP) clients in TypeScript, focusing on the mCP Hub class. We will walk through connection management with MCP servers, including the logic for connecting, disconnecting, and attempting reconnections if a connection drops or fails.

Server Configuration

The process begins with an MCP configuration file, which is often based on the Claw desktop MCP configuration. Within this configuration, a nested JSON object defines the servers. Each server object contains two key properties: command and args.

Here is an example of what that configuration looks like:

{
  "servers": {
    "my-server-name": {
      "command": "npx",
      "args": [
        "-y",
        "name-of-server-package"
      ]
    }
  }
}

In this structure, command specifies the executable to run, and args provides the necessary arguments. The -y flag, for instance, automatically confirms any prompts the server might present during startup.

The connectServer Method

The core of the connection logic resides in the connectServer method. This asynchronous method takes the server's name as an argument and returns a promise that resolves when the connection task is complete. If a connection to the server already exists, the default behavior is to reconnect.

The process involves several key steps:

  1. Client Creation: A client instance is created. For this example, we'll name it SourceBook with a version of 1.0.0. It starts with an empty capabilities object, which will later be populated with the capabilities returned by the connected MCP servers.

  2. Configuration Retrieval: The method retrieves the configuration for the specified server by its name. It throws an error if the configuration doesn't exist.

  3. Environment Sanitization: It filters out any undefined environment variables to ensure only valid key-value pairs are used, preventing misconfigurations.

  4. Variable Merging: The filtered system environment variables are merged with server-specific environment variables. This allows the base environment to be clean and valid while enabling server-specific overrides or additions.

This merged environment data, along with the command and args from the config, is passed to a transport.

Understanding MCP Transports

To understand how connections are managed, it's crucial to know what a transport is within the Model Context Protocol. According to the official documentation, transports provide the foundation for communication between clients and servers. They handle the underlying mechanics of how messages are sent and received.

MCP uses JSON-RPC 2.0 as its wire format—the encoding method for data transmitted over a network. This ensures interoperability between different systems, as long as they can both process JSON.

There are three types of messages: - Requests - Responses - Notifications

MCP supports two transport implementations: - Standard Input/Output (StdIO): This is the implementation used in our case. It's suitable for direct communication between a client and a server process. The transport configuration takes command, args, env, and stderr properties. - Server-Sent Events (SSE): This is ideal for server-to-client streaming use cases, such as a server continuously pushing weather data or live notifications to a client.

Establishing the Connection

With the transport configured, the connection can be initialized.

  1. Initialize State: The connection state is set to connecting. A connection constant is used to manage the overall lifecycle of the connection.

  2. Store Connection: The new connection object is added to a private map of active connections, where the key is the server name.

  3. Notify Listeners: A helper function, notifyStatusChange, is called to inform any registered listeners about the server's status change. This broadcasts the server name, connection status, any errors, and its capabilities.

Event handlers are registered for when the transport layer experiences an error or the connection closes.

The Connection Lifecycle and Error Handling

A comprehensive try...catch block orchestrates the connection process and handles potential failures.

Inside the try block:

  1. Log Attempt: The connection attempt is logged.
  2. Handle Stderr: Standard error output is handled.
  3. Connect Client: The client connection is established, which starts the transport.
  4. Initialization Request: An initialize request is sent to the server using client.request. This request includes client info (name, version) and the protocol version.
  5. Validate Response: The response from the server is validated against the initializedResultSchema from MCP.
  6. Parse Capabilities: The capabilities reported by the MCP server are parsed from the response, and the connection's capabilities property is updated. A warning is logged if no capabilities are returned.
  7. List Capabilities: The available tools and resources are conditionally listed based on the dynamic capabilities received from the server, such as tools, resources, and resource_templates.

Inside the catch block:

If any part of the connection process fails, the error handling logic is executed: - The error is logged to the console with the name of the problematic server. - The connection status is set to disconnected. - The error object is stored in the connection's error property. - Listeners are notified of the status change. - Finally, the error is re-thrown to propagate it to higher-level handlers if necessary.

Disconnecting and Reconnecting

The other two management methods are more straightforward.

disconnectServer This method checks if a connection to the specified server exists. If it does, it retrieves the connection, closes it, and removes it from the active connections map. If no connection exists, it returns early.

reconnectServer This method takes a server name as an argument, retrieves its configuration, and then simply calls the connectServer method. Since connectServer is designed to first disconnect any existing connection before establishing a new one, this single call efficiently handles both disconnection and reconnection in one step.

Join the 10xdev Community

Subscribe and get 8+ free PDFs that contain detailed roadmaps with recommended learning periods for each programming language or field, along with links to free resources such as books, YouTube tutorials, and courses with certificates.

Recommended For You

Up Next