# Mcp Builder

> Build Model Context Protocol servers from specifications. Use when creating an MCP server for a tool, resource, or service that AI agents should access. Generates tool definitions, resource handlers, and test suites in TypeScript or Python (FastMCP).

- **Type:** Skill
- **Install:** `agentstack add skill-rune-kit-rune-mcp-builder`
- **Verified:** Yes — security-reviewed for prompt injection and unsafe behavior
- **Seller:** [Rune-kit](https://agentstack.voostack.com/s/rune-kit)
- **Installs:** 0
- **Category:** [Agent Skills](https://agentstack.voostack.com/c/agent-skills)
- **Latest version:** 0.1.0
- **License:** MIT
- **Upstream author:** [Rune-kit](https://github.com/Rune-kit)
- **Source:** https://github.com/Rune-kit/rune/tree/master/skills/mcp-builder

## Install

```sh
agentstack add skill-rune-kit-rune-mcp-builder
```

Requires the [AgentStack CLI](https://agentstack.voostack.com/docs/cli). Works with Claude Code, Cursor, and any MCP-compatible agent.

## 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 `cook` when MCP-related task detected (keywords: "MCP server", "MCP tool", "model context protocol")
- Called by `scaffold` when MCP Server template selected
- `/rune mcp-builder ` — manual invocation
- Auto-trigger: when project contains `mcp.json`, `@modelcontextprotocol/sdk`, or `fastmcp` in dependencies

## Calls (outbound)

- `ba` (L2): if user description is vague — elicit requirements for what tools/resources the server should expose
- `research` (L3): look up target API documentation, existing MCP servers for reference
- `test` (L2): generate and run test suite for the server
- `docs` (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 detected
- `scaffold` (L1): MCP Server template in Phase 5
- User: `/rune mcp-builder` direct invocation

## Executable Steps

### Step 1 — Spec Elicitation

If description is detailed enough (tools, resources, target API specified), proceed.
If vague, ask targeted questions:

1. **What tools should this MCP server expose?** (actions the AI can perform)
2. **What resources does it manage?** (data the AI can read)
3. **What external APIs does it connect to?** (if any)
4. **TypeScript or Python?** (default: TypeScript with @modelcontextprotocol/sdk)
5. **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:**
```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):**
```python
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:
```env
# Required
API_KEY=your_api_key_here
API_BASE_URL=https://api.example.com

# Optional
LOG_LEVEL=info
CACHE_TTL=300
```

Generate config validation:
```typescript
// 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:**

1. Add `safety` metadata to each tool definition:
```typescript
export const deleteTool = {
  name: 'delete_user',
  description: '...',
  safety: 'mutation' as const,   // ← add this
  inputSchema: z.object({ id: z.string() }),
  async handler(input) { ... },
};
```

2. For every `mutation` tool, generate a preview step that surfaces WHAT WILL HAPPEN before the action runs:
```typescript
// 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
```

3. For Python (FastMCP), add a `@confirm_mutation` decorator or inline guard in the docstring:
```python
@mcp.tool()
async def delete_user(id: str) -> str:
    """[MUTATION] Delete a user by ID. Will prompt for confirmation before executing."""
    ...
```

4. 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

```typescript
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:
```json
{
  "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

```typescript
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

```typescript
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 `TokenUsage` type

### 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.

```typescript
// config.ts
const config = {
  primaryModel: process.env.PRIMARY_MODEL || 'claude-sonnet-4-20250514',
  backgroundModel: process.env.BACKGROUND_MODEL || 'claude-haiku-4-5-20251001',
};
```

## Constraints

1. MUST validate all tool inputs with Zod (TS) or Pydantic (Python) — never trust AI-provided inputs
2. MUST handle API errors gracefully — return MCP error responses, don't crash the server
3. MUST generate .env.example — never hardcode API keys or secrets
4. MUST generate tests — no MCP server without test suite
5. MUST generate installation docs for at least Claude Code — other IDEs are bonus
6. MUST use official MCP SDK (@modelcontextprotocol/sdk for TS, fastmcp for Python)
7. 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](https://github.com/Rune-kit)
- **Source:** [Rune-kit/rune](https://github.com/Rune-kit/rune)
- **License:** MIT

Install and usage instructions live in the source repository linked above.

## Pricing

- **Free** — Free

## Security capabilities

Automated source analysis of v0.1.0 — what this tool can access:

- **Network access:** no
- **Filesystem access:** no
- **Shell / process execution:** no
- **Environment & secrets:** yes
- **Dynamic code execution:** no

*"Yes" means the capability is present in the source — more access means more to trust, not that it is unsafe.*


## Versions

- **0.1.0** — security scan: passed — Imported from the upstream source.

## Links

- Listing page: https://agentstack.voostack.com/l/skill-rune-kit-rune-mcp-builder
- Seller: https://agentstack.voostack.com/s/rune-kit
- Browse the marketplace: https://agentstack.voostack.com/browse

---
Listed on AgentStack — the marketplace for AI agent skills and MCP servers. Every listing is security-reviewed. Creators keep 70%.
