Agent call to mcp-tool is working with a hard-coded service.

- Added ToolClientSpec and ToolClient to implement a tool call.
- Updated agent-manager-react to invoke an MCP tool with a tool defined
  with 'mcp-tool' type.
Not generic, need to work out how to call the right parameters.
This commit is contained in:
Cyber MacGeddon 2025-07-08 13:17:10 +01:00
parent e56186054a
commit 3978d35545
5 changed files with 85 additions and 5 deletions

View file

@ -29,4 +29,5 @@ from . document_embeddings_client import DocumentEmbeddingsClientSpec
from . agent_service import AgentService from . agent_service import AgentService
from . graph_rag_client import GraphRagClientSpec from . graph_rag_client import GraphRagClientSpec
from . tool_service import ToolService from . tool_service import ToolService
from . tool_client import ToolClientSpec

View file

@ -0,0 +1,40 @@
import json
from . request_response_spec import RequestResponse, RequestResponseSpec
from .. schema import ToolRequest, ToolResponse
class ToolClient(RequestResponse):
async def invoke(self, name, parameters={}, timeout=600):
if parameters is None:
parameters = {}
resp = await self.request(
ToolRequest(
name = name,
parameters = json.dumps(parameters),
),
timeout=timeout
)
if resp.error:
raise RuntimeError(resp.error.message)
if resp.text: return resp.text
return json.loads(resp.object)
class ToolClientSpec(RequestResponseSpec):
def __init__(
self, request_name, response_name,
):
super(ToolClientSpec, self).__init__(
request_name = request_name,
request_schema = ToolRequest,
response_name = response_name,
response_schema = ToolResponse,
impl = ToolClient,
)

View file

@ -14,12 +14,19 @@ class AgentManager:
async def reason(self, question, history, context): async def reason(self, question, history, context):
print(f"calling reason: {question}", flush=True)
tools = self.tools tools = self.tools
print(f"in reason", flush=True)
print(tools, flush=True)
tool_names = ",".join([ tool_names = ",".join([
t for t in self.tools.keys() t for t in self.tools.keys()
]) ])
print("Tool names:", tool_names, flush=True)
variables = { variables = {
"question": question, "question": question,
"tools": [ "tools": [
@ -83,6 +90,9 @@ class AgentManager:
async def react(self, question, history, think, observe, context): async def react(self, question, history, think, observe, context):
logger.info(f"question: {question}")
print(f"question: {question}", flush=True)
act = await self.reason( act = await self.reason(
question = question, question = question,
history = history, history = history,
@ -104,13 +114,12 @@ class AgentManager:
else: else:
raise RuntimeError(f"No action for {act.name}!") raise RuntimeError(f"No action for {act.name}!")
print("TOOL>>>", act) print("TOOL>>>", act, flush=True)
resp = await action.implementation(context).invoke( resp = await action.implementation(context).invoke(
**act.arguments **act.arguments
) )
print("RSETUL", resp)
resp = resp.strip() resp = resp.strip()
logger.info(f"resp: {resp}") logger.info(f"resp: {resp}")

View file

@ -7,11 +7,11 @@ import re
import sys import sys
from ... base import AgentService, TextCompletionClientSpec, PromptClientSpec from ... base import AgentService, TextCompletionClientSpec, PromptClientSpec
from ... base import GraphRagClientSpec from ... base import GraphRagClientSpec, ToolClientSpec
from ... schema import AgentRequest, AgentResponse, AgentStep, Error from ... schema import AgentRequest, AgentResponse, AgentStep, Error
from . tools import KnowledgeQueryImpl, TextCompletionImpl from . tools import KnowledgeQueryImpl, TextCompletionImpl, McpToolImpl
from . agent_manager import AgentManager from . agent_manager import AgentManager
from . types import Final, Action, Tool, Argument from . types import Final, Action, Tool, Argument
@ -67,6 +67,13 @@ class Processor(AgentService):
) )
) )
self.register_specification(
ToolClientSpec(
request_name = "mcp-tool-request",
response_name = "mcp-tool-response",
)
)
async def on_tools_config(self, config, version): async def on_tools_config(self, config, version):
print("Loading configuration version", version) print("Loading configuration version", version)
@ -106,6 +113,8 @@ class Processor(AgentService):
impl = KnowledgeQueryImpl impl = KnowledgeQueryImpl
elif impl_id == "text-completion": elif impl_id == "text-completion":
impl = TextCompletionImpl impl = TextCompletionImpl
elif impl_id == "mcp-tool":
impl = McpToolImpl
else: else:
raise RuntimeError( raise RuntimeError(
f"Tool-kind {impl_id} not known" f"Tool-kind {impl_id} not known"
@ -181,6 +190,8 @@ class Processor(AgentService):
await respond(r) await respond(r)
print("Call React", flush=True)
act = await self.agent.react( act = await self.agent.react(
question = request.question, question = request.question,
history = history, history = history,

View file

@ -23,3 +23,22 @@ class TextCompletionImpl:
arguments.get("question") arguments.get("question")
) )
# This tool implementation knows how to do MCP tool invocation. This uses
# the mcp-tool service.
class McpToolImpl:
def __init__(self, context):
self.context = context
async def invoke(self, **arguments):
client = self.context("mcp-tool-request")
print("MCP tool invocation...", flush=True)
output = await client.invoke(
name = "time",
parameters = {},
)
print(output)
print(type(output))
return output["result"]