npm package: @mcp-server-utils/core
Description: Utility belt for MCP server developers. Response builders, TOON encoding, input validation, error handling, formatting, and structured logging — powered by vurb.ts.
Author: Renato Marinho
Latest version: 1.0.0

<div align="center">

# 🧰 mcp-server-utils

**The utility belt for MCP server developers.**<br>
Response builders, TOON encoding, input validation, error handling, formatting, and structured logging.<br>
Powered by [vurb.ts](https://vurb.vinkius.com) — The Express.js for MCP Servers.

[![npm version](https://img.shields.io/npm/v/@mcp-server-utils/core.svg?color=0ea5e9&style=flat-square)](https://www.npmjs.com/package/@mcp-server-utils/core)
[![npm downloads](https://img.shields.io/npm/dw/@mcp-server-utils/core?color=0ea5e9&style=flat-square)](https://www.npmjs.com/package/@mcp-server-utils/core)
[![Node.js](https://img.shields.io/badge/node-%3E%3D18-brightgreen?style=flat-square)](https://nodejs.org)
[![MCP Standard](https://img.shields.io/badge/MCP-Standard-purple?style=flat-square)](https://modelcontextprotocol.io/)
[![License](https://img.shields.io/badge/License-Apache_2.0-blue?style=flat-square)](LICENSE)

</div>

---

## Why mcp-server-utils?

Every raw MCP SDK server reinvents the same patterns:

```typescript
// ❌ Before — raw MCP SDK boilerplate
server.setRequestHandler(CallToolRequestSchema, async (req) => {
    try {
        const data = await db.query('SELECT * FROM users');
        return { content: [{ type: 'text', text: JSON.stringify(data) }] };
    } catch (err) {
        return { content: [{ type: 'text', text: `Error: ${err}` }], isError: true };
    }
});

// ✅ After — with @mcp-server-utils/core (installs @vurb/core automatically)
import { success, error, wrapHandler, toErrorMessage } from '@mcp-server-utils/core';

server.setRequestHandler(CallToolRequestSchema,
    wrapHandler(async (req) => {
        const data = await db.query('SELECT * FROM users');
        return success(data);
    })
);
```

---

## Install

```bash
npm install @mcp-server-utils/core
```

> **Note:** This automatically installs `@vurb/core` — the full vurb.ts framework — as a dependency.

---

## 6 Modules

### 1. Response Builders

```typescript
import { success, error, paginated } from '@mcp-server-utils/core';

return success({ id: 1, name: 'Alice' });   // Auto JSON.stringify
return success('Operation complete');         // String pass-through
return error('User not found');               // isError: true

return paginated(users, { page: 1, pageSize: 20, total: 200 });
// → { data: [...20 items], pagination: { page, totalPages, hasNextPage, ... } }
```

### 2. TOON Encoding (~40% Fewer Tokens)

```typescript
import { toonSuccess, estimateSavings } from '@mcp-server-utils/core';

return toonSuccess(largeDataset);

const savings = estimateSavings(data);
console.log(`${savings.savingsPercent}% fewer tokens`);
```

### 3. Input Validation

```typescript
import { requireParam, validateParams } from '@mcp-server-utils/core';

// Single field
const name = requireParam<string>(params, 'name');

// Multiple fields with full validation
const { name, email, age } = validateParams(params, {
    name:  { type: 'string', required: true },
    email: { type: 'string', required: true, pattern: /^.+@.+$/ },
    age:   { type: 'number', required: false, default: 0, min: 0, max: 150 },
    role:  { type: 'string', required: false, enum: ['admin', 'user'] as const },
});
```

### 4. Error Handling

```typescript
import { toErrorMessage, wrapHandler, isRetryable } from '@mcp-server-utils/core';

// Safe extraction
catch (err) { return error(toErrorMessage(err)); }

// Auto-wrapped handler
server.setRequestHandler(CallToolRequestSchema,
    wrapHandler(async (req) => {
        return success(data); // Exceptions auto-caught
    })
);

// Retry logic
if (isRetryable(err)) { /* retry */ }
```

### 5. Formatting

```typescript
import { table, list, truncate, redactFields, pick, omit } from '@mcp-server-utils/core';

// Markdown table (LLM-friendly)
return success(table(users, ['id', 'name', 'email']));

// Bullet list
return success(list(items, i => `${i.name}: ${i.status}`));

// Truncate
return success(truncate(longText, 4000));

// Field operations
const safe = redactFields(user, ['password', 'ssn']);
const public = pick(user, ['id', 'name']);
const clean = omit(user, ['_id', '__v']);
```

### 6. Structured Logging

```typescript
import { createLogger } from '@mcp-server-utils/core';

const log = createLogger('my-server');

log.info('Server started', { port: 3000 });
log.warn('Slow query', { tool: 'users.list', ms: 2300 });
log.error('Connection failed', { error: err });

// JSON mode for structured ingestion
const log = createLogger('my-server', { json: true });
```

> **Why stderr?** MCP uses stdout for JSON-RPC protocol. Using `console.log` breaks stdio transport. This logger writes to stderr — always safe.

---

## vurb.ts Integration

`@mcp-server-utils/core` already includes `@vurb/core`. You can use both together:

```bash
npm install @vurb/core
```

| Feature | mcp-server-utils | vurb.ts |
|---|---|---|
| Response builders | ✅ `success()` / `error()` | ✅ Built into Presenters |
| TOON encoding | ✅ `toonSuccess()` | ✅ Native, automatic |
| Input validation | ✅ `validateParams()` | ✅ Zod/Standard Schema integration |
| Error handling | ✅ `wrapHandler()` | ✅ Middleware pipeline |
| Field filtering | ✅ `pick()` / `omit()` | ✅ Schema-based Egress Firewall |
| Logging | ✅ `createLogger()` | ✅ Telemetry + observability hooks |
| Tool builder | ❌ | ✅ Fluent API with `.describe()` `.schema()` |
| Middleware | ❌ | ✅ Auth, rate-limit, caching |
| Hot reload | ❌ | ✅ DevServer |
| Deployment | ❌ | ✅ Vercel, Cloudflare, Lambda |

---

## Contributing

See [CONTRIBUTING.md](CONTRIBUTING.md) for guidelines.

## Security

See [SECURITY.md](SECURITY.md) for vulnerability reporting.

## License

[Apache-2.0](LICENSE) — © 2026 Vinkius Labs