How to Implement MCP Tool Integration for AI Automation Workflows in Fincept Terminal

Fincept Terminal enables AI agents to invoke internal and external tools through Model Context Protocol (MCP) nodes, wiring execution bridges to a singleton service that handles discovery, validation, and async dispatch without modifying the workflow engine core.

The Fincept-Corporation/FinceptTerminal repository provides a visual workflow engine where AI automation workflows consume MCP tools as if they were native OpenAI function calls. By implementing three architectural layers—node registration, bridge wiring, and service execution—you can expose new capabilities to AI agents while maintaining clean separation between the UI editor and runtime logic.

Register the MCP Tool Node

The workflow engine uses a NodeRegistry to declare available nodes. In fincept-qt/src/services/workflow/nodes/IntegrationNodes.cpp (lines 15‑27), the register_integration_nodes function adds a generic MCP Tool node that appears in the visual editor under the MCP category:

registry.register_type({
    .type_id      = "mcp.tool_call",
    .display_name = "MCP Tool",
    .category     = "MCP",
    .description  = "Call any Fincept internal MCP tool by name",
    .icon_text    = "M",
    .accent_color = "#6366f1",
    .version      = 2,
    .inputs  = {{"input_0", "Arguments", PortDirection::Input, ConnectionType::Main}},
    .outputs = {{"output_main", "Result", PortDirection::Output, ConnectionType::Main}},
    .parameters = { {"tool", "Tool", "mcp_tool_select", "", {}, "", true} },
    .execute = nullptr,   // actual executor wired later
});

The mcp_tool_select parameter renders as a dropdown in the UI, populated dynamically from the MCP service’s cached tool list. Setting .execute = nullptr defers the runtime implementation to the bridge layer, keeping node definitions declarative.

Wire the Execution Bridge

After node registration, wire_all_bridges invokes wire_mcp_bridges in fincept-qt/src/services/workflow/adapters/ServiceBridges.cpp (lines 44‑98). This function assigns the actual execution lambda to the node’s execute callback, enabling async tool invocation:

def->execute = [](const QJsonObject& params,
                  const QVector<QJsonValue>& inputs,
                  std::function<void(bool, QJsonValue, QString)> cb) {
    QString tool = params.value("tool").toString().trimmed();
    if (tool.isEmpty()) {
        cb(false, {}, "MCP Tool: 'tool' parameter is required");
        return;
    }

    // Merge optional input object (e.g. from a Tool Picker node)
    QJsonObject input_obj = (!inputs.isEmpty() && inputs[0].isObject())
                            ? inputs[0].toObject() : QJsonObject();

    // Resolve arguments
    QJsonObject args;
    if (input_obj.contains("args") && input_obj["args"].isObject())
        args = input_obj["args"].toObject();
    else if (!input_obj.contains("tool"))
        args = input_obj;   // raw data input

    // Run in background thread
    QtConcurrent::run([tool, args, cb]() {
        auto& svc = mcp::McpService::instance();
        mcp::ToolResult result =
            tool.contains("__")
                ? svc.execute_openai_function(tool, args)   // external server
                : svc.execute_tool(mcp::INTERNAL_SERVER_ID, tool, args); // internal

        if (!result.success) {
            cb(false, {}, result.error.isEmpty() ? "MCP tool failed" : result.error);
            return;
        }
        QJsonValue out = result.data.isNull() ? QJsonValue(result.to_json()) : result.data;
        cb(true, out, {});
    });
};

The bridge implements three critical behaviors:

  • Parameter validation – Rejects execution if the tool string is empty.
  • Argument routing – Accepts either a structured Tool Picker output ({tool, args}) or a plain JSON object.
  • Server routing – Tools containing "__" are treated as serverId__toolName and dispatched via execute_openai_function to external MCP servers; otherwise, execute_tool routes to internal tools using INTERNAL_SERVER_ID.

Execution runs inside QtConcurrent::run to prevent UI blocking during network or computation-heavy operations.

Implement the MCP Service Layer

The McpService singleton declared in fincept-qt/src/mcp/McpService.h (lines 15‑36) manages the lifecycle of all MCP tools:

std::vector<UnifiedTool> get_all_tools();          // cached discovery (5 s TTL)
QJsonArray format_tools_for_openai();              // OpenAI‑compatible schema
ToolResult execute_tool(const QString&, const QString&, const QJsonObject&);
ToolResult execute_openai_function(const QString&, const QJsonObject&);
Result<void> validate_params(const QString&, const QJsonObject&);

Tool discovery maintains a 5‑second TTL cache (CACHE_TTL_MS = 5000) to minimize repeated schema generation overhead. The format_tools_for_openai() method converts internal tool definitions into the JSON schema required by OpenAI function-calling APIs. When the bridge invokes execute_tool, the service validates parameters against the tool’s schema, resolves the target server, and forwards the JSON arguments to the appropriate implementation.

Add Custom MCP Tools

