For the complete documentation index, see llms.txt. Markdown versions of documentation pages are available by appending .md to the page URL.
主导航

构建 MCP 服务器

为您的插件添加实时数据和受控工具。

当插件用例需要实时数据、身份验证、受控操作,或需要在您运营的基础设施上运行代码时,请添加 MCP 服务器。服务器定义 ChatGPT 和 Codex 可用的工具,无需返回自定义 UI。

从您的 用例清单中支持的目标入手。每个工具都应帮助完成 一个明确的用户目标,并且只提供实现 该目标所需的数据和操作。

先构建工具。服务器在没有自定义 UI 的情况下正常运行后,您可以为 MCP 服务器 添加 UI,以支持需要 可视化交互的工作流。

选择 MCP 软件开发工具包

官方软件开发工具包提供模式辅助工具、服务器脚手架和可流式传输的 HTTP 传输方式:

安装与您的服务器技术栈匹配的 SDK:

# TypeScript
npm install @modelcontextprotocol/sdk zod

# Python
pip install mcp

创建服务器

创建一个具有稳定名称和版本号的 MCP 服务器:

import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";

const server = new McpServer({
  name: "acme-projects",
  version: "1.0.0",
});

MCP 服务器还可以在初始化时 返回 instructions 字段。 ChatGPT 和 Codex 会将这些指令与工具元数据 结合使用。

使用服务器指令提供适用于多个工具的指导,例如必需的工具调用顺序或共享的速率限制。将最重要的细节放在前 512 个字符内。不要重复每个工具的描述,也不要试图改变模型的个性。

const server = new McpServer(
  { name: "acme-projects", version: "1.0.0" },
  {
    instructions:
      "Before updating a project, call get_project to confirm its ID and current status.",
  }
);

根据用户目标定义工具

为插件必须支持的每项独立操作各创建一个工具。优先采用 功能集中的操作,例如 list_projectsget_projectupdate_project,而不是在单个工具中提供多种互不相关的模式。

每个工具都需要:

  • 体现操作的名称和易于理解的标题。
  • 说明何时使用该工具的描述。
  • 明确的输入模式。
  • 如果工具返回结构化数据,则需要提供输出模式。
  • 准确的安全注解。
  • 对请求进行授权并执行操作的处理程序。

模型使用这些元数据来决定是否调用工具以及如何调用。请将名称、描述、模式和注解视为插件面向用户的行为的一部分。

import { z } from "zod";

server.registerTool(
  "list_projects",
  {
    title: "List projects",
    description:
      "Use this when the user wants to find or review projects in their Acme workspace.",
    inputSchema: {
      status: z.enum(["active", "archived"]).optional(),
    },
    outputSchema: {
      projects: z.array(
        z.object({
          id: z.string(),
          name: z.string(),
          status: z.string(),
        })
      ),
    },
    annotations: {
      readOnlyHint: true,
      openWorldHint: false,
      destructiveHint: false,
    },
  },
  async ({ status }) => {
    const projects = await listProjects({ status });

    return {
      structuredContent: { projects },
      content: [
        {
          type: "text",
          text: `Found ${projects.length} projects.`,
        },
      ],
    };
  }
);

无需 UI 即可返回有用的结果

工具结果可以包含:

  • structuredContent:简洁的数据,供模型查看并在后续 调用中使用。
  • content:帮助模型回答用户的文本或其他 MCP 内容。
  • _meta:对模型不可见的客户端专用数据。

返回足够的信息,让模型无需组件即可完成工作流程。在结构化结果中使用稳定的标识符,以便后续工具引用相同的记录。

不要在工具结果中放入 密钥、访问令牌或不必要的个人数据。_meta 对模型不可见,但不能替代 授权机制或安全存储。

从 MCP 服务器导入技能

如果您希望将技能的指令和配套文件与服务器一起进行版本管理和部署, 请将 MCP 服务器配置为提供技能。提交插件时, 扫描工具 会将这些技能的静态快照 导入草稿。

OpenAI 目前支持 SEP-2640 技能扩展草案中范围有限的静态功能子集。 该提案尚未纳入稳定版 MCP 规范。

在服务器初始化时的能力声明中 声明 io.modelcontextprotocol/skills

{
  "capabilities": {
    "extensions": {
      "io.modelcontextprotocol/skills": {}
    }
  }
}

此声明必须位于 capabilities.extensions 下。 OpenAI 不识别早期的 experimental 声明。

列出技能及其资源

支持分页的 skills/list 方法。每个条目必须包含:

  • 指向技能 SKILL.mduri
  • frontmatter,包含从 SKILL.md 的前置元数据中解析出的所有条目。 其中应包括 namedescription 条目。
  • 完整的 resources 列表,包含 SKILL.md 和所有配套文件。
  • 每个资源的 SHA-256 摘要,格式为 sha256:<64 lowercase hexadecimal characters>

