Skip to main content
Glama
theinfyark

mcp-server-plus

by theinfyark
README.md
# mcp-server-plus

## Introduction

**mcp-server-plus** is an MCP Server Toolkit — a small TypeScript framework for building [Model Context Protocol](https://modelcontextprotocol.io) servers without repeating boilerplate.

> Package name note: `mcp-server-toolkit` was already taken on npm, so this ships as **`mcp-server-plus`**.

## Why this package exists

Developers starting MCP servers repeatedly re-implement tool registration, prompts, resources, auth, logging, and tests. Popular libraries like Express and Hono succeed because they make the happy path obvious. **mcp-server-plus** aims for that same DX on top of the official `@modelcontextprotocol/sdk`.

## Installation

```bash
npm install mcp-server-plus zod
```

Requires Node.js 18+.

## Features

- Tool registration
- Prompt registry
- Resources
- Authentication / authorization
- Logging
- Metrics
- Streaming (via MCP stdio transport)
- Middleware
- CLI scaffolder
- Testing helpers

## Quick Start

```ts
import { z } from "zod";
import { createServer, toolResult } from "mcp-server-plus";

const weatherTool = {
  description: "Get weather",
  inputSchema: { city: z.string() },
  async handler({ city }: { city: string }) {
    return toolResult(`Weather in ${city}: sunny`);
  },
};

const server = createServer({
  name: "demo",
  version: "1.0.0",
});

server.tool("weather", weatherTool);

await server.start(); // stdio
```

## CLI

```bash
npx mcp-server-plus init my-weather-server
cd my-weather-server
npm install
npm start
```

## API Reference

### `createServer(options)` / `createMcpServer(options)`

Creates an `McpKitServer`.

| Option | Type | Description |
|--------|------|-------------|
| `name` | `string` | Server name |
| `version` | `string` | Server version |
| `instructions` | `string?` | Optional MCP instructions |
| `auth` | `AuthOptions?` | API key / custom auth |
| `middleware` | `Middleware[]?` | Global middleware |
| `logger` | `Logger?` | Custom logger |

### `server.tool(name, definition)`

Registers a tool (also wired into the MCP SDK).

### `server.prompt(name, definition)`

Registers a prompt template.

### `server.resource(uri, definition)`

Registers a resource.

### `server.use(middleware)`

Adds middleware around tool calls.

### `server.start()`

Connects an MCP stdio transport (streaming handled by the SDK).

### `server.invokeTool(name, args, meta?)`

In-process invocation for tests/scripts.

### Testing helpers

```ts
import { callTool, expectText } from "mcp-server-plus/testing";
```

## Examples

```ts
server.tool("weather", weatherTool);
server.prompt("greet", {
  description: "Greeting",
  arguments: [{ name: "name", required: true }],
  handler: async ({ name }) => ({
    messages: [
      { role: "user", content: { type: "text", text: `Hello ${name}` } },
    ],
  }),
});
server.resource("memo://hello", {
  mimeType: "text/plain",
  handler: async (uri) => ({
    contents: [{ uri: uri.href, text: "Hello", mimeType: "text/plain" }],
  }),
});
```

## Advanced Examples

### Auth + RBAC

```ts
const server = createServer({
  name: "secure",
  version: "1.0.0",
  // MCP_API_KEY is the expected secret only. Callers must still send meta.apiKey.
  auth: { apiKey: process.env.MCP_API_KEY, required: true },
});

server.tool("deploy", {
  roles: ["admin"],
  scopes: ["deploy"],
  handler: async () => toolResult("deployed"),
});
```

### Middleware + metrics

```ts
server.use(async (ctx, next) => {
  const started = Date.now();
  try {
    return await next();
  } finally {
    ctx.log.info("tool timing", ctx.toolName, Date.now() - started);
  }
});

console.log(server.metricsSnapshot());
```

## Framework Integration

Works with any MCP host that supports stdio servers. Point the host at your `node dist/index.js` (or `npm start`) process.

Example MCP host config:

```json
{
  "mcpServers": {
    "demo": {
      "command": "node",
      "args": ["/path/to/server/src/index.js"]
    }
  }
}
```

## TypeScript Usage

First-class TypeScript. Tool args are inferred from Zod `inputSchema` when you type the handler explicitly. Enable `strict` for best results.

## Error Handling

Typed errors: `McpKitError`, `AuthError`, `ForbiddenError`.  
Tool failures return `{ isError: true, content: [...] }` so hosts can display them safely.

## Performance

- Thin wrapper over the official SDK (no extra network hops)
- Middleware only on tool invocations
- Metrics use simple counters (low overhead)

## Best Practices

- Keep tools small and side-effect aware
- Validate inputs with Zod schemas
- Use `optional` auth for local/dev, `required` for shared hosts
- Prefer `invokeTool` in unit tests; use stdio for integration

## FAQ

**Is this an official SDK?**  
No — it builds on `@modelcontextprotocol/sdk` with nicer DX.

**Does it support streaming?**  
Yes via the MCP stdio transport used by `server.start()`.

**CJS or ESM?**  
Dual published; ESM-first.

## Migration Guide

### From raw SDK `McpServer`

Replace `registerTool` boilerplate with `server.tool(name, definition)` and keep Zod schemas. Call `server.start()` instead of manually wiring `StdioServerTransport`.

### SemVer

Breaking changes land in major versions and are documented in `CHANGELOG.md`.

## Troubleshooting

| Symptom | Fix |
|---------|-----|
| Host can’t start server | Ensure `start()` is called and stdout isn’t polluted with logs |
| Unauthorized tool calls | Send `meta.apiKey` (or Bearer). `MCP_API_KEY` is the expected secret only. |
| Types missing | Import from `mcp-server-plus` and use Node 18+ |

## Contributing

See [CONTRIBUTING.md](./CONTRIBUTING.md).

## License

MIT