feat: MCP tool client infrastructure for agent extensibility

Add the full MCP tool pipeline enabling agents to invoke external tools
(like Brave Search) via MCP servers:

- Add ToolRequest/ToolResponse types and mcp-tool topics to @trustgraph/base
- Create McpToolService (FlowProcessor) that connects to external MCP servers
  via @modelcontextprotocol/sdk StreamableHTTP transport
- Add createMcpTool() to wire MCP tools into the agent's ReAct loop
- Implement config-driven tool registration in AgentService with backward-
  compatible fallback to hardcoded tools
- Add tool filtering by group and state (port of Python tool_filter.py)
- Register mcp-tool in gateway dispatcher and export from @trustgraph/flow
- Fix flow restart race condition: skip restart when flow definitions unchanged
- Update seed config with MCP server config and tool definitions
- Add run scripts for MCP tool service and Brave Search MCP server

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
elpresidank 2026-04-10 05:45:46 -05:00
parent f2b376abef
commit b854b56558
17 changed files with 600 additions and 17 deletions

28
ts/scripts/run-brave-mcp.sh Executable file
View file

@ -0,0 +1,28 @@
#!/usr/bin/env bash
# Start the Brave Search MCP server with HTTP transport.
#
# Usage: ./scripts/run-brave-mcp.sh
#
# Requires:
# - @brave/brave-search-mcp-server (npx will auto-install)
# - BRAVE_API_KEY env var or 1Password access
set -euo pipefail
# Resolve API key from env or 1Password
if [ -z "${BRAVE_API_KEY:-}" ]; then
if command -v op &>/dev/null; then
BRAVE_API_KEY="$(op read 'op://beep-dev-secrets/beep-ai/BRAVE_API_KEY')"
echo "[brave-mcp] Loaded API key from 1Password"
else
echo "[brave-mcp] ERROR: BRAVE_API_KEY not set and 'op' CLI not found"
exit 1
fi
fi
echo "[brave-mcp] Starting Brave Search MCP server on port 8383..."
exec npx --yes @brave/brave-search-mcp-server \
--brave-api-key "$BRAVE_API_KEY" \
--transport http \
--port 8383 \
--stateless true

View file

@ -0,0 +1,18 @@
/**
* Start the MCP tool service.
*
* Usage: pnpm tsx scripts/run-mcp-tool.ts
*
* Env:
* NATS_URL (default: nats://localhost:4222)
*/
import { McpToolService } from "../packages/flow/src/agent/mcp-tool/index.js";
async function run(): Promise<void> {
await McpToolService.launch("mcp-tool");
}
run().catch((err) => {
console.error("MCP tool service failed:", err);
process.exit(1);
});

View file

@ -188,10 +188,68 @@ async function main(): Promise<void> {
// Librarian RPC (for PDF decoder)
"librarian-request": "tg.flow.librarian-request",
"librarian-response": "tg.flow.librarian-response",
// MCP tool invocation
"mcp-tool-request": "tg.flow.mcp-tool-request",
"mcp-tool-response": "tg.flow.mcp-tool-response",
},
},
});
// 3. MCP server configuration (external tool providers)
console.log("\n── MCP Configuration ──");
const braveApiKey = process.env.BRAVE_API_KEY;
if (braveApiKey) {
await pushConfig(["mcp"], {
"brave-search": JSON.stringify({
url: "http://localhost:8383/mcp",
"remote-name": "brave_web_search",
}),
});
console.log(" Brave Search MCP service configured");
} else {
console.log(" Skipping MCP config (no BRAVE_API_KEY set)");
}
// 4. Agent tool configuration (maps tools to implementations)
console.log("\n── Tool Configuration ──");
const toolConfig: Record<string, string> = {
"knowledge-query": JSON.stringify({
type: "knowledge-query",
name: "KnowledgeQuery",
description: "Query the knowledge graph for information about entities and their relationships.",
group: ["default"],
}),
"document-query": JSON.stringify({
type: "document-query",
name: "DocumentQuery",
description: "Search the document library for relevant information using semantic search.",
group: ["default"],
}),
"triples-query": JSON.stringify({
type: "triples-query",
name: "TriplesQuery",
description: "Query for specific triples (subject-predicate-object relationships) in the knowledge graph.",
group: ["default"],
}),
};
// Add Brave Search tool if API key is available
if (braveApiKey) {
toolConfig["brave-search"] = JSON.stringify({
type: "mcp-tool",
name: "brave-search",
description: "Search the web using Brave Search. Returns web search results including titles, URLs, and descriptions.",
"mcp-tool": "brave-search",
group: ["default"],
arguments: [
{ name: "query", type: "string", description: "The search query" },
],
});
console.log(" Brave Search tool added");
}
await pushConfig(["tool"], toolConfig);
console.log("\nConfiguration seeded successfully.");
}