//tmcpbypi0

tmcp

Typescript SDK to build MCP servers in an agnostic way

1
0
1

[!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:

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

Supported Schema Libraries

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

  • undefinedZod - @tmcp/adapter-zod
  • undefinedValibot - @tmcp/adapter-valibot
  • undefinedArkType - @tmcp/adapter-arktype
  • undefinedEffect Schema - @tmcp/adapter-effect
  • undefinedZod 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 contributing guidelines for details.

Acknowledgments

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

License

MIT © Paolo Ricciuti

[beta]v0.13.0