Skip to content

Wanaku MCP Router Internals

This document provides a detailed look at the internal architecture and implementation of the Wanaku MCP Router backend.

Overview

The Wanaku router backend is built around a bridge architecture that abstracts MCP operations and delegates actual work to capability services via gRPC. The bridge pattern separates transport concerns from business logic, enabling flexible and testable implementations.

Core Abstraction: Bridge Interface

The root abstraction for all operations within Wanaku MCP Router is the Bridge interface. All MCP operations are executed by implementations of this interface.

Bridge Hierarchy

classDiagram
    class Bridge {
        <<interface>>
    }

    class ResourceBridge {
        <<interface>>
        +read(arguments, resource) Uni~ResourceResponse~
    }

    class ToolsBridge {
        <<interface>>
        +execute(arguments, reference) Uni~ToolResponse~
    }

    class ProvisionBridge {
        <<interface>>
        +provision(name, configData, secretsData, service) ProvisioningReference
    }

    class McpBridge {
        <<interface>>
        +listTools(client) List~RemoteToolReference~
        +executeTool(client, arguments, reference) Uni~ToolResponse~
        +listResources(client) List~ResourceReference~
        +read(client, arguments, resource) Uni~ResourceResponse~
    }

    class WanakuBridgeTransport {
        <<interface>>
        +provision(name, config, secrets, service) ProvisioningReference
        +invokeTool(request, service) Uni~ToolResponse~
        +acquireResource(request, service, arguments, resource) Uni~List~ResourceContents~~
        +executeCode(request, service) Iterator~CodeExecutionReply~
        +probeHealth(request, service) HealthProbeReply
    }

    class ResourceAcquirerBridge {
        -transport WanakuBridgeTransport
        -provisionerBridge ProvisionerBridge
        +read(arguments, resource) Uni~ResourceResponse~
    }

    class InvokerBridge {
        -transport WanakuBridgeTransport
        -serviceResolver ServiceResolver
        +execute(arguments, reference) Uni~ToolResponse~
    }

    class ProvisionerBridge {
        -serviceResolver ServiceResolver
        -transport WanakuBridgeTransport
        +provision(...) ProvisioningReference
        +resolveService(type, serviceType) ServiceTarget
    }

    class GrpcTransport {
        -channelManager GrpcChannelManager
        +provision(...) ProvisioningReference
        +invokeTool(...) Uni~ToolResponse~
        +acquireResource(...) Uni~List~ResourceContents~~
    }

    Bridge <|-- ResourceBridge
    Bridge <|-- ToolsBridge
    ProvisionBridge <|.. ProvisionerBridge
    ResourceBridge <|.. ResourceAcquirerBridge
    ToolsBridge <|.. InvokerBridge
    WanakuBridgeTransport <|.. GrpcTransport
    ResourceAcquirerBridge o-- WanakuBridgeTransport
    ResourceAcquirerBridge o-- ProvisionerBridge
    InvokerBridge o-- WanakuBridgeTransport

    style Bridge fill:#4A90E2
    style ResourceBridge fill:#50C878
    style ToolsBridge fill:#50C878
    style ProvisionBridge fill:#50C878
    style McpBridge fill:#50C878
    style WanakuBridgeTransport fill:#9B59B6
    style ResourceAcquirerBridge fill:#FFB347
    style InvokerBridge fill:#FFB347
    style ProvisionerBridge fill:#FFB347
    style GrpcTransport fill:#E67E22

The bridge architecture is organized into specialized interfaces and uses composition over inheritance:

  • Bridge - Base marker interface for all bridge implementations
  • ResourceBridge - Extended interface for asynchronous resource reading
  • ToolsBridge - Extended interface for asynchronous tool execution
  • ProvisionBridge - Interface for provisioning configuration and secrets to remote services
  • McpBridge - Interface for interacting with remote MCP servers (forwarding)
  • WanakuBridgeTransport - Transport abstraction interface that decouples protocol from business logic, with async-first operations and built-in response transformation

Transport Abstraction

The bridge architecture uses composition over inheritance to separate transport concerns from business logic:

  • ResourceAcquirerBridge and InvokerBridge delegate all transport operations to a WanakuBridgeTransport implementation
  • GrpcTransport implements WanakuBridgeTransport and handles all gRPC-specific communication
  • ProvisionerBridge consolidates shared provisioning logic and service resolution, eliminating duplication between bridges
  • Response transformers (ToolResponseTransformer, ResourceResponseTransformer) convert transport-specific types (e.g., gRPC protobuf replies) into MCP domain types within the transport layer, keeping bridge implementations protocol-agnostic
  • This design enables:
    • Easy testing with mock transports
    • Support for alternative transport protocols (HTTP, WebSocket, etc.)
    • Clear separation between routing logic and communication details
    • Independent evolution of transport and business logic

