从 0 到 1 开发 Codex Plugin:把工具、MCP 和智能体接起来

AI 时代程序员必备技能

Codex、Claude Code、Cursor、Hermes Agent、OpenClaw等工程化实战专栏 ,讲透 AI 如何接管脏活累活

从 0 到 1 开发 Codex Plugin:把工具、MCP 和智能体接起来

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

Codex 插件开发实战

1. 先把几个概念分清楚

做插件开发时,最容易混在一起的词有四个:Plugin、Skill、MCP、Agent。

我的理解是:

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

插件与智能体的分层架构

一个好用的插件,通常不是“把所有东西塞进一个脚本”,而是把能力拆成三层:

  1. 插件层:负责安装、发现、展示。
  2. 工具层:通过 MCP 暴露可调用能力。
  3. 智能体层:负责推理、编排、调用、追踪。

2. 推荐的开发流程

我建议按下面 6 步推进:

开发一个 Codex 插件的 6 步流程

第一步:定义一个足够具体的场景

不要一上来做“万能办公助手”。插件最适合从一个高频、可验证的小场景开始。

例如:

  • 把一篇 Markdown 自动转成 CSDN 可发布格式。
  • 从公司知识库检索 API 文档,并生成接口调用示例。
  • 自动读取项目 issue,生成修复计划和 PR 描述。
  • 把文章、封面图、摘要一键同步到内容平台。

判断一个场景是否适合做插件,可以问三个问题:

  1. 这个任务是不是会重复发生?
  2. 输入和输出是否能说清楚?
  3. 执行结果是否能验证对错或好坏?

如果三个答案都是“是”,就值得做成插件。

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);

实际项目里,你可以把 formatForCsdnpublishToCsdn 换成自己的业务逻辑:调用数据库、访问内部 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 博客,配图,先生成草稿,不要直接发布。

智能体会自己拆成:

  1. 读取文章。
  2. 调用 format_article
  3. 检查图片引用。
  4. 调用 publish_article 的 dry-run。
  5. 汇总结果和下一步。

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_article
  • validate_assets
  • create_draft
  • publish_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

AI 时代程序员必备技能

Codex、Claude Code、Cursor、Hermes Agent、OpenClaw等工程化实战专栏 ,讲透 AI 如何接管脏活累活

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值