mcpez
v1.2.1
Published
Minimal, ergonomic MCP server wrapper for TypeScript/Bun
Readme
mcpez
Minimal, ergonomic ESM wrapper for building MCP servers with TypeScript and Bun.
Install
bun add mcpezQuickstart
Minimal Examples
Prompt
import { prompt, z } from "mcpez"
prompt(
"review-code",
{
description: "Review code for best practices and potential issues",
argsSchema: {
code: z.string(),
},
},
({ code }) => ({
messages: [
{
role: "user",
content: {
type: "text",
text: `Please review this code:\n\n${code}`,
},
},
],
}),
)Note: Zod is bundled with mcpez, so you don't need to install it separately.
Why Zod is Bundled
mcpez bundles Zod v3 to ensure compatibility with the MCP SDK, which requires Zod v3 specifically. Since Zod v4 has breaking changes that cause runtime errors like keyValidator._parse is not a function, bundling Zod v3 prevents version conflicts and provides a simpler, error-free developer experience. You can import z directly from mcpez:
Tool
import { tool, z } from "mcpez"
tool(
"add",
{
description: "Add two numbers",
inputSchema: {
a: z.number(),
b: z.number(),
},
},
async ({ a, b }) => {
const result = a + b
return {
content: [{ type: "text", text: `${a} + ${b} = ${result}` }],
}
},
)
// No need to manually call startServer(); the server boots on the next tick.Resource
import { resource } from "mcpez"
resource(
"config",
"config://app",
{
description: "Application configuration data",
mimeType: "text/plain",
},
async (uri) => ({
contents: [
{
uri: uri.href,
text: "App configuration here",
},
],
}),
)Logging and Notifications
import { tool, log, notifyToolListChanged, getServer } from "mcpez"
// Register a simple tool
tool(
"greet",
{ description: "Greet the user" },
async () => {
// Send a log message to the client
log.info("Greeting tool was called")
return {
content: [
{
type: "text",
text: "Hello from mcpez!",
},
],
}
},
)
// Register another tool that modifies the tool list
tool(
"add_tool",
{ description: "Simulate adding a new tool" },
async () => {
log.info("New tool would be added here")
// Notify the client that the tool list has changed
notifyToolListChanged()
return {
content: [
{
type: "text",
text: "Tool list changed!",
},
],
}
},
)
// Example of using getServer() for advanced operations
const server = getServer()
if (server) {
log.debug("Server is running, can access advanced APIs")
} else {
log.debug("Server not started yet, logging is queued")
}Fully Configured Example
import { prompt, resource, startServer, tool, z } from "mcpez"
tool(
"echo",
{
description: "Echoes back the provided message",
inputSchema: { message: z.string() },
},
async ({ message }) => {
const output = { echo: `Tool echo: ${message}` }
return {
content: [{ type: "text", text: JSON.stringify(output) }],
}
},
)
resource(
"echo",
"echo://message",
{
description: "Echoes back messages as resources",
},
async (uri) => ({
contents: [
{
uri: uri.href,
text: `Resource echo: Hello!`,
},
],
}),
)
prompt(
"echo",
{
description: "Creates a prompt to process a message",
argsSchema: { message: z.string() },
},
({ message }) => ({
messages: [
{
role: "user",
content: {
type: "text",
text: `Please process this message: ${message}`,
},
},
],
}),
)
// Start with custom server name and version
await startServer("example-full-server", { version: "1.0.0" })API
prompt(name, options, handler)tool(name, options, handler)resource(name, options)resourceTemplate(name, options)startServer(name, serverOptions?, transport?)getServer()- Get the running server instancelog.info(data, logger?)- Send a logging message (other helpers:debug,notice,warning,error,critical,alert,emergency)notifyResourceListChanged()- Notify when resources changenotifyToolListChanged()- Notify when tools changenotifyPromptListChanged()- Notify when prompts change
All register* calls can be made before startServer; they are queued and applied
when the server starts. startServer is optional and defaults to StdioServerTransport.
ESM only
This package ships ESM only. Ensure your project has "type": "module" or uses
ES module import syntax.
License
MIT
