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
- Write the boundary contract.
- Scaffold strict TypeScript with the official SDK.
- Implement one read-only typed tool.
- Test valid, invalid, traversal, unknown, and shutdown cases.
- 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.