mcp-context-engineering
by crzyc0d3r
README.md
# mcp-context-engineering
A small, runnable project that demonstrates **context engineering for MCP
servers**: keeping a Model Context Protocol server's footprint in the model's
context window small, so agents are cheaper and more accurate.
## The problem
When an MCP client (Claude Desktop, Cursor, an SDK app) connects to an MCP
server, it pulls **every** advertised tool definition - name, description and
full input schema - into the model's context. A server with 30-60+ tools can
burn well over 10k tokens on definitions before the agent does anything. That
causes two problems:
- **Wasted tokens.** You pay for tool definitions the agent will never call.
- **Reduced accuracy.** The model gets distracted by irrelevant tools and is
more likely to pick the wrong one or hallucinate parameters.
## The two techniques
This project implements both halves of the fix on a catalog of 33 mock
"web-data" tools (Amazon, LinkedIn, TikTok, GitHub, Zillow, browser
automation, batch scraping, ...) organised into logical groups.
1. **Scope the tools you advertise.** Load only the capabilities an agent
needs - either by whole *group* (`GROUPS=social`) or by *hand-picking*
individual tools (`TOOLS=web_data_amazon_product,...`). Only those
definitions ever reach the context.
2. **Optimise the output those tools return.** Strip token-wasting Markdown
(bold/italic, image syntax, heading markers, code fences, link URLs) from
scraped pages before they enter the context, keeping every word the model
actually reads.
### Measured impact (from the bundled offline report)
Full catalog = 33 tools ≈ **4,556 tokens** of definitions if loaded un-scoped.
| Configuration | Tools | Def. tokens | Saved vs. all |
|----------------------------------------|:-----:|:-----------:|:-------------:|
| default (base tools only) | 3 | 506 | **89%** |
| `GROUPS=ecommerce` | 9 | 1,318 | **71%** |
| `GROUPS=social` | 11 | 1,566 | **66%** |
| `GROUPS=social,business` | 14 | 1,973 | **57%** |
| `TOOLS=` amazon,ebay,google_shopping | 3 | 416 | **91%** |
| `GROUPS=research` + 1 custom tool | 6 | 917 | **80%** |
| `PRO_MODE=true` (load everything) | 33 | 4,556 | 0% |
Strip-markdown on a scraped page: **243 → 149 tokens (~39% fewer).**
Numbers use a built-in heuristic token estimator; pass `--tiktoken` to the
report for exact counts if `tiktoken` is installed. The point is the *ratios*,
which are stable.
## The pattern in one sentence
Scope the tools you load, trim the output they return, and let the MCP server
handle the hard parts.
## Code map
```
mcp-context-engineering/
├── src/mcp_context_engineering/
│ ├── __init__.py # Public API re-exports + version.
│ ├── tool_groups.py # Source of truth for groups: BASE_TOOLS + 8 logical
│ │ # groups (ecommerce, social, business, research,
│ │ # finance, app_stores, browser, advanced_scraping)
│ │ # and helpers (all_tool_names, total_tool_count).
│ ├── tool_catalog.py # Full catalog of 33 ToolSpecs: name, description,
│ │ # JSON input schema, and an OFFLINE mock handler
│ │ # each. Also MARKDOWN_TOOLS (which outputs to strip)
│ │ # and a SAMPLE_MARKDOWN_PAGE for the demo.
│ ├── context_config.py # The scoping brain. Reads PRO_MODE / GROUPS / TOOLS,
│ │ # resolves the exact tool set (resolve_context),
│ │ # and defines named PRESETS.
│ ├── strip_markdown.py # Dependency-free output optimiser: strips Markdown
│ │ # formatting, keeps words + code, links optional.
│ ├── token_utils.py # Lightweight offline token estimator + tool-def
│ │ # token counting (tiktoken optional).
│ └── server.py # The MCP server (official SDK low-level Server,
│ │ # stdio). Advertises only scoped tools; strips
│ │ # Markdown output. build_server() for tests.
├── scripts/
│ ├── run_server.py # Launch the server over stdio (what a client runs).
│ └── token_report.py # Offline demo: prints the savings tables above.
├── examples/
│ ├── claude_desktop_social_agent.json # config: one group
│ ├── claude_desktop_price_monitor.json # config: hand-picked tools
│ └── claude_desktop_pro_mode.json # config: everything (baseline)
├── tests/
│ └── test_context_engineering.py # 23 offline tests (unittest)
├── requirements.txt # Just the official `mcp` SDK (tiktoken optional).
├── .env.example # All config vars, documented.
└── .gitignore
```
### How the pieces fit
`tool_groups.py` defines which tool *names* belong to which group.
`tool_catalog.py` gives each name a full definition (description + schema) and a
mock handler. `context_config.py` reads the environment and decides the exact
subset of names to expose. `server.py` asks `context_config` for that subset,
advertises only those definitions via `tools/list`, and - when a
`MARKDOWN_TOOLS` tool is called - runs its output through `strip_markdown.py`
before returning it. `token_utils.py` powers the offline `token_report.py`,
which quantifies both wins without touching the network.
## Data flow
```mermaid
flowchart TD
subgraph Config["Configuration (env vars)"]
E["PRO_MODE / GROUPS / TOOLS<br/>STRIP_MARKDOWN"]
end
E --> RC["context_config.resolve_context()"]
TG["tool_groups.py<br/>(group -> tool names)"] --> RC
RC -->|"scoped list of tool names"| SRV["server.py (MCP Server)"]
TC["tool_catalog.py<br/>(name -> description, schema, handler)"] --> SRV
subgraph MCP["MCP session (stdio)"]
CLIENT["MCP client / LLM agent"]
SRV
end
SRV -->|"tools/list: ONLY scoped definitions"| CLIENT
CLIENT -->|"tools/call(name, args)"| SRV
SRV -->|"handler() output"| STRIP["strip_markdown.py<br/>(markdown tools only)"]
STRIP -->|"trimmed text"| CLIENT
RC -.offline.-> REPORT["scripts/token_report.py"]
TC -.offline.-> REPORT
TU["token_utils.py"] -.-> REPORT
REPORT -.-> OUT["savings tables"]
```
## Quick start
```bash
# 1. (optional) create a virtualenv
python -m venv .venv && source .venv/bin/activate # Windows: .venv\Scripts\activate
# 2. install the one dependency
pip install -r requirements.txt
# 3. see the token savings - fully offline, no key, no network
python scripts/token_report.py
python scripts/token_report.py --json # machine-readable
# 4. run the tests
python -m unittest discover -s tests -v
```
## Running the MCP server
The server speaks MCP over stdio and is configured entirely through environment
variables:
```bash
# default: just the small base tool set
python scripts/run_server.py
# a focused social-media agent
GROUPS=social python scripts/run_server.py
# hand-pick exactly the tools a price monitor needs
TOOLS=web_data_amazon_product,web_data_ebay_product,web_data_google_shopping \
python scripts/run_server.py
# the un-scoped baseline (loads everything)
PRO_MODE=true python scripts/run_server.py
# disable output trimming
STRIP_MARKDOWN=false GROUPS=social python scripts/run_server.py
```
Valid group ids: `ecommerce`, `social`, `business`, `research`, `finance`,
`app_stores`, `browser`, `advanced_scraping`. See `.env.example` for the full
list of variables.
### Wiring into an MCP client
Copy one of the files in `examples/` into your client's server config (for
Claude Desktop that is `claude_desktop_config.json`), replace `/ABSOLUTE/PATH`
with the path to your checkout, and restart the client. The three examples show
a scoped group, a hand-picked set, and the load-everything baseline.
## Notes on the tools
Every tool handler in this project returns **canned, offline sample data**.
There is no API key and no network access anywhere - the goal is to demonstrate
the context-engineering pattern, not to scrape live sites. To make it real, swap
the handlers in `tool_catalog.py` for calls to an actual web-data backend and
read its credentials from an environment variable (a placeholder,
`WEB_DATA_API_KEY`, is documented in `.env.example`).
## Built on / inspired by
- **Model Context Protocol Python SDK** - the official SDK this server uses:
https://github.com/modelcontextprotocol/python-sdk
- **Protocol docs & spec:** https://modelcontextprotocol.io
- **Bright Data MCP server** - an open-source MCP server that popularised the
tool-group scoping and strip-markdown output optimisation modelled here:
https://github.com/brightdata/brightdata-mcp
## License
MIT (see `LICENSE` if present, or treat the sample code as MIT-licensed).
This server cannot be deployed
Maintenance
ActivitySlowing
ResponsivenessNo issues