Create MCP Plugin
Step 0: Language selection
Before proceeding with any other steps in this skill, ask the user which language to continue in using AskUserQuestion. Keep this initial prompt in English because the preferred language is not yet known.
- Question:
Which language should I continue in? - Options:
English,日本語 (Japanese)
Use the selected language for all subsequent user-facing messages and for every further AskUserQuestion prompt in this skill. Do not translate code, file paths, shell commands, or file contents.
Scaffold a new MCP plugin that runs inside agent containers, following the established pattern (mcp-ollama, mcp-vercel).
UX Note: Use AskUserQuestion for all user-facing questions.
Step 1: Gather information
AskUserQuestion:
- Plugin name (lowercase, no
mcp-prefix — e.g., "youtube", "github", "notion") - One-line description (e.g., "YouTube analytics and video search")
- Does it need an API token/key? If yes, what env var name? (e.g.,
YOUTUBE_API_KEY)
Step 2: Generate package
Create container/plugins/mcp-{name}/ with three files:
package.json
{
"name": "@nagi/mcp-{name}",
"version": "0.0.1",
"type": "module",
"main": "dist/index.js",
"scripts": {
"build": "tsc",
"start": "node dist/index.js",
"lint": "tsc --noEmit"
},
"dependencies": {
"@modelcontextprotocol/sdk": "^1.12.1",
"zod": "^4.3.6"
},
"devDependencies": {
"@types/node": "^22.10.0",
"typescript": "^5.7.0"
}
}
tsconfig.json
{
"compilerOptions": {
"target": "ES2022",
"module": "NodeNext",
"moduleResolution": "NodeNext",
"lib": ["ES2022"],
"outDir": "./dist",
"rootDir": "./src",
"strict": true,
"esModuleInterop": true,
"skipLibCheck": true,
"forceConsistentCasingInFileNames": true,
"declaration": true,
"declarationMap": true,
"sourceMap": true
},
"include": ["src/**/*"],
"exclude": ["node_modules", "dist"]
}
src/index.ts
Generate a starter MCP server with a placeholder tool. Follow this pattern:
/**
* {Name} MCP Server for Nagi
* {description}
*/
import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio.js";
import { z } from "zod";
// Read config from environment (passed via entry.ts registerMcpPlugin env option)
const API_TOKEN = process.env.{ENV_VAR} || "";
function log(msg: string): void {
console.error(`[{NAME_UPPER}] ${msg}`);
}
const server = new McpServer({
name: "{name}",
version: "1.0.0",
});
// TODO: Add tools here
server.tool(
"{name}_hello",
"A placeholder tool — replace with real functionality",
{
message: z.string().describe("A test message"),
},
async (args) => {
log(`Hello: ${args.message}`);
return {
content: [{ type: "text" as const, text: `Hello from {name}: ${args.message}` }],
};
},
);
const transport = new StdioServerTransport();
await server.connect(transport);
log("{Name} MCP server started");
Replace all {name}, {Name}, {NAME_UPPER}, {description}, {ENV_VAR} placeholders.
If no API token is needed, remove the API_TOKEN line.
Step 3: Add to Dockerfile
AskUserQuestion: Which agent's Dockerfile should include this plugin?
- Claude Code —
container/claude-code/Dockerfile - Open Code —
container/open-code/Dockerfile - Both — Add to both
Append the following block to the selected Dockerfile before the # Create workspace directories line:
COPY container/plugins/mcp-{name}/package*.json /app/mcp-plugins/{name}/
RUN cd /app/mcp-plugins/{name} && npm install
COPY container/plugins/mcp-{name}/src/ /app/mcp-plugins/{name}/src/
COPY container/plugins/mcp-{name}/tsconfig.json /app/mcp-plugins/{name}/
RUN cd /app/mcp-plugins/{name} && npx tsc
Step 4: Add to deploy/templates/host/entry.template.ts
Add a registerMcpPlugin block to deploy/templates/host/entry.template.ts:
If API token required:
const {name}Env = readEnvFile(["{ENV_VAR}"]);
if ({name}Env.{ENV_VAR}) {
orchestrator.registerMcpPlugin("{name}", {
entryPoint: "/app/mcp-plugins/{name}/dist/index.js",
env: { {ENV_VAR}: {name}Env.{ENV_VAR} },
});
}
If no API token:
orchestrator.registerMcpPlugin("{name}", {
entryPoint: "/app/mcp-plugins/{name}/dist/index.js",
});
Step 5: Build & verify
pnpm install
pnpm build
All packages must build successfully.
Step 6: Next steps
Tell the user:
- Implement tools — Edit
container/plugins/mcp-{name}/src/index.tsto add real MCP tools - Rebuild Docker image —
./container/claude-code/build.shand/or./container/open-code/build.sh - Sync entry.ts — Run
/deployand select Host to add the plugin registration to your local entry.ts - If API token needed — Add
{ENV_VAR}=...to.env - Restart nagi — Run
/nagi-restart - Test — Send a message in Slack and ask the agent to use the new tools
Reference
Existing MCP plugins to study:
container/plugins/mcp-ollama/— No API token, connects to local service viahost.docker.internalcontainer/plugins/mcp-vercel/— RequiresVERCEL_API_TOKEN, calls external REST API