claude-code-mcp
0/15 complete

Module 4: Building an MCP Server · 25 min

Scaffolding a TypeScript MCP Server From Scratch

// sabak

Turn this lesson into one checked practice output

By the end, you should be able to explain the core idea behind “Scaffolding a TypeScript MCP Server From Scratch” in your own words, apply it to one small real or sample task, and identify what still needs human review.

  1. 1

    Learn

    Read the 25-minute lesson without copying an output blindly.

  2. 2

    Try

    Use a small, non-sensitive example that you can inspect line by line.

  3. 3

    Review

    Check facts, fit, and risk; save one improvement note for next time.

Build the smallest read-only server first. The official MCP TypeScript SDK and specification evolve, so pin the current supported SDK and follow its repository examples instead of memorizing an old constructor signature.

Define the Boundary

For a sample product server:

transport: local stdio
capability: get one approved product by SKU
data: synthetic JSON fixture
no network, write, secrets, or arbitrary file paths
result: typed product summary with source version

Initialize a TypeScript project, enable strict checks, add the official SDK at a pinned version, and create source/tests. Validate environment at startup and close cleanly on termination.

Implement With Schemas

Register get_product with a narrow description and strict SKU input. Server code validates again, retrieves from an allowlisted fixture, and returns controlled text or structured content per current SDK support. Return NOT_FOUND without leaking paths.

Do not let model input become a file name. Map SKU to an in-memory or database record through parameterized access.

Worked Example

The fixture contains PK-A14 with title, PKR price, availability label, and version. A valid call returns those approved fields. ../../.env, unknown properties, long input, and unknown SKU fail safely.

The server writes protocol messages only to the proper transport; diagnostics use stderr or structured logging as required so they do not corrupt stdio communication.

Failure Cases to Diagnose

  • Latest dependency floats: pin and audit the lockfile.
  • Console diagnostics break stdio: separate protocol and logs.
  • Schema exists only in description: validate at runtime.
  • Arbitrary file read from SKU: use controlled lookup.
  • Stack trace returned to client: map safe errors.
  • No shutdown behavior: close resources and cancel work.

Operator Note

Expose a harmless health or version path through the mechanism recommended by the current SDK, or document how operators verify startup without invoking business actions. The response should identify server and capability version, not secrets or environment internals. Build and test on a clean checkout so an undeclared global dependency cannot make the server appear healthy only on the author’s machine.

🇵🇰 Pakistan Angle

Use labelled synthetic catalog data. A real Daraz/shop/customer export requires authorization and minimization. Do not embed client credentials in an example server.

Represent PKR amounts exactly and include whether the figure is sample, current source data, or pending verification. The model must not invent tax or delivery.

Hands-On Exercise

  1. Write the boundary contract.
  2. Scaffold strict TypeScript with the official SDK.
  3. Implement one read-only typed tool.
  4. Test valid, invalid, traversal, unknown, and shutdown cases.
  5. Record SDK/protocol versions.

Completion Rubric

  • Server has one narrow read capability.
  • SDK and lockfile are pinned.
  • Inputs are runtime-validated.
  • Data access cannot escape its source.
  • Errors/logs do not corrupt protocol or leak paths.
  • Tests and version record exist.

Sources

Key takeaway: start with one pinned, schema-validated, read-only capability over synthetic data; broaden only after the boundary is tested.

Self-check

Before you mark Lesson 4.1 complete

  • Can I explain “Scaffolding a TypeScript MCP Server From Scratch” without reading the lesson back word for word?
  • Did I complete the lesson’s practice step on a real or clearly labelled sample task?
  • Did I check the result for invented facts, private data, unsafe actions, and mismatch with the brief?