Add support for MCP servers to Agent Framework, closes #898

This commit is contained in:
davidmezzetti
2025-04-12 11:13:26 -04:00
parent 9647c7e918
commit 97a5192cdf
6 changed files with 55 additions and 19 deletions
+9 -4
View File
@@ -34,18 +34,20 @@ def today() -> str:
return datetime.today().isoformat()
agent = Agent(
model="hugging-quants/Meta-Llama-3.1-8B-Instruct-AWQ-INT4",
tools=[today, wikipedia, arxiv, "websearch"],
llm="hugging-quants/Meta-Llama-3.1-8B-Instruct-AWQ-INT4",
)
```
## llm
## model
```yaml
llm: string|llm instance
model: string|llm instance
```
LLM path or LLM pipeline instance. See the [LLM pipeline](../../pipeline/text/llm) for more information.
LLM model path or LLM pipeline instance. The `llm` parameter is also supported for backwards compatibility.
See the [LLM pipeline](../../pipeline/text/llm) for more information.
## tools
@@ -83,7 +85,10 @@ A tool instance can be provided. Additionally, the following strings load tools
| Tool | Description |
|:------------|:----------------------------------------------------------|
| http.* | HTTP Path to a Model Context Protocol (MCP) server |
| python | Runs a Python action |
| websearch | Runs a websearch using the built-in websearch tool |
| webview | Extracts content from a web page |
## method
+7 -7
View File
@@ -41,9 +41,9 @@ def today() -> str:
return datetime.today().isoformat()
agent = Agent(
model="hugging-quants/Meta-Llama-3.1-8B-Instruct-AWQ-INT4",
tools=[today, wikipedia, arxiv, "websearch"],
llm="hugging-quants/Meta-Llama-3.1-8B-Instruct-AWQ-INT4",
max_iterations=10,
max_steps=10,
)
```
@@ -86,31 +86,32 @@ from txtai import Agent, LLM
llm = LLM("hugging-quants/Meta-Llama-3.1-8B-Instruct-AWQ-INT4")
websearcher = Agent(
model=llm,
tools=["websearch"],
llm=llm,
)
wikiman = Agent(
model=llm,
tools=[{
"name": "wikipedia",
"description": "Searches a Wikipedia database",
"provider": "huggingface-hub",
"container": "neuml/txtai-wikipedia"
}],
llm=llm,
)
researcher = Agent(
model=llm,
tools=[{
"name": "arxiv",
"description": "Searches a database of scientific papers",
"provider": "huggingface-hub",
"container": "neuml/txtai-arxiv"
}],
llm=llm,
)
agent = Agent(
model=llm,
tools=[{
"name": "websearcher",
"description": "I run web searches, there is no answer a web search can't solve!",
@@ -124,8 +125,7 @@ agent = Agent(
"description": "I'm a science guy. I search arXiv to get all my answers.",
"target": researcher
}],
llm=llm,
max_iterations=10
max_steps=10
)
```
+1 -1
View File
@@ -27,7 +27,7 @@ extras["dev"] = [
"pylint",
]
extras["agent"] = ["smolagents>=1.13"]
extras["agent"] = ["mcpadapt>=0.1.0", "smolagents>=1.13"]
extras["ann"] = [
"annoy>=1.16.3",
+3 -3
View File
@@ -32,8 +32,8 @@ class ProcessFactory:
constructor = CodeAgent
# Create model backed by LLM pipeline
llm = config.pop("llm")
llm = PipelineModel(**llm) if isinstance(llm, dict) else PipelineModel(llm)
model = config.pop("model", config.pop("llm", None))
model = PipelineModel(**model) if isinstance(model, dict) else PipelineModel(model)
# Create the agent process
return constructor(tools=ToolFactory.create(config), model=llm, **config)
return constructor(tools=ToolFactory.create(config), model=model, **config)
+12 -3
View File
@@ -6,7 +6,10 @@ import inspect
from types import FunctionType, MethodType
from smolagents import DuckDuckGoSearchTool, Tool, tool as CreateTool
import mcpadapt.core
from mcpadapt.smolagents_adapter import SmolAgentsAdapter
from smolagents import DuckDuckGoSearchTool, PythonInterpreterTool, Tool, tool as CreateTool, VisitWebpageTool
from transformers.utils import chat_template_utils, TypeHintParsingException
from ...embeddings import Embeddings
@@ -20,7 +23,7 @@ class ToolFactory:
"""
# Default toolkit
DEFAULTS = {"websearch": DuckDuckGoSearchTool()}
DEFAULTS = {"python": PythonInterpreterTool(), "websearch": DuckDuckGoSearchTool(), "webview": VisitWebpageTool()}
@staticmethod
def create(config):
@@ -58,8 +61,14 @@ class ToolFactory:
elif isinstance(tool, str) and tool in ToolFactory.DEFAULTS:
tool = ToolFactory.DEFAULTS[tool]
# Support importing MCP tool collections
elif isinstance(tool, str) and tool.startswith("http"):
tools.extend(mcpadapt.core.MCPAdapt({"url": tool}, SmolAgentsAdapter()).tools())
tool = None
# Add tool
tools.append(tool)
if tool:
tools.append(tool)
return tools
+23 -1
View File
@@ -6,9 +6,11 @@ import os
import tempfile
import unittest
from unittest.mock import patch
from datetime import datetime
from smolagents import CodeAgent
from smolagents import CodeAgent, PythonInterpreterTool
from txtai.agent import Agent
from txtai.embeddings import Embeddings
@@ -107,3 +109,23 @@ class TestAgent(unittest.TestCase):
self.assertIsNotNone(agent)
self.assertIsInstance(agent.tools["embeddings1"]("test"), list)
# pylint: disable=C0115,C0116
@patch("mcpadapt.core.MCPAdapt")
def testToolsMCP(self, mcp):
"""
Test adding a MCP tool collection
"""
class MCPAdapt:
def __init__(self, *args):
self.args = args
def tools(self):
return [PythonInterpreterTool()]
# Patch MCP adapter for testing
mcp.side_effect = MCPAdapt
agent = Agent(tools=["http://localhost:8000/mcp"], llm="hf-internal-testing/tiny-random-LlamaForCausalLM", max_steps=1)
self.assertEqual(len(agent.tools), 2)