Skip to content

How to Create Custom OpenAI Codex Plugins with @plugin-creator

Problem

My team has a custom deployment pipeline that no generic plugin covers. We deploy to a proprietary internal platform with specific validation steps, rollback procedures, and approval workflows. When I asked Codex to help with deployments, it would suggest generic solutions that didn’t fit our process.

I tried documenting our workflow in comments and README files, but that documentation became stale. Team members would forget steps or use outdated commands. We needed a way to capture this knowledge in a reusable, executable format.

What is @plugin-creator?

@plugin-creator is a tool that helps me prototype Codex plugins locally. It guides through defining skills, configuring MCP integrations, and packaging everything into an installable plugin.

The tool solves this problem: Teams have unique workflows that generic plugins don’t cover. Custom deployment pipelines, proprietary integrations, company-specific coding standards—these require custom solutions.

With @plugin-creator, I can:

  • Define skills my plugin provides
  • Configure MCP connections to external tools
  • Add app integrations for IDE support
  • Test locally before sharing
  • Package and distribute to team or community

Environment

  • Node.js 18+ or Python 3.10+
  • Codex CLI installed
  • Basic understanding of MCP (Model Context Protocol)
  • A workflow you want to automate

Getting Started

First, I installed @plugin-creator:

installation.sh
npm install -g @openai/plugin-creator
# Verify installation
plugin-creator --version

I got this output:

Terminal window
@openai/plugin-creator v2.1.0

Then I initialized a new plugin project:

create-plugin.sh
plugin-creator init my-deploy-plugin
cd my-deploy-plugin

The tool created this structure:

Project Structure
my-deploy-plugin/
├── plugin.json
├── skills/
│ └── deploy.yaml
├── mcp/
│ └── servers.json
├── integrations/
│ └── vscode.json
└── README.md

Defining Skills

Skills are the core of a Codex plugin. Each skill defines a capability the plugin provides.

I opened skills/deploy.yaml and defined my deployment skill:

skills/deploy.yaml
name: deploy
description: Deploy application to internal platform with validation and rollback
trigger:
phrases:
- "deploy to staging"
- "deploy to production"
- "run deployment"
patterns:
- "deploy.*to.*(staging|production)"
steps:
- name: validate
action: run_command
command: npm run validate
fail_message: "Validation failed. Check the errors above."
- name: build
action: run_command
command: npm run build
fail_message: "Build failed. Fix the errors before deploying."
- name: notify
action: run_command
command: ./scripts/notify-team.sh
args:
environment: "${target_env}"
- name: deploy
action: run_command
command: ./scripts/deploy.sh
args:
environment: "${target_env}"
version: "${version}"
- name: verify
action: run_command
command: ./scripts/verify-deployment.sh
timeout: 300
fail_message: "Deployment verification failed. Check logs."

The skill definition uses trigger phrases and patterns. When I say “deploy to staging,” Codex recognizes this and runs through the steps.

I also added a rollback skill for emergencies:

skills/rollback.yaml
name: rollback
description: Rollback to previous deployment version
trigger:
phrases:
- "rollback deployment"
- "undo last deploy"
steps:
- name: confirm
action: ask_user
message: "Rollback to which version? (last, or specify version tag)"
- name: rollback
action: run_command
command: ./scripts/rollback.sh
args:
version: "${user_response}"

Configuring MCP Connections

MCP (Model Context Protocol) lets my plugin connect to external tools. I configured connections to our internal systems.

I edited mcp/servers.json:

mcp/servers.json
{
"servers": {
"internal-api": {
"command": "node",
"args": ["./mcp-servers/internal-api/index.js"],
"env": {
"API_URL": "${INTERNAL_API_URL}",
"API_KEY": "${INTERNAL_API_KEY}"
}
},
"deployment-tracker": {
"command": "python",
"args": ["./mcp-servers/deployment-tracker/main.py"],
"env": {
"TRACKER_URL": "${DEPLOYMENT_TRACKER_URL}"
}
}
}
}

Then I created the MCP server for our internal API:

mcp-servers/internal-api/index.ts
import { Server } from '@modelcontextprotocol/sdk/server/index.js'
import { StdioServerTransport } from '@modelcontextprotocol/sdk/server/stdio.js'
import {
CallToolRequestSchema,
ListToolsRequestSchema,
} from '@modelcontextprotocol/sdk/types.js'
const server = new Server(
{ name: 'internal-api', version: '1.0.0' },
{ capabilities: { tools: {} } }
)
server.setRequestHandler(ListToolsRequestSchema, async () => ({
tools: [
{
name: 'check_service_status',
description: 'Check status of internal services',
inputSchema: {
type: 'object',
properties: {
service: {
type: 'string',
description: 'Service name (api, worker, cache)'
}
},
required: ['service']
}
},
{
name: 'get_deployment_history',
description: 'Get recent deployment history for a service',
inputSchema: {
type: 'object',
properties: {
service: { type: 'string' },
limit: { type: 'number', default: 10 }
},
required: ['service']
}
}
]
}))
server.setRequestHandler(CallToolRequestSchema, async (request) => {
const { name, arguments: args } = request.params
if (name === 'check_service_status') {
const status = await fetchServiceStatus(args?.service)
return {
content: [{ type: 'text', text: JSON.stringify(status, null, 2) }]
}
}
if (name === 'get_deployment_history') {
const history = await fetchDeploymentHistory(args?.service, args?.limit)
return {
content: [{ type: 'text', text: JSON.stringify(history, null, 2) }]
}
}
throw new Error(`Unknown tool: ${name}`)
})
async function main() {
const transport = new StdioServerTransport()
await server.connect(transport)
}
main().catch(console.error)

