MCP-based tool-use fine-tuning framework
Project description
MCPTune
Fine-tune a small language model to call a specific MCP server's tools.
Give MCPTune an MCP server and a base model. It discovers the server's tools, generates a synthetic tool-use dataset, and fine-tunes the model to emit that server's tool calls in a format a runtime can execute. A built-in minimal runtime and evaluation let you measure whether the fine-tune actually worked.
The thesis MCPTune exists to test: small models can be trained to do reliable
MCP tool-calling for a specific server, cheaply and locally. This release is
the pipeline that produces and measures that - run examples/evaluate.py to
get the base-vs-tuned number for your server and model.
Install
pip install mcptune # core: discovery, dataset generation, formats
pip install "mcptune[transformers]" # add LoRA fine-tuning + the runtime model runner
From source (for development):
git clone https://github.com/TomasrRodrigues/mcptune
cd mcptune
pip install -e ".[dev]"
How it works
discover → sample args → synthesize intent → execute → synthesize answer → train → evaluate
adapter sampling synthesis runtime synthesis LoRA runtime
The model only ever emits a tool-call request as text. A runtime parses it, executes it against the MCP server, and feeds the result back. MCPTune trains the model to emit those requests well; the orchestration runtime is a separate concern (this repo ships a minimal one for evaluation and demos; production deployments use an MCP-aware framework).
Quickstart
import asyncio
from fastmcp import FastMCP
from mcptune import MCPTune
server = FastMCP("demo")
@server.tool
def get_weather(city: str) -> str:
"""Get the current weather for a city."""
return f"Sunny and 22C in {city}"
async def main():
tuner = MCPTune(
model="Qwen/Qwen2.5-1.5B-Instruct",
mcpserver=server,
llm_backend="ollama", # natural intents + arguments (needs Ollama)
llm_model="qwen2.5:3b",
seed=42,
)
tools = await tuner.discover()
dataset = tuner.build_dataset(tools, samples_per_tool=8) # sample + intent (offline)
dataset = await tuner.execute(dataset) # tool results + final answers
for row in dataset[:3]:
print(f"{row.user_intent} -> {row.tool_name}({row.arguments})")
asyncio.run(main())
Fine-tune on the dataset (needs mcptune[transformers]):
from mcptune.training.backends.transformers_backend import TransformersTrainerBackend
tuner = MCPTune(
model="Qwen/Qwen2.5-1.5B-Instruct",
mcpserver=server,
llm_backend="ollama", llm_model="qwen2.5:3b",
trainer=TransformersTrainerBackend(output_dir="./checkpoints"),
seed=42,
)
tools = await tuner.discover()
dataset = await tuner.execute(tuner.build_dataset(tools, samples_per_tool=20))
trained = tuner.train(dataset, config={"epochs": 1})
Then measure base vs tuned with examples/evaluate.py, or run the model against
your server through the minimal runtime with examples/run_agent.py.
What's in 0.1.0
| Capability | Status |
|---|---|
| Tool discovery + JSONSchema fidelity (FastMCP) | ✅ |
| Structural + semantic argument sampling (seeded) | ✅ |
| Intent synthesis (template / Ollama / transformers) | ✅ |
| Native tool-use training format + SFT masking | ✅ |
| Tool execution + answer synthesis (full loop) | ✅ |
| LoRA fine-tuning (transformers + PEFT) | ✅ |
| Minimal runtime + before/after evaluation | ✅ |
| stdio / HTTP adapters | 🚧 planned |
| Full evaluation pipeline, forward-mode generation | 🚧 0.2.0 |
| Production runtime, multi-turn, personas | 🚧 1.0.0 |
Documentation
Supported models
Native tool-call emission targets Qwen (<tool_call>) first. Other open-weight
families with tool-aware chat templates (Llama 3.1+, Mistral) need a parser entry
in mcptune.runtime.parsing. MCPTune fine-tunes open-weight models only - it does
not train closed APIs.
Contributing
See CONTRIBUTING.md for the workflow and architectural constraints. Issues are tracked by milestone (0.1.x, 0.2.0, 1.0.0).
License
MIT - see LICENSE.
Project details
Release history Release notifications | RSS feed
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
Built Distribution
Filter files by name, interpreter, ABI, and platform.
If you're not sure about the file name format, learn more about wheel file names.
Copy a direct link to the current filters
File details
Details for the file mcptune-0.1.1.tar.gz.
File metadata
- Download URL: mcptune-0.1.1.tar.gz
- Upload date:
- Size: 35.4 kB
- Tags: Source
- Uploaded using Trusted Publishing? No
- Uploaded via: twine/6.2.0 CPython/3.12.3
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
dea981538ce94be26e8fdcc1d5a64ab05eea402fef1f3bdb21af1f7187828517
|
|
| MD5 |
6d3cd13b0445a9b9ec7cf16429441767
|
|
| BLAKE2b-256 |
3a4b6b5d29678709908dcd5dddafb0a172db49c89ae6328b8d3afefaccc6e280
|
File details
Details for the file mcptune-0.1.1-py3-none-any.whl.
File metadata
- Download URL: mcptune-0.1.1-py3-none-any.whl
- Upload date:
- Size: 47.2 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? No
- Uploaded via: twine/6.2.0 CPython/3.12.3
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
407d68ce21a308b85c83b47728bd31400feea64f9fe68d2b6e72d8af677c7738
|
|
| MD5 |
e2300ed5f87659a61c764f31d83f4978
|
|
| BLAKE2b-256 |
9563bc1679445f6382a5f82ce1ef70fe73566f7535e8e9fac3435cf2b09c1a30
|