mcp-from-scratch
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-from-scratchsearch the docs for python dataclasses"
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-from-scratch
A from-scratch implementation of the Model Context Protocol (MCP): raw JSON-RPC 2.0 server, HTTP and stdio transports, a minimal ReAct agent loop, and a trajectory-grading evaluation harness. Built with stdlib and FastAPI only — no LangChain, no MCP SDK, no third-party agent frameworks.
Why this exists
Most "MCP" code on the internet is npm install and five lines of config. When my agent's tool call fails at 3 a.m., I want to be able to read the spec and fix it, not grep through four layers of SDK abstractions. This repo is the smallest version that teaches you what JSON-RPC actually looks like on the wire — and then gives you an eval harness to grade what your agent did with it.
┌──────────┐ HTTP/stdio ┌─────────────┐
│ Client │ ───────────────► │ MCP Server │
└──────────┘ │ (raw JSON- │
│ RPC 2.0) │
└──────┬──────┘
│ dispatch
┌──────┴──────┐
│ Tool/Resource│
│ Registry │
└──────┬──────┘
│
┌──────┴──────┐
│ search_docs │
│ (corpus.json)│
└─────────────┘Related MCP server: docusaurus-plugin-mcp
What's in here
src/mcp_from_scratch/jsonrpc.py— JSON-RPC 2.0 codec:JsonRpcRequest,JsonRpcResponse,JsonRpcError, encode/decode helpers, full error-code coverage (-32700parse,-32600invalid request,-32601method not found,-32602invalid params,-32603internal).src/mcp_from_scratch/transport_http.py— FastAPI HTTP transport, singlePOST /rpcendpoint, line-delimited JSON overContent-Type: application/json.src/mcp_from_scratch/transport_stdio.py— Stdio line-delimited JSON transport for piping agents.src/mcp_from_scratch/server.py— MCP server core: tool registry, resource registry, full dispatch over the five MCP methods (initialize,tools/list,tools/call,resources/list,resources/read).src/mcp_from_scratch/tools/search_docs.py— A single tool:search_docs(query) -> list[dict]over the bundled corpus.src/mcp_from_scratch/resources/docs.py— A single resource:docs://{slug}returning doc content.src/mcp_from_scratch/agent_loop.py— A minimal ReAct agent loop as an explicit state machine.Thought → Act → Observe, with a deterministic stub LLM (keyword router) and a real LLM hook for production.max_stepsbudget.src/mcp_from_scratch/eval/trajectory.py—TrajectoryandStepdata structures.src/mcp_from_scratch/eval/graders.py— Grader suite:exact_match,substring_match(contains),tool_called,step_count,llm_judge.src/mcp_from_scratch/eval/harness.py—run_eval(agent_fn, test_set, graders) -> EvalReport, plus a CLI runner.data/eval_set.json— Four-task eval suite: Python dataclasses, JSON-RPC spec, MCP tools, async I/O.examples/run_eval.py— Demo runner that emitseval_report.json.
Quickstart
git clone https://github.com/aditya0si/mcp-from-scratch
cd mcp-from-scratch
pip install -e ".[dev]"
# Run unit tests
pytest
# Run the eval harness against the bundled demo agent
python examples/run_eval.py
# → writes eval_report.json with per-task scoresTry the MCP server
# Start the HTTP transport
python -m mcp_from_scratch.transport_http
# → listens on http://127.0.0.1:8765/rpcA curl roundtrip — full MCP initialize then tools/list:
curl -s http://127.0.0.1:8765/rpc \
-H 'Content-Type: application/json' \
-d '{"jsonrpc":"2.0","id":1,"method":"initialize","params":{"client":"demo","version":"0.1.0"}}'
# {"jsonrpc":"2.0","id":1,"result":{"server":"mcp-from-scratch","version":"0.1.0","capabilities":{"tools":true,"resources":true}}}
curl -s http://127.0.0.1:8765/rpc \
-H 'Content-Type: application/json' \
-d '{"jsonrpc":"2.0","id":2,"method":"tools/list"}'
# {"jsonrpc":"2.0","id":2,"result":[{"name":"search_docs","description":"...","inputSchema":{...}}]}Then call the tool:
curl -s http://127.0.0.1:8765/rpc \
-H 'Content-Type: application/json' \
-d '{"jsonrpc":"2.0","id":3,"method":"tools/call","params":{"name":"search_docs","arguments":{"query":"python json-rpc"}}}'How the agent loop works
State machine, no LangChain. Each step is explicit:
class AgentLoop:
def step(self, task: str) -> Step:
thought = self.llm.think(self.history, task)
action = self.router.parse(thought) # tool_call | final_answer
if action.type == "final_answer":
return Step(thought=thought, action=action, observation="")
observation = self.tools.call(action.tool, action.arguments)
return Step(thought=thought, action=action, observation=observation)Loop terminates on final_answer or after max_steps. The LLM is an injected callable — for tests we use a deterministic stub (keyword router), for production we wire in any function-calling LLM.
Eval harness — what's graded
Each test runs the agent against a task, captures the full Trajectory, then scores it with the grader list:
Grader | What it checks |
| Final answer equals expected (case/whitespace normalized) |
| Final answer contains an expected substring |
| A specific tool name appears in the trajectory |
| Total steps ≤ a maximum |
| An LLM rates the final answer 1-5 against the expected |
run_eval(agent_fn, test_set, graders=[...]) returns:
{
"total_tests": 4,
"passed_tests": 4,
"pass_rate": 1.0,
"per_test": [
{
"id": "eval-python-dataclass",
"task": "...",
"passed": true,
"final_answer": "...",
"trajectory": { "steps": [...], "tool_calls": [...] },
"grader_results": [
{"grader": "exact_match", "passed": true, "score": 1.0, "reason": "..."},
{"grader": "tool_called", "passed": true, "score": 1.0, "reason": "..."},
{"grader": "step_count", "passed": true, "score": 1.0, "reason": "..."}
]
}
],
"aggregate": { "avg_steps": 1.75, "avg_tool_calls": 0.75 }
}Run python examples/run_eval.py to regenerate.
Tests
29 unit tests across five files:
tests/test_jsonrpc.py 6 tests
tests/test_server.py 7 tests
tests/test_transport_http.py 6 tests
tests/test_agent_loop.py 4 tests
tests/test_eval_harness.py 6 testsAll passing on Python 3.11+. CI runs them on every PR.
Project layout
mcp-from-scratch/
├── data/
│ ├── corpus.json # ~20 short docs the tool searches over
│ └── eval_set.json # 4-task evaluation set
├── examples/
│ └── run_eval.py # demo runner
├── src/mcp_from_scratch/
│ ├── agent_loop.py
│ ├── eval/
│ │ ├── graders.py
│ │ ├── harness.py
│ │ └── trajectory.py
│ ├── jsonrpc.py
│ ├── resources/
│ │ └── docs.py
│ ├── server.py
│ ├── tools/
│ │ └── search_docs.py
│ ├── transport_http.py
│ └── transport_stdio.py
└── tests/
├── test_agent_loop.py
├── test_eval_harness.py
├── test_jsonrpc.py
├── test_server.py
└── test_transport_http.pyWhy no LangChain / SDK
Because the point is to understand what's underneath. After reading this code, when you use the official MCP SDK or LangGraph you'll know exactly what JSON-RPC message is on the wire, why the tool call failed, and where the dispatch lives. You'll also be able to debug production agents without grepping four layers of abstraction.
Roadmap
Real LLM integration examples (OpenAI function calling, Anthropic, Groq)
Streaming responses over SSE
Resource subscriptions and notifications
Pluggable tool registry (load from YAML)
More graders: cost, latency, token-budget
CI workflow with GitHub Actions
License
MIT.
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
Agent-native MCP server over the public saagarpatel.dev corpus. Read-only, stateless.
MCP server for agentverse documentation, generated by doc2mcp.
Nifty's MCP server — exposes tasks, projects, messages, and files as tools for AI agents.
Turn a GitHub repo or docs site into agent-ready context: pack it or search it, over MCP.
Related MCP Servers
- AlicenseNot gradedqualityAmaintenanceLocal-first MCP server for querying multi-repo engineering documentation artifacts from a SQLite corpus.11AGPL 3.0
- AlicenseNot gradedqualityCmaintenanceExposes Docusaurus documentation and OpenAPI specs as an MCP server, enabling AI agents to search docs and inspect API endpoints.13MIT
- AlicenseAqualityBmaintenanceEnables searching and retrieving documentation from crawled documentation sites as an MCP server, allowing coding agents to query real docs instead of relying on training data.4MIT
- AlicenseNot gradedqualityAmaintenanceBuilds a keyword-searchable index from markdown documentation bundles and serves it to LLM agents via MCP, with retrieval logging and reporting for curation.MIT
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/aditya0si/mcp-from-scratch'
If you have feedback or need assistance with the MCP directory API, please join our Discord server