从 0 到 1 开发 Codex Plugin:把工具、MCP 和智能体接起来
写给想把内部脚本、业务 API、内容工作流接入 Codex / 智能体系统的开发者。本文会从插件结构讲起,逐步接入 Skill、MCP Server 和业务智能体,最后给出一套可以照着改的最小示例。

1. 先把几个概念分清楚
做插件开发时,最容易混在一起的词有四个:Plugin、Skill、MCP、Agent。
我的理解是:
- Plugin:一个可安装、可分发的能力包。它负责告诉 Codex:我是谁、我有哪些技能、有没有 MCP 工具、图标和展示信息在哪里。
- Skill:可复用工作流。它不是代码库里的普通 README,而是给 Codex 看的“操作手册”:什么时候用、输入是什么、步骤怎么走、怎么验证结果。
- MCP Server:工具和数据的桥。它把本地脚本、数据库、SaaS API 包装成模型能调用的工具,比如
search_docs、create_ticket、publish_article。 - Agent:真正执行任务的智能体运行时。它根据用户目标进行计划、调用工具、观察结果、必要时交接给其他 Agent,最后汇总答案或写入业务系统。

一个好用的插件,通常不是“把所有东西塞进一个脚本”,而是把能力拆成三层:
- 插件层:负责安装、发现、展示。
- 工具层:通过 MCP 暴露可调用能力。
- 智能体层:负责推理、编排、调用、追踪。
2. 推荐的开发流程
我建议按下面 6 步推进:

第一步:定义一个足够具体的场景
不要一上来做“万能办公助手”。插件最适合从一个高频、可验证的小场景开始。
例如:
- 把一篇 Markdown 自动转成 CSDN 可发布格式。
- 从公司知识库检索 API 文档,并生成接口调用示例。
- 自动读取项目 issue,生成修复计划和 PR 描述。
- 把文章、封面图、摘要一键同步到内容平台。
判断一个场景是否适合做插件,可以问三个问题:
- 这个任务是不是会重复发生?
- 输入和输出是否能说清楚?
- 执行结果是否能验证对错或好坏?
如果三个答案都是“是”,就值得做成插件。
3. 插件目录结构
一个典型插件可以长这样:

my-plugin/
├─ .codex-plugin/
│ └─ plugin.json
├─ skills/
│ └─ content-assistant/
│ └─ SKILL.md
├─ scripts/
│ └─ sync_csdn.ts
├─ assets/
│ └─ icon.png
├─ .mcp.json
└─ README.md
其中最核心的是这几个文件:
.codex-plugin/plugin.json:插件 manifest,描述插件身份、版本、展示信息和能力入口。skills/**/SKILL.md:告诉 Codex 如何使用这个插件能力。.mcp.json:声明 MCP server,让工具出现在智能体可调用列表里。scripts/:放真实业务逻辑,便于本地测试和复用。assets/:插件图标、截图、模板等静态资源。
4. 写 plugin.json
plugin.json 是插件入口。一个最小但比较完整的示例如下:
{
"name": "content-publisher",
"version": "0.1.0",
"description": "Prepare and publish technical articles with Codex.",
"author": {
"name": "Your Team",
"email": "dev@example.com",
"url": "https://example.com"
},
"homepage": "https://example.com/content-publisher",
"repository": "https://github.com/your-team/content-publisher",
"license": "MIT",
"keywords": ["content", "publisher", "csdn", "mcp"],
"skills": "./skills/",
"mcpServers": "./.mcp.json",
"interface": {
"displayName": "Content Publisher",
"shortDescription": "Format and publish technical articles.",
"longDescription": "A Codex plugin that formats Markdown articles, prepares assets, and connects publishing tools through MCP.",
"developerName": "Your Team",
"category": "Productivity",
"capabilities": ["Write", "Interactive"],
"websiteURL": "https://example.com",
"privacyPolicyURL": "https://example.com/privacy",
"termsOfServiceURL": "https://example.com/terms",
"defaultPrompt": [
"Format this Markdown article for CSDN.",
"Generate a cover and publishing checklist.",
"Publish this article with images."
],
"brandColor": "#2F7EA8",
"composerIcon": "./assets/icon.png",
"logo": "./assets/icon.png"
}
}
这里有几个实践建议:
name用小写短横线,比如content-publisher。version用语义化版本,比如0.1.0。- 路径建议用
./开头的相对路径。 - 如果写了
mcpServers,就真的要有.mcp.json。 defaultPrompt最好写成用户会直接点击的短句,不要写成说明书。
5. 写一个 Skill:让 Codex 知道什么时候用它
Skill 的重点不是“介绍功能”,而是把工作流写清楚。
例如 skills/content-assistant/SKILL.md:
---
name: content-assistant
description: Use when the user wants to format, package, or prepare a technical article for CSDN publishing.
---
# Content Assistant
## When to use
Use this skill when the user asks to:
- format a Markdown article for CSDN
- generate a cover image prompt
- prepare image references and publishing checklist
- convert code-heavy notes into a polished blog draft
## Workflow
1. Read the article or user-provided topic.
2. Create a CSDN-friendly structure: title, summary, sections, code blocks, conclusion.
3. Put generated assets under `outputs/assets/`.
4. Save the final article under `outputs/`.
5. Verify that every image referenced in Markdown exists.
6. Report the final Markdown path and asset list.
## Quality rules
- Keep code blocks executable or clearly marked as pseudocode.
- Use concise section titles.
- Do not invent API behavior; cite official docs when needed.
- For image-heavy articles, prefer local relative paths like `assets/cover.png`.
这段 Skill 会影响 Codex 的行为:当用户说“帮我写一篇 CSDN 博客并配图”时,Codex 就能知道该走这套流程,而不是只在聊天里给一段散文。
6. 接入 MCP:把业务能力变成工具
Skill 解决的是“怎么做”,MCP 解决的是“能调用什么”。
比如我们想给插件加两个工具:
format_article:把 Markdown 整理成 CSDN 风格。publish_article:把文章发布到指定平台,或先生成发布草稿。
可以先写 .mcp.json:
{
"mcpServers": {
"content-publisher": {
"command": "node",
"args": ["./scripts/mcp-server.js"],
"env": {
"CONTENT_API_BASE": "https://api.example.com"
}
}
}
}
再写一个最小 MCP Server。下面是伪代码风格,重点看结构:
// scripts/mcp-server.js
import { Server } from "@modelcontextprotocol/sdk/server/index.js";
import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio.js";
const server = new Server({
name: "content-publisher",
version: "0.1.0"
});
server.tool(
"format_article",
{
title: "Format article",
description: "Format Markdown into a CSDN-ready article.",
inputSchema: {
type: "object",
properties: {
markdown: { type: "string" },
style: { type: "string", enum: ["tutorial", "deep-dive", "summary"] }
},
required: ["markdown"]
}
},
async ({ markdown, style = "tutorial" }) => {
const formatted = await formatForCsdn(markdown, style);
return {
content: [
{
type: "text",
text: formatted
}
]
};
}
);
server.tool(
"publish_article",
{
title: "Publish article",
description: "Create or publish an article draft.",
inputSchema: {
type: "object",
properties: {
title: { type: "string" },
markdown: { type: "string" },
dryRun: { type: "boolean" }
},
required: ["title", "markdown"]
}
},
async ({ title, markdown, dryRun = true }) => {
if (dryRun) {
return {
content: [{ type: "text", text: `Draft prepared: ${title}` }]
};
}
const url = await publishToCsdn(title, markdown);
return {
content: [{ type: "text", text: `Published: ${url}` }]
};
}
);
const transport = new StdioServerTransport();
await server.connect(transport);
实际项目里,你可以把 formatForCsdn、publishToCsdn 换成自己的业务逻辑:调用数据库、访问内部 API、跑脚本、查知识库都可以。
关键是:MCP 工具的输入输出要稳定。模型最怕的是工具行为模糊,比如同一个字段有时是 URL,有时是正文,有时又是文件路径。
7. 接入智能体:让工具真正跑起来
当 MCP 工具可用后,就可以把它们接到业务智能体里。智能体的职责不是“替代工具”,而是根据目标选择工具、组织调用顺序,并解释执行结果。