Extending Fincept Terminal with new capabilities follows a four-step pattern that requires no changes to the workflow engine core:

  1. Implement the tool in fincept-qt/src/mcp/tools/ (e.g., RiskAnalysisTool.cpp). Inherit from the base tool interface and implement ToolResult execute(const QJsonObject& args).

  2. Register the tool in McpService::refresh_cache(). The MCP provider registry automatically discovers tools added to the McpProvider map, or you can manually insert them into the internal server’s tool list.

  3. Expose to the UI automatically. The mcp_tool_select dropdown queries McpService::format_tools_for_openai(), so new tools appear immediately in the workflow editor without modifying IntegrationNodes.cpp.

  4. Configure external servers optionally. For tools hosted outside the terminal process, add server endpoints via the MCP Servers UI managed in fincept-qt/src/screens/settings/McpServersSection.cpp. External tools follow the serverId__toolName naming convention in the bridge routing logic.

Practical Workflow Configuration

Below is a minimal workflow graph demonstrating how an MCP Tool node chains into subsequent automation steps:

{
  "nodes": [
    {
      "id": "1",
      "type": "mcp.tool_call",
      "params": { "tool": "get_quote" },
      "inputs": [{ "port": "input_0", "data": { "symbol": "AAPL" } }]
    },
    {
      "id": "2",
      "type": "utility.api_call",
      "params": {
        "url": "https://example.com/notify",
        "method": "POST",
        "body": { "message": "{{node_1.output_main}}" }
      }
    }
  ],
  "connections": [
    { "from": "1", "out": "output_main", "to": "2", "in": "input_0" }
  ]
}

Execution proceeds as follows:

  1. Node 1 invokes the internal get_quote tool via McpService::execute_tool, returning a JSON payload such as {"price": 174.23}.
  2. The result flows through output_main into Node 2, which posts the data to an external webhook via the utility.api_call node.

All tool discovery, argument validation, and routing logic remains encapsulated within the MCP service layer.

Key Source Files Reference

File Role Location
IntegrationNodes.cpp Registers the generic MCP Tool node definition fincept-qt/src/services/workflow/nodes/
ServiceBridges.cpp Implements the async execution bridge and routing logic fincept-qt/src/services/workflow/adapters/
McpService.h Defines the singleton service for discovery, validation, and dispatch fincept-qt/src/mcp/
McpServersSection.cpp UI for managing external MCP server connections fincept-qt/src/screens/settings/
McpServersScreen.cpp Full-screen server management interface fincept-qt/src/screens/mcp_servers/

These files constitute the complete pipeline from visual node configuration to runtime execution of MCP-enabled AI automation workflows.

Summary

  • Node registration in IntegrationNodes.cpp declares the mcp.tool_call type with a dynamic mcp_tool_select parameter.
  • Bridge wiring in ServiceBridges.cpp implements async execution, routing tools containing "__" to external servers and others to the internal MCP service.
  • Service layer caching uses a 5‑second TTL via McpService::get_all_tools() to optimize OpenAI schema generation.
  • Tool addition requires only implementing the interface in fincept-qt/src/mcp/tools/ and registering in the provider cache; UI updates are automatic.
  • External servers integrate through the settings UI and follow the serverId__toolName naming convention in workflow parameters.

Frequently Asked Questions

How does Fincept Terminal distinguish between internal and external MCP tools?

The execution bridge in ServiceBridges.cpp checks for the presence of "__" in the tool parameter string. Tools without this separator route to McpService::execute_tool using INTERNAL_SERVER_ID, while compound names like alphavantage__get_news trigger execute_openai_function, which dispatches to the external server registry. This naming convention eliminates the need for separate node types.

What caching strategy does the MCP service use for tool discovery?

McpService maintains an in-memory cache of the complete tool list with a 5‑second TTL (CACHE_TTL_MS = 5000). When the cache expires, get_all_tools() refreshes the registry by querying both internal tool providers and configured external MCP servers, then regenerates the OpenAI-compatible schema via format_tools_for_openai().

How do I expose a new internal tool to the workflow editor without modifying UI code?

Create your tool implementation in fincept-qt/src/mcp/tools/ and ensure it registers within McpService::refresh_cache(). The mcp_tool_select dropdown parameter automatically populates from McpService::instance().format_tools_for_openai(), so your tool appears immediately in the node editor without touching IntegrationNodes.cpp or QML files.

Can MCP tool execution block the UI thread?

No. The bridge explicitly wraps tool calls inside QtConcurrent::run, executing them in a background thread pool. The callback mechanism (std::function<void(bool, QJsonValue, QString)>) returns results asynchronously to the workflow engine, ensuring the visual editor remains responsive during long-running operations such as external API calls or complex calculations.

Have a question about this repo?

These articles cover the highlights, but your codebase questions are specific. Give your agent direct access to the source. Share this with your agent to get started:

Share the following with your agent to get started:
curl -s "https://instagit.com/install.md"

Works with
Claude Codex Cursor VS Code OpenClaw Any MCP Client

Maintain an open-source project? Get it listed too →