How mksglu/context-mode Auto-Detects Platforms via MCP Protocol Handshake
mksglu/context-mode detects the client platform during the MCP initialization handshake by reading the clientInfo.name field from the initialize request, mapping it to an internal PlatformId via the CLIENT_NAME_TO_PLATFORM registry in src/adapters/client-map.ts, and instantiating the matching adapter with high confidence.
The mksglu/context-mode repository implements a Model Context Protocol (MCP) server that seamlessly identifies which IDE or CLI tool is connecting—whether Claude Code, Gemini CLI, Cursor, or OpenCode. This auto-detection occurs instantly during the protocol handshake, eliminating the need for manual platform configuration.
The MCP Handshake Detection Flow
Platform detection follows a strict sequence that begins when the transport connects and ends with a cached, platform-specific adapter ready to handle requests.
Server Initialization
In src/server.ts, the main() function (lines 29-35) instantiates an MCPServer and opens a stdio transport. This establishes the low-level communication channel that will carry the MCP protocol messages between the client and server.
Client Identification via the initialize Request
When an MCP client connects, the protocol mandates an initialize request containing a clientInfo object with name and version properties. According to the source code in src/server.ts (lines 302-305), the server retrieves this metadata immediately after the transport attaches by calling server.server.getClientVersion().
Platform Resolution Core Logic
The detectPlatform() function in src/adapters/detect.ts (lines 33-44) receives the client metadata and performs a lookup against CLIENT_NAME_TO_PLATFORM. This mapping table—curated from the Apify MCP Client Capabilities Registry—links standard MCP client names to internal PlatformId values.
When a match is found, the function returns a DetectionSignal object containing:
platform: The resolvedPlatformId(e.g.,"cursor","claude-code")confidence:"high"reason: A descriptive string including the originalclientInfo.name
Adapter Selection and Caching
With a valid DetectionSignal, the server invokes getAdapter(signal.platform) from src/adapters/detect.ts (lines 24-28). This utility uses dynamic import() to lazily load only the platform-specific adapter code, keeping the server memory footprint minimal.
The instantiated adapter is then stored in the module-level _detectedAdapter variable (lines 1000-1006 in src/server.ts), making it available for the remainder of the session for operations like session-path calculation.
Fallback Detection Chain
If the MCP handshake lacks clientInfo or the client name is unrecognized, the detection logic degrades gracefully through a predefined hierarchy implemented in src/adapters/detect.ts (lines 46-62):
- Environment variable checks – Searches for platform-specific environment markers
- Config directory heuristics – Inspects filesystem paths for known configuration directories
- Default platform – Returns
"claude-code"with low confidence, ensuring the server remains operational
This fallback chain guarantees that context-mode remains functional even when receiving connections from non-compliant or unidentified MCP clients.
Practical Implementation Example
When a client such as Cursor initiates a connection, the handshake data flows through the detection pipeline:
// Client sends during MCP initialization
const clientInfo = { name: "cursor-vscode", version: "2.3.1" };
await mcpConnection.sendRequest("initialize", { clientInfo });
// Server-side processing in context-mode:
// 1. server.server.getClientVersion() returns clientInfo
// 2. detectPlatform(clientInfo) checks CLIENT_NAME_TO_PLATFORM
// 3. Returns { platform: "cursor", confidence: "high", ... }
// 4. getAdapter("cursor") dynamically imports cursor adapter
Summary
- Handshake-driven detection: Platform identification relies on the
clientInfo.namefield sent in the MCPinitializerequest, extracted viagetClientVersion()insrc/server.ts. - Zero-configuration: The
CLIENT_NAME_TO_PLATFORMmapping insrc/adapters/client-map.tsenables instant recognition without user intervention. - High-confidence signals: Valid matches return a
DetectionSignalwithconfidence: "high"and detailed reasoning for debugging. - Lazy loading:
getAdapter()uses dynamic imports to load only the required platform adapter, optimizing startup performance. - Robust fallbacks: If handshake data is unavailable, the system checks environment variables and config directories before defaulting to the Claude Code adapter.
Frequently Asked Questions
How does context-mode extract client information from the MCP protocol?
The server retrieves the clientInfo object by calling server.server.getClientVersion() immediately after the transport connects, as implemented in src/server.ts at lines 302-305. This method extracts the name and version fields that the client sent in the initialize request.
What happens if an unknown MCP client connects?
If clientInfo.name is not found in CLIENT_NAME_TO_PLATFORM, the detectPlatform function in src/adapters/detect.ts (lines 46-62) falls back to environment variable inspection and configuration directory heuristics. If these fail, it defaults to the Claude Code adapter with low confidence, ensuring the server remains functional.
Where is the platform-to-adapter mapping defined?
The mapping from MCP client names to internal platform IDs is maintained in src/adapters/client-map.ts. This registry is derived from the Apify MCP Client Capabilities Registry and maps strings like "cursor-vscode" to the PlatformId "cursor".
Why does context-mode use lazy loading for adapters?
The getAdapter function in src/adapters/detect.ts uses dynamic import() statements to load platform-specific code only when a matching client is detected. This approach minimizes the initial startup time and memory footprint of the MCP server, as unnecessary adapter code is never loaded into memory.
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 →