Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 5 additions & 3 deletions cmd/soda/run.go
Original file line number Diff line number Diff line change
Expand Up @@ -295,6 +295,7 @@ func runPipeline(cfg *config.Config, opts pipelineOpts) error {
MemoryMB: uint64(cfg.Sandbox.Limits.MemoryMB),
CPUPercent: uint32(cfg.Sandbox.Limits.CPUPercent),
MaxPIDs: uint32(cfg.Sandbox.Limits.MaxPIDs),
UseNetNS: cfg.Sandbox.UseNetNS,
ClaudeBinary: cfg.Sandbox.Binary,
Proxy: sandbox.ProxyConfig{
Enabled: cfg.Sandbox.Proxy.Enabled,
Expand Down Expand Up @@ -1629,9 +1630,10 @@ func convertMCPConfig(cfg config.MCPConfig) pipeline.MCPConfig {
servers := make(map[string]pipeline.MCPServerConfig, len(cfg.Servers))
for name, srv := range cfg.Servers {
servers[name] = pipeline.MCPServerConfig{
Command: srv.Command,
Args: srv.Args,
Env: srv.Env,
Command: srv.Command,
Args: srv.Args,
Env: srv.Env,
AllowedHosts: srv.AllowedHosts,
}
}
return pipeline.MCPConfig{Servers: servers}
Expand Down
16 changes: 9 additions & 7 deletions internal/config/config.go
Original file line number Diff line number Diff line change
Expand Up @@ -58,9 +58,10 @@ type OpencodeConfig struct {

// MCPServerConfig holds the definition of a single MCP server process.
type MCPServerConfig struct {
Command string `yaml:"command"`
Args []string `yaml:"args,omitempty"`
Env map[string]string `yaml:"env,omitempty"`
Command string `yaml:"command"`
Args []string `yaml:"args,omitempty"`
Env map[string]string `yaml:"env,omitempty"`
AllowedHosts []string `yaml:"allowed_hosts,omitempty"` // hosts the server is permitted to reach; empty = unrestricted
}

// MCPConfig holds MCP server declarations available to pipeline phases.
Expand Down Expand Up @@ -170,10 +171,11 @@ type ExtractionStrategy struct {

// SandboxConfig holds sandbox execution settings.
type SandboxConfig struct {
Enabled bool `yaml:"enabled"`
Binary string `yaml:"binary"`
Limits SandboxLimits `yaml:"limits"`
Proxy SandboxProxyConfig `yaml:"proxy"`
Enabled bool `yaml:"enabled"`
Binary string `yaml:"binary"`
UseNetNS bool `yaml:"use_net_ns"` // enable network namespace isolation; requires unprivileged user namespaces
Limits SandboxLimits `yaml:"limits"`
Proxy SandboxProxyConfig `yaml:"proxy"`
}

// SandboxProxyConfig holds LLM proxy settings for sandboxed execution.
Expand Down
14 changes: 8 additions & 6 deletions internal/pipeline/engine.go
Original file line number Diff line number Diff line change
Expand Up @@ -81,9 +81,10 @@ type EngineConfig struct {
// MCPServerConfig holds the definition of a single MCP server process.
// Mirrors config.MCPServerConfig — kept separate to avoid cross-package imports.
type MCPServerConfig struct {
Command string
Args []string
Env map[string]string
Command string
Args []string
Env map[string]string
AllowedHosts []string // hosts the server is permitted to reach; empty = unrestricted
}

// MCPConfig holds MCP server declarations available to pipeline phases.
Expand Down Expand Up @@ -864,9 +865,10 @@ func (e *Engine) runPhase(ctx context.Context, phase PhaseConfig) error {
for _, name := range phase.MCPServers {
if def, ok := e.config.MCPConfig.Servers[name]; ok {
mcpServers[name] = runner.MCPServerConfig{
Command: def.Command,
Args: def.Args,
Env: def.Env,
Command: def.Command,
Args: def.Args,
Env: def.Env,
AllowedHosts: def.AllowedHosts,
}
} else {
fmt.Fprintf(e.config.Stderr, "engine: warning: MCP server %q in phase %q not in global config\n", name, phase.Name)
Expand Down
19 changes: 13 additions & 6 deletions internal/runner/mcp.go
Original file line number Diff line number Diff line change
Expand Up @@ -37,8 +37,11 @@ func WriteMCPConfigFile(dir string, servers map[string]MCPServerConfig) (string,
MCPServers: make(map[string]mcpServerEntry, len(servers)),
}
for name, srv := range servers {
entry := mcpServerEntry(srv)
entry.Command = resolveMCPCommand(srv.Command)
entry := mcpServerEntry{
Command: resolveMCPCommand(srv.Command),
Args: srv.Args,
Env: srv.Env,
}
envelope.MCPServers[name] = entry
}

Expand Down Expand Up @@ -72,8 +75,9 @@ func WriteMCPConfigFile(dir string, servers map[string]MCPServerConfig) (string,
return f.Name(), cleanup, nil
}

// mcpServerEntry has the same fields as config.MCPServerConfig, enabling
// direct type conversion. The separate type exists for JSON tag control.
// mcpServerEntry contains only the fields written to the MCP config JSON file.
// AllowedHosts from MCPServerConfig is intentionally omitted — it is a soda-side
// networking policy field, not part of the Claude Code MCP config format.

// WriteOpencodeMCPConfig writes (or merges) MCP server declarations into
// {workDir}/.opencode.json. If the file already exists, the mcpServers key
Expand All @@ -100,8 +104,11 @@ func WriteOpencodeMCPConfig(workDir string, servers map[string]MCPServerConfig)
// paths so the agent process can find them without relying on PATH.
mcpEntries := make(map[string]mcpServerEntry, len(servers))
for name, srv := range servers {
entry := mcpServerEntry(srv)
entry.Command = resolveMCPCommand(srv.Command)
entry := mcpServerEntry{
Command: resolveMCPCommand(srv.Command),
Args: srv.Args,
Env: srv.Env,
}
mcpEntries[name] = entry
}

Expand Down
7 changes: 4 additions & 3 deletions internal/runner/runner.go
Original file line number Diff line number Diff line change
Expand Up @@ -17,9 +17,10 @@ type Runner interface {
// MCPServerConfig holds the definition of a single MCP server process.
// Mirrors config.MCPServerConfig — kept separate to avoid cross-package imports.
type MCPServerConfig struct {
Command string
Args []string
Env map[string]string
Command string
Args []string
Env map[string]string
AllowedHosts []string // hosts the server is permitted to reach; empty = unrestricted
}

// RunOpts holds everything needed to execute one phase.
Expand Down
62 changes: 0 additions & 62 deletions internal/sandbox/config_build.go

This file was deleted.

Loading