tmcp

paoloricciuti/tmcp

3.5

If you are the rightful owner of tmcp and would like to certify it and/or have it hosted online, please leave a comment on the right or send an email to henry@mcphub.com.

tmcp is a lightweight, schema-agnostic Model Context Protocol (MCP) server implementation with a unified API design.

Tools
1
Resources
0
Prompts
0

[!WARNING] Unfortunately i published the 1.0 by mistake...this package is currently under heavy development so there will be breaking changes in minors...threat this 1.x as the 0.x of any other package. Sorry for the disservice, every breaking will be properly labeled in the PR name.

tmcp

A lightweight, schema-agnostic Model Context Protocol (MCP) server implementation with unified API design.

Why tmcp?

tmcp offers significant advantages over the official MCP SDK:

  • 🔄 Schema Agnostic: Works with any validation library through adapters
  • 📦 No Weird Dependencies: Minimal footprint with only essential dependencies (looking at you express)
  • 🎯 Unified API: Consistent, intuitive interface across all MCP capabilities
  • 🔌 Extensible: Easy to add support for new schema libraries
  • ⚡ Lightweight: No bloat, just what you need

Supported Schema Libraries

tmcp works with all major schema validation libraries through its adapter system:

  • Zod - @tmcp/adapter-zod
  • Valibot - @tmcp/adapter-valibot
  • ArkType - @tmcp/adapter-arktype
  • Effect Schema - @tmcp/adapter-effect
  • Zod v3 - @tmcp/adapter-zod-v3

Installation

pnpm install tmcp
# Choose your preferred schema library adapter
pnpm install @tmcp/adapter-zod zod
# Choose your preferred transport
pnpm install @tmcp/transport-stdio  # For CLI/desktop apps
pnpm install @tmcp/transport-http   # For web-based clients

Quick Start

Standard I/O Transport (CLI/Desktop)

import { McpServer } from 'tmcp';
import { ZodJsonSchemaAdapter } from '@tmcp/adapter-zod';
import { StdioTransport } from '@tmcp/transport-stdio';
import { z } from 'zod';

const adapter = new ZodJsonSchemaAdapter();
const server = new McpServer(
	{
		name: 'my-server',
		version: '1.0.0',
		description: 'My awesome MCP server',
	},
	{
		adapter,
		capabilities: {
			tools: { listChanged: true },
			prompts: { listChanged: true },
			resources: { listChanged: true },
		},
	},
);

// Define a tool with type-safe schema
server.tool(
	{
		name: 'calculate',
		description: 'Perform mathematical calculations',
		schema: z.object({
			operation: z.enum(['add', 'subtract', 'multiply', 'divide']),
			a: z.number(),
			b: z.number(),
		}),
	},
	async ({ operation, a, b }) => {
		switch (operation) {
			case 'add':
				return a + b;
			case 'subtract':
				return a - b;
			case 'multiply':
				return a * b;
			case 'divide':
				return a / b;
		}
	},
);

// Start the server with stdio transport
const transport = new StdioTransport(server);
transport.listen();

HTTP Transport (Web-based)

import { McpServer } from 'tmcp';
import { ZodJsonSchemaAdapter } from '@tmcp/adapter-zod';
import { HttpTransport } from '@tmcp/transport-http';
import { z } from 'zod';

const adapter = new ZodJsonSchemaAdapter();
const server = new McpServer(/* ... same server config ... */);

// Add tools as above...

// Create HTTP transport
const transport = new HttpTransport(server);

// Use with your preferred HTTP server (Bun example)
Bun.serve({
	port: 3000,
	async fetch(req) {
		const response = await transport.respond(req);
		if (response === null) {
			return new Response('Not Found', { status: 404 });
		}
		return response;
	},
});

API Reference

McpServer

The main server class that handles MCP protocol communications.

Constructor
new McpServer(serverInfo, options);
  • serverInfo: Server metadata (name, version, description)
  • options: Configuration object with adapter and capabilities
Methods
tool(definition, handler)

Register a tool with optional schema validation.

server.tool(
	{
		name: 'tool-name',
		description: 'Tool description',
		schema: yourSchema, // optional
	},
	async (input) => {
		// Tool implementation
		return result;
	},
);
prompt(definition, handler)

Register a prompt template with optional schema validation.

server.prompt(
  {
	name: 'prompt-name',
	description: 'Prompt description',
	schema: yourSchema, // optional
	complete: (arg, context) => ['completion1', 'completion2'] // optional
  },
  async (input) => {
	// Prompt implementation
	return { messages: [...] };
  }
);
resource(definition, handler)

Register a static resource.

server.resource(
  {
	name: 'resource-name',
	description: 'Resource description',
	uri: 'file://path/to/resource'
  },
  async (uri, params) => {
	// Resource implementation
	return { contents: [...] };
  }
);
template(definition, handler)

Register a URI template for dynamic resources.

server.template(
  {
	name: 'template-name',
	description: 'Template description',
	uri: 'file://path/{id}/resource',
	complete: (arg, context) => ['id1', 'id2'] // optional
  },
  async (uri, params) => {
	// Template implementation using params.id
	return { contents: [...] };
  }
);
receive(request)

Process an incoming MCP request.

const response = server.receive(jsonRpcRequest);

Advanced Examples

Multiple Schema Libraries

// Use different schemas for different tools
import { z } from 'zod';
import * as v from 'valibot';

server.tool(
	{
		name: 'zod-tool',
		schema: z.object({ name: z.string() }),
	},
	async ({ name }) => `Hello ${name}`,
);

server.tool(
	{
		name: 'valibot-tool',
		schema: v.object({ age: v.number() }),
	},
	async ({ age }) => `Age: ${age}`,
);

Resource Templates with Completion

server.template(
	{
		name: 'user-profile',
		description: 'Get user profile by ID',
		uri: 'users/{userId}/profile',
		complete: (arg, context) => {
			// Provide completions for userId parameter
			return ['user1', 'user2', 'user3'];
		},
	},
	async (uri, params) => {
		const user = await getUserById(params.userId);
		return {
			contents: [
				{
					uri,
					mimeType: 'application/json',
					text: JSON.stringify(user),
				},
			],
		};
	},
);

Complex Validation

const complexSchema = z.object({
	user: z.object({
		name: z.string().min(1),
		email: z.string().email(),
		age: z.number().min(18).max(120),
	}),
	preferences: z
		.object({
			theme: z.enum(['light', 'dark']),
			notifications: z.boolean(),
		})
		.optional(),
	tags: z.array(z.string()).default([]),
});

server.tool(
	{
		name: 'create-user',
		description: 'Create a new user with preferences',
		schema: complexSchema,
	},
	async (input) => {
		// Input is fully typed and validated
		const { user, preferences, tags } = input;
		return await createUser(user, preferences, tags);
	},
);

Contributing

Contributions are welcome! Please see our for details.

Acknowledgments

Huge thanks to Sean O'Bannon that provided us with the @tmcp scope on npm.

License

MIT © Paolo Ricciuti