以 OpenAI Agents SDK 的思想来看,一个智能体通常由几部分组成:
instructions:这个 Agent 的角色、边界和输出风格。tools:可调用工具,可以来自普通函数,也可以来自 MCP Server。handoff:复杂场景下交给另一个 Agent。trace:记录执行过程,方便调试工具调用链路。
示例伪代码:
from agents import Agent, Runner
from agents.mcp import MCPServerStdio
content_mcp = MCPServerStdio(
params={
"command": "node",
"args": ["./scripts/mcp-server.js"],
}
)
agent = Agent(
name="CSDN Publishing Agent",
instructions="""
你是一个技术内容发布助手。
你需要先检查文章结构,再调用工具格式化 Markdown。
如果用户要求发布,默认先 dry-run,除非用户明确说直接发布。
输出必须包含:文章路径、图片清单、发布前检查项。
""",
mcp_servers=[content_mcp],
)
result = Runner.run_sync(
agent,
"把这篇插件开发笔记整理成 CSDN 博客,并生成发布草稿。"
)
print(result.final_output)
这层接入完成后,用户就不需要记命令了。他只需要说目标:
把这篇插件开发笔记整理成 CSDN 博客,配图,先生成草稿,不要直接发布。
智能体会自己拆成:
- 读取文章。
- 调用
format_article。 - 检查图片引用。
- 调用
publish_article的 dry-run。 - 汇总结果和下一步。
8. 本地调试清单
开发插件时,我建议按这个顺序调试:
8.1 先测业务脚本
不要一上来就接 Codex。先确认脚本本身能跑:
node ./scripts/mcp-server.js
或者把核心逻辑拆出来单测:
node ./scripts/format-article.test.js
8.2 再测 MCP 工具
检查三件事:
- 工具是否能被列出来。
- 输入 schema 是否清晰。
- 返回值是否稳定,错误信息是否可读。
建议所有危险操作默认 dryRun: true,比如发文章、删数据、改工单状态。
8.3 再测 Skill 触发
用几种真实用户说法测试:
- “帮我整理成 CSDN 博客”
- “把这篇发 CSDN,先生成草稿”
- “给这篇文章配图并检查图片路径”
如果 Codex 没有触发你的 Skill,通常是 description 写得太泛。把它改得更像用户真实会说的话。
8.4 最后测端到端
端到端测试要覆盖:
- 无图文章。
- 有图文章。
- 代码块很多的文章。
- 工具失败时的降级逻辑。
- 发布前确认逻辑。
9. 常见坑
坑一:Skill 写成了产品介绍
Skill 不是宣传页。它应该告诉 Codex 怎么执行任务。
不推荐:
This plugin is powerful and can publish articles efficiently.
推荐:
When the user asks to publish an article, first run dry-run, list changes, and ask for confirmation before final publish.
坑二:MCP 工具粒度太粗
一个 do_everything 工具很难调试,也很难让模型稳定调用。
更好的方式是拆成:
format_articlevalidate_assetscreate_draftpublish_draft
每个工具只做一件事。
坑三:危险动作没有确认
发布、删除、付款、发邮件、改状态,都应该默认 dry-run,并要求用户明确确认。
{
"dryRun": true
}
这个小字段能省掉很多事故。
坑四:返回值太随意
工具返回值最好结构稳定:
{
"ok": true,
"draftId": "draft_123",
"url": "https://example.com/drafts/draft_123",
"warnings": ["cover image is missing alt text"]
}
不要今天返回字符串,明天返回数组,后天返回 HTML。
10. 发布和迭代建议
如果是团队内部插件,我建议至少准备这些东西:
README.md:说明安装、配置、调试方式。assets/icon.png:插件图标。examples/:放 2 到 3 个真实任务示例。CHANGELOG.md:记录版本变化。tests/:至少覆盖核心脚本和 MCP 工具输入输出。
迭代时也要注意:插件更新后,通常需要重新安装或重新开一个会话,才能让 Codex 读取到新的 Skill 和 MCP 工具。
11. 一个最小可用版本的路线图
如果你准备动手做第一个插件,可以按这个节奏来:
Day 1:跑通本地插件
- 创建
.codex-plugin/plugin.json - 写一个最小
SKILL.md - 准备图标和 README
- 本地安装并确认插件能被识别
Day 2:接入 MCP 工具
- 写一个只读工具,比如
search_docs - 写一个 dry-run 工具,比如
create_draft - 测试工具 schema 和返回值
Day 3:接入智能体
- 写 Agent instructions
- 接入 MCP Server
- 打开 trace,观察工具调用是否符合预期
- 优化工具名、描述和输入字段
Day 4:加入真实业务流
- 接入内部 API
- 增加鉴权和错误处理
- 增加发布前确认
- 准备团队使用文档
12. 总结
开发 Codex Plugin 的核心不是“写一个复杂插件”,而是把能力边界拆清楚:
- Plugin 负责分发和发现。
- Skill 负责沉淀工作流。
- MCP 负责把真实能力变成工具。
- Agent 负责计划、调用、观察和总结。
当这四层分开后,插件会更容易调试,也更容易扩展。你可以先从一个小场景开始,比如“格式化并发布技术文章”,等工具链稳定后,再逐步接入知识库、工单系统、内容平台和团队内部 API。
真正好用的智能体,不是一个会说很多话的聊天框,而是一个能稳定调用工具、可观察、可回放、出错能解释的工程系统。
参考资料
- OpenAI Agents SDK 文档:https://openai.github.io/openai-agents-python/
- Model Context Protocol 文档:https://modelcontextprotocol.io/docs/getting-started/intro
- OpenAI Codex 插件说明:https://help.openai.com/en/articles/20001256-plugins-in-codex

342

被折叠的 条评论
为什么被折叠?



