MCP server build guide

How to Create an MCP Server: A Practical TypeScript Guide

Build a small TypeScript MCP server from a bounded tool definition through validation, logging, inspection, and a first client connection.

11 min readEducational field noteReviewed 2026-08-26
For
TypeScript developers building their first MCP server or a focused internal capability.
Problem
A first server tutorial can produce a working process without teaching the boundaries that keep a tool understandable, testable, and safe to connect to a real system.
Useful outcome
Build a minimal server route with one typed tool, explicit validation, useful errors, safe logs, and a repeatable inspection path.

The route

Build one useful capability before adding a catalog.

A small server is easier to inspect, secure, and connect than a collection of generic endpoints with unclear ownership.

Step 01
Scope
Define tools, data, permissions, and success
Step 02
Build
Implement a small, typed server route
Step 03
Inspect
Exercise discovery, calls, errors, and logs
Step 04
Ship
Connect, observe, and recover safely
A small server is easier to inspect, secure, and connect than a collection of generic endpoints with unclear ownership.

Workflow context: TypeScript / MCP SDK / stdio / MCP Inspector / HTTP APIs

Choose one bounded tool.

Start with an operation that has a clear input, a clear result, and a safe test environment. A weather lookup, a read-only catalog query, or a structured calculation is a better first tool than a generic execute command. Name the tool after the user outcome and document what it will not do.

Write the input schema before writing the handler. Decide which fields are required, which values are allowed, how missing data is reported, and what evidence belongs in the result. The schema is part of the interface a client and model will use.

Validate and fail at the server boundary.

Do not rely on the model or client to enforce the contract. Validate types, ranges, identifiers, permissions, and downstream assumptions inside the server. Return a structured error that tells the caller whether the request was invalid, unauthorized, unavailable, or partially completed.

Keep external calls behind a small adapter so tests can exercise the tool without reaching production. If the tool calls an API, set timeouts, avoid logging credentials, and make retry behavior explicit instead of allowing a client to repeat an unsafe action blindly.

  • Reject unknown or dangerous inputs early.
  • Use stderr for local diagnostics rather than corrupting stdio protocol output.
  • Return enough status and evidence for a human to review the result.

Inspect discovery before you test the action.

Connect the server to MCP Inspector and verify that initialization succeeds, the tool appears with the expected name and schema, and the description does not overclaim. Then call it with a normal input, a missing field, an invalid value, and a dependency failure.

Keep those cases as a small regression set. A server that works once in a client UI is not finished; the team should be able to reproduce the discovery and call behavior after a dependency or SDK update.

Add a transport and credential boundary deliberately.

Use a local transport while the capability is being designed and inspected. Move to a remote HTTP deployment only after deciding how the server authenticates clients, scopes access, stores secrets, limits rate, and records requests. The deployment step is a change in exposure, not just a different command.

Document the client configuration and a safe shutdown path. A reader should know how to remove the server, rotate a credential, and tell whether a call reached the upstream system.

Reference material

Start with the platform documentation.

This field note is an educational guide. Platform behavior, availability, permissions, and plan limits should always be checked against the current vendor documentation.