All bridge operations follow an async-first design using Mutiny Uni types. The transport layer returns already-transformed domain objects, so bridges never handle transport-specific types directly.

Leveraging these specialized interfaces, we have the concrete classes ResourceAcquirerBridge and InvokerBridge that use gRPC via the transport abstraction to exchange data with capability services providing access to resources and tools. Additionally, DefaultMcpBridge provides forwarding to remote MCP servers using the langchain4j MCP client.

Resources

A resource is, essentially, anything that can be read by using the MCP protocol. For instance:

  • Files
  • Read-only JMS Queues
  • Topics
  • Static resources (i.e.: a web page)

Among other things, resources can be subscribed to, so that changes to its data and state are notified to the subscribers.

For instance, the ability to read files is handled by the wanaku-provider-file which is a gRPC server that is capable of consuming files isolated from other providers:

graph TB
    Bridge[Bridge<br/>Base Interface]
    ResourceBridge[ResourceBridge<br/>Resource Operations]
    ResourceAcquirerBridge[ResourceAcquirerBridge<br/>Business Logic]
    Transport[WanakuBridgeTransport<br/>Transport Abstraction]
    GrpcTransport[GrpcTransport<br/>gRPC Implementation]
    FileProvider[Wanaku Provider - File<br/>gRPC Server]

    Bridge -->|extends| ResourceBridge
    ResourceBridge -->|implements| ResourceAcquirerBridge
    ResourceAcquirerBridge -->|uses| Transport
    Transport -->|implements| GrpcTransport
    GrpcTransport -->|gRPC| FileProvider

    style Bridge fill:#4A90E2
    style ResourceBridge fill:#50C878
    style ResourceAcquirerBridge fill:#FFB347
    style Transport fill:#9B59B6
    style GrpcTransport fill:#E67E22
    style FileProvider fill:#DDA0DD

Ideally, providers should leverage Apache Camel whenever possible.

Tools

A tool is anything that can be invoked by an LLM in a request/response fashion and used to provide data to it.

Examples:

  • Request/reply over JMS
  • Calling REST APIs
  • Executing subprocesses that provide an output
  • Executing an RPC invocation and waiting for its response

In Wanaku, every tool invocation is remote and handled by the InvokerBridge class which uses the gRPC protocol via the transport abstraction to communicate with the service that provides the tool.

graph TB
    Bridge[Bridge<br/>Base Interface]
    ToolsBridge[ToolsBridge<br/>Tool Operations]
    InvokerBridge[InvokerBridge<br/>Business Logic]
    Transport[WanakuBridgeTransport<br/>Transport Abstraction]
    GrpcTransport[GrpcTransport<br/>gRPC Implementation]
    ToolProvider[Tool Service<br/>HTTP/Exec/Tavily/etc.<br/>gRPC Server]

    Bridge -->|extends| ToolsBridge
    ToolsBridge -->|implements| InvokerBridge
    InvokerBridge -->|uses| Transport
    Transport -->|implements| GrpcTransport
    GrpcTransport -->|gRPC| ToolProvider

    style Bridge fill:#4A90E2
    style ToolsBridge fill:#50C878
    style InvokerBridge fill:#FFB347
    style Transport fill:#9B59B6
    style GrpcTransport fill:#E67E22
    style ToolProvider fill:#DDA0DD

Configuration and Secrets Provisioning System

Both resource providers and tool services support a provisioning system that handles configuration and secret management. Provisioning logic is consolidated in the ProvisionerBridge class, which eliminates duplication between InvokerBridge and ResourceAcquirerBridge.

Provisioning Flow

sequenceDiagram
    participant Router as Router Backend
    participant PB as ProvisionerBridge
    participant Transport as WanakuBridgeTransport
    participant Service as Capability Service
    participant ConfigStore as Configuration Store

    Router->>PB: provision(name, config, secrets, service)
    PB->>Transport: provision(name, config, secrets, service)
    Transport->>Service: gRPC Provision(config, secrets)
    Service->>Service: Apply Configuration
    Service-->>Transport: ProvisionReply
    Transport-->>PB: ProvisioningReference
    PB-->>Router: ProvisioningReference

    Note over Service: Service ready<br/>with configuration

Provisioning Capabilities