采用 skill:// URI 约定。包含 SKILL.md 的目录名称必须 与技能名称一致。例如:

{
  "skills": [
    {
      "uri": "skill://dice-roller/tabletop-dice/SKILL.md",
      "frontmatter": {
        "name": "tabletop-dice",
        "description": "Roll one or more dice and report each result and the total."
      },
      "resources": [
        {
          "uri": "skill://dice-roller/tabletop-dice/SKILL.md",
          "digest": "sha256:0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef"
        },
        {
          "uri": "skill://dice-roller/tabletop-dice/references/notation.md",
          "digest": "sha256:abcdef0123456789abcdef0123456789abcdef0123456789abcdef0123456789"
        }
      ]
    }
  ],
  "nextCursor": "optional-next-page-cursor"
}

示例摘要展示了所需的格式。对于文本资源,请对 content.text 的 UTF-8 字节计算哈希值。对于 blob 资源,请先对 content.blob 进行 base64 解码,再对解码后的字节计算哈希值。

还需为列出的每个 SKILL.md URI 支持 skills/get。返回一个 skill 对象, 其结构应与 skills/list 的完整条目结构一致。

使用以下请求参数:

  • 对于首次 skills/list 请求,接受空对象({})。
  • 对于后续每次 skills/list 请求,接受先前返回的游标,例如 { "cursor": "next-page-cursor" }
  • 对于 skills/get,接受目录中列出的 URI,例如 { "uri": "skill://dice-roller/tabletop-dice/SKILL.md" }

返回列出的每个资源

为清单中的每个 URI 支持 resources/read。返回且仅返回一个 内容项,其 URI 应与请求一致。OpenAI 接受 UTF-8 文本或 经过 base64 编码的 blob。

导入期间,OpenAI 会验证以下事项:

  • OpenAI 能够获取列出的每个资源并核实其摘要。
  • 获取的 SKILL.md 前置元数据与目录条目完全一致。
  • 资源路径安全、唯一,且不存在规范化冲突。
  • 完整技能符合导入限制。

导入器最多接受分布在 10 页目录中的 5 个名称唯一的技能。每个技能最多可包含 100 个文件,大小限制如下:

内容限制
SKILL.md256 KiB
每个配套文件1 MiB
单个技能的所有资源5 MiB
单次扫描生成的技能归档文件8 MiB

归档文件的总大小限制包含 ZIP 打包开销。

如果任何条目未通过验证或超出限制, 扫描工具 仍会返回 服务器的工具,但不会更新草稿中已导入的技能。请修复 服务器后重新扫描。

从 MCP 导入的技能是提交时的快照,并非运行时实时 资源。更改技能后,请再次运行 扫描工具 ,审查导入的 技能,然后提交新的插件版本。完整流程请参阅 提交插件

对请求进行身份验证和授权

当工具读取私有数据或代表用户执行操作时,请添加身份验证。 在 MCP 服务器中对每个请求强制执行授权检查;切勿依赖 模型判断用户是否拥有访问权限。

有关 OAuth 发现、安全方案 和授权质询,请参阅用户身份验证

为改善多账户使用体验,请提供一个需要身份验证的 只读账户资料工具,并使用 _meta["openai/profile"]: true 对其进行标记。 OpenAI 使用账户资料来一致地识别已连接的账户, 帮助用户区分这些账户。请根据请求中经过验证的 凭据获取账户资料,并确保每次工具调用都限定在这些凭据的作用域内。即使没有账户资料工具,用户也可以 连接多个账户。有关模式和实现示例,请参阅 支持多个账户

工具注解与引导式提取

根据实际行为设置注解:

  • readOnlyHint:仅当工具无法更改状态时才设为 true
  • destructiveHint:当工具可能造成不可逆或难以 撤销的结果时,设为 true
  • openWorldHint:当工具访问公共互联网或范围不受限定的 外部实体时,设为 true,通过网页搜索等只读操作进行访问也包括在内。 如果工具仅限于访问范围明确的私有账户或工作空间,则可以将此项设为 false,即使该服务托管在外部也是如此。

注解可帮助 ChatGPT 和 Codex 选择适当的确认和安全 行为,但不能替代您服务器中的授权、验证或 确认机制。

当服务器需要原始工具调用中未提供的结构化信息时, 请使用 MCP 引导式提取。仅请求用户能够合理提供的 信息。不要用它来收集机密信息或绕过 正常的身份验证。

企业知识兼容性

