在已安装 Codex 的前提下配置 Serena(Windows + PowerShell)

本文说明如何在 已经安装 Codex CLI 的情况下,把本地启动的 Serena MCP Server 接入到 Codex 中,使 Codex 可以通过 HTTP 访问:

http://127.0.0.1:9121/mcp

适用环境:

  • Windows

  • PowerShell

  • 已安装并可正常使用 Codex CLI

  • 通过本地 uvx 启动 serena

  • Codex 通过 HTTP MCP 方式连接 Serena


1. 目标

完成配置后,你将得到一套可用流程:

  • 使用 git 克隆 serena 到本地

  • 使用 uvx 从本地仓库运行 serena

  • 在 PowerShell 中使用 serena start / serena stop / serena status

  • 在 Codex 配置文件中注册 Serena MCP Server

  • 启动 Codex 后自动连接本地 Serena 服务


2. 前置条件

在开始前,请确认以下工具已经可用。

2.1 已安装 Git

执行:

git --version

如果能输出版本号,说明 Git 可用。

2.2 已安装 uv / uvx

执行:

uv --version
uvx --version

说明:

  • uvx 不是独立安装的工具

  • uvxuv 提供

  • 安装 uv 后,通常即可直接使用 uvx

  • 如果没有安装,可以使用 pip install uv的方式安装,需要有python环境

如果 uvx 命令不可用,需要先修复 uv 的安装或 PATH。

2.3 已安装 Codex CLI

本文默认你已经完成 Codex CLI 安装,并且能正常启动 Codex。


3. 克隆 Serena 到固定目录

本文使用固定路径:

D:\Projects\serena

执行:

git clone https://github.com/oraios/serena.git D:\Projects\serena

注意:

  • 后续脚本会直接引用 D:\Projects\serena

  • 如果你改了路径,后面的命令也必须同步修改

  • 为了减少维护成本,建议直接使用这个固定路径


4. Serena 的运行方式

这里采用的命令形式是:

uvx --from D:\Projects\serena serena ...其他参数

它的含义是:

  • 不依赖全局安装 serena

  • 直接从本地仓库 D:\Projects\serena 解析并运行

  • 本地仓库更新后,调用始终基于最新本地代码

这也是本文推荐的方式,因为行为更明确,维护更简单。


5. 把 Serena 管理脚本写入 PowerShell Profile

先查看你的 PowerShell Profile 路径:

$PROFILE

如果该文件不存在,可以创建它。然后把下面整段脚本写入 Profile。


6. 推荐写入 $PROFILE 的完整脚本

function indexproject {
    uvx --from D:\Projects\serena serena project index
}
​
$script:SerenaPidDir = Join-Path $env:USERPROFILE ".serena"
$script:SerenaPidFile = Join-Path $script:SerenaPidDir "mcp-server-codex-9121.pid"
$script:SerenaStartArgs = @(
    "--from", "D:\Projects\serena",
    "serena", "start-mcp-server",
    "--context", "codex",
    "--transport", "streamable-http",
    "--port", "9121"
)
​
function Get-SerenaProcess {
    if (-not (Test-Path $script:SerenaPidFile)) {
        return $null
    }
​
    $pidText = (Get-Content $script:SerenaPidFile -Raw -ErrorAction SilentlyContinue).Trim()
    if (-not $pidText) {
        Remove-Item $script:SerenaPidFile -ErrorAction SilentlyContinue
        return $null
    }
​
    $pid = 0
    if (-not [int]::TryParse($pidText, [ref]$pid)) {
        Remove-Item $script:SerenaPidFile -ErrorAction SilentlyContinue
        return $null
    }
​
    $proc = Get-Process -Id $pid -ErrorAction SilentlyContinue
    if (-not $proc) {
        Remove-Item $script:SerenaPidFile -ErrorAction SilentlyContinue
        return $null
    }
​
    return $proc
}
​
function serena-start {
    $existingProc = Get-SerenaProcess
    if ($existingProc) {
        Write-Host "Serena MCP server is already running. PID: $($existingProc.Id)"
        return
    }
​
    if (-not (Test-Path $script:SerenaPidDir)) {
        New-Item -ItemType Directory -Path $script:SerenaPidDir | Out-Null
    }
​
    $proc = Start-Process -FilePath "uvx" -ArgumentList $script:SerenaStartArgs -PassThru
    Set-Content -Path $script:SerenaPidFile -Value $proc.Id
​
    Start-Sleep -Seconds 1
    $runningProc = Get-Process -Id $proc.Id -ErrorAction SilentlyContinue
    if (-not $runningProc) {
        Remove-Item $script:SerenaPidFile -ErrorAction SilentlyContinue
        Write-Host "Serena MCP server failed to start."
        return
    }
​
    Write-Host "Serena MCP server started. PID: $($proc.Id), Port: 9121"
}
​
function serena-stop {
    $proc = Get-SerenaProcess
    if (-not $proc) {
        Write-Host "Serena MCP server is not running."
        return
    }
​
    Stop-Process -Id $proc.Id -Force -ErrorAction SilentlyContinue
    Remove-Item $script:SerenaPidFile -ErrorAction SilentlyContinue
    Write-Host "Serena MCP server stopped."
}
​
function serena-status {
    $proc = Get-SerenaProcess
    if ($proc) {
        Write-Host "Serena MCP server is running. PID: $($proc.Id), Started: $($proc.StartTime), Port: 9121"
        return
    }
​
    Write-Host "Serena MCP server is not running."
}
​
function serena {
    param(
        [Parameter(Position = 0)]
        [string]$Action,
        [Parameter(ValueFromRemainingArguments = $true)]
        [string[]]$RemainingArgs
    )
​
    switch ($Action) {
        "start" { serena-start; return }
        "stop" { serena-stop; return }
        "status" { serena-status; return }
        default {
            $args = @("--from", "D:\Projects\serena", "serena")
            if ($Action) {
                $args += $Action
            }
            if ($RemainingArgs) {
                $args += $RemainingArgs
            }
            & uvx @args
        }
    }
}

