Codex MCP 与 Skills 跨 Docker 共享问题总结与后续规范

本文总结本次遇到的 Codex MCP / Skills 识别问题、根因、恢复方式,以及以后在多 Docker / 多机器环境下添加 MCP 工具与 Skills 的推荐做法。


1. 场景背景

当前环境特点:

  • 多个 Docker / 多台机器共用主机上的同一个 workspace 文件夹;
  • 每个 Docker 内部的 ~/.codex~/.agents~/.bashrc、依赖环境可能不同;
  • 已经在某一台机器或 Docker 中配置好了 Codex MCP 工具和 Skills;
  • 希望其他 Docker / 机器上的 Codex 也能复用同一套 MCP 与 Skills。

期望目标:

text 复制代码
所有 Docker 复用:
- MCP 工具配置
- Skills 仓库
- AGENTS.md 使用规则

每个 Docker 自己维护:
- Codex 登录状态
- API Key 环境变量
- node/npm/npx/python 等运行依赖

2. 本次出现的问题

2.1 Codex MCP 面板只显示 codex_apps

现象:

text 复制代码
MCP 面板只显示:
codex_apps    已通过身份验证(API 密钥)    已启用

没有显示之前配置过的:

text 复制代码
context7
sequential-thinking
arxiv-mcp-server
chrome-devtools
drawio

2.2 config.toml 曾出现 duplicate key 错误

报错:

text 复制代码
failed to load configuration: /root/.codex/config.toml:15:11: duplicate key

原因是多次使用 cat >> ~/.codex/config.toml 追加配置,导致重复出现了同名 TOML table,例如:

toml 复制代码
[projects."/workspace"]
trust_level = "trusted"

[projects."/workspace"]
trust_level = "trusted"

或者重复出现:

toml 复制代码
[mcp_servers.context7]
...

[mcp_servers.context7]
...

TOML 不允许同一个 key / table 重复定义,因此 Codex 无法加载配置。


3. 根因分析

3.1 Skills 能识别,但 MCP 不一定能识别

这是因为 Skills 与 MCP 的发现机制不同

项目 Skills MCP
常见位置 ~/.agents/skills 或项目 .agents/skills ~/.codex/config.toml 或项目 .codex/config.toml
是否依赖当前项目路径 用户级 skills 不太依赖 项目级 MCP 强依赖
是否需要 trust 项目 用户级 skills 通常不需要 项目级 .codex/config.toml 通常需要 trust
本次现象 Skills 能识别 MCP 只显示 codex_apps

如果 Skills 放在:

bash 复制代码
~/.agents/skills

那么它们是用户级资源,即使当前打开的是 /workspace/root/workspace 或其他目录,也可能被识别。

但 MCP 如果只放在:

bash 复制代码
/workspace/.codex/config.toml

就属于项目级配置。Codex 当前会话必须正确加载这个项目配置,否则不会显示这些 MCP server。


3.2 /root/workspace/workspace 实际是同一个目录

检查结果:

bash 复制代码
PWD=/root/workspace/.codex
pwd -P
/workspace/.codex

readlink -f /workspace
/workspace
readlink -f /root/workspace
/workspace

/root/workspace -> /workspace/

说明:

text 复制代码
/root/workspace 是 /workspace 的软链接

因此这台机器上 MCP 不显示的根因不是路径不一致,而是:

text 复制代码
Codex 当前只加载了用户级 ~/.codex/config.toml,
没有加载项目级 /workspace/.codex/config.toml 里的 MCP servers。

3.3 为什么项目级 .codex/config.toml 可能没有被加载

常见原因包括:

  1. VS Code / Codex 当前打开的根目录不是 /workspace,而是某个子目录;
  2. Codex 当前会话是在 MCP 配置修改前创建的,旧会话没有热加载;
  3. 项目级配置没有被 trust;
  4. VS Code Codex 插件没有 Reload Window;
  5. MCP 配置放在项目级,但当前会话只读到了用户级配置;
  6. config.toml 有 duplicate key,导致整个配置加载失败。

4. 最稳妥的解决方式

4.1 MCP 配置优先放到用户级 ~/.codex/config.toml

