mcp-scaffold
by abduznik
README.md
# mcp-scaffold
A generic, plug-and-play MCP (Model Context Protocol) server. Clone it, add your own
tools to `tools.js`, run it, and connect it to Claude, Cursor, or Windsurf. No MCP SDK,
no framework, no build step — just Node's built-in `http` module.
## Quick start
```bash
git clone https://github.com/abduznik/mcp-scaffold.git
cd mcp-scaffold
npm install # no dependencies, but keeps npm happy
npm start
```
```
mcp-scaffold running on http://localhost:3939/mcp
Registered tools: (none yet — add some in tools.js)
```
That's expected — `tools.js` ships with its example tool commented out. See below to
turn it on.
## Try the example tool
Open `tools.js`. Near the top of the `tools` array there's a `roll_dice` example, fully
commented out:
```javascript
export const tools = [
// ── EXAMPLE TOOL — commented out by default ─────────────────────────────────
// Uncomment the block below to try a working example (rolls dice). Comment it
// back out (or delete it) once you're ready to add your own tools instead.
//
// {
// name: "roll_dice",
// ...
// },
];
```
Uncomment that block (just the `{ ... }` object — remove the leading `//` from each
line), restart the server, and `roll_dice` is live:
```
Registered tools: roll_dice
```
Comment it back out any time to disable it again — nothing else in the project needs to
change either way.
## Add your own tool
`mcp-server.js` is generic plumbing — you shouldn't need to edit it. Everything you touch
lives in `tools.js`:
```javascript
export const tools = [
// ...existing tools...
{
name: "my_tool",
description: "One clear sentence describing what it does and when to use it.",
inputSchema: {
type: "object",
properties: {
arg_one: { type: "string", description: "What this argument is for" },
},
required: ["arg_one"],
},
handler({ arg_one }) {
return `You said: ${arg_one}`;
},
},
];
```
Restart the server (`npm start`) and your tool is live.
**The `description` field matters more than it looks.** The model reads it to decide
*when* to call your tool, not just what it does. Be specific about the trigger ("use this
when the user asks to...") rather than just naming the function.
## Test it before connecting any AI client
Always verify with `curl` first — if something's broken, this tells you whether the bug
is in your server or in the client config.
```bash
# initialize
curl -s -X POST localhost:3939/mcp \
-d '{"jsonrpc":"2.0","id":1,"method":"initialize"}'
# tools/list — confirm your tool shows up
curl -s -X POST localhost:3939/mcp \
-d '{"jsonrpc":"2.0","id":2,"method":"tools/list"}'
# tools/call — confirm it actually runs (after uncommenting roll_dice)
curl -s -X POST localhost:3939/mcp \
-d '{"jsonrpc":"2.0","id":3,"method":"tools/call","params":{"name":"roll_dice","arguments":{"sides":20,"count":2}}}'
```
## Connect it to Claude Desktop
Add this to `claude_desktop_config.json`
(macOS: `~/Library/Application Support/Claude/claude_desktop_config.json`):
```json
{
"mcpServers": {
"mcp-scaffold": {
"type": "url",
"url": "http://localhost:3939/mcp"
}
}
}
```
Restart Claude Desktop. Ask it to do whatever your tool does, in plain language — the
model calls your tool on its own when it decides it's relevant.
## Deploying it for free (optional)
This server has zero dependencies, so it also runs unmodified on Cloudflare Workers —
just wrap the same logic in a `fetch(request)` export instead of `http.createServer`.
Free tier, no credit card, public URL anyone can connect to.
## How it works
- `mcp-server.js` — generic MCP protocol handler. Answers the three methods every MCP
client needs: `initialize`, `tools/list`, `tools/call`. Reads whatever tools are
exported from `tools.js` and wires them up automatically.
- `tools.js` — where your tools live. Each tool is `{ name, description, inputSchema,
handler }`. `handler` can be sync or async and can return anything that stringifies
sensibly — that string is what the model sees back.
## License
MIT — do whatever you want with it.
This server cannot be deployed
Maintenance
ActivityMaintained
ResponsivenessNo issues