企业知识可以使用您 MCP 服务器中的只读工具。要让 插件具备作为企业知识来源的资格,请实现标准的 searchfetch 工具输入模式,并使用 readOnlyHint: true 标记其他只读工具。

对于模型应引用的来源,请返回用户可以打开的绝对 URL。 将内部文档标识符保留在结果的 id 字段中。有关所需的 模式和结果结构,请参阅 为 ChatGPT 和 API 集成构建 MCP 服务器

在本地运行和测试

提供一个支持流式传输的 HTTP 端点,通常位于 /mcp,然后使用 MCP Inspector 检查该端点:

npx @modelcontextprotocol/inspector

在 Inspector 界面中,选择 Streamable HTTP ,然后输入 http://localhost:3000/mcp

使用 Inspector 执行以下操作:

  1. 确认初始化成功。
  2. 审查服务器指令及其声明的工具列表。
  3. 分别使用具有代表性的输入和无效输入调用每个工具。
  4. 验证模式、结果、错误和注解。
  5. 确认访问私有数据和执行写入操作时会强制执行授权检查。

然后在开发者模式下将服务器连接到 ChatGPT, 并运行用例清单中的直接请求、 间接请求、边界情况请求和范围外请求。

部署端点

要提交公开插件,请将 MCP 服务器部署到稳定且可通过 公网访问的 HTTPS 端点。安全 MCP 隧道 可以在开发者模式下连接私有 MCP 服务器,但不满足 公开提交的要求。

生产环境端点必须:

  • 支持 MCP 的流式 HTTP 传输。
  • 通过稳定的 URL 响应请求,URL 通常以 /mcp 结尾。
  • 满足插件工作流对延迟和可用性的要求。
  • 能够访问所需的服务和数据存储。
  • 保持身份验证和授权边界。
  • 为失败的初始化和工具调用生成日志和指标。

如果 MCP 服务器必须保持私有,请部署一个公共 HTTPS 代理,将 MCP 请求转发到私有服务器。使用 由 OpenAI 管理的 mTLS 验证 ChatGPT 作为 MCP 客户端的身份;当您的 插件需要用户身份验证时,使用 OAuth 2.1。如果您的网络要求使用 IP 允许列表, 请使用已公布的ChatGPT 连接器 IP 范围, 并自动更新允许列表。IP 允许列表不能替代 身份验证或授权。

公共端点必须保持可访问,以便进行插件审查和 域名验证。公开提交时, 不要仅使用安全 MCP 隧道,也不要使用临时隧道或 本地端点。

选择基础设施

您可以将 MCP 服务器部署到无服务器、容器、边缘或传统 应用基础设施。请根据以下因素选择平台:

  • 对运行时和依赖项的支持。
  • 流式响应的行为。
  • 冷启动和请求延迟。
  • 对所需服务的网络访问能力。
  • 数据驻留和合规要求。
  • 机密信息管理。
  • 日志记录、追踪和告警。
  • 对回滚和版本管理的支持。

如果服务器还托管可选的 UI 资源,请将这些资源部署到稳定的源, 并确保这些源在组件的 内容安全策略允许范围内。

配置生产环境端点

部署前:

  1. 通过主机的机密信息管理系统设置生产环境凭据。
  2. 配置授权服务器和允许的重定向行为。
  3. 为开销较大或外部可见的工具设置超时和速率限制。
  4. 移除调试响应和不必要的个人数据。
  5. 确认日志中不包含访问令牌或敏感的工具结果。

部署后,使用 MCP Inspector 调用生产环境端点。验证 初始化、服务器指令、工具、模式、注解、 身份验证、结果和错误。

规划更新

保持已发布的工具名称和模式向后兼容。在不破坏现有契约的前提下 添加字段或工具。如果元数据发生变化,请刷新 开发者模式连接,并在提交前重新运行评估集。

对于可选 UI,如果 HTML、JavaScript 或 CSS 的变更 可能导致缓存的组件无法正常工作,请更新资源标识符中的版本。

添加可选 UI

工具能够端到端正常工作后,再判断是否有用例需要可视化 交互。表格、地图、可编辑日程或对比视图可能会因 UI 而 受益。查询、状态检查或后台操作通常不需要 UI。

继续参阅为您的 MCP 服务器添加 UI,以 注册 MCP Apps 资源并将其与选定的工具关联。

安全提醒

  • 将所有工具输入视为不可信数据。
  • 在服务器端验证参数并强制执行授权检查。
  • 对于会产生重大影响的写入操作,要求确认。
  • 不要在工具元数据和结果中包含机密信息或敏感数据。
  • 在日志中记录足够的上下文以便调查故障,但不要记录凭证或不必要的个人数据。
  • 对开销较大或对外可见的操作实施速率限制。