Skip to main content
This guide will walk you through creating a simple MCP server with FastMCP. You’ll learn how to define tools, run your server, and test it with the CLI.

Build your first server

1

Create a new file

Create a new TypeScript file for your server:
touch server.ts
2

Import FastMCP and define your server

Import FastMCP and create a new server instance:
server.ts
import { FastMCP } from "fastmcp";
import { z } from "zod";

const server = new FastMCP({
  name: "My First Server",
  version: "1.0.0",
});
The server configuration accepts:
  • name - Your server’s name (shown to clients)
  • version - Semantic version number
  • Optional settings for authentication, logging, health checks, and more
3

Add a tool

Tools are executable functions that clients and LLMs can call. Let’s add a simple addition tool:
server.ts
server.addTool({
  name: "add",
  description: "Add two numbers",
  parameters: z.object({
    a: z.number().describe("The first number"),
    b: z.number().describe("The second number"),
  }),
  execute: async (args) => {
    return String(args.a + args.b);
  },
});
What’s happening here:
  • name - Unique identifier for the tool
  • description - Tells LLMs when to use this tool
  • parameters - Zod schema defining expected inputs (FastMCP also supports ArkType and Valibot)
  • execute - Async function that performs the action and returns a string result
4

Start the server

Add the start command to run your server:
server.ts
server.start({
  transportType: "stdio",
});
The stdio transport is perfect for local development and integrates with MCP clients like Claude Desktop.

Complete example

Here’s the complete server code:
server.ts
import { FastMCP } from "fastmcp";
import { z } from "zod";

const server = new FastMCP({
  name: "My First Server",
  version: "1.0.0",
});

server.addTool({
  name: "add",
  description: "Add two numbers",
  parameters: z.object({
    a: z.number().describe("The first number"),
    b: z.number().describe("The second number"),
  }),
  execute: async (args) => {
    return String(args.a + args.b);
  },
});

server.start({
  transportType: "stdio",
});

Test your server

FastMCP includes a CLI for testing servers without setting up a full MCP client.
Run your server with the interactive CLI:
npx fastmcp dev server.ts
You’ll see a prompt where you can test calling your tool:
? What would you like to do?
> Call a tool
  List tools
  Exit
Select “Call a tool”, choose add, and enter parameters:
? Select a tool: add
? Enter arguments (JSON): {"a": 5, "b": 3}

Result: 8

Use MCP Inspector

For a visual debugging experience, use the MCP Inspector:
npx fastmcp inspect server.ts
This opens a web UI where you can:
  • Browse available tools, resources, and prompts
  • Test tool execution with a visual interface
  • Inspect request/response payloads
  • Debug errors in real-time

Add more features

Add a resource

Resources make data available to clients:
server.addResource({
  uri: "file:///logs/app.log",
  name: "Application Logs",
  mimeType: "text/plain",
  async load() {
    return {
      text: "Example log content",
    };
  },
});

Add a prompt

Prompts define reusable templates for LLM interactions:
server.addPrompt({
  name: "git-commit",
  description: "Generate a Git commit message",
  arguments: [
    {
      name: "changes",
      description: "Git diff or description of changes",
      required: true,
    },
  ],
  load: async (args) => {
    return `Generate a concise but descriptive commit message for these changes:\n\n${args.changes}`;
  },
});

Add streaming output

For long-running operations, stream partial results:
server.addTool({
  name: "stream-poem",
  description: "Generate a poem line by line",
  parameters: z.object({
    theme: z.string().describe("Theme for the poem"),
  }),
  annotations: {
    streamingHint: true,
  },
  execute: async (args, { streamContent }) => {
    const lines = [
      `Poem about ${args.theme} - line 1`,
      `Poem about ${args.theme} - line 2`,
      `Poem about ${args.theme} - line 3`,
    ];
    
    for (const line of lines) {
      await streamContent({
        type: "text",
        text: line + "\n",
      });
      await new Promise(resolve => setTimeout(resolve, 1000));
    }
  },
});

Use different schema libraries

FastMCP supports multiple schema validation libraries:
import { z } from "zod";

server.addTool({
  name: "example",
  description: "Example with Zod",
  parameters: z.object({
    name: z.string(),
    age: z.number(),
  }),
  execute: async (args) => {
    return `Hello, ${args.name}!`;
  },
});

Deploy to production

For production deployments, use HTTP streaming:
server.start({
  transportType: "httpStream",
  httpStream: {
    port: 8080,
  },
});
Your server will be available at http://localhost:8080/mcp.
FastMCP also supports edge runtimes like Cloudflare Workers. See the deployment guide for details.

Next steps

Tools

Learn about tool parameters, error handling, and progress reporting

Resources

Discover how to expose files, images, and dynamic data

Prompts

Create reusable prompt templates with auto-completion

Authentication

Secure your server with OAuth 2.1 or custom authentication

Build docs developers (and LLMs) love