Install
$ agentstack add skill-rune-kit-rune-mcp-builder ✓ scanned · ✓ verified, works with Claude Code, Cursor, and more.
Security review
✓ PassedNo issues found. Passed automated security review. · v0.1.0 How review works →
- ✓ Prompt-injection patterns
- ✓ Secret / credential exfiltration
- ✓ Dangerous shell & filesystem operations
- ✓ Untrusted network calls
- ✓ Known-malicious package signatures
What it can access
- ✓ Network access No
- ✓ Filesystem access No
- ✓ Shell / process execution No
- ● Environment & secrets Used
- ✓ Dynamic code execution No
From automated source analysis of v0.1.0. “Used” means the capability is present in the source — more access means more to trust, not that it’s unsafe.
Verified badge
Passed review? Show it. Paste this badge into your README, it links to the public security report.
Reliability & compatibility
Declared compatibility
Compatibility is declared by the source manifest. End-to-end runtime verification is coming, see below.
We're building live execution health for every listing: tool-call success rate, median latency, uptime, and last-checked timestamps, measured, not self-reported. It isn't live yet, so we don't show numbers we can't stand behind.
How agent discovery & health will work →About
mcp-builder
Purpose
MCP server builder. Generates complete, tested MCP servers from a natural language description or specification. Handles tool definitions, resource handlers, input validation, error handling, configuration, tests, and documentation. Supports TypeScript (official SDK) and Python (FastMCP).
Triggers
- Called by
cookwhen MCP-related task detected (keywords: "MCP server", "MCP tool", "model context protocol") - Called by
scaffoldwhen MCP Server template selected /rune mcp-builder— manual invocation- Auto-trigger: when project contains
mcp.json,@modelcontextprotocol/sdk, orfastmcpin dependencies
Calls (outbound)
ba(L2): if user description is vague — elicit requirements for what tools/resources the server should exposeresearch(L3): look up target API documentation, existing MCP servers for referencetest(L2): generate and run test suite for the serverdocs(L2): generate server documentation (tool catalog, installation, configuration)verification(L3): verify server builds and tests pass
Called By (inbound)
cook(L1): when MCP-related task detectedscaffold(L1): MCP Server template in Phase 5- User:
/rune mcp-builderdirect invocation
Executable Steps
Step 1 — Spec Elicitation
If description is detailed enough (tools, resources, target API specified), proceed. If vague, ask targeted questions:
- What tools should this MCP server expose? (actions the AI can perform)
- What resources does it manage? (data the AI can read)
- What external APIs does it connect to? (if any)
- TypeScript or Python? (default: TypeScript with @modelcontextprotocol/sdk)
- Authentication? (API keys, OAuth, none)
If user provides a detailed spec or existing API docs → extract answers, confirm.
Step 2 — Architecture Design
Determine server structure based on spec:
TypeScript (default):
mcp-server-/
├── src/
│ ├── index.ts — server entry point, tool/resource registration
│ ├── tools/
│ │ ├── .ts — one file per tool
│ │ └── index.ts — tool registry
│ ├── resources/
│ │ ├── .ts — one file per resource type
│ │ └── index.ts — resource registry
│ ├── lib/
│ │ ├── client.ts — external API client (if applicable)
│ │ └── types.ts — shared types
│ └── config.ts — environment variable validation
├── tests/
│ ├── tools/
│ │ └── .test.ts
│ └── resources/
│ └── .test.ts
├── package.json
├── tsconfig.json
├── .env.example
└── README.md
Python (FastMCP):
mcp-server-/
├── src/
│ ├── server.py — FastMCP server with tool/resource decorators
│ ├── tools/
│ │ └── .py
│ ├── resources/
│ │ └── .py
│ ├── lib/
│ │ ├── client.py — external API client
│ │ └── types.py — Pydantic models
│ └── config.py — settings via pydantic-settings
├── tests/
│ ├── test_.py
│ └── test_.py
├── pyproject.toml
├── .env.example
└── README.md
Step 3 — Generate Server Code
Tool Generation
For each tool:
TypeScript:
import { z } from 'zod';
export const toolName = {
name: 'tool_name',
description: 'What this tool does — used by AI to decide when to call it',
inputSchema: z.object({
param1: z.string().describe('Description for AI'),
param2: z.number().optional().describe('Optional parameter'),
}),
async handler(input: { param1: string; param2?: number }) {
// Implementation
return { content: [{ type: 'text', text: JSON.stringify(result) }] };
},
};
Python (FastMCP):
from fastmcp import FastMCP
mcp = FastMCP("server-name")
@mcp.tool()
async def tool_name(param1: str, param2: int | None = None) -> str:
"""What this tool does — used by AI to decide when to call it."""
# Implementation
return json.dumps(result)
Resource Generation
For each resource:
- URI template with parameters
- Read handler that returns structured content
- List handler for collections
Configuration
Generate .env.example with all required environment variables:
# Required
API_KEY=your_api_key_here
API_BASE_URL=https://api.example.com
# Optional
LOG_LEVEL=info
CACHE_TTL=300
Generate config validation:
// config.ts
import { z } from 'zod';
const envSchema = z.object({
API_KEY: z.string().min(1, 'API_KEY is required'),
API_BASE_URL: z.string().url().default('https://api.example.com'),
LOG_LEVEL: z.enum(['debug', 'info', 'warn', 'error']).default('info'),
});
export const config = envSchema.parse(process.env);
Step 3.5 — Tool Safety Classification
Before generating tests, classify every tool as query or mutation:
| Category | Examples | Behavior | |---|---|---| | query | read, list, search, get, fetch | Auto-approve — no confirmation needed | | mutation | create, update, delete, send, write, publish | Require user confirmation before execution |
Implementation rules:
- Add
safetymetadata to each tool definition:
export const deleteTool = {
name: 'delete_user',
description: '...',
safety: 'mutation' as const, // ← add this
inputSchema: z.object({ id: z.string() }),
async handler(input) { ... },
};
- For every
mutationtool, generate a preview step that surfaces WHAT WILL HAPPEN before the action runs:
// In the handler, before executing:
if (tool.safety === 'mutation') {
return {
content: [{ type: 'text', text:
`⚠️ Will delete user "${user.name}" (ID: ${input.id}). This cannot be undone.\nConfirm? (yes/no)`
}],
requiresConfirmation: true,
};
}
// Proceed only after confirmation received
- For Python (FastMCP), add a
@confirm_mutationdecorator or inline guard in the docstring:
@mcp.tool()
async def delete_user(id: str) -> str:
"""[MUTATION] Delete a user by ID. Will prompt for confirmation before executing."""
...
- Document the safety classification in the README tool catalog (add a
🔒badge on mutation tools).
Step 4 — Generate Tests
For each tool:
- Happy path: valid input → expected output
- Validation: invalid input → proper error message
- Error handling: API failure → graceful error response
- Edge cases: empty input, max limits, special characters
For each resource:
- Read: valid URI → expected content
- Not found: invalid URI → proper error
- List: collection URI → paginated results
describe('tool_name', () => {
it('should return results for valid input', async () => {
const result = await toolName.handler({ param1: 'test' });
expect(result.content[0].type).toBe('text');
// Assert expected structure
});
it('should handle API errors gracefully', async () => {
// Mock API failure
const result = await toolName.handler({ param1: 'trigger-error' });
expect(result.isError).toBe(true);
});
});
Step 5 — Generate Documentation
Produce README.md with:
- Server description and purpose
- Tool catalog (name, description, parameters, example usage)
- Resource catalog (URI templates, content types)
- Installation instructions (npm/pip, Claude Code config, Cursor config)
- Configuration reference (all env vars with descriptions)
- Example usage showing AI interactions
Claude Code installation snippet:
{
"mcpServers": {
"server-name": {
"command": "node",
"args": ["path/to/dist/index.js"],
"env": {
"API_KEY": "your_key"
}
}
}
}
Step 6 — Verify
Invoke rune:verification:
- TypeScript:
tsc --noEmit+npm test - Python:
mypy src/+pytest - Ensure all tools respond correctly
- Ensure configuration validation works
Output Format
Generated Project Structure
TypeScript:
mcp-server-/
├── src/
│ ├── index.ts — server entry, tool/resource registration
│ ├── tools/.ts — one file per tool (Zod input schema + handler)
│ ├── resources/.ts — one file per resource (URI template + reader)
│ ├── lib/client.ts — external API client
│ ├── lib/types.ts — shared TypeScript interfaces
│ └── config.ts — env var validation (Zod schema)
├── tests/tools/.test.ts — per-tool tests (happy, validation, error, edge)
├── tests/resources/.test.ts
├── package.json, tsconfig.json, .env.example, README.md
Python (FastMCP):
mcp-server-/
├── src/
│ ├── server.py — FastMCP server with @mcp.tool() decorators
│ ├── tools/.py — tool implementations
│ ├── resources/.py
│ ├── lib/client.py — external API client
│ ├── lib/types.py — Pydantic models
│ └── config.py — pydantic-settings
├── tests/test_.py
├── pyproject.toml, .env.example, README.md
README Structure
- Server description + tool catalog (name, description, params, example)
- Resource catalog (URI templates, content types)
- Installation: Claude Code, Cursor, Windsurf config snippets
- Configuration reference (env vars with descriptions)
Reference Pattern: Multi-Provider Adapter
When the MCP server needs to call multiple AI providers (e.g., both Anthropic and OpenAI), use the Provider Adapter pattern to normalize different APIs behind a unified interface.
Interface
interface ProviderAdapter {
formatRequest(params: RequestParams): { url: string; init: RequestInit };
parseResponse(data: unknown): { content: string; usage: TokenUsage | null };
formatStreamRequest(params: RequestParams): { url: string; init: RequestInit };
parseSSEEvent(eventType: string, data: string): StreamChunk | null;
}
Discriminated Union for Stream Chunks
type StreamChunk =
| { type: "thinking"; content: string }
| { type: "text"; content: string }
| { type: "done" }
| { type: "done_with_usage"; usage: TokenUsage }
| { type: "usage_delta"; inputTokens?: number; outputTokens?: number }
| { type: "error"; message: string };
When to Apply
- MCP server wraps multiple AI providers (e.g., a router server that dispatches to Claude, GPT, or local models)
- MCP server aggregates responses from multiple APIs with different response formats
- MCP server needs to support streaming from providers with different SSE event schemas
Key Implementation Notes
- Each provider adapter handles its own SSE event types (Anthropic:
content_block_delta,message_start; OpenAI:response.output_text.delta,[DONE]) - Buffer management for SSE: handle incomplete lines, track event types, manage abort signals
- Provider-specific prompt tuning: some models benefit from additional constraints (e.g., "Maximum 2-3 paragraphs" for verbose models)
- Per-provider token tracking: normalize different usage reporting formats into a single
TokenUsagetype
Cost-Aware Model Selection
When building MCP servers that call AI providers, support dual-model configuration — allow users to specify a primary model for critical operations and a cheaper model for background tasks (summarization, classification, metadata extraction). This avoids burning expensive API credits on tasks that don't need maximum quality.
// config.ts
const config = {
primaryModel: process.env.PRIMARY_MODEL || 'claude-sonnet-4-20250514',
backgroundModel: process.env.BACKGROUND_MODEL || 'claude-haiku-4-5-20251001',
};
Constraints
- MUST validate all tool inputs with Zod (TS) or Pydantic (Python) — never trust AI-provided inputs
- MUST handle API errors gracefully — return MCP error responses, don't crash the server
- MUST generate .env.example — never hardcode API keys or secrets
- MUST generate tests — no MCP server without test suite
- MUST generate installation docs for at least Claude Code — other IDEs are bonus
- MUST use official MCP SDK (@modelcontextprotocol/sdk for TS, fastmcp for Python)
- Tool descriptions MUST be AI-friendly — clear, specific, include parameter semantics
Sharp Edges
| Failure Mode | Severity | Mitigation | |---|---|---| | Tool descriptions too vague for AI to use effectively | HIGH | Step 3: descriptions must explain WHEN to use the tool, not just WHAT it does | | Missing input validation → server crashes on bad input | HIGH | Constraint 1: Zod/Pydantic validation on all inputs | | Hardcoded API keys in generated code | CRITICAL | Constraint 3: always use env vars + .env.example | | Tests mock everything → no real integration coverage | MEDIUM | Generate both unit tests (mocked) and integration test template (real API) | | Generated server doesn't match MCP spec | HIGH | Use official SDK — don't hand-roll protocol handling | | Installation docs only for Claude Code | LOW | Include Cursor/Windsurf config examples too | | Mutation tool without confirmation gate | CRITICAL | Step 3.5: classify every tool — any write/delete/send without a preview+confirm step is a footgun |
Done When
- Server specification elicited (tools, resources, target API, language)
- Architecture designed (file structure, module boundaries)
- Server code generated (tools, resources, config, types)
- Test suite generated (happy path, validation, errors, edge cases)
- Documentation generated (README with tool catalog, installation, config)
- Verification passed (types + tests)
- Ready to install in Claude Code / Cursor / other IDEs
Returns
| Artifact | Format | Location | |----------|--------|----------| | MCP server source code | TypeScript or Python | mcp-server-/src/ | | Tool definitions (one per tool) | TS/Python files | src/tools/.ts or .py | | Resource handlers | TS/Python files | src/resources/.ts or .py | | Test suite | TS/Python test files | tests/ | | README with tool catalog | Markdown | mcp-server-/README.md | | Environment config template | .env.example | project root |
Cost Profile
~3000-6000 tokens input, ~2000-5000 tokens output. Sonnet — MCP server generation is a structured code task, not architectural reasoning.
Scope guardrail: mcp-builder generates the server and tests — it does not deploy, register with MCP registries, or configure the host IDE beyond providing the installation snippet.
Source & license
This open-source skill is cataloged on AgentStack and links to its original source — we do not rehost the code.
- Author: Rune-kit
- Source: Rune-kit/rune
- License: MIT
Install and usage instructions live in the source repository linked above.
Reviews
No reviews yet, be the first.
Write a review
Versions
- v0.1.0 Imported from the upstream source.