Context Course documentation
Building Your Own Plugin
Building Your Own Plugin
Unit 2 produced a text-processor MCP server. In this lesson we package it as a plugin. For Claude Code and Codex that means a manifest plus bundled skills and MCP config; for OpenCode it means a plugin module written in TypeScript, with MCP configuration handled separately; for Pi it means a package declared in package.json, optionally paired with pi-mcp-adapter when you want MCP tools inside Pi.
Plugin Project Structure
Create your plugin directory alongside the server you already built:
mkdir text-processor-plugin
cd text-processor-plugin
# Directory structure
mkdir -p skills/{analyze-text,extract-keywords,check-reading-level}
# Create core files
touch README.md
touch skills/analyze-text/SKILL.md
touch skills/extract-keywords/SKILL.md
touch skills/check-reading-level/SKILL.mdNotice what’s different from Unit 2: no server code here. For Claude Code and Codex, the plugin references the MCP server you already built and deployed. OpenCode’s native plugin branch below adds behavior in code and can still point at the same server separately if you want both surfaces. The Pi branch below reuses the same skills/ directory inside a Pi package, and can pair those skills with the pi-mcp-adapter setup from Unit 2 when you want MCP tools available in Pi.
Step 1: Write the Skills
This step applies directly to Claude Code, Codex, and Pi, where the bundle can ship skills/. If you’re following the OpenCode branch, skip ahead to Step 2: OpenCode plugins are code modules, not skill bundles.
Skills teach the agent when and how to use your MCP tools. Each skill wraps one of the tools from your text-processor server.
Skill 1: Analyze Text
Create skills/analyze-text/SKILL.md:
# Analyze Text
Use the `analyze_text` tool from the text-processor MCP server to compute text statistics.
## When to Use
Use this skill when the user asks about text statistics, word counts, character counts, sentence counts, average word length, or readability metrics.
## How to Use
Call the `analyze_text` tool with the full text as input. The tool returns JSON with:
- `total_characters`, `characters_without_spaces`
- `total_words`, `total_sentences`
- `average_word_length`, `average_sentence_length`
- `unique_words`
## Example
User: "How complex is this paragraph?"
1. Call `analyze_text` with the paragraph
2. Interpret the statistics (high unique word ratio = diverse vocabulary, long average sentence length = complex prose)
3. Summarize findings in plain languageSkill 2: Extract Keywords
Create skills/extract-keywords/SKILL.md:
# Extract Keywords
Use the `extract_keywords` tool from the text-processor MCP server to find the most important words in text.
## When to Use
Use this skill when the user asks for keywords, key terms, topic extraction, or content summarization.
## How to Use
Call `extract_keywords` with the text and an optional `count` parameter (default: 5). The tool returns JSON with a `keywords` array, each containing `word` and `frequency`.
## Example
User: "What are the main topics in this article?"
1. Call `extract_keywords` with count=10
2. Group related keywords into themes
3. Present themes with supporting keyword frequenciesSkill 3: Check Reading Level
Create skills/check-reading-level/SKILL.md:
# Check Reading Level
Use the `check_reading_level` tool from the text-processor MCP server to estimate text difficulty.
## When to Use
Use this skill when the user asks about reading level, text difficulty, grade level, or audience appropriateness.
## How to Use
Call `check_reading_level` with the text. The tool returns JSON with:
- `grade_level` (numeric Flesch-Kincaid grade)
- `reading_level` (Elementary School, Middle School, High School, or College/Academic)
## Example
User: "Is this documentation appropriate for beginners?"
1. Call `check_reading_level` with the text
2. Compare the grade level to the target audience
3. Suggest simplifications if the level is too highStep 2: Create the Plugin Entry Point
Claude Code and Codex use manifests to declare what the plugin provides. OpenCode uses a plugin module instead. Pi uses package.json plus optional extensions/. The entry point differs by platform.
Create the Claude Code manifest directory:
mkdir -p .claude-pluginCreate .claude-plugin/plugin.json:
{
"name": "text-processor-plugin",
"version": "1.0.0",
"description": "Text analysis skills powered by the text-processor MCP server",
"author": {
"name": "Your Name"
}
}Create .mcp.json to point at your server. If you’re using the local server from Unit 2:
{
"mcpServers": {
"text-processor": {
"command": "python",
"args": ["../text-processor-mcp/server.py"]
}
}
}Or if you deployed to Hugging Face Spaces:
{
"mcpServers": {
"text-processor": {
"url": "https://YOUR-USERNAME-text-processor-mcp.hf.space/gradio_api/mcp/"
}
}
}Step 3: Create the Human-Facing README
For all three platforms, keep human documentation in README.md. Claude Code and Codex use plugin.json for install metadata; OpenCode loads the plugin module directly, so the README is for developers rather than the runtime.
Create README.md at the plugin root:
# Text Processor Plugin
Plugin examples for text-analysis workflows built from the Unit 2 server and the Unit 3 skills.
## Skills
- **Analyze Text** — Word counts, sentence stats, vocabulary diversity
- **Extract Keywords** — Find the most frequent meaningful terms
- **Check Reading Level** — Flesch-Kincaid grade level estimation
## Claude Code and Codex
The manifest-first versions bundle:
- skills in `skills/`
- plugin metadata in `.claude-plugin/plugin.json` or `.codex-plugin/plugin.json`
- optional MCP config in `.mcp.json`
## OpenCode
The OpenCode version is a local or npm-loaded JS/TS plugin module under `.opencode/plugins/` or the `plugin` array in `opencode.json`.
## Related MCP Server
If you also connect the `text-processor` MCP server, it provides:
- `analyze_text` — Compute text statistics
- `extract_keywords` — Extract frequent terms
- `check_reading_level` — Estimate reading difficulty
- `reverse_text` — Reverse a string
## Setup
The plugin can use your local server or the deployed Spaces version:
**Local:** Ensure `text-processor-mcp/server.py` is available and the MCP runtime is installed.
**Remote:** Update the `.mcp.json` or `opencode.json` URL to your deployed Space:
`https://YOUR-USERNAME-text-processor-mcp.hf.space/gradio_api/mcp/`Step 4: Test Your Plugin
To test a local plugin, expose it through a local marketplace file. Create marketplace.json next to your plugin directory:
{
"name": "local-example-plugins",
"owner": { "name": "you" },
"plugins": [
{
"name": "text-processor-plugin",
"source": "./text-processor-plugin",
"description": "Text analysis skills"
}
]
}Then inside Claude Code:
/plugin marketplace add /absolute/path/to/marketplace.json /plugin install text-processor-plugin@local-example-plugins
Once installed, test the skills conversationally:
Analyze the reading level of this text: "The mitochondria is the powerhouse of the cell. It provides energy through oxidative phosphorylation."
After editing plugin files, use /plugin to disable and re-enable the plugin so Claude Code picks up changes.
Complete Plugin Structure
For Claude Code and Codex (assuming you use both), the final manifest-first plugin directory looks like:
text-processor-plugin/
├── .claude-plugin/
│ └── plugin.json # Claude Code manifest
├── .codex-plugin/
│ └── plugin.json # Codex manifest
├── .mcp.json # Shared MCP config for both
├── README.md # Documentation
└── skills/
├── analyze-text/SKILL.md
├── extract-keywords/SKILL.md
└── check-reading-level/SKILL.mdFor OpenCode, the plugin surface is separate:
.opencode/ ├── plugins/ │ └── text-processor-plugin.ts └── package.json # optional
Notice there’s no server code in the manifest-first plugin. The MCP server lives separately — either running locally from Unit 2’s text-processor-mcp/ directory or deployed on Hugging Face Spaces. Claude Code and Codex point at that server through .mcp.json. OpenCode can point at it separately in opencode.json, but that MCP config is adjacent to the plugin rather than inside it.
This separation is a key design principle: skills describe how to use tools, MCP servers provide the tools, and plugins package reusable agent behavior in the way each platform expects.
Best Practices
When building plugins, write skill descriptions that explain when to use a tool (not just what it does), reference existing MCP servers instead of duplicating code, keep only plugin.json inside the manifest directory, never hardcode API keys (use environment variables), version semantically (1.0.0, 1.1.0, 2.0.0), and test locally before publishing. For OpenCode, keep the plugin module small and focused, then add npm dependencies only when the hook or tool really needs them.
Key Takeaways
Claude Code and Codex plugins are manifests that bundle skills and optional MCP or app config. OpenCode plugins are JS/TS modules; skills and MCP servers live beside them. In both worlds the MCP server from Unit 2 stays where it is — the plugin just references or complements it.
Next, a quiz, then installing and using published plugins.
Update on GitHub