Skip to main content
Glama
berryj85

MCP Server Template

by berryj85
README.md
# MCP Server Template

[![Bun](https://img.shields.io/badge/Bun-1.0+-black?logo=bun)](https://bun.sh/)
[![TypeScript](https://img.shields.io/badge/TypeScript-5.0+-blue.svg)](https://www.typescriptlang.org/)
[![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg)](https://opensource.org/licenses/MIT)

Production-ready MCP server template for building Model Context Protocol servers with TypeScript and Bun runtime.

## What is this?

This is a template project for creating MCP servers. It includes:

- TypeScript with strict type checking
- Bun runtime for fast execution
- Zod schema validation
- Structured logging (stderr only)
- Retry utilities with exponential backoff
- Unit and integration test setup
- Production-ready error handling

## Installation

```bash
bun install
```

## Quick Start

```bash
# Start the MCP server
bun run start

# Development with hot reload
bun run dev
```

### MCP Configuration

Add to your MCP client configuration:

```json
{
  "mcpServers": {
    "mcp-server-template": {
      "command": "bun",
      "args": ["run", "/path/to/mcp-server-template/src/server.ts"]
    }
  }
}
```

Or use the built version:

```json
{
  "mcpServers": {
    "mcp-server-template": {
      "command": "node",
      "args": ["/path/to/mcp-server-template/dist/server.js"]
    }
  }
}
```

## Adding Tools

### 1. Define Schema

In `src/types/index.ts`:

```typescript
import { z } from "zod";

export const MyToolInputSchema = z.object({
  param1: z.string().min(1).describe("Parameter description"),
  param2: z.number().optional().describe("Optional parameter"),
});

export type MyToolInput = z.infer<typeof MyToolInputSchema>;
```

### 2. Add Tool Definition

In `src/tools/index.ts`:

```typescript
export const toolDefinitions = [
  {
    name: "my_tool",
    description: "Description of what the tool does",
    inputSchema: {
      type: "object" as const,
      properties: {
        param1: { type: "string", description: "Parameter description" },
        param2: { type: "number", description: "Optional parameter" },
      },
      required: ["param1"],
    },
  },
];
```

### 3. Implement Handler

```typescript
export async function handleMyTool(input: unknown): Promise<CallToolResult> {
  try {
    const validated = MyToolInputSchema.parse(input);
    log.info('Executing tool', { tool: 'my_tool', params: validated });
    
    // Your logic here
    const result = { data: "..." };
    
    log.info('Tool completed', { tool: 'my_tool', success: true });
    return createSuccessResult(result);
  } catch (error) {
    const message = error instanceof Error ? error.message : String(error);
    return createErrorResult(message, "my_tool");
  }
}
```

### 4. Add to Router

```typescript
export async function handleToolCall(name: string, args: unknown): Promise<CallToolResult> {
  switch (name) {
    case "my_tool":
      return handleMyTool(args);
    default:
      return createErrorResult(`Unknown tool: ${name}`, name);
  }
}
```

### 5. Write Tests

Create `tests/unit/my_tool.test.ts`:

```typescript
import { describe, test, expect } from "bun:test";
import { handleMyTool } from "../../src/tools/index.js";

describe("My Tool", () => {
  test("should work correctly", async () => {
    const result = await handleMyTool({ param1: "test" });
    expect(result.isError).toBe(false);
  });
});
```

### 6. Document Tool

Create `docs/tools/my_tool.md`:

```markdown
# my_tool

Description of what the tool does.

## Parameters

| Name | Type | Required | Description |
|------|------|----------|-------------|
| param1 | string | Yes | Description |

## Examples

**Input:**
\`\`\`json
{ "param1": "value" }
\`\`\`

**Output:**
\`\`\`json
{ "data": "result" }
\`\`\`
```

## Available Scripts

| Script | Description |
|--------|-------------|
| `bun run dev` | Start development server with hot reload |
| `bun run build` | Build for production |
| `bun run start` | Run production build |
| `bun test` | Run unit tests |
| `bun run test:coverage` | Run tests with coverage |
| `bun run test:runtime` | Run runtime testcases |
| `bun run lint` | Run Biome linter |
| `bun run lint:fix` | Auto-fix lint issues |
| `bun run format` | Format code with Biome |
| `bun run typecheck` | Type check without emit |

## Configuration

### Environment Variables

- `DEBUG=true` - Enable debug logging

## Troubleshooting

### Server won't start

- Ensure Bun is installed: `bun --version`
- Check TypeScript errors: `bun run typecheck`

### Tool execution fails

- Check input schema matches the tool definition
- Enable debug mode: `DEBUG=true bun run start`

## Development

See [DEVELOPMENT.md](./DEVELOPMENT.md) for development setup.

## License

MIT License - see [LICENSE](./LICENSE) for details.