Documentation
¶
Index ¶
- Constants
- func Run(ctx context.Context, args RunArgs, stdin io.Reader, stdout, stderr io.Writer, ...) error
- type BridgeCaller
- type BridgeClient
- type ExecInitializeParams
- type ExecInitializeResult
- type JSONRPCError
- type JSONRPCMessage
- type MCPCallToolParams
- type MCPCallToolResult
- type MCPInitializeResult
- type MCPListToolsResult
- type MCPServer
- type MCPServerInfo
- type MCPTool
- type MCPToolContent
- type ProcessOutputChunk
- type ProcessReadParams
- type ProcessReadResult
- type ProcessStartParams
- type ProcessStartResult
- type RunArgs
- type ShellResult
- type ShellRunner
- type Translator
Constants ¶
const ( ExecMethodInitialize = "initialize" ExecMethodInitialized = "initialized" // notification ExecMethodProcessStart = "process/start" ExecMethodProcessRead = "process/read" ExecMethodProcessExited = "process/exited" // notification (informational; we poll instead) ExecMethodProcessClosed = "process/closed" // notification (informational) )
Method names — must match codex-rs/exec-server/src/protocol.rs.
Variables ¶
This section is empty.
Functions ¶
func Run ¶
func Run(ctx context.Context, args RunArgs, stdin io.Reader, stdout, stderr io.Writer, logger *slog.Logger) error
Run dials the bridge, initializes the exec-server session, then runs the stdio MCP server loop until stdin EOF or context cancellation.
stdout is dedicated to MCP JSON-RPC frames; anything written to it outside MCPServer.Serve corrupts the MCP stream. Diagnostic output goes through `logger`. The `stderr` parameter is accepted for signature symmetry with main.go's `os.Stderr` argument and is reserved for future direct writes (e.g., panic dumps); current code does not write to it. Callers wanting to capture stderr-style diagnostics should configure `logger` accordingly.
Types ¶
type BridgeCaller ¶
type BridgeCaller interface {
Call(ctx context.Context, method string, params json.RawMessage) (json.RawMessage, error)
Notify(ctx context.Context, method string, params json.RawMessage) error
}
BridgeCaller is the slice of BridgeClient that Translator needs. Defined as an interface so tests can script call sequences.
type BridgeClient ¶
type BridgeClient struct {
// contains filtered or unexported fields
}
BridgeClient wraps one WebSocket connection to /bridge/{exe_id} on codex-exec-gateway and exposes a JSON-RPC client interface that env-mcp uses to talk codex's exec-server protocol.
Concurrency model: a single background goroutine reads frames and dispatches them to a per-id reply channel; Call() blocks on its channel until the goroutine delivers, the context is cancelled, or the connection closes.
func DialBridge ¶
func DialBridge(ctx context.Context, wsURL, authToken string, logger *slog.Logger) (*BridgeClient, error)
DialBridge dials wsURL and, when authToken is non-empty, sets `Authorization: Bearer <authToken>` on the upgrade request. Returns once the WebSocket handshake completes; subsequent reads are pumped by a background goroutine.
nhooyr.io/websocket does NOT request `permessage-deflate` by default — we rely on that, because codex's exec-server closes connections that do (see spec § PoC #2 gotchas).
func (*BridgeClient) Call ¶
func (bc *BridgeClient) Call(ctx context.Context, method string, params json.RawMessage) (json.RawMessage, error)
Call sends a JSON-RPC request and blocks until the response arrives, the context is cancelled, or the connection closes.
func (*BridgeClient) Close ¶
func (bc *BridgeClient) Close()
Close shuts the connection. Safe to call repeatedly; first call wins.
func (*BridgeClient) Notify ¶
func (bc *BridgeClient) Notify(ctx context.Context, method string, params json.RawMessage) error
Notify sends a JSON-RPC notification (no id, no reply expected).
type ExecInitializeParams ¶
type ExecInitializeParams struct {
ClientName string `json:"clientName"`
ResumeSessionID *string `json:"resumeSessionId,omitempty"`
}
ExecInitializeParams matches codex-rs's InitializeParams (camelCase).
type ExecInitializeResult ¶
type ExecInitializeResult struct {
SessionID string `json:"sessionId"`
}
type JSONRPCError ¶
type JSONRPCError struct {
Code int `json:"code"`
Message string `json:"message"`
Data json.RawMessage `json:"data,omitempty"`
}
type JSONRPCMessage ¶
type JSONRPCMessage struct {
JSONRPC string `json:"jsonrpc"`
ID *int64 `json:"id,omitempty"`
Method string `json:"method,omitempty"`
Params json.RawMessage `json:"params,omitempty"`
Result json.RawMessage `json:"result,omitempty"`
Error *JSONRPCError `json:"error,omitempty"`
}
JSONRPCMessage is the JSON-RPC 2.0 envelope shared by both MCP (over stdio) and exec-server (over ws). The ID field is a pointer so notifications (which have no ID) marshal cleanly without the field.
type MCPCallToolParams ¶
type MCPCallToolParams struct {
Name string `json:"name"`
Arguments json.RawMessage `json:"arguments"`
}
MCPCallToolParams is the request body of `tools/call`.
type MCPCallToolResult ¶
type MCPCallToolResult struct {
Content []MCPToolContent `json:"content"`
IsError bool `json:"isError"`
}
MCPCallToolResult is the response body of `tools/call`.
type MCPInitializeResult ¶
type MCPInitializeResult struct {
ProtocolVersion string `json:"protocolVersion"`
Capabilities map[string]any `json:"capabilities"`
ServerInfo MCPServerInfo `json:"serverInfo"`
}
MCPInitializeResult is the response to `initialize`.
type MCPListToolsResult ¶
type MCPListToolsResult struct {
Tools []MCPTool `json:"tools"`
}
MCPListToolsResult is the response to `tools/list`.
type MCPServer ¶
type MCPServer struct {
// contains filtered or unexported fields
}
MCPServer is a minimal newline-delimited JSON-RPC stdio MCP server that exposes a single `shell` tool. Concurrency: requests are handled sequentially in the order they arrive; this matches the MCP stdio model and keeps the server free of intra-process synchronization other than the write-mutex.
func NewMCPServer ¶
func NewMCPServer(exeDesc string, tr ShellRunner, logger *slog.Logger) *MCPServer
type MCPServerInfo ¶
type MCPTool ¶
type MCPTool struct {
Name string `json:"name"`
Description string `json:"description"`
InputSchema json.RawMessage `json:"inputSchema"`
}
type MCPToolContent ¶
type ProcessOutputChunk ¶
type ProcessOutputChunk struct {
Seq uint64 `json:"seq"`
Stream string `json:"stream"` // "stdout" | "stderr"
Chunk string `json:"chunk"`
}
ProcessOutputChunk: chunk is base64-encoded raw bytes (per codex's ByteChunk wrapper that uses serde_with for base64 encoding).
type ProcessReadParams ¶
type ProcessReadResult ¶
type ProcessStartParams ¶
type ProcessStartResult ¶
type ProcessStartResult struct {
ProcessID string `json:"processId"`
}
type ShellResult ¶
ShellResult is what RunShell returns; mapped into MCP CallToolResult by the caller (mcp_server.go).
type ShellRunner ¶
type ShellRunner interface {
RunShell(ctx context.Context, argv []string, cwd string) (ShellResult, error)
}
ShellRunner is the slice of Translator that MCPServer uses. Defined as an interface so mcp_server tests don't need a real bridge.
type Translator ¶
type Translator struct {
// contains filtered or unexported fields
}
Translator turns MCP shell tool calls into exec-server JSON-RPC sequences (process/start, then process/read until exited or closed).
func NewTranslator ¶
func NewTranslator(b BridgeCaller) *Translator
func (*Translator) RunShell ¶
func (t *Translator) RunShell(ctx context.Context, argv []string, cwd string) (ShellResult, error)
RunShell runs argv on the bound executor in cwd and returns the aggregated output. Never returns ctx-independent errors — transport failures surface as `IsError=true` with the failure in Text.