Skip to main content

Command Palette

Search for a command to run...

Building a Production MCP Server: Lessons from 30+ Apps

After reviewing 30+ apps, here's what separates weekend prototypes from tools people actually use.

Updated
6 min read

After cataloging and reviewing over 30 MCP applications at getmcpapps.com, I've seen what works, what breaks, and what separates a weekend prototype from something people actually use. Here's what I've learned.

The Gap Between "It Works" and "It Ships"

Most MCP server tutorials end at "hello world." You get stdio working, you register a tool, Claude calls it, and you're done. That's fine for learning. But the apps that actually get installed and stay installed handle a dozen things the tutorials don't mention.

1. Error Messages That Actually Help

When your MCP server breaks, Claude shows the user a JSON error. That error is the only debugging information they'll see. Make it count.

Bad:

{"error": "Failed"}

Better:

{"error": "API key missing. Set GITHUB_TOKEN in environment."}

Best:

{
  "error": "GitHub API authentication failed",
  "details": "GITHUB_TOKEN not found in environment. Get one at: https://github.com/settings/tokens",
  "docs": "https://github.com/yourname/mcp-server#setup"
}

The best error messages include:

  • What went wrong (not just "failed")
  • Why it went wrong
  • How to fix it (with a link if possible)

2. Handle Rate Limits Before They Hit

Every external API has rate limits. If your MCP server doesn't handle them, users will hit walls and blame your tool.

Strategies that work:

  • Check remaining quota before expensive calls. If you're about to make 50 API requests and the user has 10 left, tell them upfront.
  • Exponential backoff on 429s. Don't just retry immediately. Wait 1s, then 2s, then 4s.
  • Cache aggressively. If Claude asks for the same GitHub repo info twice in 30 seconds, return the cached version.

The MCP servers that stay installed are the ones that don't burn through API quotas.

3. Validation is Not Optional

Claude will send you garbage inputs. Users will typo repository names, paste malformed URLs, request files that don't exist. Your server needs to validate before calling external APIs.

Validate:

  • Required fields are present
  • URLs are actual URLs
  • File paths don't escape boundaries (../../etc/passwd)
  • Enum values match allowed options
  • Numeric ranges make sense

Return a clear error immediately. Don't let the external API tell them the input was wrong — you should catch it first.

4. Timeouts Everywhere

Network calls hang. APIs go down. Filesystems block on NFS mounts. If your MCP server doesn't have timeouts, it will freeze Claude.

Timeout every:

  • HTTP requests (5-10s for most APIs)
  • File operations (especially on network drives)
  • Database queries
  • Subprocess calls

When a timeout fires, return a useful error. "GitHub API timed out after 10s. Check your network connection."

5. Secrets Management

Storing API keys in plaintext config files is how MCP servers end up on "please don't install this" lists.

Do:

  • Use environment variables (process.env.API_KEY)
  • Support .env files for local dev
  • Document exactly which env vars are needed
  • Check for secrets on startup and fail fast with clear instructions

Don't:

  • Commit secrets to git (add .env to .gitignore)
  • Log secrets (even in debug mode)
  • Pass secrets in URLs (they end up in logs)

6. Installation Should Be One Command

The best MCP servers install with:

npx your-mcp-server

or

pip install your-mcp-server

No cloning repos. No manual npm installs. No "first run these 5 setup commands." If it takes more than one line, most people won't install it.

Ship:

  • An npm package (for Node)
  • A PyPI package (for Python)
  • A binary (for Go/Rust)

Make it trivial to try. You can add advanced setup options in the docs, but the happy path should be one command.

7. Logs (But Not Too Many)

When things break, users need logs. When things work, users want silence.

Log:

  • Errors (always)
  • Warnings (rate limits approaching, deprecated features)
  • Startup configuration (which env vars were found)

Don't log:

  • Every tool call (spams the console)
  • Request/response bodies (security risk)
  • Stack traces for expected errors (validation failures)

Support a DEBUG=1 mode for troubleshooting, but keep the default quiet.

8. Testing (Yes, Really)

MCP servers are harder to test than normal APIs because Claude is in the loop. But you can still test the core logic.

Test:

  • Tool parameter validation (pass garbage, expect clear errors)
  • API response parsing (mock the external API)
  • Error handling (simulate timeouts, rate limits, auth failures)
  • Edge cases (empty results, huge results, malformed data)

The apps with test coverage are the ones that don't break on updates.

9. Documentation Is Your Marketing

Your README is the landing page. If it doesn't clearly explain what the server does and why someone would want it, nobody installs it.

Good READMEs include:

  • One sentence: what does this do?
  • Installation (one command)
  • Setup (which env vars, where to get API keys)
  • Example usage (show Claude using it)
  • Troubleshooting (common errors and fixes)

A GIF showing it in action is worth 500 words of explanation.

10. Versioning and Updates

Once people install your MCP server, they'll expect it to keep working. That means:

Semantic versioning. Breaking changes need a major version bump. Bug fixes are patch releases.

Changelog. Tell people what changed. "Fixed rate limiting bug" is useful. "Various improvements" is not.

Backward compatibility when possible. If you rename a tool, support the old name for one version with a deprecation warning.

11. Graceful Degradation

Not everyone has API keys. Not everyone has network access. Not everyone runs the latest version of Claude.

Design for:

  • Offline mode (cache what you can, explain what needs network)
  • Missing credentials (offer limited functionality instead of failing entirely)
  • Older Claude versions (don't assume features from the latest release)

The best MCP servers work in as many environments as possible.

The Checklist

Before you call it "production ready":

  • [ ] Clear error messages with actionable fixes
  • [ ] Rate limit handling (check quota, backoff, cache)
  • [ ] Input validation on all parameters
  • [ ] Timeouts on all external calls
  • [ ] Environment variables for secrets
  • [ ] One-command installation
  • [ ] Quiet logs by default, DEBUG mode available
  • [ ] Tests for core logic
  • [ ] README with install/setup/examples
  • [ ] Semantic versioning + changelog

What Actually Matters

After reviewing 30+ MCP apps, here's what separates the ones people use from the ones people try once and uninstall:

Reliability > features. A server that does 3 things well beats one that does 10 things poorly.

Error messages > everything. When it breaks (and it will), users need to know why and how to fix it.

Easy install > perfect code. If it's hard to install, it doesn't matter how good it is.

Ship something simple that works reliably. You can add features later. You can't un-burn someone's API quota or un-frustrate them after a cryptic error.


Based on patterns from 30+ production MCP servers cataloged at getmcpapps.com. If you're building an MCP server and want feedback, submit it to the catalog.

More from this blog

T

The Plug

22 posts