Adding App Integrations

App integrations let my plugin work with IDEs and other tools. I added VS Code support.

I edited integrations/vscode.json:

integrations/vscode.json
{
"commands": [
{
"command": "myDeployPlugin.deploy",
"title": "Deploy Current Project",
"category": "Deploy"
},
{
"command": "myDeployPlugin.rollback",
"title": "Rollback Deployment",
"category": "Deploy"
}
],
"menus": {
"commandPalette": [
{
"command": "myDeployPlugin.deploy",
"when": "workspaceFolderCount > 0"
}
]
},
"keybindings": [
{
"command": "myDeployPlugin.deploy",
"key": "ctrl+shift+d",
"mac": "cmd+shift+d"
}
]
}

Testing Locally

Before packaging, I tested the plugin locally:

test-plugin.sh
# Install dependencies
npm install
# Run local test
plugin-creator test
# Test specific skill
plugin-creator test --skill deploy

The test output showed:

Testing plugin: my-deploy-plugin
Skill: deploy
Trigger: "deploy to staging"
Step 1/5: validate
Command: npm run validate
Status: PASS
Step 2/5: build
Command: npm run build
Status: PASS
Step 3/5: notify
Command: ./scripts/notify-team.sh
Status: PASS
Step 4/5: deploy
Command: ./scripts/deploy.sh --env staging
Status: PASS
Step 5/5: verify
Command: ./scripts/verify-deployment.sh
Status: PASS
All tests passed.

I also tested the MCP server:

test-mcp.sh
npx mcp-inspector node ./mcp-servers/internal-api/index.ts

The inspector showed:

MCP Inspector running at http://localhost:5173
Server connected: internal-api v1.0.0
Available tools:
- check_service_status
- get_deployment_history

Packaging and Distribution

Once tests passed, I packaged the plugin:

package-plugin.sh
plugin-creator package
# Output
# Created: my-deploy-plugin-1.0.0.tgz

I shared it with my team by publishing to our internal registry:

publish-plugin.sh
plugin-creator publish --registry https://plugins.internal.company.com

Team members installed it with:

install-plugin.sh
codex plugin install @company/my-deploy-plugin

For public distribution, I published to the community registry:

publish-public.sh
plugin-creator publish --public

Best Practices

DO

Start with a clear problem

Define what workflow you’re automating before creating the plugin. My deployment plugin solved a specific problem: our internal deployment process wasn’t captured anywhere.

Test each skill independently

Terminal window
plugin-creator test --skill deploy
plugin-creator test --skill rollback

Use environment variables for secrets

{
"env": {
"API_KEY": "${INTERNAL_API_KEY}"
}
}

Document trigger phrases

Tell your team how to invoke each skill. I added a quick reference to our README:

## Usage
- "deploy to staging" - Deploy to staging environment
- "deploy to production" - Deploy to production (requires approval)
- "rollback deployment" - Rollback to previous version

DON’T

Don’t hardcode secrets

// WRONG
const apiKey = 'sk-internal-xxxxx'
// CORRECT
const apiKey = process.env.INTERNAL_API_KEY

Don’t skip validation steps

Each deployment skill should validate before acting. This prevents bad deployments:

steps:
- name: validate
action: run_command
command: npm run validate
fail_message: "Validation failed"

Don’t forget error handling

MCP tools should handle errors gracefully:

try {
const result = await fetchServiceStatus(service)
return { content: [{ type: 'text', text: JSON.stringify(result) }] }
} catch (error) {
return {
content: [{ type: 'text', text: `Error: ${error.message}` }],
isError: true
}
}

Don’t make triggers too broad

# WRONG - too broad
trigger:
patterns:
- "deploy.*"
# CORRECT - specific
trigger:
phrases:
- "deploy to staging"
- "deploy to production"

Common Issues

Issue 1: MCP Server Not Connecting

When I ran the test, I got:

Error: MCP server "internal-api" failed to connect

The issue was missing environment variables. I added them to .env:

.env
INTERNAL_API_URL=https://api.internal.company.com
INTERNAL_API_KEY=sk-internal-xxxxx

Then I loaded them in the test:

Terminal window
plugin-creator test --env-file .env

Issue 2: Skills Not Triggering

My skill wasn’t being recognized. I checked the trigger patterns:

# WRONG - pattern didn't match natural language
trigger:
patterns:
- "^deploy$"
# CORRECT - includes common phrases
trigger:
phrases:
- "deploy to staging"
- "deploy to production"
patterns:
- "deploy.*to.*(staging|production)"

Issue 3: Package Too Large

When packaging, I got:

Warning: Package exceeds 50MB limit

I added files to .pluginignore:

.pluginignore
node_modules/
*.log
.env
tests/fixtures/

Summary

In this post, I showed how to create custom Codex plugins using @plugin-creator. The key points are:

  • Custom plugins capture team-specific workflows in reusable format
  • Skills define what the plugin does and when it triggers
  • MCP connections let plugins interact with external systems
  • Test locally before packaging and distribution
  • Use environment variables for secrets, never hardcode them

My deployment plugin transformed our team’s tacit knowledge into an executable workflow. Now when someone says “deploy to staging,” Codex runs through our validation, build, notification, and deployment steps automatically. No more missed steps or outdated documentation.

Final Words + More Resources

My intention with this article was to help others share my knowledge and experience. If you want to contact me, you can contact by email: Email me

Here are also the most important links from this article along with some further resources that will help you in this scope:

Oh, and if you found these resources useful, don’t forget to support me by starring the repo on GitHub!

Comments