Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
40 changes: 40 additions & 0 deletions docs/docs/how-to/tools-and-agents.md
Original file line number Diff line number Diff line change
Expand Up @@ -275,6 +275,46 @@ gets generated (see examples above).
> **Warning:** `local_code_interpreter` executes Python code in the current process.
> Do not use it in production contexts without sandboxing.

## MCP tools

Mellea can consume tools from any [MCP](https://modelcontextprotocol.io/) server
and drop them into an agent loop. Install with `pip install 'mellea[tools]'`.

The workflow is two steps: discover what the server offers, then instantiate the
tools you want.

```python
# Requires: mellea[tools]
# Returns: list[MelleaTool]
from mellea.stdlib.tools.mcp import discover_mcp_tools, http_connection

connection = http_connection("https://api.example.com/mcp/", api_key="...")

specs = await discover_mcp_tools(connection)
tools = [s.as_mellea_tool() for s in specs if s.name in {"search", "fetch"}]
```

`http_connection`, `sse_connection`, and `stdio_connection` build the transport
config. Each tool invocation opens a short-lived session, so callers do not need
to manage the connection lifetime.

Once built, MCP tools work like any other `MelleaTool`: pass them via
`ModelOption.TOOLS` to `instruct()` or to `react()`:

```python
# Requires: mellea[tools]
# Returns: str
result, _ = await react(
goal="Find recent pull requests I authored.",
context=ChatContext(),
backend=m.backend,
tools=tools,
)
```

See [`docs/examples/mcp/github_activity_summary.py`](https://github.com/generative-computing/mellea/blob/main/docs/examples/mcp/github_activity_summary.py)
for a complete example against the hosted GitHub MCP server.

---

**See also:** [Tutorial 04: Making Agents Reliable](../tutorials/04-making-agents-reliable) | [Instruct, Validate, Repair](../concepts/instruct-validate-repair)
69 changes: 56 additions & 13 deletions docs/examples/mcp/README.md
Original file line number Diff line number Diff line change
@@ -1,27 +1,40 @@
# Write a poem MCP
This is a simple example to show how to write a MCP tool
with Mellea and instruct-validate-repair. Being able to
speak the tool language allows you to integrate with
Claude Desktop, Langflow, ...
# MCP examples

See code in [mcp_example.py](mcp_example.py)
Two directions are covered here:

- **Expose Mellea as an MCP server** — [`mcp_example.py`](mcp_example.py).
Makes a Mellea instruct-validate-repair loop callable as an MCP tool from
Claude Desktop, Langflow, or any MCP client.
- **Consume MCP server tools from Mellea** —
[`github_activity_summary.py`](github_activity_summary.py). Discovers tools on
a remote MCP server and drops them into a Mellea `react()` loop.

## Write a poem MCP (Mellea as server)

A simple example to show how to write a MCP tool with Mellea and
instruct-validate-repair. Being able to speak the tool language lets you integrate
with Claude Desktop, Langflow, and other MCP clients.

See code in [`mcp_example.py`](mcp_example.py).

### Running the poem server

Install the MCP SDK:

## Run the example
You need to install the mcp package:
```bash
uv pip install "mcp[cli]"
```

and run the example in MCP debug UI:
Run the example in the MCP debug UI:

```bash
uv run mcp dev docs/examples/mcp/mcp_example.py
```

### Use in Langflow

## Use in Langflow
Follow this path (JSON) to use it in Langflow: [https://docs.langflow.org/mcp-client#mcp-stdio-mode](https://docs.langflow.org/mcp-client#mcp-stdio-mode)

The JSON to register your MCP tool is the following. Be sure to insert the absolute path to the directory containing the mcp_example.py file:
Follow [this guide](https://docs.langflow.org/mcp-client#mcp-stdio-mode) to register
the tool. Insert the absolute path to the directory containing `mcp_example.py`:

```json
{
Expand All @@ -41,6 +54,36 @@ The JSON to register your MCP tool is the following. Be sure to insert the absol
}
```

## GitHub activity summary (Mellea as client)

Uses the hosted GitHub MCP server to summarize recent pull requests.
Demonstrates the two-step workflow (discover tools, pick the ones you need,
wrap as `MelleaTool`) and drives multi-turn tool use via `react()`.

See code in [`github_activity_summary.py`](github_activity_summary.py), and
the [Tools and Agents how-to guide](../../docs/how-to/tools-and-agents) for
the API overview.

### Running the activity summary

Install Mellea with tools support:

```bash
pip install 'mellea[tools]'
```

Set a GitHub token with `repo` and `read:user` scopes:

```bash
export GITHUB_TOKEN=<your token>
```

Run:

```bash
uv run python docs/examples/mcp/github_activity_summary.py --days 14
```

The script discovers every tool on the GitHub MCP server, filters down to
`get_me` and `search_pull_requests`, then asks the model to summarize your
pull-request activity over the specified window.
77 changes: 77 additions & 0 deletions docs/examples/mcp/github_activity_summary.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,77 @@
# pytest: skip_always
"""Example: summarise recent GitHub activity using the GitHub MCP server.

Demonstrates the mellea MCP workflow:
1. Discover all tools on the server with discover_mcp_tools()
2. Pick only the ones needed by name
3. Drive multi-turn tool use with mellea's react() loop

Prerequisites:
pip install 'mellea[tools]'
export GITHUB_TOKEN=<token with repo + read:user scopes>

Usage:
uv run python docs/examples/mcp/github_activity_summary.py
"""

import argparse
import asyncio
import os
from datetime import UTC, datetime, timedelta

from mellea import start_session
from mellea.backends import model_ids
from mellea.core.base import AbstractMelleaTool
from mellea.stdlib.context import ChatContext
from mellea.stdlib.frameworks.react import react
from mellea.stdlib.tools.mcp import discover_mcp_tools, http_connection

GITHUB_MCP_URL = "https://api.githubcopilot.com/mcp/"
TOOLS_NEEDED = {"get_me", "search_pull_requests"}


async def main(days: int) -> None:
token = os.environ.get("GITHUB_TOKEN")
if not token:
raise SystemExit("GITHUB_TOKEN environment variable is required")

now = datetime.now(UTC)
since = (now - timedelta(days=days)).strftime("%Y-%m-%d")
today = now.strftime("%Y-%m-%d")

connection = http_connection(GITHUB_MCP_URL, api_key=token)
m = start_session(model_id=model_ids.IBM_GRANITE_4_1_8B)

# --- Tool discovery ---
specs = await discover_mcp_tools(connection)
print(f"Discovered {len(specs)} tools on the GitHub MCP server")

# --- Tool selection ---
relevant = [s for s in specs if s.name in TOOLS_NEEDED]
print(f"Using {len(relevant)} tools: {[s.name for s in relevant]}")
tools: list[AbstractMelleaTool] = [s.as_mellea_tool() for s in relevant]

# --- Agent loop ---
result, _ = await react(
goal=(
f"Today is {today}. Find my GitHub username, then search for pull requests "
f"I authored since {since} filtering by my username. "
"List each pull request with its title, number, and repository."
),
context=ChatContext(),
backend=m.backend,
tools=tools,
loop_budget=6,
)

print("\n--- Activity Summary ---")
print(result.value)


if __name__ == "__main__":
parser = argparse.ArgumentParser()
parser.add_argument(
"--days", type=int, default=14, help="How many days back to look"
)
args = parser.parse_args()
asyncio.run(main(args.days))
Loading
Loading