Goal and Architecture
In this lesson, you will build a local MCP server that exposes one structured capability: calculating a shipping quote from a package weight, destination zone, and service level. The capability is implemented as an MCP tool because a client actively invokes it with arguments and receives a result. By the end, an MCP-compatible client can discover the tool, inspect its input schema, validate a call, and receive both human-readable text and structured data.
The server will use TypeScript, Node.js 20 or later, and the official MCP TypeScript server package. It will communicate through the stdio transport. In this model, an MCP client starts the server as a child process and exchanges JSON-RPC messages through standard input and standard output. This transport is appropriate for local AI applications, command-line hosts, and development tools. A remotely deployed shared server would normally use Streamable HTTP instead.
The request flow is simple. The client starts the process, completes the MCP initialization handshake, lists available tools, and calls the selected tool. The SDK validates the supplied arguments before running your handler. Your handler performs the business calculation and returns an MCP result. This separation is important: MCP defines discovery and communication, while your application code owns the shipping rules.

Project Setup
Create a new project and install the server SDK, Zod, TypeScript, and the tsx runner. The package is configured as an ES module because the current SDK uses ES module imports. The tsx runner executes the TypeScript entry point directly, which keeps this first exercise focused on MCP rather than build tooling.
Add scripts to package.json so the launch command is stable. The server script runs the stdio process, while the inspect script starts the MCP Inspector and tells it how to launch that same process.
The exact resolved dependency versions may be newer when you install them. The important architectural detail is that new server projects use the dedicated server package rather than the older monolithic SDK package. If package installation fails, confirm that Node.js and npm are available and that your Node.js version is at least 20.
Implementing the Server
Create src/index.ts with the following implementation. The createServer function constructs a fresh MCP server and registers the calculate-shipping tool. The input schema accepts a positive package weight, one of three destination zones, and one of two service levels. The output schema describes the structured result that clients can consume without parsing prose.
The tool description should state what the capability does, because an AI agent uses the name, description, and generated JSON Schema when deciding whether to call it. The schema is also an executable boundary. A negative weight, an unsupported zone, or an unknown service is rejected before the calculation handler executes.
Understanding the Result
The handler returns two representations of the same outcome. The content array contains a text block that a model or user interface can read directly. The structuredContent value contains predictable fields for applications that need to display a price, compare options, save the result, or pass it to another tool. Because an output schema is registered, the structured value must match that schema.
For an input containing a weight of 3 kilograms, the regional zone, and express service, the base cost is 20 dollars. The express surcharge is 12 dollars, producing a total of 32 dollars and an estimated delivery time of four days. A successful result has this logical shape.
Structured output is preferable to embedding all information in one sentence. A client should not need regular expressions to recover the total price or delivery estimate. The text remains useful for model context, while the structured object provides a stable application interface.
Running and Testing
Start the server directly to verify that the process loads without a syntax or import error. It should print its status message and continue waiting because an stdio server needs an MCP client to send requests. Stop it with the terminal interrupt command after confirming that it remains active.
Next, launch the MCP Inspector. The Inspector starts your server, performs the connection handshake, and provides a browser interface for listing and calling tools. Connect to the server, open the Tools view, select calculate-shipping, and submit valid values such as 3, regional, and express.
Verify three behaviors rather than checking only the happy path. First, confirm that the tool appears with the expected description and input fields. Second, call it with valid data and compare the structured result with the calculation rules. Third, try an invalid weight such as minus 2 or an unsupported zone. The invalid request should fail schema validation instead of reaching the handler.

Common Failures and Next Steps
The most destructive stdio mistake is writing application logs to standard output. Standard output is reserved for protocol messages, so an ordinary log line can corrupt the JSON-RPC stream and disconnect the client. Use standard error for diagnostics, as shown by the status message. This restriction applies to your own code and to libraries that may print unexpected output.
If the Inspector cannot start the process, run the start command directly from the project root. Import errors usually indicate incorrect package names, an old Node.js version, or a missing ES module configuration. If the tool is visible but calls fail, inspect the submitted argument names and types. The schema expects a numeric weight and exact enum values; a numeric string is not automatically equivalent to a number.
A server that starts successfully is not automatically a useful MCP server. Its tool needs a precise description, constrained inputs, deterministic behavior, and results that are easy for both models and applications to consume. You now have the complete local path: create a server, register a structured tool, serve it over stdio, and exercise it with a real MCP client. The next practical step is connecting the same launch command to an AI host or replacing the local calculation with a database or external service while preserving the tool contract.
Lesson Checkpoint
Review what you learned and get feedback on your work.