Skip to content

Protocol-Lattice/codemode

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

6 Commits
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

codemode

A Go library that executes dynamically generated Go snippets against MCP (Model Context Protocol) tools using the Yaegi interpreter.

Overview

codemode bridges LLM-generated Go code with MCP tools at runtime. It provides two layers:

  • CodeModeMCP — executes arbitrary Go snippets inside a sandboxed Yaegi interpreter, with an injected codemode helper that can call MCP tools.
  • CodeModeOrchestrator — wraps CodeModeMCP with an LLM-driven pipeline that decides whether tools are needed, selects them, generates a snippet, and executes it.

Installation

go get github.com/Protocol-Lattice/codemode

Usage

Direct execution — CodeModeMCP

client := yourMCPClient // implements codemode.MCPClient
cm := codemode.NewCodeModeMCP(client)

result, err := cm.Execute(ctx, codemode.CodeModeArgs{
    Code:    `__out = codemode.Sprintf("hello %s", "world")`,
    Timeout: 5000, // ms — defaults to 30000 if <= 0
})
// result.Value  → "hello world"
// result.Stdout → captured stdout
// result.Stderr → captured stderr

Snippets run inside a func run() any wrapper. Assign the return value to __out. No imports or package declarations — just Go statements.

Available helpers inside snippets

Helper Signature Description
codemode.CallTool (name string, args map[string]any) (any, error) Call an MCP tool by name
codemode.ListTools () ([]mcp.Tool, error) List all available MCP tools
codemode.Sprintf (format string, a ...any) string fmt.Sprintf
codemode.Errorf (format string, a ...any) error fmt.Errorf

CallTool returns the tool's StructuredContent when present; otherwise it returns the concatenated TextContent blocks as a single string. Tool errors (IsError == true) are surfaced as Go errors.

LLM orchestrator — CodeModeOrchestrator

cm := &codemode.CodeModeOrchestrator{
    CodeModeMCP: codemode.NewCodeModeMCP(mcpClient),
    // model: your Model implementation (calls an LLM)
    // cache: your ToolSelectionCache (optional)
}

used, result, err := cm.CallTool(ctx, "search for files modified today")

CallTool runs the full pipeline:

  1. Decide — asks the LLM whether any tool is needed for the prompt.
  2. Select — asks the LLM to choose matching tools from the available set.
  3. Generate — asks the LLM to produce a Go snippet using those tools.
  4. Execute — runs the snippet via Yaegi and returns the result.

Returns (toolsUsed bool, result any, err error). If the LLM decides no tools are needed (or selects none), toolsUsed is false and result is nil.

Snippet execution uses a fixed 20-second timeout.

Interfaces

// Implement to provide an MCP server connection.
type MCPClient interface {
    ListTools(ctx context.Context, request mcp.ListToolsRequest) (*mcp.ListToolsResult, error)
    CallTool(ctx context.Context, request mcp.CallToolRequest) (*mcp.CallToolResult, error)
}

// Implement to provide an LLM for orchestration. The returned value is
// stringified via fmt.Sprint; a JSON object is then extracted and parsed.
type Model interface {
    Generate(ctx context.Context, prompt string) (any, error)
}

// Optional caching layer for tool specs and tool selections.
type ToolSelectionCache interface {
    GetToolSpecs() []mcp.Tool
    SetToolSpecs([]mcp.Tool)

    GetSelectedTools(query, tools string) []string
    SetSelectedTools(query, tools string, selected []string)

    InvalidateToolSpecs()
    InvalidateSelections()
    InvalidateAll()

    Stats() CacheStats
    StartCleanupRoutine(ctx context.Context, interval time.Duration)
}

Cache

CodeModeOrchestrator accepts an optional ToolSelectionCache to avoid redundant LLM round-trips. The cache stores:

  • Tool specs — the merged, deduplicated list returned by ToolSpecs().
  • Tool selections — keyed by (query, rendered tool list).

Provide your own implementation, or leave cache nil to disable caching.

cm.InvalidateToolSpecsCache()              // clear cached tool specs
cm.InvalidateSelectionsCache()             // clear cached tool selections
cm.InvalidateAllCaches()                   // clear everything
stats := cm.CacheStats()                   // Hits / Misses
cm.StartCacheCleanup(ctx, 5*time.Minute)   // run periodic eviction

The Decide step is not cached; Select and ToolSpecs are.

Sandboxing

Snippets are evaluated by Yaegi with a deliberately minimal stdlib surface — only context, fmt, and reflect are imported — plus the injected codemode helpers. There is no os, no filesystem, and no network access from inside a snippet. All side effects must go through MCP tool calls.

Execution runs in a goroutine guarded by context.WithTimeout. Interpreter panics are recovered and returned as errors, with captured stdout / stderr preserved on the CodeModeResult.

About

MCP codemode

Resources

Stars

Watchers

Forks

Packages

 
 
 

Contributors

Languages