为了避免项目级配置未加载,最稳妥的方式是:

text 复制代码
把 MCP servers 放到用户级 ~/.codex/config.toml

这样不依赖当前打开的是哪个目录。

推荐的干净配置如下:

toml 复制代码
model = "gpt-5.5"
model_reasoning_effort = "high"
sandbox_mode = "workspace-write"
personality = "pragmatic"

[plugins."github@openai-curated"]
enabled = true

[projects."/workspace"]
trust_level = "trusted"

[projects."/root/workspace"]
trust_level = "trusted"

[tui.model_availability_nux]
"gpt-5.5" = 1

# =========================
# MCP Servers
# User-level config: always available in this Docker
# =========================

[mcp_servers.chrome-devtools]
command = "npx"
args = ["-y", "chrome-devtools-mcp@latest"]
startup_timeout_sec = 30
tool_timeout_sec = 120
enabled = true

[mcp_servers.context7]
command = "npx"
args = ["-y", "@upstash/context7-mcp"]
env_vars = ["CONTEXT7_API_KEY"]
startup_timeout_sec = 30
tool_timeout_sec = 120
enabled = true

[mcp_servers.sequential-thinking]
command = "npx"
args = ["-y", "@modelcontextprotocol/server-sequential-thinking"]
startup_timeout_sec = 30
tool_timeout_sec = 120
enabled = true

[mcp_servers.arxiv-mcp-server]
command = "npx"
args = ["-y", "@langgpt/arxiv-mcp-server@latest"]
env_vars = ["SILICONFLOW_API_KEY"]
startup_timeout_sec = 30
tool_timeout_sec = 120
enabled = true

[mcp_servers.arxiv-mcp-server.env]
WORK_DIR = "/workspace/arxiv-mcp-server"

[mcp_servers.drawio]
command = "npx"
args = ["-y", "@next-ai-drawio/mcp-server@latest"]
startup_timeout_sec = 30
tool_timeout_sec = 120
enabled = true

4.2 重建用户级配置的命令

如果 ~/.codex/config.toml 已经混乱或有 duplicate key,可以直接备份后重建:

bash 复制代码
cp ~/.codex/config.toml ~/.codex/config.toml.bak.$(date +%Y%m%d_%H%M%S) 2>/dev/null || true

cat > ~/.codex/config.toml <<'EOF'
model = "gpt-5.5"
model_reasoning_effort = "high"
sandbox_mode = "workspace-write"
personality = "pragmatic"

[plugins."github@openai-curated"]
enabled = true

[projects."/workspace"]
trust_level = "trusted"

[projects."/root/workspace"]
trust_level = "trusted"

[tui.model_availability_nux]
"gpt-5.5" = 1

[mcp_servers.chrome-devtools]
command = "npx"
args = ["-y", "chrome-devtools-mcp@latest"]
startup_timeout_sec = 30
tool_timeout_sec = 120
enabled = true

[mcp_servers.context7]
command = "npx"
args = ["-y", "@upstash/context7-mcp"]
env_vars = ["CONTEXT7_API_KEY"]
startup_timeout_sec = 30
tool_timeout_sec = 120
enabled = true

[mcp_servers.sequential-thinking]
command = "npx"
args = ["-y", "@modelcontextprotocol/server-sequential-thinking"]
startup_timeout_sec = 30
tool_timeout_sec = 120
enabled = true

[mcp_servers.arxiv-mcp-server]
command = "npx"
args = ["-y", "@langgpt/arxiv-mcp-server@latest"]
env_vars = ["SILICONFLOW_API_KEY"]
startup_timeout_sec = 30
tool_timeout_sec = 120
enabled = true

[mcp_servers.arxiv-mcp-server.env]
WORK_DIR = "/workspace/arxiv-mcp-server"

[mcp_servers.drawio]
command = "npx"
args = ["-y", "@next-ai-drawio/mcp-server@latest"]
startup_timeout_sec = 30
tool_timeout_sec = 120
enabled = true
EOF

5. 环境变量配置

MCP 配置中使用:

toml 复制代码
env_vars = ["CONTEXT7_API_KEY"]
env_vars = ["SILICONFLOW_API_KEY"]

说明真实 API Key 不写入 config.toml,而是从环境变量读取。

简单方式:写入 ~/.bashrc

bash 复制代码
cat >> ~/.bashrc <<'EOF'

# MCP API Keys for Codex
export CONTEXT7_API_KEY="你的 Context7 API Key"
export SILICONFLOW_API_KEY="你的 SiliconFlow API Key"
EOF

source ~/.bashrc

检查是否生效:

bash 复制代码
python3 - <<'PY'
import os
for k in ["CONTEXT7_API_KEY", "SILICONFLOW_API_KEY"]:
    print(f"{k}: {'OK' if os.environ.get(k) else 'MISSING'}")
PY

注意:如果使用 VS Code Codex 插件,.bashrc 新增环境变量后,插件进程不一定立刻继承,需要 Reload Window 或重连 Remote-SSH。


6. 依赖检查

很多 MCP 使用 npx 启动,因此每个 Docker 内部都需要检查:

bash 复制代码
node -v
npm -v
npx -v
python3 --version

如果缺失:

bash 复制代码
apt update
apt install -y nodejs npm

7. 手动测试 MCP 是否能启动

stdio 类型 MCP 不建议手动长期后台启动。Codex 会根据 commandargs 自动启动它们。

手动运行主要用于排错。

7.1 Context7

bash 复制代码
timeout 10s npx -y @upstash/context7-mcp
echo "context7 exit=$?"

7.2 Sequential Thinking

bash 复制代码
timeout 10s npx -y @modelcontextprotocol/server-sequential-thinking
echo "sequential-thinking exit=$?"

7.3 arxiv MCP

bash 复制代码
mkdir -p /workspace/arxiv-mcp-server

timeout 10s env WORK_DIR=/workspace/arxiv-mcp-server SILICONFLOW_API_KEY="$SILICONFLOW_API_KEY" npx -y @langgpt/arxiv-mcp-server@latest
echo "arxiv exit=$?"

7.4 drawio MCP

bash 复制代码
timeout 10s npx -y @next-ai-drawio/mcp-server@latest
echo "drawio exit=$?"

如果返回:

text 复制代码
124

通常表示该 stdio MCP server 能启动,只是在等待 MCP client 输入,属于正常现象。


8. Reload Window 很关键

修改 MCP 配置或环境变量后,旧 Codex 会话不一定热加载。

推荐顺序:

text 复制代码
1. 保存 ~/.codex/config.toml
2. source ~/.bashrc
3. VS Code 执行 Developer: Reload Window
4. 新建 Codex 会话
5. 如果仍不生效,Remote-SSH: Kill VS Code Server on Host 后重连

之前已经验证过:

text 复制代码
Reload Window 后,所有 MCP 工具恢复可用。

9. 多 Docker 共享的推荐结构

如果所有 Docker 共用 /workspace,推荐结构:

text 复制代码
/workspace/
├── .codex/config.toml          # 可选:项目级 MCP 配置
├── .agents/skills/             # 共享 skills
├── AGENTS.md                   # 项目级 Codex 使用规则
├── .shared_bashrc              # 可选:共享环境变量和 alias
└── arxiv-mcp-server/           # arxiv MCP 工作目录

但是从稳定性角度看,MCP 最稳是放:

text 复制代码
~/.codex/config.toml

Skills 可以共享:

text 复制代码
/workspace/.agents/skills

然后在每个 Docker 中链接到用户级:

bash 复制代码
mkdir -p ~/.agents
rm -rf ~/.agents/skills
ln -s /workspace/.agents/skills ~/.agents/skills

10. 如果想让所有 Docker 共用 bashrc

不建议直接把所有 Docker 的 ~/.bashrc 都软链接为同一个文件,因为不同容器可能有自己的 conda、CUDA、PATH 配置。

推荐方式是:每个 Docker 自己保留 ~/.bashrc,但都 source 一个共享文件:

text 复制代码
/workspace/.shared_bashrc

创建共享文件:

bash 复制代码
cat > /workspace/.shared_bashrc <<'EOF'
# Shared bashrc for all Docker containers

export CONTEXT7_API_KEY="你的 Context7 API Key"
export SILICONFLOW_API_KEY="你的 SiliconFlow API Key"

export WORKSPACE=/workspace
export CODEX_WORKSPACE=/workspace

alias ll='ls -alF'
alias la='ls -A'
alias l='ls -CF'

export NPM_CONFIG_CACHE=/workspace/.cache/npm
export PIP_CACHE_DIR=/workspace/.cache/pip

mkdir -p /workspace/.cache/npm /workspace/.cache/pip 2>/dev/null || true
EOF

每个 Docker 的 ~/.bashrc 加入:

bash 复制代码
grep -qxF '[ -f /workspace/.shared_bashrc ] && source /workspace/.shared_bashrc' ~/.bashrc || \
echo '[ -f /workspace/.shared_bashrc ] && source /workspace/.shared_bashrc' >> ~/.bashrc

source ~/.bashrc

11. 以后添加新的 MCP 工具应该怎么做

11.1 推荐流程

  1. 先不要直接追加到配置文件末尾;
  2. 先备份:
bash 复制代码
cp ~/.codex/config.toml ~/.codex/config.toml.bak.$(date +%Y%m%d_%H%M%S)
  1. 打开配置文件手动编辑:
bash 复制代码
nano ~/.codex/config.toml
  1. 添加新的 MCP table,例如:
toml 复制代码
[mcp_servers.new-tool]
command = "npx"
args = ["-y", "some-mcp-package@latest"]
startup_timeout_sec = 30
tool_timeout_sec = 120
enabled = true
  1. 如果需要 API Key,优先使用环境变量:
toml 复制代码
env_vars = ["NEW_TOOL_API_KEY"]

然后在 .bashrc.shared_bashrc 中配置:

bash 复制代码
export NEW_TOOL_API_KEY="你的 key"
  1. 检查 TOML 语法:
bash 复制代码
python3 - <<'PY'
import os
try:
    import tomllib
except ModuleNotFoundError:
    print("Python < 3.11, skip TOML check.")
    raise SystemExit(0)
path = os.path.expanduser("~/.codex/config.toml")
with open(path, "rb") as f:
    tomllib.load(f)
print("config.toml OK")
PY
  1. Reload Window 并新建 Codex 会话。

11.2 避免 duplicate key

添加前先检查是否已经存在:

bash 复制代码
grep -n '^\[mcp_servers\.context7\]' ~/.codex/config.toml
grep -n '^\[mcp_servers\.sequential-thinking\]' ~/.codex/config.toml
grep -n '^\[projects\."/workspace"\]' ~/.codex/config.toml

不要重复添加同名 table。

错误示例:

toml 复制代码
[mcp_servers.context7]
...

[mcp_servers.context7]
...

正确做法是编辑已有 table,而不是追加新的同名 table。


12. 以后添加新的 Skills 应该怎么做

12.1 用户级 Skills

放到:

text 复制代码
~/.agents/skills/<skill-name>/SKILL.md

例如:

bash 复制代码
mkdir -p ~/.agents/skills/my-new-skill
nano ~/.agents/skills/my-new-skill/SKILL.md

标准结构:

markdown 复制代码
---
name: my-new-skill
description: Use this skill when ...
---

# My New Skill

## When to use

...

## Workflow

1. ...
2. ...
3. ...

## Output Format

...

检查是否能被扫描到:

bash 复制代码
find ~/.agents/skills -maxdepth 3 -name SKILL.md -print

12.2 共享 Skills

如果希望多个 Docker 共用 Skills,推荐放到:

text 复制代码
/workspace/.agents/skills

然后每个 Docker 创建软链接:

bash 复制代码
mkdir -p ~/.agents
rm -rf ~/.agents/skills
ln -s /workspace/.agents/skills ~/.agents/skills

检查:

bash 复制代码
find ~/.agents/skills -maxdepth 3 -name SKILL.md -print

12.3 如果一个仓库内部有很多子 skills

例如:

text 复制代码
ai-infra-skills/.claude/skills/01-server/SKILL.md
ai-infra-skills/.claude/skills/02-env-source-log/SKILL.md
...

由于层级较深,普通扫描器不一定发现。推荐把子 skill 软链接到顶层:

bash 复制代码
for d in ~/.agents/skills/ai-infra-skills/.claude/skills/*; do
  if [ -f "$d/SKILL.md" ]; then
    name="ai-infra-$(basename "$d")"
    ln -sfn "$d" "$HOME/.agents/skills/$name"
    echo "linked: $HOME/.agents/skills/$name -> $d"
  fi
done

同时建议给总仓库补一个根目录入口:

text 复制代码
~/.agents/skills/ai-infra-skills/SKILL.md

用来说明:

text 复制代码
先读 INDEX.md
再读 EXPERT_KNOWLEDGE_MAP.md
再进入 knowledge / .claude/skills / .claude/rules

13. 推荐的长期规范

MCP 规范

text 复制代码
1. MCP server 优先写入用户级 ~/.codex/config.toml。
2. 共享项目级 /workspace/.codex/config.toml 可以保留,但不要依赖它作为唯一来源。
3. 不要反复 cat >> 追加同名 table。
4. 添加前先 grep 检查是否存在。
5. API Key 用 env_vars,不直接写入 config.toml。
6. 修改后必须 Reload Window。

Skills 规范

text 复制代码
1. 每个 skill 必须有 SKILL.md。
2. 可共享的 skills 放 /workspace/.agents/skills。
3. 每个 Docker 用软链接把 ~/.agents/skills 指向共享目录。
4. 深层子 skills 用软链接暴露到顶层。
5. 修改或新增后 Reload Window / 新建 Codex 会话。

多 Docker 规范

text 复制代码
共享:
- /workspace/.agents/skills
- /workspace/AGENTS.md
- /workspace/.shared_bashrc
- 可选 /workspace/.codex/config.toml

每个 Docker 独立:
- ~/.codex/config.toml 中的最终 MCP 配置
- Codex 登录状态
- API Key 环境变量
- node/npm/python 依赖

14. 最终结论

本次问题的根本原因不是 /root/workspace/workspace 路径不同,因为它们实际指向同一目录;真正原因是:

text 复制代码
Codex 当前会话没有加载项目级 /workspace/.codex/config.toml 中的 MCP 配置,
因此只显示默认的 codex_apps。

最稳的解决方式是:

text 复制代码
把 MCP servers 写入用户级 ~/.codex/config.toml,
API Key 通过环境变量提供,
Reload Window 后新建 Codex 会话。

以后添加 MCP 或 Skills 时,按以下原则:

text 复制代码
MCP:编辑 ~/.codex/config.toml,避免重复 table,修改后 Reload Window。
Skills:确保每个 skill 有 SKILL.md,最好共享到 /workspace/.agents/skills,再软链接到 ~/.agents/skills。
相关推荐
羽翼安全2 小时前
多摄像头接入检测 + 文件加密:监控室防拍照系统的两道设备与数据防线
运维·网络·人工智能
疋瓞2 小时前
批处理_自定义带锁文件夹应用案例_03
运维·服务器
运维行者_2 小时前
如何为您的企业选择最佳网络监控工具
大数据·运维·服务器·网络·数据库
qq_452396232 小时前
第一篇:《Kubernetes 是什么?为什么它是云原生基石?》
云原生·容器·kubernetes
Benszen2 小时前
云计算基础-4:Linux 进程管理
linux·运维·云计算
逸模10 小时前
告别熬夜手工整理台账,逸模智能归集实现项目数据自动化存档
大数据·运维·人工智能·笔记·其他·信息可视化·自动化
sbjdhjd10 小时前
Redis 主从复制、哨兵高可用与 Cluster 集群部署实验手册
运维·前端·redis·云原生·开源·bootstrap·html
AOwhisky11 小时前
MySQL 学习笔记(第四期):SQL 语言之多表查询
linux·运维·网络·数据库·笔记·学习·mysql
ggaofeng11 小时前
glusterfs如何在k8s中使用
云原生·容器·kubernetes·glusterfs