Documentation
¶
Overview ¶
Package debugmcp exposes a luapure debug Session over the Model Context Protocol (MCP), so an LLM agent can drive breakpoints, stepping and expression evaluation through tool calls. It speaks MCP's JSON-RPC 2.0 wire format with no external dependencies — only the Go standard library and the luapure package.
The protocol surface is intentionally small: initialize, tools/list and tools/call, plus a set of debug tools (see Server). Transport is abstracted (Transport), so the same Server runs over stdio today and HTTP later. The debuggee's source need not live with the client: source text is fetched on demand through a SourceResolver, mirroring the luapure Session design.
Index ¶
Constants ¶
This section is empty.
Variables ¶
This section is empty.
Functions ¶
This section is empty.
Types ¶
type Server ¶
type Server struct {
// NewState returns a fresh, library-loaded LState for each launch. Required.
NewState func() *luapure.LState
// Source resolves a program id to its Lua source text — used to load a
// program launched by id, and to serve display context for get_source. May
// be nil if every launch passes its source inline.
Source luapure.SourceResolver
// Name and Version are reported to the client at initialize.
Name string
Version string
// contains filtered or unexported fields
}
Server exposes a luapure debug session over MCP. Construct it with a state factory and a source resolver, then run Serve over a Transport.
Lifecycle. The debuggee runs on its own goroutine; the control tools (launch, continue, step_*) block until the program next stops (a breakpoint) or finishes, returning that outcome, while the inspection tools (stack, variables, evaluate, get_source) read the paused state. This maps the inherently stateful debug loop onto MCP's request/response model: one tool call advances or queries, exactly once.
func (*Server) HandleMessage ¶
HandleMessage processes one JSON-RPC message and returns the reply frame, or nil for a notification (no reply). It is the shared core behind the stdio/TCP Serve loop and the HTTP Handler. Safe for concurrent calls (the HTTP server invokes it per request); blocking control tools do not hold the server lock, so a pause can land while a continue is in flight.
func (*Server) Handler ¶
Handler returns an http.Handler implementing MCP's Streamable HTTP transport for this server: a POST carries one JSON-RPC message and the response body is the single JSON-RPC reply. There is no SSE stream — this debug server never pushes unsolicited messages (a control tool returns its stop synchronously), so plain JSON replies suffice.
SECURITY. The handler performs no authentication, TLS, Origin validation or rate limiting, and it executes arbitrary Lua on the caller's behalf — exposing it unguarded is remote code execution. Mount it behind middleware that enforces auth and validates Origin (DNS-rebinding protection), bind to localhost unless the front is trusted, and prefer a sandboxed NewState for untrusted callers. One Server is one debug session; route each session (e.g. by its Mcp-Session-Id) to its own Server and Handler.
Control tools (launch/continue/step_*) block until the next stop, so the POST is held open until then — configure generous server write/idle timeouts, and send pause as a separate concurrent request to interrupt a long run.
type Transport ¶
type Transport interface {
Read() ([]byte, error) // next message frame; io.EOF when the peer closes
Write(msg []byte) error
Close() error
}
Transport carries whole JSON-RPC messages as byte frames. Read returns the next inbound message; Write sends one; both are one message per call. An implementation must be safe for one reader and one writer used concurrently.