Skip to content

Commit 4997c74

Browse files
committed
Enhanced README.md file to make it educationally more valuable
1 parent 04e2114 commit 4997c74

File tree

1 file changed

+136
-149
lines changed

1 file changed

+136
-149
lines changed

README.md

Lines changed: 136 additions & 149 deletions
Original file line numberDiff line numberDiff line change
@@ -3,84 +3,103 @@
33
<div align="center">
44

55
[![MCP Version](https://img.shields.io/badge/MCP-1.0.0-blue)](https://modelcontextprotocol.io)
6-
[![TypeScript](https://img.shields.io/badge/TypeScript-5.7-blue)](https://www.typescriptlang.org/)
6+
[![TypeScript](https://img.shields.io/badge/TypeScript-5.x-blue)](https://www.typescriptlang.org/)
7+
[![Architecture](https://img.shields.io/badge/Architecture-Process--Isolated-blueviolet)](https://spec.modelcontextprotocol.io/specification/basic/transports/#stdio)
78
[![License](https://img.shields.io/badge/License-MIT-green)](LICENSE)
89

910
</div>
1011

1112
## 🎯 Overview
1213

13-
This repository demonstrates a **learning-edition MCP calculator server using STDIO transport**. It showcases the classic local-pipe transport where the server runs as a child process and communicates via `stdin` and `stdout` using newline-delimited JSON-RPC messages.
14+
This repository demonstrates a **learning-edition MCP calculator server using STDIO transport**. It is a reference implementation for the classic local pipe transport, where the server runs as a child process and communicates with a parent process via `stdin` and `stdout` using newline-delimited JSON-RPC messages.
15+
16+
This transport is the most performant and secure option for local inter-process communication (IPC).
1417

1518
### Key Characteristics
1619

17-
- **Zero-network latency**: Direct inter-process communication (microseconds)
18-
- **Per-process state**: All state resets when the process exits
19-
- **No sockets, no SSE, no HTTP**: Pure stdin/stdout communication
20-
- **Perfect isolation**: Process-level security boundary
21-
- **Ideal for**: CLI tools, IDE plugins, local development
20+
- **Transport Layer:** Direct `stdin`/`stdout` pipes between parent (client) and child (server) processes.
21+
- **State Model:** Ephemeral, in-process memory. All state (e.g., calculation history) is lost when the process exits.
22+
- **Latency:** The lowest possible latency (microseconds), as it avoids all network stack overhead.
23+
- **Security:** Extremely high due to OS-level process isolation. There is no network attack surface.
24+
- **Use Case:** Ideal for high-performance, secure local tooling, such as command-line interfaces (CLIs), IDE plugins, and build-system integrations.
2225

23-
## 📊 Transport Comparison Table
26+
## 📊 Transport Comparison
2427

25-
| Dimension | **STDIO** (this) | **SSE** | **Streamable HTTP** | **Streamable HTTP Stateless** |
26-
|-----------|------------------|---------|---------------------|-------------------------------|
27-
| **Transport layer** | Local pipes (`stdin`/`stdout`) | 2 × HTTP endpoints (`GET /connect` + `POST /messages`) | Single HTTP endpoint `/mcp` (JSON or SSE) | Single HTTP endpoint (per request) |
28-
| **Bidirectional streaming** |**Yes (full duplex)** | ⚠️ Server→client only | ✅ Yes (server push + client stream) | ✅ Within each request |
29-
| **State management** | **Process memory** | Server memory (session mapping) | Session-based (`Mcp-Session-Id`) | ❌ None (stateless) |
30-
| **Latency** |**Fastest (microseconds)** | 🚀 Good (after connection) | 💫 Moderate (HTTP overhead) | 💫 Moderate |
31-
| **Security** | 🔒 **Process isolation** | 🌐 Network exposed | 🌐 Network exposed | 🌐 Network exposed |
32-
| **Scalability** | ⚠️ **Single process** | ✅ Multi-client | ✅ Horizontal (with sticky sessions) | ♾️ Infinite (stateless) |
33-
| **Ideal use case** | **Local CLI tools, IDE plugins** | Web apps, real-time updates | Enterprise APIs, complex workflows | Serverless, edge computing |
28+
This table compares the four primary MCP transport mechanisms demonstrated in the learning series. The implementation in **this repository is highlighted**.
3429

35-
## 🔄 STDIO Transport Flow
30+
| Dimension | **STDIO** | SSE (Legacy) | Streamable HTTP (Stateful) | Streamable HTTP (Stateless) |
31+
|:-----------|:-----------|:---------|:---------------------|:-------------------------------|
32+
| **Transport Layer** | **Local Pipes (`stdin`/`stdout`)** | 2 × HTTP endpoints (`GET`+`POST`) | Single HTTP endpoint `/mcp` | Single HTTP endpoint `/mcp` |
33+
| **Bidirectional Stream** |**Yes (full duplex)** | ⚠️ Server→Client only | ✅ Yes (server push + client stream) | ✅ Yes (within each request) |
34+
| **State Management** | **Ephemeral (Process Memory)** | Ephemeral (Session Memory) | Persistent (Session State) | ❌ None (Stateless) |
35+
| **Resumability** |**None** | ❌ None | ✅ Yes (`Last-Event-Id`) | ❌ None (by design) |
36+
| **Scalability** | ⚠️ **Single Process** | ✅ Multi-Client | ✅ Horizontal (Sticky Sessions) | ♾️ Infinite (Serverless) |
37+
| **Security** | 🔒 **Process Isolation** | 🌐 Network Exposed | 🌐 Network Exposed | 🌐 Network Exposed |
38+
| **Ideal Use Case** |**CLI Tools, IDE Plugins** | Legacy Web Apps | Enterprise APIs, Workflows | Serverless, Edge Functions |
3639

40+
## 📐 Architecture and Flow
41+
42+
The STDIO transport architecture is based on a parent-child process model. A client application spawns the MCP server as a child process and communicates with it by writing to the child's `stdin` and reading from its `stdout`.
43+
44+
```mermaid
45+
sequenceDiagram
46+
participant Client (Parent Process)
47+
participant Server (Child Process)
48+
49+
Client->>Server: Writes JSON-RPC request to stdin stream
50+
Server-->>Client: Writes JSON-RPC response to stdout stream
51+
52+
Note over Client,Server: Communication is full-duplex, concurrent, and newline-delimited.
3753
```
38-
┌─────────────┐ stdin ┌─────────────┐
39-
│ Client │ ─────────────────────► │ Server │
40-
│ (Parent) │ │ (Child) │
41-
│ Process │ ◄───────────────────── │ Process │
42-
└─────────────┘ stdout └─────────────┘
43-
44-
JSON-RPC messages
45-
(newline-delimited)
46-
```
4754

48-
Each JSON-RPC message is sent as a single line terminated with `\n`. The server processes requests concurrently and emits progress notifications for long-running operations.
55+
### Dual Server Implementations for Learning
56+
57+
This repository contains two distinct server implementations to illustrate different levels of abstraction:
58+
59+
1. **High-Level (SDK-based): `dist/server.js`**
60+
- Built using the official `@modelcontextprotocol/sdk`.
61+
- Uses high-level abstractions like `server.registerTool()` and `server.registerResource()`.
62+
- Represents the standard, recommended approach for building MCP servers.
4963

50-
## 📊 Golden Standard Feature Matrix
64+
2. **Low-Level (Manual): `dist/server-stdio.js`**
65+
- A from-scratch implementation of the newline-delimited JSON-RPC protocol.
66+
- Manually parses `stdin`, handles message framing, and constructs JSON-RPC responses.
67+
- Excellent for learning the fundamental mechanics of the MCP transport protocol itself.
68+
69+
## ✨ Feature Compliance
70+
71+
This server implements the complete MCP Golden Standard feature set for the learning edition.
5172

5273
| Name | Status | Implementation |
53-
|------|--------|----------------|
54-
| `calculate` | **Core ✅** | Basic arithmetic with optional streaming progress (10%, 50%, 90%) |
55-
| `batch_calculate` | **Extended ✅** | Process multiple calculations in single request |
56-
| `advanced_calculate` | **Extended ✅** | Factorial, logarithm, combinatorics operations |
57-
| `demo_progress` | **Extended ✅** | Demonstrates 5 progress notifications → final result |
58-
| `explain-calculation` | **Core ✅** | Returns Markdown explanation of calculations |
59-
| `generate-problems` | **Core ✅** | Returns Markdown practice problems |
60-
| `calculator-tutor` | **Core ✅** | Returns Markdown tutoring content |
61-
| `solve_math_problem` | **Extended ✅** | May send `elicitInput` request back to client |
62-
| `explain_formula` | **Extended ✅** | Interactive formula explanation |
63-
| `calculator_assistant` | **Extended ✅** | Interactive calculator assistance |
64-
| `calculator://constants` | **Core ✅** | Mathematical constants (π, e, φ, √2, ln2, ln10) |
65-
| `calculator://history/{id}` | **Extended ✅** | Store last 50 calculation results in memory |
66-
| `calculator://stats` | **Extended ✅** | Server uptime and request statistics |
67-
| `formulas://library` | **Extended ✅** | Collection of mathematical formulas |
68-
69-
**✅ All 7 tools, 3 prompts, and 4 resources confirmed working with MCP Inspector CLI**
70-
71-
## 🚀 Quick Start
74+
|:------|:--------|:----------------|
75+
| `calculate` | **Core ✅** | Basic arithmetic with optional streaming progress. |
76+
| `batch_calculate` | **Extended ✅** | Processes multiple calculations in a single request. |
77+
| `advanced_calculate` | **Extended ✅** | Factorial, logarithm, and combinatorics operations. |
78+
| `demo_progress` | **Extended ✅** | Demonstrates progress notifications over the `stdout` stream. |
79+
| `explain-calculation` | **Core ✅** | Returns a Markdown explanation of a calculation. |
80+
| `generate-problems` | **Core ✅** | Returns Markdown-formatted practice problems. |
81+
| `calculator-tutor` | **Core ✅** | Returns Markdown-formatted tutoring content. |
82+
| `solve_math_problem` | **Extended ✅** | Solves a math problem, may elicit input. |
83+
| `explain_formula` | **Extended ✅** | Provides an interactive formula explanation. |
84+
| `calculator_assistant` | **Extended ✅** | Offers interactive calculator assistance. |
85+
| `calculator://constants` | **Core ✅** | Resource for mathematical constants (π, e, φ, etc.). |
86+
| `calculator://history/{id}` | **Extended ✅** | Resource for the last 50 calculation results stored in memory. |
87+
| `calculator://stats` | **Extended ✅** | Resource for server uptime and request statistics. |
88+
| `formulas://library` | **Extended ✅** | Resource for a collection of mathematical formulas. |
89+
90+
## 🚀 Getting Started
7291

7392
### Prerequisites
7493

75-
- Node.js 18.x or higher
76-
- npm or yarn
94+
* Node.js (v18.x or higher)
95+
* npm or yarn
7796

7897
### Installation
7998

8099
```bash
81100
# Clone the repository
82-
git clone <repository-url>
83-
cd calculator-learning-demo-stdio
101+
git clone https://github.com/modelcontextprotocol/mcp-server-examples.git
102+
cd mcp-server-examples/stdio
84103

85104
# Install dependencies
86105
npm install
@@ -91,39 +110,64 @@ npm run build
91110

92111
### Running the Server
93112

113+
The server is designed to be spawned by a client. You can run it directly to send it commands interactively.
114+
94115
```bash
95-
# Start the server
116+
# Run the low-level (manual) server implementation
96117
npm start
97118

98-
# Development mode with auto-reload
119+
# Run the high-level (SDK) server implementation
120+
node dist/server.js --stdio
121+
122+
# Run in development mode (rebuilds on changes)
99123
npm run dev
124+
```
125+
126+
### Testing with MCP Inspector
100127

101-
# Test with MCP Inspector CLI
102-
npm run inspector
128+
Interact with the SDK-based server using the official MCP Inspector CLI. This command spawns the server and pipes its I/O to the inspector.
129+
130+
```bash
131+
npx @modelcontextprotocol/inspector --cli "node dist/server.js --stdio"
103132
```
104133

105-
## 📋 API Examples
134+
## 📋 API Usage Examples
106135

107-
### Basic Calculation
136+
All requests must be a single JSON object terminated by a newline character (`\n`).
108137

109-
Interactive session (stdin shown with ``):
138+
### High-Level (SDK) Server (`dist/server.js`)
110139

111-
```
140+
The SDK uses a structured `tools/call` method.
141+
142+
```bash
143+
# Request (as a single line)
112144
→ {"jsonrpc":"2.0","id":1,"method":"tools/call","params":{"name":"calculate","arguments":{"a":7,"b":6,"op":"multiply"}}}
113-
{"jsonrpc":"2.0","id":1,"result":{"content":[{"type":"text","text":"Result: 42"}]}}
145+
146+
# Response
147+
{"jsonrpc":"2.0","id":1,"result":{"content":[{"type":"text","text":"7 × 6 = 42"}]}}
114148
```
115149

116-
### Batch Operations
150+
### Low-Level (Manual) Server (`dist/server-stdio.js`)
117151

118-
```
119-
→ {"jsonrpc":"2.0","id":2,"method":"tools/call","params":{"name":"batch_calculate","arguments":{"calculations":[{"a":10,"b":5,"op":"add"},{"a":20,"b":4,"op":"multiply"}]}}}
120-
{"jsonrpc":"2.0","id":2,"result":{"content":[{"type":"text","text":"Results: [15, 80]"}]}}
152+
This implementation uses direct method names, bypassing the `tools/call` wrapper.
153+
154+
```bash
155+
# Request (as a single line)
156+
→ {"jsonrpc":"2.0","id":1,"method":"calculate","params":{"a":7,"b":6,"op":"multiply"}}
157+
158+
# Response
159+
{"jsonrpc":"2.0","id":1,"result":{"value":42,"meta":{"calculationId":"...","timestamp":"..."}}}
121160
```
122161

123162
### Progress Demonstration
124163

125-
```
164+
Progress notifications are sent as standard JSON-RPC notifications (no `id` field) over `stdout`.
165+
166+
```bash
167+
# Request
126168
→ {"jsonrpc":"2.0","id":3,"method":"tools/call","params":{"name":"demo_progress","arguments":{}}}
169+
170+
# Response Stream
127171
{"jsonrpc":"2.0","method":"progress","params":{"progressToken":"progress_3","progress":20,"total":100}}
128172
{"jsonrpc":"2.0","method":"progress","params":{"progressToken":"progress_3","progress":40,"total":100}}
129173
{"jsonrpc":"2.0","method":"progress","params":{"progressToken":"progress_3","progress":60,"total":100}}
@@ -132,111 +176,54 @@ Interactive session (stdin shown with `→`):
132176
{"jsonrpc":"2.0","id":3,"result":{"content":[{"type":"text","text":"Progress demonstration completed"}]}}
133177
```
134178

135-
### Advanced Mathematics
136-
137-
```
138-
→ {"jsonrpc":"2.0","id":4,"method":"tools/call","params":{"name":"advanced_calculate","arguments":{"operation":"factorial","n":5}}}
139-
{"jsonrpc":"2.0","id":4,"result":{"content":[{"type":"text","text":"5! = 120"}]}}
140-
```
141-
142-
### Access Resources
143-
144-
```
145-
→ {"jsonrpc":"2.0","id":5,"method":"resources/read","params":{"uri":"calculator://constants"}}
146-
{"jsonrpc":"2.0","id":5,"result":{"contents":[{"uri":"calculator://constants","mimeType":"application/json","text":"{\"pi\":3.141592653589793,\"e\":2.718281828459045,\"phi\":1.618033988749895}"}]}}
147-
148-
→ {"jsonrpc":"2.0","id":6,"method":"resources/read","params":{"uri":"calculator://stats"}}
149-
{"jsonrpc":"2.0","id":6,"result":{"contents":[{"uri":"calculator://stats","mimeType":"application/json","text":"{\"uptimeMs\":12500,\"requestCount\":6}"}]}}
150-
```
151-
152-
### Use Prompts
153-
154-
```
155-
→ {"jsonrpc":"2.0","id":7,"method":"prompts/get","params":{"name":"explain-calculation","arguments":{"expression":"25 × 4","level":"intermediate"}}}
156-
{"jsonrpc":"2.0","id":7,"result":{"description":"Explain the calculation: 25 × 4 at intermediate level with step-by-step breakdown","messages":[{"role":"user","content":{"type":"text","text":"Please explain how to calculate 25 × 4 step by step..."}}]}}
157-
```
158-
159-
## 🛠️ Transport Internals
160-
161-
### Message Framing
179+
## 🧠 State Management Model
162180

163-
- Each JSON-RPC envelope MUST end with `\n`
164-
- No non-JSON output on `stdout` (diagnostic logs go to `stderr`)
165-
- Supports concurrent request processing
181+
**Principle:** State is ephemeral and strictly scoped to the lifetime of the server process.
166182

167-
### Concurrency Model
183+
- **Mechanism:** All state is held in standard JavaScript variables and `Map` objects within the Node.js process.
184+
- **Stored Data:**
185+
- **Calculation History:** A `Map` stores the last 50 calculation results as a ring buffer.
186+
- **Server Statistics:** Variables track the process start time and total request count.
187+
- **In-flight Requests:** The MCP SDK maintains a `Map` to track concurrent requests and route responses correctly.
188+
- **Lifecycle:** When the process exits for any reason, all in-memory state is irrevocably lost. Each new process starts with a clean slate. This is a fundamental and intentional design choice for this transport.
168189

169-
- Maintains `Map<id, PromiseResolver>` for in-flight requests
170-
- Notifications (no `id` field) are fire-and-forget
171-
- Progress notifications reference original request ID
190+
## 🛡️ Security Model
172191

173-
### Exit Codes
192+
The STDIO transport provides the most secure environment of all MCP transports by leveraging operating system primitives.
174193

175-
- **0**: Normal shutdown
176-
- **65**: Fatal parse error (EX_DATAERR)
177-
- **70**: Unhandled exception (EX_SOFTWARE)
194+
- **Process Isolation:** The server runs in a separate memory space from the client, preventing any direct memory access or interference. The OS enforces this boundary.
195+
- **No Network Exposure:** Communication is entirely via local IPC pipes. There are no open ports, making network-based attacks (e.g., CSRF, MitM, remote exploits) impossible.
196+
- **Input Validation:** All incoming request parameters are rigorously validated by Zod schemas (defined in `src/types.ts`) to ensure type safety and prevent injection-style attacks.
197+
- **Resource Limiting:** The server enforces hard limits on batch sizes (`maxBatchSize: 100`) and history storage (`maxHistorySize: 50`) to prevent resource exhaustion attacks.
198+
- **Exit Code Signaling:** The server uses standard Unix exit codes to signal its termination status to the parent process (e.g., `0` for success, `65` for data errors, `70` for software errors), allowing the client to react appropriately.
178199

179200
## 🧪 Testing
180201

202+
This project includes a test suite that spawns the server as a child process to validate its I/O behavior.
203+
181204
```bash
182-
# Run all tests
205+
# Run all tests defined in jest.config.js
183206
npm test
184207

185-
# Run with coverage
208+
# Run tests and generate a code coverage report
186209
npm run test:coverage
187210

188-
# Run integration tests
189-
npm run test:integration
190-
191-
# Watch mode for development
211+
# Run tests in watch mode for interactive development
192212
npm run test:watch
193-
194-
# Memory leak testing
195-
npm run test:memory
196213
```
197214

198-
### Test Coverage
199-
200-
The implementation includes comprehensive testing:
201-
- Unit tests for all 7 tools
202-
- Resource access validation
203-
- Prompt generation testing
204-
- Progress notification flow
205-
- Error handling and exit codes
206-
- Memory usage validation
207-
208-
## 📝 State Management
209-
210-
**Important**: All state is stored in process memory and resets when the process exits:
211-
212-
- **Calculation history**: Last 50 operations
213-
- **Request counters**: Total requests processed
214-
- **Uptime statistics**: Process start time
215-
- **Formula library**: Static mathematical formulas
216-
217-
This behavior is by design for STDIO transport - each client spawns a fresh server process.
218-
219-
## 🔒 Security Considerations
220-
221-
- **Process isolation**: Server runs in separate process with restricted permissions
222-
- **No network exposure**: Communication only via local pipes
223-
- **Input validation**: All parameters validated with Zod schemas
224-
- **Resource limits**: Max batch size (100), max history (50)
225-
- **Exit code signaling**: Proper error reporting to parent process
226-
227-
## 📖 Resources
215+
## 📚 Project Resources
228216

229-
- [MCP Specification](https://spec.modelcontextprotocol.io)
230-
- [Model Context Protocol Documentation](https://modelcontextprotocol.io)
231-
- [STDIO Transport Documentation](https://spec.modelcontextprotocol.io/specification/basic/transports/#stdio)
217+
* [MCP Specification](https://spec.modelcontextprotocol.io)
218+
* [Model Context Protocol Documentation](https://modelcontextprotocol.io)
219+
* [STDIO Transport Documentation](https://spec.modelcontextprotocol.io/specification/basic/transports/#stdio)
232220

233221
## 📝 License
234222

235-
This project is licensed under the MIT License - see the [LICENSE](LICENSE) file for details.
223+
This project is licensed under the MIT License.
236224

237225
---
238226

239227
<p align="center">
240-
✅ <strong>Fully Compliant with MCP Learning Edition Golden Standard</strong><br/>
241-
All 7 tools, 3 prompts, and 4 resources confirmed working with modern MCP SDK
228+
✅ <strong>Fully Compliant with MCP Learning Edition Golden Standard</strong>
242229
</p>

0 commit comments

Comments
 (0)