Files
multica/server/internal/daemon/execenv/omp_mcp.go
feig a92e8f6f7e MUL-6689: feat(agents): support MCP config for the Oh-My-Pi runtime (#7565)
Adds MCP configuration support to the Oh-My-Pi (omp) runtime. The MCP tab is
now visible for omp agents, and the managed config is materialised as
`{workDir}/.omp/mcp.json` — omp's highest-precedence project-level path —
before the runtime starts.

Materialisation lives in `execenv` and is recorded in `sidecarManifest`, so it
inherits refuse-to-clobber on a pre-existing file plus daemon-side teardown and
reuse cleanup. `Reuse` declines (returns nil, forcing a fresh Prepare) when the
config cannot be written, matching the Cursor path, so a leftover file from a
crashed run cannot silently carry stale MCP servers into the next task.
`.pi` and `.omp` are added to the repo-cache git excludes so runtime sidecars —
which for MCP routinely embed third-party tokens — cannot be committed by an
agent; `.pi/skills/` was already being written unexcluded before this change.
`listRuntimeLocalMcpServers` reports omp's user-scope inventory from
`~/.omp/agent/mcp.json`, with a comment recording that this is deliberately
narrower than omp's full discovery chain.

Pi itself is excluded by design. Upstream states the position in its README
("**No MCP.** Build CLI tools with READMEs, or build an extension that adds MCP
support."), confirmed against pi 0.67.2: no MCP code in the published bundle,
no MCP flag or subcommand, and a probe server placed in a project config is
never launched. There is no `.pi/mcp.json` convention to write into, so the
negative assertion pinning `pi` out of the allowlist is kept and now carries
that reasoning.

Closes #7558 for omp only; Pi would require authoring a Pi extension for the
daemon to inject, which is separate work.
2026-08-28 15:53:09 +08:00

34 lines
836 B
Go

package execenv
import (
"bytes"
"encoding/json"
"errors"
"path/filepath"
)
func prepareOmpMcpConfig(workDir, provider string, raw json.RawMessage, manifest *sidecarManifest) error {
if provider != "omp" {
return nil
}
trimmed := bytes.TrimSpace(raw)
if len(trimmed) == 0 || bytes.Equal(trimmed, []byte("null")) {
return nil
}
if workDir == "" {
return errors.New("managed mcp_config requires a working directory")
}
configDir := filepath.Join(workDir, "."+provider)
if err := recordMkdirAll(configDir, 0o700, manifest); err != nil {
return err
}
path := filepath.Join(configDir, "mcp.json")
if err := recordWriteFile(path, raw, 0o600, manifest); err != nil {
if errors.Is(err, errPathPreExists) {
return errors.New("managed mcp_config would overwrite existing " + path)
}
return err
}
return nil
}