7. 重载 PowerShell Profile

保存 Profile 后,执行:

. $PROFILE

这样当前 PowerShell 会话就会立即加载刚才的函数。


8. 验证 Serena 是否能独立启动

先不要急着打开 Codex,先验证 Serena 本身能否启动。

执行:

serena start

再查看状态:

serena status

如果显示正在运行,并且端口是 9121,说明 Serena MCP Server 已正常启动。

如需停止:

serena stop

9. 在 Codex 中配置 Serena MCP Server

接下来修改 Codex 配置文件,在其中加入 Serena 的 MCP 配置。

核心配置如下:

[mcp_servers.serena]
url = "http://127.0.0.1:9121/mcp"
startup_timeout_sec = 30

这段配置表示:

  • MCP Server 名称是 serena

  • Codex 不负责启动这个服务

  • Codex 只会连接一个已经运行中的本地 HTTP MCP 服务

  • 连接地址固定为 http://127.0.0.1:9121/mcp

这和上面的 PowerShell 启动脚本是配套的。


10. 推荐的使用顺序

每次使用前,按以下顺序操作。

第 1 步:打开 PowerShell

确保 Profile 已自动加载。

第 2 步:启动 Serena

serena start

第 3 步:确认 Serena 状态

serena status

第 4 步:启动 Codex

此时 Codex 会从配置文件读取:

[mcp_servers.serena]
url = "http://127.0.0.1:9121/mcp"

然后连接本地 Serena MCP Server。

第 5 步:结束使用后可停止 Serena

serena stop

11. indexproject 的作用

Profile 中还定义了一个辅助命令:

indexproject

它实际执行的是:

uvx --from D:\Projects\serena serena project index

作用是调用 Serena 的项目索引能力。通常在你进入某个项目目录后执行,用于让 Serena 为当前项目建立索引。


12. 常见问题

12.1 uvx 无法识别

现象:

uvx : The term 'uvx' is not recognized...

处理方式:

uv --version
uvx --version

如果命令不存在,先修复 uv 安装或 PATH,再继续。


12.2 serena start 后立即退出

最常见原因:

  • D:\Projects\serena 不存在

  • 本地 Serena 仓库没有正确克隆

  • uvx --from D:\Projects\serena serena start-mcp-server ... 本身执行失败

建议直接手工验证核心命令:

uvx --from D:\Projects\serena serena start-mcp-server --context codex --transport streamable-http --port 9121

如果这条命令执行失败,优先修复 Serena 本身,不要先排查 Codex。


12.3 Codex 无法连接 Serena

按顺序检查以下三项:

  • Serena 是否已经启动:

serena status
  • Codex 配置里的 URL 是否正确:

[mcp_servers.serena]
url = "http://127.0.0.1:9121/mcp"
  • Serena 启动端口是否也是 9121

"--port", "9121"

只要端口不一致,Codex 就一定无法连接。


12.4 PID 文件存在,但服务实际没运行

当前脚本中的 Get-SerenaProcess 已处理这类情况:

  • PID 文件为空会删除

  • PID 不是合法数字会删除

  • PID 对应进程不存在也会删除

因此这套脚本已经具备基本自清理能力,不需要再额外写一套兜底逻辑。


13. 最简操作示例

13.1 克隆 Serena

git clone <SERENA_REPOSITORY_URL> D:\Projects\serena

13.2 把脚本写入 $PROFILE

将本文第 6 节的完整脚本加入你的 PowerShell Profile。

13.3 重载 Profile

. $PROFILE

13.4 启动 Serena

serena start

13.5 查看状态

serena status

13.6 启动 Codex

确保 Codex 配置中包含:

[mcp_servers.serena]
url = "http://127.0.0.1:9121/mcp"
startup_timeout_sec = 5

14. 结论

这套配置的结构是清晰且稳定的:

  • uvx --from D:\Projects\serena 负责从本地仓库运行 Serena

  • PowerShell Profile 负责 Serena MCP Server 的生命周期管理

  • PID 文件机制负责避免重复启动和清理失效状态

  • Codex 通过 http://127.0.0.1:9121/mcp 连接本地 Serena MCP Server

它的优点是:

  • 不需要把 serena 全局安装到系统

  • Serena 的启动和停止由你手动控制

  • Codex 配置简单

  • 路径、端口、上下文固定,问题更容易排查