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

View file

@ -7,11 +7,11 @@ import re
import sys
from ... base import AgentService, TextCompletionClientSpec, PromptClientSpec
from ... base import GraphRagClientSpec
from ... base import GraphRagClientSpec, ToolClientSpec
from ... schema import AgentRequest, AgentResponse, AgentStep, Error
from . tools import KnowledgeQueryImpl, TextCompletionImpl
from . tools import KnowledgeQueryImpl, TextCompletionImpl, McpToolImpl
from . agent_manager import AgentManager
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):
print("Loading configuration version", version)
@ -106,6 +113,8 @@ class Processor(AgentService):
impl = KnowledgeQueryImpl
elif impl_id == "text-completion":
impl = TextCompletionImpl
elif impl_id == "mcp-tool":
impl = McpToolImpl
else:
raise RuntimeError(
f"Tool-kind {impl_id} not known"
@ -181,6 +190,8 @@ class Processor(AgentService):
await respond(r)
print("Call React", flush=True)
act = await self.agent.react(
question = request.question,
history = history,

View file

@ -23,3 +23,22 @@ class TextCompletionImpl:
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"]