MCP Starter
Click on "Install Server".
Wait a few minutes for the server to deploy. Once ready, it will show a "Started" state.
In the chat, type
@followed by the MCP server name and your instructions, e.g., "@MCP Starterlook up order ORD-2025-001"
That's it! The server will respond to your query, and you can continue using it as needed.
Here is a step-by-step guide with screenshots.
MCP Starter
A production-grade Model Context Protocol server you can fork for client work. Both transports are implemented and tested: stdio (local) and Streamable HTTP (remote, stateless).
54 tests, clean typecheck, no any in the source.
npm install
npm test # 54 passing
npm run build
npm start # stdio
npm run start:http
npm run inspect # official MCP Inspector UIWhat MCP is
MCP is a standard way to give an AI assistant access to somebody else's system. Before it, every integration was one-off: custom code for Shopify, more for HubSpot, more for the client's internal database. MCP replaces that with one protocol, so any assistant that speaks it — Claude Desktop, Claude Code, Cursor, ChatGPT — can use any MCP server.
A server exposes three things:
Concept | What it is | In this repo |
Tools | Actions the model can take |
|
Resources | Read-only data pulled into context | the return policy, an order record |
Prompts | Reusable templates the user picks |
|
Tools are what clients pay for. Resources and prompts are polish.
Transport is how the assistant reaches the server. stdio: the host launches the server as a local process and talks over stdin/stdout — used for anything touching a local machine, zero hosting cost. Streamable HTTP: the server lives at a URL — used for multi-user or SaaS-backed work, costs hosting but the customer installs nothing. Same server code, different entrypoint.
Related MCP server: etsy-mcp
What makes this production grade
Most MCP examples online are a server.tool() call and a console.log. Here is the difference.
Destructive actions are gated by a signed, single-use token
refund_order moves money. Calling it without a confirmToken does not refund — it returns a summary plus a token. The model must show the summary to the user and call again with the token.
The token is an HMAC bound to the exact arguments, so the model cannot get approval for a $1 refund and then execute a $189 one. It is single-use, so a retry loop can't fire twice, and it expires in five minutes. All four properties are tested, including the escalation attempt.
Errors never leak internals to the model
Every handler is wrapped. Domain errors become a clean isError tool result the model can recover from; unknown throws become a generic message while the real one goes to the logs. A test asserts a Postgres connection string in an exception never reaches the model-visible text.
Errors are also classified retryable vs not, and the retry logic respects it — a 404 fails once instead of burning the full retry budget.
Upstream calls have deadlines, retries, and jitter
Hard per-attempt timeout (a hung vendor API would otherwise hang the whole assistant turn), exponential backoff with full jitter, Retry-After honored, caller cancellation respected without retrying. Tested with an injected fetch and clock, so the suite is fast and deterministic.
Auth is constant-time; the server refuses to run open in production
Tokens are SHA-256 hashed before comparison, so timingSafeEqual gets equal-length buffers and comparison time leaks nothing. With NODE_ENV=production and no tokens configured, the server returns 500 rather than serving an open endpoint.
DNS-rebinding protection that actually works
A local MCP server is reachable from any web page the user visits: the page resolves an attacker domain to 127.0.0.1 and POSTs to it. Checking the Host header blocks this.
The SDK ships this feature, but it does an exact string compare against the raw header — which includes the port — so an allowlist of 127.0.0.1 silently 403s every request on any non-default port. Our integration test caught it. host-guard.ts compares hostname and port separately: an entry without a port matches any port, an entry with one must match both. IPv6 literals and case-insensitivity are handled and tested.
Everything else
Structured tool output (
outputSchema+structuredContent) so hosts get typed data, not a string to re-parseTool annotations (
readOnlyHint,destructiveHint,idempotentHint) so hosts can prompt appropriatelyPer-credential rate limiting (token bucket, lazy refill, swept to bound memory)
Single-flight TTL cache — a model firing the same tool three times in a turn makes one upstream call
Structured NDJSON logging to stderr with request IDs, child loggers, and automatic secret redaction
Config validated at boot — bad config kills the process with a readable message
Graceful shutdown — SIGTERM drains in-flight requests with a hard-stop backstop
Multi-stage Dockerfile, non-root, with a healthcheck
CI across Node 20/22/24 plus
npm audit
Layout
src/
config.ts zod-validated env
logger.ts NDJSON to stderr, redaction
errors.ts error taxonomy, public vs internal messages
http-client.ts timeouts, retries, jitter
cache.ts TTL + single-flight
rate-limit.ts token bucket
confirm.ts HMAC confirmation tokens
factory.ts dependency graph + server assembly
domain/orders.ts upstream adapter (HTTP + in-memory)
tools/
wrap.ts timing, logging, error normalization
orders.ts the tools themselves
transports/
stdio.ts local entrypoint
http.ts remote entrypoint
host-guard.ts DNS-rebinding protection
test/
unit.test.ts 37 tests
integration.test.ts 17 tests, real MCP client + real HTTP serverWire it into Claude Desktop
~/Library/Application Support/Claude/claude_desktop_config.json:
{
"mcpServers": {
"starter": {
"command": "node",
"args": ["/absolute/path/to/mcp-starter/dist/transports/stdio.js"]
}
}
}Restart Claude Desktop.
Deploy the HTTP version
docker build -t mcp-starter .
docker run -p 3000:3000 \
-e NODE_ENV=production \
-e MCP_AUTH_TOKENS="$(openssl rand -hex 32)" \
-e ALLOWED_HOSTS=your-domain.com \
mcp-starterOr push to GitHub and point Railway at it with start command npm run start:http. Set MCP_AUTH_TOKENS and ALLOWED_HOSTS. See .env.example for every setting.
Building a client's server
Replace
HttpOrderServiceinsrc/domain/orders.tswith their API. Parse responses through a zod schema so an upstream change surfaces as one validation error instead of malformed data reaching the model.Rewrite the tools around what their staff does by hand every day. One tool per job to be done, not per API endpoint. Five well-named tools beat twenty.
Write descriptions that say when to call the tool. That single line drives most of the accuracy.
Mark every destructive tool
destructiveHint: trueand route it throughConfirmationGate.Keep
InMemoryOrderServiceworking. It's how the tests stay fast and how you demo without credentials.
Gotchas that bite people
Never write to stdout in a stdio server. One
console.logcorrupts the protocol stream. Everything here logs to stderr.Don't return raw API dumps. Every token of tool output is context the model must read.
Stateless HTTP scales; sessions don't. This creates a fresh server per request, so it runs on any number of instances with no sticky routing. If you need session state, switch
sessionIdGeneratortorandomUUID— but then you own session eviction.
Scoping this as paid work
Wrap one internal API for Claude Desktop — stdio, no hosting, clean one-time deliverable.
Hosted multi-tenant server with auth — HTTP, needs hosting, key rotation, and upkeep when the upstream API changes. Never sell this as a fixed one-time build; attach a retainer.
Fix or finish a half-built MCP server — fits the Fix & Finish line.
This server cannot be installed
Maintenance
Resources
Unclaimed servers have limited discoverability.
Looking for Admin?
If you are the server author, to access and configure the admin panel.
Latest Blog Posts
- Who's Calling? MCP Hosts Are an Identity Blind Spot (And the Spec Knows It)By Om-Shree-0709 on .mcpAgent IdentityOAuth 2.1
- Your AI Chatbot Just Exposed Your CEO's Salary to an InternBy Om-Shree-0709 on .Agent IdentityMCP SecurityOAuth Delegation
- Why MCP Servers Need Execution Sandboxing (And Why Your Current Stack Isn't Enough)By Om-Shree-0709 on .Agentic AiPrompt InjectionWebAssembly
MCP directory API
We provide all the information about MCP servers via our MCP API.
curl -X GET 'https://glama.ai/api/mcp/v1/servers/LKocaj/mcp-starter'
If you have feedback or need assistance with the MCP directory API, please join our Discord server