llm-toolkit
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., "@llm-toolkitsummarize this article about quantum computing into 5 bullet points"
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.
Build Your Own MCP Server (and Deploy It)
A complete, working MCP server that turns an LLM API into MCP tools — built to be taught. It runs locally over stdio for Claude Desktop / Claude Code, and remotely over HTTP once you deploy it.
Backed by Groq — fast inference, OpenAI-compatible API, free tier that survives a room full of students hammering it during a workshop.
Everything lives in one file: server.py. ~170 lines including comments.
Part 0 — What is MCP, in one minute
MCP (Model Context Protocol) is a standard way to give an AI client new abilities. You write a server; any MCP client can use it.
A server can expose three things:
Primitive | What it is | Who controls it |
Tool | A function the model can call | The model decides |
Resource | Read-only data the client can pull in | The client/app decides |
Prompt | A reusable prompt template | The user picks it |
Two transports:
stdio — the client launches your server as a subprocess and talks over stdin/stdout. Local only. Zero networking. This is how 90% of MCP servers run.
streamable HTTP — your server is a web service at a URL. This is what you deploy so other people (or hosted clients) can use it.
The same server.py does both. That's the whole trick.
Part 1 — What we're building
llm-toolkit: an MCP server that gives any MCP client four LLM-powered tools.
Tool | Does |
| Ask a question, pick concise / detailed / eli5 |
| Text → N bullet points |
| Translate, preserving markdown and code blocks |
| Unstructured text → structured JSON |
Plus one resource (config://server-info) and one prompt (code_review) so students
see all three primitives.
Part 2 — Run it locally
Setup
python -m venv .venvWindows: .\.venv\Scripts\activate — macOS/Linux: source .venv/bin/activate
pip install -r requirements.txtGet a free key at console.groq.com → API Keys. Then copy
.env.example to .env and paste it in:
cp .env.example .env.env is gitignored. The server loads it automatically from its own directory, so it
works no matter where the client launches it from.
Inspect it before wiring it up
The MCP Inspector is the single best teaching tool — it shows the tool list and lets you call tools by hand, no AI client needed.
npx @modelcontextprotocol/inspector python server.pyOpen the printed URL, hit Connect, then List Tools. You'll see all four.
Part 3 — Connect it to a client
Claude Code
claude mcp add llm-toolkit -e GROQ_API_KEY=gsk_... -- python /absolute/path/to/server.pyOr commit a .mcp.json in your project root so the whole team gets it — see
.mcp.json.example.
Claude Desktop
Edit claude_desktop_config.json:
macOS —
~/Library/Application Support/Claude/claude_desktop_config.jsonWindows —
%APPDATA%\Claude\claude_desktop_config.json
Paste the mcpServers block from .mcp.json.example, then fully quit and reopen
Claude Desktop. The tools appear under the tools icon.
Absolute paths only. The #1 reason a local MCP server "doesn't show up" is a relative path — the client's working directory is not yours. Use the full path to both the python binary (
.venv/bin/python) andserver.py.
Part 4 — Deploy it
Switch to HTTP mode with one flag:
python server.py --httpServer is now at http://localhost:8000/mcp. Ship that same command in a container.
Option A — Render, no Docker (recommended)
Render has a native Python runtime. No Dockerfile, no container build. It installs
requirements.txt and runs your start command directly. This is the fastest path from
laptop to public URL.
Step 1 — get the code on GitHub.
git init && git add -A && git commit -m "MCP server"Create an empty repo at github.com/new, then:
git remote add origin https://github.com/<you>/llm-toolkit-mcp.git && git push -u origin mainStep 2 — create the service.
Render dashboard → New → Web Service → connect the repo. Render reads
render.yaml and configures itself:
Setting | Value |
Runtime | Python (not Docker) |
Build command |
|
Start command |
|
Step 3 — set the key. Dashboard → Environment → add GROQ_API_KEY. It's marked
sync: false in render.yaml, so it lives only in the dashboard, never in git.
Step 4 — deploy. Your public endpoint is https://<your-app>.onrender.com/mcp.
No health check on purpose.
GET /mcpopens an SSE stream that stays open by design. A health check pointed at it hangs, and Render reads the timeout as a dead service and restart-loops it. WithhealthCheckPathomitted, Render just verifies the process binds$PORT— the correct check for this server.
Free-tier instances sleep after ~15 min idle. The first call after a sleep takes ~30–50s while it wakes. Some MCP clients time out before that and report the server as broken. Warm it with a curl before class starts.
Option B — Other no-Docker hosts
Host | How |
Railway | Connect repo. Nixpacks auto-detects Python. Set start command to |
Hugging Face Spaces | Free, no sleep. Docker Space, or Gradio Space with a custom |
Google Cloud Run |
|
Any VPS |
|
Option C — Fly.io
fly launch --no-deployfly secrets set GROQ_API_KEY=gsk_...fly deployEndpoint: https://<your-app>.fly.dev/mcp
Option D — Any container host
The Dockerfile is kept for hosts that want a container. Works on
Railway, Cloud Run, ECS, a VPS:
docker build -t llm-toolkit-mcp .docker run -p 8000:8000 -e GROQ_API_KEY=gsk_... llm-toolkit-mcpVerify the deployment
One curl proves the server is alive and speaking MCP:
curl -X POST https://your-app.onrender.com/mcp -H "Content-Type: application/json" -H "Accept: application/json, text/event-stream" -d '{"jsonrpc":"2.0","id":1,"method":"initialize","params":{"protocolVersion":"2025-06-18","capabilities":{},"clientInfo":{"name":"curl","version":"1"}}}'You should get back a serverInfo block naming llm-toolkit.
Connect a client to the deployed server
claude mcp add --transport http llm-toolkit https://your-app.onrender.com/mcpStudents paste that one line and instantly have your four tools. That's the payoff moment of the whole workshop — no install, no key, no Python on their machine.
Sharing it publicly — read this first
A deployed MCP server with no auth is open to the entire internet. Anyone who learns the URL can call your tools, and every call spends your Groq quota.
For a workshop that is usually fine, and Groq's free tier is what makes it fine: when the quota runs out you get HTTP 429 errors, not a bill. The failure mode is "tools stop answering," not "surprise invoice."
It stops being fine the moment you put a paid key behind it. Then add auth before
sharing the URL — the MCP SDK's auth parameter, or an API gateway in front.
Two habits worth keeping either way:
Treat the URL as semi-secret. Share it in class, don't post it publicly.
Rotate the key after the workshop. It's one dashboard click.
Part 5 — Things worth teaching explicitly
The docstring is the API. The model picks tools by reading the docstring and the type hints. A vague docstring means a tool that never gets called. This is the single highest-leverage thing in the whole file.
One function owns the provider. Every tool calls call_llm(). Swapping Groq for
OpenAI, Anthropic, or a local Ollama means editing that one function — the four tools
never change. Demo this live; it lands hard.
Return errors as strings, don't raise. call_llm catches GroqError and returns
the message as text. The client shows the user a real error instead of a dead tool call.
stateless_http=True means no sticky sessions, so the server scales behind a load
balancer. Turn it off only if you add per-session state.
Never commit the key. .env is gitignored, render.yaml uses sync: false,
Fly uses fly secrets.
Public HTTP servers are open by default. This one has no auth — fine for a demo,
not for production. Real deployments add OAuth via the SDK's auth parameter, or sit
behind an API gateway.
Version drift is real. MCP Python SDK 2.0 renamed FastMCP to MCPServer. Most
tutorials online still show FastMCP and will fail on a fresh install. Good moment to
teach reading the installed package instead of trusting a blog post.
Part 6 — Exercises for the class
Add a
sentiment(text)tool. (Copysummarize, change the system prompt.)Make
ask_llmaccept amax_tokensargument and watch the schema update automatically in the Inspector.Point
call_llmat a different provider without touching any tool.Add a resource
config://usagethat reports how many tool calls the process has served. (Hint: a module-level counter.)Break a docstring on purpose, then ask the model to use that tool. Watch it fail to pick the tool. That's the lesson.
Part 7 — Getting other people to use it
Handing the tools to someone else is three separate problems: reachable, connectable, discoverable. Solve them in that order.
1. Reachable. A server on localhost is usable by exactly one person. Deploy it
(Part 4) and you have a public URL. Nothing below works until this is done.
2. Connectable. Give people USING-IT.md — a standalone page with
copy-paste config for Claude Code, Claude Desktop, and Cursor, plus a troubleshooting
table. For a workshop, the remote route is the one to use: students paste one line and
have working tools with no Python, no repo, and no API key of their own.
3. Discoverable. Only if you want strangers to find it, not just your class:
Channel | What it gets you |
GitHub topics | Free search traffic |
The official MCP registry | Listed in client "browse servers" UIs |
| PR to add your repo |
Smithery / Glama and similar directories | Hosted install buttons |
Registry requirements move quickly — check the current MCP registry docs for the manifest format before publishing.
A note on the honest ceiling. People adopt an MCP server when it does something they cannot already do. This one wraps a generic LLM, which most clients already have built in — perfect for teaching the protocol, weak as a product. A server that reaches your database, your internal API, or your proprietary data is the one that gets real users. Worth saying out loud to the class.
Part 8 — What makes it production ready
The workshop version and the production version differ in ways that have nothing to do with MCP. This is the list, and every item exists because of a failure that actually happened while building this server.
Protecting the key
A public MCP endpoint is a public spending endpoint: every call costs you.
Guard | Env var | Default | Why |
Bearer auth |
| empty = open | Gate access once a paid key is behind it |
Rate limit |
| 30/IP | One script cannot drain your quota |
Input cap |
| 20000 | A pasted novel is rejected before it costs tokens |
Body cap |
| 1 MB | Oversized payloads die before parsing |
Auth is off by default so the server stays open for a workshop on a free key. Turn it on before pointing a paid key at a public URL:
MCP_AUTH_TOKEN=$(python -c "import secrets;print(secrets.token_urlsafe(32))") python server.py --httpClients then send Authorization: Bearer <token>.
Surviving the provider
Models get retired without notice. Groq removed llama-3.3-70b-versatile during
development — it worked at 07:15 and 404'd an hour later. Every tool broke at once,
and a 404 reads like "your server is broken," not "the vendor moved."
MODEL_CHAIN fixes this: on a model-not-found error the call rolls to the next model
instead of failing. Other errors — a bad key, a rate limit — fail fast, because
retrying those across five models just wastes time.
Timeouts (LLM_TIMEOUT_SECONDS) and retries (LLM_MAX_RETRIES) are handed to the
vendor SDKs, which already implement backoff correctly.
Health checks
/health returns plain JSON. Never health-check /mcp — it is an SSE stream that
stays open by design, so the probe hangs, the platform calls the service dead, and you
get a restart loop that looks like a crash. This cost a real debugging cycle here.
Logging
Everything goes to stderr, never stdout. In stdio mode stdout carries the JSON-RPC
stream, so one stray print() corrupts the protocol. This is the most common way to
break an MCP server while debugging it.
The MCP-level middleware logs every method with its duration, and works for both transports.
Tests and CI
pytest tests/ runs offline with no API key and spends nothing. It covers the rate
limiter's window expiry, input caps, model fallback, tool schema preservation, and
config validation.
GitHub Actions runs the suite on 3.11 and 3.12, boots the server, and scans the full git history for committed API keys — the failure that is unrecoverable, because a pushed key is public the moment it lands.
Known limits
Worth being honest with a class about what is still missing:
Rate limiting is per-process. Scale to N instances and you allow N times the limit. Swap in Redis before it matters.
One shared token, not per-user keys. Fine for a class, not for customers.
No usage metering. You cannot tell who spent what.
Free-tier cold starts still take 30–50s after idle.
File map
File | Why it exists |
| The entire server — tools, resource, prompt |
|
|
| Container for any host |
| One-click Render deploy |
| Fly.io deploy |
| Which env vars exist |
| Client config to copy |
| Standalone page to hand to users |
| Auth, rate limiting, size caps, logging |
| Offline test suite, no API key needed |
| CI: tests, boot check, secret scan |
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.
Related MCP Connectors
MCP server for AI dialogue using various LLM models via AceDataCloud
MCP server providing access to the Scorecard API to evaluate and optimize LLM systems.
MCP server for Pentest-Tools.com: run scans, manage findings and reports via your preffered LLM.
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/aihunter9892/mcpserver'
If you have feedback or need assistance with the MCP directory API, please join our Discord server