The provisioning system allows runtime configuration of services through gRPC-based provisioning requests that establish:

  • Configuration URIs: Service-specific settings (endpoints, options, parameters)
  • Secret URIs: Sensitive credentials (API keys, passwords, tokens)
  • Property Schemas: Expected configuration structure and validation rules

Benefits

  • Dynamic Configuration: Update service settings without restarting services
  • Secure Credential Management: Secrets delivered via encrypted gRPC channels
  • Schema Validation: Ensure configuration correctness before deployment
  • Centralized Management: Configuration managed through router backend
  • Flexible Deployment: Support different configurations per environment

Implementation Details

Provisioning is implemented through:

  1. ProvisionerBridge: Consolidates provisioning logic and service resolution, shared by both tool and resource bridges
  2. gRPC Protocol: Capability services implement the Provisioner gRPC interface
  3. Configuration Store: Router backend stores tool/resource configurations in Infinispan
  4. Secret Integration: Integration with Kubernetes Secrets or external secret managers
  5. Validation: Schema-based validation ensures configuration correctness

Component Interaction Patterns

Resource Read Pattern

When an LLM requests a resource, the following interaction occurs:

sequenceDiagram
    participant MCP as MCP Client
    participant Router as Router Backend
    participant RAB as ResourceAcquirerBridge
    participant PB as ProvisionerBridge
    participant Transport as GrpcTransport
    participant Provider as Resource Provider

    MCP->>Router: ReadResource(file:///data/doc.txt)
    Router->>RAB: read(arguments, resource)
    RAB->>PB: resolveService(type, "resource-provider")
    PB-->>RAB: ServiceTarget
    RAB->>RAB: Build ResourceRequest
    RAB->>Transport: acquireResource(request, service, arguments, resource)
    Transport->>Provider: gRPC ReadResource(uri)
    Provider->>Provider: Read File from Filesystem
    Provider-->>Transport: gRPC Response (contents)
    Transport->>Transport: Transform via ResourceResponseTransformer
    Transport-->>RAB: Uni~List~ResourceContents~~
    RAB-->>Router: Uni~ResourceResponse~
    Router-->>MCP: MCP Resource Response

Tool Invocation Pattern

When an LLM invokes a tool, the interaction pattern is:

sequenceDiagram
    participant MCP as MCP Client
    participant Router as Router Backend
    participant IB as InvokerBridge
    participant Transport as GrpcTransport
    participant Tool as Tool Service

    MCP->>Router: CallTool(http://api.example.com/data)
    Router->>IB: execute(toolArguments, toolReference)
    IB->>IB: Resolve service, build ToolInvokeRequest
    IB->>Transport: invokeTool(request, service)
    Transport->>Tool: gRPC InvokeTool(uri, params)
    Tool->>Tool: Execute HTTP Request
    Tool-->>Transport: gRPC Response (result)
    Transport->>Transport: Transform via ToolResponseTransformer
    Transport-->>IB: Uni~ToolResponse~
    IB-->>Router: Uni~ToolResponse~
    Router-->>MCP: MCP Tool Response

Key Design Patterns

Bridge Pattern

The router uses the Bridge pattern to:

  • Separate abstraction (business logic) from implementation (transport)
  • Provide a unified interface for MCP operations
  • Enable composition over inheritance for flexibility
  • Support multiple transport implementations (gRPC, HTTP, etc.)
  • Facilitate testing with mock transports

Composition Over Inheritance

The architecture favors composition:

  • Bridges have-a transport instead of being-a transport
  • InvokerBridge and ResourceAcquirerBridge delegate to WanakuBridgeTransport
  • GrpcTransport implements transport-specific logic
  • Clear separation enables independent evolution of components

Factory Pattern

Service creation uses factories to:

  • Instantiate appropriate proxy implementations based on URI schemes
  • Manage gRPC client lifecycle
  • Handle service registration and deregistration

Strategy Pattern

Different capability types use strategy pattern to:

  • Implement specific tool invocation logic
  • Handle different resource types and protocols
  • Apply different authentication mechanisms

Thread Safety and Concurrency

Concurrent Request Handling

  • Async Processing: Router uses Quarkus reactive programming model
  • Thread Pools: Dedicated thread pools for MCP requests and gRPC calls
  • Connection Pooling: gRPC channels are pooled and reused
  • State Management: Service registry uses concurrent data structures

Isolation Guarantees

  • Request Isolation: Each MCP request is processed independently
  • Service Isolation: Capability services run in separate processes
  • Namespace Isolation: Tools/resources in different namespaces don't interfere