init claude-code
This commit is contained in:
@@ -0,0 +1,136 @@
|
||||
/**
|
||||
* SDK MCP Transport Bridge
|
||||
*
|
||||
* This file implements a transport bridge that allows MCP servers running in the SDK process
|
||||
* to communicate with the Claude Code CLI process through control messages.
|
||||
*
|
||||
* ## Architecture Overview
|
||||
*
|
||||
* Unlike regular MCP servers that run as separate processes, SDK MCP servers run in-process
|
||||
* within the SDK. This requires a special transport mechanism to bridge communication between:
|
||||
* - The CLI process (where the MCP client runs)
|
||||
* - The SDK process (where the SDK MCP server runs)
|
||||
*
|
||||
* ## Message Flow
|
||||
*
|
||||
* ### CLI → SDK (via SdkControlClientTransport)
|
||||
* 1. CLI's MCP Client calls a tool → sends JSONRPC request to SdkControlClientTransport
|
||||
* 2. Transport wraps the message in a control request with server_name and request_id
|
||||
* 3. Control request is sent via stdout to the SDK process
|
||||
* 4. SDK's StructuredIO receives the control response and routes it back to the transport
|
||||
* 5. Transport unwraps the response and returns it to the MCP Client
|
||||
*
|
||||
* ### SDK → CLI (via SdkControlServerTransport)
|
||||
* 1. Query receives control request with MCP message and calls transport.onmessage
|
||||
* 2. MCP server processes the message and calls transport.send() with response
|
||||
* 3. Transport calls sendMcpMessage callback with the response
|
||||
* 4. Query's callback resolves the pending promise with the response
|
||||
* 5. Query returns the response to complete the control request
|
||||
*
|
||||
* ## Key Design Points
|
||||
*
|
||||
* - SdkControlClientTransport: StructuredIO tracks pending requests
|
||||
* - SdkControlServerTransport: Query tracks pending requests
|
||||
* - The control request wrapper includes server_name to route to the correct SDK server
|
||||
* - The system supports multiple SDK MCP servers running simultaneously
|
||||
* - Message IDs are preserved through the entire flow for proper correlation
|
||||
*/
|
||||
|
||||
import type { Transport } from '@modelcontextprotocol/sdk/shared/transport.js'
|
||||
import type { JSONRPCMessage } from '@modelcontextprotocol/sdk/types.js'
|
||||
|
||||
/**
|
||||
* Callback function to send an MCP message and get the response
|
||||
*/
|
||||
export type SendMcpMessageCallback = (
|
||||
serverName: string,
|
||||
message: JSONRPCMessage,
|
||||
) => Promise<JSONRPCMessage>
|
||||
|
||||
/**
|
||||
* CLI-side transport for SDK MCP servers.
|
||||
*
|
||||
* This transport is used in the CLI process to bridge communication between:
|
||||
* - The CLI's MCP Client (which wants to call tools on SDK MCP servers)
|
||||
* - The SDK process (where the actual MCP server runs)
|
||||
*
|
||||
* It converts MCP protocol messages into control requests that can be sent
|
||||
* through stdout/stdin to the SDK process.
|
||||
*/
|
||||
export class SdkControlClientTransport implements Transport {
|
||||
private isClosed = false
|
||||
|
||||
onclose?: () => void
|
||||
onerror?: (error: Error) => void
|
||||
onmessage?: (message: JSONRPCMessage) => void
|
||||
|
||||
constructor(
|
||||
private serverName: string,
|
||||
private sendMcpMessage: SendMcpMessageCallback,
|
||||
) {}
|
||||
|
||||
async start(): Promise<void> {}
|
||||
|
||||
async send(message: JSONRPCMessage): Promise<void> {
|
||||
if (this.isClosed) {
|
||||
throw new Error('Transport is closed')
|
||||
}
|
||||
|
||||
// Send the message and wait for the response
|
||||
const response = await this.sendMcpMessage(this.serverName, message)
|
||||
|
||||
// Pass the response back to the MCP client
|
||||
if (this.onmessage) {
|
||||
this.onmessage(response)
|
||||
}
|
||||
}
|
||||
|
||||
async close(): Promise<void> {
|
||||
if (this.isClosed) {
|
||||
return
|
||||
}
|
||||
this.isClosed = true
|
||||
this.onclose?.()
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* SDK-side transport for SDK MCP servers.
|
||||
*
|
||||
* This transport is used in the SDK process to bridge communication between:
|
||||
* - Control requests coming from the CLI (via stdin)
|
||||
* - The actual MCP server running in the SDK process
|
||||
*
|
||||
* It acts as a simple pass-through that forwards messages to the MCP server
|
||||
* and sends responses back via a callback.
|
||||
*
|
||||
* Note: Query handles all request/response correlation and async flow.
|
||||
*/
|
||||
export class SdkControlServerTransport implements Transport {
|
||||
private isClosed = false
|
||||
|
||||
constructor(private sendMcpMessage: (message: JSONRPCMessage) => void) {}
|
||||
|
||||
onclose?: () => void
|
||||
onerror?: (error: Error) => void
|
||||
onmessage?: (message: JSONRPCMessage) => void
|
||||
|
||||
async start(): Promise<void> {}
|
||||
|
||||
async send(message: JSONRPCMessage): Promise<void> {
|
||||
if (this.isClosed) {
|
||||
throw new Error('Transport is closed')
|
||||
}
|
||||
|
||||
// Simply pass the response back through the callback
|
||||
this.sendMcpMessage(message)
|
||||
}
|
||||
|
||||
async close(): Promise<void> {
|
||||
if (this.isClosed) {
|
||||
return
|
||||
}
|
||||
this.isClosed = true
|
||||
this.onclose?.()
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user