starter-mcp-server
README.md
# starter-mcp-server
> **Course:** MCP & Tool Ecosystems
> **Path:** Agentic Coding Path · Position 11
A Gold Standard MCP server scaffold. Three working primitives (tools, resources, prompts)
wired to Claude Desktop in under 5 minutes. Extend it with your own tools using the
patterns in `agent.spec.md`.
---
## What Is MCP?
The **Model Context Protocol** is an open standard that lets Claude (and other AI models)
call code you write — fetching data, running calculations, querying databases — without
leaving the conversation.
```
You → Claude → calls your tool → tool runs → result back to Claude → Claude answers you
```
This server implements MCP over **stdio**, which means Claude Desktop spawns it as a
child process and communicates via stdin/stdout. No HTTP, no ports, no hosting needed.
---
## Quick Start
### 1. Install and build
```bash
npm install
npm run build
```
### 2. Find your absolute path
```bash
pwd
# → /Users/yourname/projects/starter-mcp-server
```
### 3. Configure Claude Desktop
Open (or create) your Claude Desktop config file:
- **macOS:** `~/Library/Application Support/Claude/claude_desktop_config.json`
- **Windows:** `%APPDATA%\Claude\claude_desktop_config.json`
Add the `mcpServers` block (replace the path with your real path from step 2):
```json
{
"mcpServers": {
"starter-mcp-server": {
"command": "node",
"args": ["/Users/yourname/projects/starter-mcp-server/dist/index.js"]
}
}
}
```
See `claude_desktop_config.json.example` for a full example with environment variables.
### 4. Restart Claude Desktop
Fully quit and reopen Claude Desktop. Look for the **🔨 hammer icon** near the chat input.
Click it — you should see `starter-mcp-server` listed with three tools.
### 5. Test it
Try asking Claude:
> *"Use the calculate_sum tool to add 847 and 293."*
> *"Read the system://info resource and tell me how much free memory this machine has."*
---
## What's Included
### Tools (Claude can call these)
| Tool | What it does |
|---|---|
| `calculate_sum` | Adds two numbers: `a + b` |
| `calculate_percentage` | `part` is X% of `whole` |
| `calculate_compound_interest` | Final balance after compounding |
### Resources (Claude can read these)
| URI | What it returns |
|---|---|
| `system://info` | Platform, Node version, memory, uptime (JSON) |
| `system://env` | Variables prefixed with `SAFE_` from your `.env` (JSON) |
### Prompts (appear in Claude's "/" menu)
| Prompt | What it does |
|---|---|
| `/explain_tool` | Ask Claude to explain any tool by name |
---
## Development Workflow
**Test without Claude Desktop** (uses the MCP Inspector UI):
```bash
npm run inspect
```
**Watch mode** (auto-restarts on file changes):
```bash
npm run dev
```
After editing source files, run `npm run build` before testing with Claude Desktop.
Claude Desktop caches the built output — it reads from `dist/`, not `src/`.
---
## Adding Your First Tool
1. Create `src/tools/weather.ts` — follow the exact pattern in `src/tools/math.ts`
2. Export `weatherTools: Tool[]` and `handleWeatherTool(name, args): string | null`
3. In `src/index.ts`, add two lines (marked with `// ADD NEW ...` comments)
4. Run `npm run build`
5. Restart Claude Desktop
The `agent.spec.md` file contains a copy-paste prompt you can give to Claude Code
to build a complete new tool for you.
---
## File Structure
```
src/
index.ts ← server setup + request routing
tools/
math.ts ← 3 math tools (the pattern to copy)
resources/
system.ts ← 2 system info resources
prompts/
index.ts ← 1 sample prompt
dist/ ← compiled JS (generated by npm run build)
claude_desktop_config.json.example
.env.example
agent.spec.md ← AI prompt to extend this server
```
---
## Critical Rule: Never Use `console.log`
`stdout` is reserved for the MCP JSON-RPC protocol. Any `console.log()` call will corrupt
the stream and break Claude Desktop's connection to this server.
**Always use `console.error()`** for debug output. It writes to stderr, which is safe.
```typescript
// ✅ Safe — writes to stderr
console.error("debug:", someValue);
// ❌ Breaks the server — writes to stdout
console.log("debug:", someValue);
```