A plugin packages skills, MCP configuration, or both. Load its files into your own environment or upload a ZIP to an OpenAI-hosted environment.
Package the plugin
This plugin combines a documentation-search skill with the OpenAI documentation MCP. It needs network access but no credentials or local server dependencies.
docs-helper/
├── .codex-plugin/plugin.json
├── .mcp.json
└── skills/docs-search/SKILL.md
Declare the skill directory and MCP configuration in .codex-plugin/plugin.json:
{
"name": "docs-helper",
"version": "1.0.0",
"description": "Find answers in OpenAI developer documentation.",
"skills": "./skills/",
"mcpServers": "./.mcp.json"
}
Paths resolve from the plugin root. They must start with ./, stay inside the plugin, and contain no .. components. See Package your plugin for the full manifest format.
Add the server to .mcp.json. This file uses the plugin format, which differs from agent.tools:
{
"mcpServers": {
"openai_docs": {
"type": "http",
"url": "https://developers.openai.com/mcp"
}
}
}
Add the instructions to skills/docs-search/SKILL.md:
---
name: docs-search
description: Find answers in OpenAI developer documentation.
---
Use the openai_docs MCP server to find relevant documentation.
Answer the question and link to the sources you used.
Register plugins in a self-hosted sandbox
Copy the plugin to /workspace/plugins/docs-helper and add that absolute path to environment.capability_directories. Select the plugin root, which contains .codex-plugin/plugin.json.
import OpenAI from "openai";
const client = new OpenAI();
const result = await client.beta.agents.sessions.create({
agent: {
model: "gpt-6-astra",
},
environment: {
type: "self_hosted",
workspace_directory: "/workspace",
capability_directories: ["/workspace/plugins/docs-helper"],
},
});
console.log(result.id);Connect the executor before the agent uses the plugin. Allow the environment to reach https://developers.openai.com/mcp.
For multiple plugins, list each root. A parent directory can discover nested skills, but does not load every child plugin’s MCP configuration.
Upload plugins to an OpenAI-hosted sandbox
Supply one ZIP per plugin in environment.plugins. Each ZIP must contain one plugin folder with .codex-plugin/plugin.json inside it. The request’s name and description must match the manifest.
This helper packages your folder and creates a session. Pass your API client and the path to docs-helper. OpenAI extracts and registers the plugin automatically.
import base64
import json
import shutil
from pathlib import Path
from tempfile import TemporaryDirectory
def upload_plugin(client, plugin_directory):
plugin_directory = Path(plugin_directory).resolve()
manifest = json.loads((plugin_directory / ".codex-plugin/plugin.json").read_text())
with TemporaryDirectory() as temporary:
archive = shutil.make_archive(
str(Path(temporary) / "plugin"),
"zip",
root_dir=plugin_directory.parent,
base_dir=plugin_directory.name,
)
return client.beta.agents.sessions.create(
agent={"model": "gpt-6-astra"},
environment={
"type": "openai_hosted",
"plugins": [
{
"type": "inline",
"name": manifest["name"],
"description": manifest["description"],
"source": {
"type": "base64",
"media_type": "application/zip",
"data": base64.b64encode(
Path(archive).read_bytes()
).decode(),
},
}
],
},
)Reuse a hosted plugin setup
Create an environment template with the plugin list. For later sessions, set environment.environment_template_id to the saved template ID.
Omit environment.plugins to inherit the template’s plugin list. Supplying a list replaces it. Each session gets its own environment; the root agent and its subagents share it.
Authenticate MCP servers
The example needs no authentication. For other plugin MCP servers:
- HTTP:
bearer_token_env_varreads an environment variable and sends its value as a bearer token. Otherhttp_headersvalues are literal;env_http_headersis not supported. - Stdio:
env_varslists environment variables to pass to the server process. Install the executable and its dependencies in the environment. A relativecwdresolves from the plugin root.
Keep secrets out of plugin files and archives. Plugin MCP connections run from the session’s environment. See MCP authentication for credential boundaries.
For hosted stdio MCPs, omit the network policy or set it to enabled. The disabled and restricted network policies are not supported for these connections.
Test a plugin
Send a normal session message that asks for the skill:
Use docs-search to explain how to stream Responses API output. Include links to the documentation.
Check that the turn completed and that its saved items include a successful call to openai_docs. The answer should follow the skill’s instructions and cite the documentation. For a skill-only plugin, check its output against the instructions; an MCP call is not required.
Create a new session after changing plugin files or a template. Existing sessions do not reload the tools. For connection errors, see MCP troubleshooting. Delete test sessions and stop self-hosted compute when finished.