MCP Demo
by VictorC55
README.md
# MCP Demo
A learning project for the **Model Context Protocol (MCP)**. It has one MCP
**server** that exposes a few example tools, and two **clients** that let a
language model discover and call those tools — one driven by a **local model via
LM Studio** (free, offline) and one driven by **Claude** (Anthropic API).
The point of the project is to show that **the server is model-agnostic**: the
same `server.py` works with any model — only the client changes.
## How it fits together
```
You type a question
│
▼
client (drives the LLM) ──► LLM decides to call a tool
│ │
│ spawns over stdio │
▼ ▼
server.py ◄─────────── client executes the tool call
(add1, multiply2, greet) and feeds the result back
```
- **`server.py`** — the MCP server (built with FastMCP). Defines the tools.
- **`client_lmstudio.py`** — chat loop that drives a **local** model (LM Studio).
- **`client_claude.py`** — same idea, driven by **Claude** (needs an API key).
The client launches `server.py` as a subprocess and talks to it over **stdio**
(standard in/out). It lists the server's tools, hands them to the model, and runs
the loop: model asks to call a tool → client runs it against the server → result
goes back to the model → repeat until the model gives a final answer.
## Tools exposed by the server
| Tool | What it does |
|------|--------------|
| `add1(a, b)` | Returns `a + b + 1` (the extra `+1` proves the tool actually ran) |
| `multiply2(a, b)` | Returns `a * b * 2` |
| `greet(name, excited=False)` | Returns a greeting; `excited=True` adds enthusiasm |
There's also a `config://version` resource returning the app version.
> These are placeholder tools. To make the project do something real, replace
> the bodies with actual logic (a DB query, an API call, a computation) — the
> wiring stays exactly the same.
## Setup
Requires Python 3.10+.
```bash
python3 -m venv .venv
source .venv/bin/activate
pip install -r requirements.txt
```
That installs everything: `mcp[cli]` (the server + Inspector), `openai` (the LM
Studio client), and `anthropic[mcp]` (the Claude client — only needed if you use
that one).
## Running with a local model (LM Studio) — free, no API key
This is the recommended way to try it — it runs entirely on your machine.
1. **Install and open [LM Studio](https://lmstudio.ai).**
2. **Download a model that supports tool/function calling.** This project uses
**`qwen2.5-7b-instruct-1m`**, which handles tools well. Other good picks:
Qwen2.5 Instruct, Llama 3.1/3.2 Instruct. Small or non-instruct models often
call tools poorly.
3. **Start the local server:** LM Studio → **Developer / Local Server** tab →
load the model → **Start Server**. It listens on `http://localhost:1234/v1`
(an OpenAI-compatible endpoint).
4. **Check the model id** shown in LM Studio matches the `MODEL` constant near
the top of `client_lmstudio.py`; update it if you loaded a different model.
5. **Run the client:**
```bash
.venv/bin/python client_lmstudio.py
```
6. **Chat.** Type a question at the `You:` prompt, e.g.
*"Greet Alice excitedly, then add 5 and 7."* Type `exit` or `quit` to leave.
If the "5 + 7" answer comes back as **13** (not 12), that confirms the model
really called your `add1` tool instead of doing its own arithmetic.
**Notes on local models:** they follow instructions less reliably than cloud
models — responses may be verbose or occasionally skip a tool. Verbosity is tuned
via the system prompt at the top of the client's `messages` list. Swapping to a
stronger model in LM Studio also helps.
## Running with Claude (Anthropic API) — costs a small amount
1. Get an API key at [console.anthropic.com](https://console.anthropic.com)
(Settings → API Keys).
2. Export it:
```bash
export ANTHROPIC_API_KEY=sk-ant-...
```
3. Run:
```bash
.venv/bin/python client_claude.py
```
Same behavior, but Claude follows instructions and calls tools more reliably.
Costs are tiny (a fraction of a cent for this demo).
## Inspecting the server directly (no LLM)
To poke the tools by hand in a browser UI:
```bash
.venv/bin/mcp dev server.py
```
This opens the **MCP Inspector**, where you can call each tool manually. (If it
errors trying to spawn `uv`, either install `uv`, or in the Inspector set
**Command** to your venv's python and **Arguments** to `server.py`.)
## Things worth remembering
- **The client and server transport must match.** These clients spawn the server
and talk over **stdio**, so `server.py` must end with `mcp.run()`. If you switch
it to `mcp.run(transport="sse")` (an HTTP server), the stdio client breaks —
it'll try to parse the web-server's log lines as protocol messages.
- **In stdio mode, don't `print()` inside tools** — stdout *is* the protocol
channel. Use `print(..., file=sys.stderr)` for debugging.
- **The server never changes when you switch models.** MCP standardizes the tool
server; each model provider just needs its own client (or a framework that
abstracts them).
## Possible next steps
- Replace the placeholder tools with real functionality.
- Add a graphical UI (Streamlit / Gradio / Chainlit for a quick chat box, or
FastAPI + a web frontend for a real webapp).
- Serve the tools over HTTP (`transport="streamable-http"`) so they can be
reached remotely instead of only as a local subprocess.
This server cannot be deployed
Maintenance
ActivityInactive
ResponsivenessNo issues