# MCP Server and FilteredStdioServerTransport Initialization Flow in DesktopCommanderMCP

> Understand the DesktopCommanderMCP initialization flow. Discover how FilteredStdioServerTransport buffers logs and the MCP server registers handlers for a seamless JSON-RPC handshake.

- Repository: [Eduard Ruzga/DesktopCommanderMCP](https://github.com/wonderwhy-er/DesktopCommanderMCP)
- Tags: internals
- Published: 2026-07-25

---

**The DesktopCommanderMCP repository initializes by creating a `FilteredStdioServerTransport` instance to buffer pre-handshake logs, then instantiates the MCP server to register command handlers, completing the JSON-RPC handshake before flushing buffered messages to the client.**

The initialization flow for the MCP server and FilteredStdioServerTransport in DesktopCommanderMCP follows a defensive sequence designed to prevent protocol corruption during startup. This TypeScript implementation wraps the standard stdio transport with a filtering layer that queues log messages until the client-server handshake completes. Understanding this bootstrapping process is essential for developers extending the server's command handlers or debugging transport-level timing issues.

## FilteredStdioServerTransport: The Buffering Layer

The `FilteredStdioServerTransport` class in [`src/custom-stdio.ts`](https://github.com/wonderwhy-er/DesktopCommanderMCP/blob/main/src/custom-stdio.ts) extends the base `StdioServerTransport` to solve a critical timing problem: logs emitted before the MCP handshake finishes must not corrupt the JSON-RPC message stream over stdio.

### Transport Construction and State Management

When instantiated, the transport initializes two private fields that control its buffering behavior:

```typescript
// src/custom-stdio.ts
export class FilteredStdioServerTransport extends StdioServerTransport {
    private initialized = false;
    private bufferedMessages: Array<{level: LogLevel, args: any[]}> = [];

    constructor() {
        super();
        // Buffering begins immediately; no messages sent until handshake
    }
}

```

The `initialized` boolean flag remains `false` during construction and early startup. Any calls to the logging methods during this phase are captured in the `bufferedMessages` array rather than being sent to the client. This prevents malformed output from interfering with the MCP protocol's initialization sequence.

### Handshake Completion and Message Flushing

The transport listens for the MCP client's `initialized` notification. Upon receipt, it triggers the `enableAfterInit()` method (or internal equivalent) that flips the state and releases queued messages:

```typescript
// src/custom-stdio.ts
enableAfterInit() {
    this.initialized = true;
    this.flushBuffered();
}

private flushBuffered() {
    for (const msg of this.bufferedMessages) {
        super.sendLog(msg.level, msg.args);
    }
    this.bufferedMessages = [];
}

```

This mechanism ensures that log messages emitted during module loading and handler registration are delivered to the client only after the transport is fully ready to accept JSON-RPC notifications.

## MCP Server Initialization Sequence

The entry point at [`src/index.ts`](https://github.com/wonderwhy-er/DesktopCommanderMCP/blob/main/src/index.ts) orchestrates the startup sequence in three distinct phases, ensuring the transport is ready before any commands are processed.

### Step 1: Transport Instantiation

At approximately line 55 in [`src/index.ts`](https://github.com/wonderwhy-er/DesktopCommanderMCP/blob/main/src/index.ts), the process begins by creating the filtered transport:

```typescript
// src/index.ts
import { FilteredStdioServerTransport } from './custom-stdio.js';

const transport = new FilteredStdioServerTransport();

```

This single line establishes the stdio connection and begins buffering any immediate log output. The transport import occurs at line 6, establishing the dependency on the custom implementation.

### Step 2: Server Creation and Handler Registration

Immediately after transport creation, [`src/index.ts`](https://github.com/wonderwhy-er/DesktopCommanderMCP/blob/main/src/index.ts) triggers the server initialization defined in [`src/server.ts`](https://github.com/wonderwhy-er/DesktopCommanderMCP/blob/main/src/server.ts). This module constructs the `MCPServer` instance and registers modular command handlers:

```typescript
// src/server.ts
const server = new MCPServer(transport);
server.registerHandlers([
    require('./handlers/process-handlers'),
    require('./handlers/filesystem-handlers'),
    require('./handlers/terminal-handlers'),
    // Additional handler modules
]);

```

The server binds all command implementations to the transport's JSON-RPC dispatcher during this phase. Because the transport buffers all output, these registration steps can emit diagnostic logs without risk of protocol corruption.

### Step 3: Handshake Completion and Finalization

Once the MCP client sends the `initialized` notification, the transport processes the message through its `handleInitialize` method (or event listener), sets `this.initialized = true`, and flushes the buffer. Following this, [`src/index.ts`](https://github.com/wonderwhy-er/DesktopCommanderMCP/blob/main/src/index.ts) typically emits a final log confirming successful startup, which now travels immediately to the client without entering the buffer.

## Global Logger Integration

The global logging utility in [`src/utils/logger.ts`](https://github.com/wonderwhy-er/DesktopCommanderMCP/blob/main/src/utils/logger.ts) maintains a module-level reference to the transport instance, enabling any part of the codebase to emit logs while respecting the initialization state:

```typescript
// src/utils/logger.ts
import type { FilteredStdioServerTransport } from '../custom-stdio.js';

let mcpTransport: FilteredStdioServerTransport | undefined;

export function logInfo(...args: any[]) {
    if (mcpTransport?.initialized) {
        mcpTransport.sendLog('info', args);
    } else if (mcpTransport) {
        mcpTransport.bufferedMessages.push({level: 'info', args});
    }
}

```

This design allows handler modules and utility functions to log freely during startup without checking transport state manually. The logger transparently routes messages to the buffer or the live transport based on the `initialized` flag.

## Complete Initialization Example

The following pattern from [`src/index.ts`](https://github.com/wonderwhy-er/DesktopCommanderMCP/blob/main/src/index.ts) demonstrates the full initialization flow:

```typescript
// src/index.ts
import { FilteredStdioServerTransport } from './custom-stdio.js';
import { startMCPServer } from './server.js';

async function main() {
    // 1. Create transport (starts buffering)
    const transport = new FilteredStdioServerTransport();
    
    // 2. Initialize server and register handlers
    //    All logs during this phase are buffered
    await startMCPServer(transport);
    
    // 3. Transport automatically handles handshake
    //    and calls enableAfterInit() when ready
    console.error('MCP server fully initialized');
}

main();

```

And the corresponding transport implementation:

```typescript
// src/custom-stdio.ts
import { StdioServerTransport } from '@modelcontextprotocol/sdk/server/stdio.js';

export class FilteredStdioServerTransport extends StdioServerTransport {
    private initialized = false;
    private bufferedMessages: Array<{level: string, args: any[]}> = [];

    sendLog(level: string, args: any[]) {
        if (!this.initialized) {
            this.bufferedMessages.push({level, args});
            return;
        }
        super.sendLog(level, args);
    }

    enableAfterInit() {
        this.initialized = true;
        for (const {level, args} of this.bufferedMessages) {
            super.sendLog(level, args);
        }
        this.bufferedMessages = [];
    }
}

```

## Summary

- **`FilteredStdioServerTransport`** in [`src/custom-stdio.ts`](https://github.com/wonderwhy-er/DesktopCommanderMCP/blob/main/src/custom-stdio.ts) wraps the base transport with a buffering mechanism using the `initialized` flag and `bufferedMessages` array.
- **[`src/index.ts`](https://github.com/wonderwhy-er/DesktopCommanderMCP/blob/main/src/index.ts)** instantiates the transport before creating the server, ensuring all early logs are captured.
- **[`src/server.ts`](https://github.com/wonderwhy-er/DesktopCommanderMCP/blob/main/src/server.ts)** registers modular handlers (process, filesystem, terminal) with the `MCPServer` instance after the transport exists.
- **[`src/utils/logger.ts`](https://github.com/wonderwhy-er/DesktopCommanderMCP/blob/main/src/utils/logger.ts)** coordinates with the transport to route messages through the buffer or directly to the client based on handshake state.
- The system flushes all buffered notifications automatically once the MCP JSON-RPC handshake completes, ensuring protocol integrity throughout startup.

## Frequently Asked Questions

### What is the purpose of FilteredStdioServerTransport?

The `FilteredStdioServerTransport` class prevents JSON-RPC protocol violations by buffering log messages emitted during server startup until the MCP initialization handshake completes. This ensures that diagnostic output from module loading and handler registration does not corrupt the stdio message framing expected by the client.

### How does the MCP server know when to start processing commands?

The server begins processing commands only after the transport receives the `initialized` notification from the MCP client. This event triggers the `enableAfterInit()` method in [`src/custom-stdio.ts`](https://github.com/wonderwhy-er/DesktopCommanderMCP/blob/main/src/custom-stdio.ts), which sets the internal `initialized` flag to `true` and flushes any buffered messages, signaling that the transport is ready for two-way communication.

### Where are the command handlers registered in DesktopCommanderMCP?

Command handlers are registered in [`src/server.ts`](https://github.com/wonderwhy-er/DesktopCommanderMCP/blob/main/src/server.ts), which imports handler modules from [`src/handlers/process-handlers.ts`](https://github.com/wonderwhy-er/DesktopCommanderMCP/blob/main/src/handlers/process-handlers.ts), [`src/handlers/filesystem-handlers.ts`](https://github.com/wonderwhy-er/DesktopCommanderMCP/blob/main/src/handlers/filesystem-handlers.ts), and other subdirectories. These handlers are bound to the `MCPServer` instance immediately after the `FilteredStdioServerTransport` is instantiated in [`src/index.ts`](https://github.com/wonderwhy-er/DesktopCommanderMCP/blob/main/src/index.ts).

### Can I safely add logging before the transport is initialized?

Yes, the global logger in [`src/utils/logger.ts`](https://github.com/wonderwhy-er/DesktopCommanderMCP/blob/main/src/utils/logger.ts) automatically buffers any log calls made before the handshake completes. It checks the `mcpTransport?.initialized` state and pushes messages to the internal `bufferedMessages` array, delivering them to the client only after `enableAfterInit()` is called.