Skill: mcp-codegen
Understand and work with the TypeScript and Python code generated by mcp-server-builder.
Best use case
Skill: mcp-codegen is best used when you need a repeatable AI agent workflow instead of a one-off prompt.
Understand and work with the TypeScript and Python code generated by mcp-server-builder.
Teams using Skill: mcp-codegen should expect a more consistent output, faster repeated execution, less prompt rewriting.
When to use this skill
- You want a reusable workflow that can be run more than once with consistent structure.
When not to use this skill
- You only need a quick one-off answer and do not need a reusable workflow.
- You cannot install or maintain the underlying files, dependencies, or repository context.
Installation
Claude Code / Cursor / Codex
Manual Installation
- Download SKILL.md from GitHub
- Place it in
.claude/skills/mcp-codegen/SKILL.mdinside your project - Restart your AI agent — it will auto-discover the skill
How Skill: mcp-codegen Compares
| Feature / Agent | Skill: mcp-codegen | Standard Approach |
|---|---|---|
| Platform Support | Not specified | Limited / Varies |
| Context Awareness | High | Baseline |
| Installation Complexity | Unknown | N/A |
Frequently Asked Questions
What does this skill do?
Understand and work with the TypeScript and Python code generated by mcp-server-builder.
Where can I find the source code?
You can find the source code on GitHub using the link provided at the top of the page.
Related Guides
SKILL.md Source
# Skill: mcp-codegen
Understand and work with the TypeScript and Python code generated by mcp-server-builder.
---
## What Gets Generated
mcp-server-builder generates a single-file MCP server in TypeScript or Python. The generated file is a complete, runnable server that only needs stub functions filled in with real implementation logic.
---
## TypeScript Output Structure
Generated file: `<server-name>.ts`
```
1. File header comment (name, version, generator info)
2. Imports: @modelcontextprotocol/sdk
3. Server instantiation: new Server({ name, version })
4. TOOLS array: all tool definitions with inputSchema
5. ListToolsRequestSchema handler: returns TOOLS
6. CallToolRequestSchema handler: switch on tool name
7. Per-tool stub async functions with typed args
8. RESOURCES array: all resource definitions
9. ListResourcesRequestSchema handler
10. ReadResourceRequestSchema handler
11. Transport setup + server.connect()
```
### TypeScript tool stub signature
For a tool with input schema:
```json
{
"properties": {
"query": { "type": "string" },
"limit": { "type": "integer" }
},
"required": ["query"]
}
```
The generated stub is:
```typescript
async function web_search(args: { query: string; limit?: number }) {
// TODO: implement web_search logic
throw new Error("Not implemented");
}
```
JSON Schema types map to TypeScript:
- `string` -> `string`
- `integer` / `number` -> `number`
- `boolean` -> `boolean`
- `array` -> `unknown[]`
- `object` -> `Record<string, unknown>`
Optional properties (not in `required`) get `?` suffix.
### Running TypeScript output
```bash
# Install deps
npm install @modelcontextprotocol/sdk zod
# Run (ts-node)
npx ts-node my-server.ts
# Or compile first
npx tsc my-server.ts --module commonjs --target es2020 --outDir dist
node dist/my-server.js
```
---
## Python Output Structure
Generated file: `<server_name>.py`
```
1. Module docstring (name, version, generator info)
2. Imports: asyncio, typing, mcp, mcp.server, mcp.types
3. server = Server("name")
4. @server.list_tools() handler returning list[types.Tool]
5. @server.call_tool() handler with if/elif dispatch
6. Per-tool stub async functions with type hints
7. @server.list_resources() handler
8. @server.read_resource() handler
9. async def main() with stdio_server context manager
10. if __name__ == "__main__": asyncio.run(main())
```
### Python tool stub signature
For the same schema:
```python
async def web_search(query: str, limit: int = 10) -> list[types.TextContent]:
# TODO: implement web_search logic
raise NotImplementedError()
```
JSON Schema types map to Python:
- `string` -> `str`
- `integer` -> `int`
- `number` -> `float`
- `boolean` -> `bool`
- `array` -> `list`
- `object` -> `dict`
Optional properties get default value `None` (or schema `default` if provided).
### Running Python output
```bash
# Install deps
pip install mcp
# Run
python my_server.py
```
---
## Claude Desktop Integration
After running the server, add it to Claude Desktop's `claude_desktop_config.json`:
### stdio transport (most common)
```json
{
"mcpServers": {
"my-server": {
"command": "node",
"args": ["/absolute/path/to/my-server.js"]
}
}
}
```
For Python:
```json
{
"mcpServers": {
"my-server": {
"command": "python",
"args": ["/absolute/path/to/my_server.py"]
}
}
}
```
### sse transport
```json
{
"mcpServers": {
"my-server": {
"url": "http://localhost:8080/sse"
}
}
}
```
### http transport
```json
{
"mcpServers": {
"my-server": {
"url": "http://localhost:8080/mcp"
}
}
}
```
Config file locations:
- macOS: `~/Library/Application Support/Claude/claude_desktop_config.json`
- Windows: `%APPDATA%\Claude\claude_desktop_config.json`
- Linux: `~/.config/Claude/claude_desktop_config.json`
---
## Filling in Stub Functions
The generated stubs have `throw new Error("Not implemented")` (TypeScript) or `raise NotImplementedError()` (Python). Replace them with real logic.
### TypeScript example: read_file
Generated stub:
```typescript
async function read_file(args: { path: string; encoding?: string }) {
throw new Error("Not implemented");
}
```
Implemented:
```typescript
import { readFile as fsReadFile } from "node:fs/promises";
async function read_file(args: { path: string; encoding?: string }) {
const encoding = (args.encoding ?? "utf-8") as BufferEncoding;
const content = await fsReadFile(args.path, { encoding });
const stat = await import("node:fs/promises").then(m => m.stat(args.path));
return {
content: [{ type: "text" as const, text: JSON.stringify({ content, size: stat.size }) }]
};
}
```
### Python example: read_file
Generated stub:
```python
async def read_file(path: str, encoding: str = "utf-8") -> list[types.TextContent]:
raise NotImplementedError()
```
Implemented:
```python
import aiofiles
import json
import os
async def read_file(path: str, encoding: str = "utf-8") -> list[types.TextContent]:
async with aiofiles.open(path, encoding=encoding) as f:
content = await f.read()
size = os.path.getsize(path)
result = json.dumps({"content": content, "size": size, "encoding": encoding})
return [types.TextContent(type="text", text=result)]
```
---
## Tool Return Format
MCP tools return a list of content blocks. The generated code uses `TextContent` by default:
TypeScript:
```typescript
return {
content: [{ type: "text", text: JSON.stringify(result) }]
};
```
Python:
```python
return [types.TextContent(type="text", text=json.dumps(result))]
```
For image content:
```typescript
return {
content: [{ type: "image", data: base64Data, mimeType: "image/png" }]
};
```
---
## Adding to the Generated Code
After exporting, you may need to add:
- Environment variable reading (`process.env.API_KEY` / `os.environ["API_KEY"]`)
- HTTP client imports (`node-fetch`, `axios`, `httpx`, `aiohttp`)
- Database connections
- Authentication headers
The generated file is yours to modify. Re-export from mcp-server-builder if you add new tools or change schemas (not for implementation logic).
---
## Validation Rules
The code generator enforces these rules before generating:
| Rule | Detail |
|------|--------|
| Tool name | snake_case, no spaces, no hyphens |
| Schema depth | Max 3 levels of nested objects |
| Required fields | `name`, `description` per tool |
| URI template | Valid RFC 6570 syntax |
| Version | Semver format (1.0.0) |
| Transport | One of: stdio, sse, http |
If any rule is violated, the export endpoint returns a 400 error with a structured error list.
---
## Common Patterns
### Tool that calls an external API
```typescript
async function fetch_stock_price(args: { symbol: string }) {
const resp = await fetch(`https://api.example.com/quote/${args.symbol}`);
const data = await resp.json();
return {
content: [{ type: "text", text: JSON.stringify({
symbol: args.symbol,
price: data.price,
change: data.change
})}]
};
}
```
### Tool that reads from a database
```typescript
import Database from "better-sqlite3";
const db = new Database("./data.db");
async function query_users(args: { name_filter?: string }) {
const rows = name_filter
? db.prepare("SELECT * FROM users WHERE name LIKE ?").all(`%${args.name_filter}%`)
: db.prepare("SELECT * FROM users").all();
return {
content: [{ type: "text", text: JSON.stringify(rows) }]
};
}
```
### Resource handler
```typescript
server.setRequestHandler(ReadResourceRequestSchema, async (request) => {
const uri = request.params.uri;
// Match uri pattern and return content
if (uri.startsWith("file://")) {
const path = uri.replace("file://", "");
const content = await readFile(path, "utf-8");
return { contents: [{ uri, mimeType: "text/plain", text: content }] };
}
throw new Error(`Unknown resource: ${uri}`);
});
```Related Skills
Skill: Uptime Monitoring
## Overview
Skill: Status Page
## Overview
Skill: unit-conversion
## Overview
Skill: recipe-scaler
## Overview
reading-list
Operate the reading-list API to save, manage, tag, search, and export articles.
email-digest
Configure, test, and troubleshoot the reading-list daily email digest delivered via nodemailer.
websocket-realtime
Use the WebSocket connection in poll-builder to receive live vote updates. Use when you need to stream real-time poll results, monitor a poll for new votes, or build a live dashboard. Triggers include "live results", "real-time updates", "stream votes", "watch poll", or "WebSocket".
poll-builder
Self-hosted poll creation tool with real-time results. Use when you need to create a poll, check vote counts, close a poll, export results, or get the shareable link for a poll. Triggers include "create poll", "vote", "poll results", "survey", "collect votes", "share poll", or any task involving polling or voting.
Skill: personal-finance
## Overview
Skill: csv-import
## Overview
Skill: Syntax Highlighting
## Purpose
Skill: Pastebin Core
## Purpose