envmcp

package
v0.50.11 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: May 16, 2026 License: MIT Imports: 18 Imported by: 0

Documentation

Index

Constants

View Source
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

func (*MCPServer) Serve

func (s *MCPServer) Serve(ctx context.Context, in io.Reader, out io.Writer) error

Serve reads requests from in until EOF and writes responses to out. Returns nil on clean EOF, error on unrecoverable read/write failure.

type MCPServerInfo

type MCPServerInfo struct {
	Name    string `json:"name"`
	Version string `json:"version"`
}

type MCPTool

type MCPTool struct {
	Name        string          `json:"name"`
	Description string          `json:"description"`
	InputSchema json.RawMessage `json:"inputSchema"`
}

type MCPToolContent

type MCPToolContent struct {
	Type string `json:"type"`
	Text string `json:"text"`
}

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 ProcessReadParams struct {
	ProcessID string `json:"processId"`
	AfterSeq  uint64 `json:"afterSeq"`
	MaxBytes  int    `json:"maxBytes"`
	WaitMs    int    `json:"waitMs"`
}

type ProcessReadResult

type ProcessReadResult struct {
	Chunks   []ProcessOutputChunk `json:"chunks"`
	NextSeq  uint64               `json:"nextSeq"`
	Exited   bool                 `json:"exited"`
	ExitCode *int                 `json:"exitCode"`
	Closed   bool                 `json:"closed"`
	Failure  *string              `json:"failure"`
}

type ProcessStartParams

type ProcessStartParams struct {
	ProcessID string            `json:"processId"`
	Argv      []string          `json:"argv"`
	Cwd       string            `json:"cwd"`
	Env       map[string]string `json:"env"`
	TTY       bool              `json:"tty"`
	PipeStdin bool              `json:"pipeStdin"`
	Arg0      *string           `json:"arg0"`
}

type ProcessStartResult

type ProcessStartResult struct {
	ProcessID string `json:"processId"`
}

type RunArgs

type RunArgs struct {
	ExeID     string
	BridgeURL string
	TokenEnv  string
	ExeDesc   string
	TurnID    string
}

RunArgs is the parsed CLI input for `codex-app-gateway env-mcp`.

type ShellResult

type ShellResult struct {
	Text    string
	IsError bool
}

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.

Directories

Path Synopsis

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL