# MCP (/aiway/mcp)



The **MCP connector** exposes KubeMQ messaging operations as
[Model Context Protocol](https://modelcontextprotocol.io) tools, so Claude and other AI
models can publish, subscribe, and call KubeMQ — and reach registered agents — without
a KubeMQ-specific client library. It speaks MCP protocol version `2025-11-25` over
JSON-RPC 2.0 at a single endpoint on the [shared HTTP server](/connectors/concepts/shared-http-server).

<Callout type="info">
  **Part of Aiway.** MCP is one of the two doors into
  [KubeMQ Aiway](/aiway), the AI Agents Fabric. New here? Start with the
  [Aiway overview](/aiway), or follow the end-to-end
  [Aiway tutorial](/aiway/tutorial).
</Callout>

## What MCP is [#what-mcp-is]

The Model Context Protocol is an open standard for connecting AI models to external
tools and data over a uniform JSON-RPC 2.0 interface. A model's MCP client connects to
an MCP **server**, asks it which tools it offers (`tools/list`), and invokes them by
name (`tools/call`). KubeMQ is one such server: every KubeMQ messaging operation is
published as a named MCP tool.

Because the protocol is standard, any MCP-aware model or runtime can use KubeMQ with no
KubeMQ code on the caller. You point the official MCP SDK for your language — or a
client like Claude Desktop — at the endpoint, and the model gains messaging, persistent
events, request/reply, channel introspection, and a bridge to A2A agents as native
tools.

## Why MCP with KubeMQ [#why-mcp-with-kubemq]

* **No KubeMQ SDK on the caller** — clients use the official MCP SDK for their
  language; KubeMQ is just an MCP server they connect to.
* **One endpoint** — `POST /mcp` for JSON-RPC requests (single or batch), plus
  `GET /mcp` for a keepalive SSE stream, both on the shared HTTP port `9090`.
* **15 ready-to-use tools** — 11 core messaging tools plus 4 agent-bridge tools,
  covering every KubeMQ pattern.
* **A bridge to agents** — the model can list, inspect, and message agents registered
  with the [A2A connector](/aiway/a2a) through the same tool interface.
* **Enabled by default** — start kubemq-server and `/mcp` is live; there is no flag to
  turn it on.

## How it works [#how-it-works]

An MCP client connects to the `/mcp` endpoint, completes the `initialize` handshake to
obtain a session, then calls tools. The connector translates each tool call into a
native KubeMQ operation; agent-bridge tools forward over the broker to the A2A registry.

<Mermaid
  chart="`
graph LR
MODEL[&#x22;AI model / agent<br/>(MCP client)&#x22;]
MCP{{&#x22;MCP connector<br/>/mcp :9090&#x22;}}
ARR[&#x22;Array&#x22;]
BROKER[&#x22;Message Broker&#x22;]
AGENT[&#x22;Registered agent&#x22;]

MODEL -- &#x22;tools/list · tools/call&#x22; --> MCP
MCP -- &#x22;messaging tools&#x22; --> ARR
ARR --> BROKER
MCP -. &#x22;agent bridge&#x22; .-> AGENT

class MODEL external
class MCP aiway
class ARR,BROKER broker
class AGENT external
`"
/>

*The MCP connector turns JSON-RPC tool calls into KubeMQ operations and bridges to A2A agents.*

The connector runs on the [shared HTTP server](/connectors/concepts/shared-http-server) and
inherits its middleware, [authentication](/aiway/mcp/guides/authentication),
and [observability](/connectors/concepts/observability). The reserved `_AGENTS_.` channel
prefix is rejected for direct messaging tools — use the agent-bridge tools to reach
agents.

## The 15 tools [#the-15-tools]

KubeMQ exposes 15 MCP tools across five categories — 11 core messaging tools that are
always available, plus 4 agent-bridge tools that appear when the agent registry is
present.

| Category           | Tools                                                                                     |  Count |
| ------------------ | ----------------------------------------------------------------------------------------- | -----: |
| Queue              | `queue_send`, `queue_receive`, `queue_peek`                                               |      3 |
| Events             | `events_publish`, `events_store_publish`, `events_store_read`, `events_store_read_latest` |      4 |
| Command / Query    | `command_send`, `query_send`                                                              |      2 |
| Channel management | `channel_list`, `channel_info`                                                            |      2 |
| Agent bridge       | `agent_list`, `agent_info`, `agent_send`, `agent_query`                                   |      4 |
| **Total**          |                                                                                           | **15** |

<Cards>
  <Card title="Queue tools" href="/aiway/mcp/tools/queues" description="Point-to-point messaging — queue_send, queue_receive, queue_peek." />

  <Card title="Events tools" href="/aiway/mcp/tools/events" description="Pub/sub and persistent events — events_publish and the events-store tools." />

  <Card title="Command & query tools" href="/aiway/mcp/tools/commands-queries" description="Synchronous request/reply — command_send and query_send." />

  <Card title="Channel tools" href="/aiway/mcp/tools/channel-management" description="Introspect channels — channel_list and channel_info." />

  <Card title="Agent-bridge tools" href="/aiway/mcp/tools/agent-bridge" description="Reach A2A agents — agent_list, agent_info, agent_send, agent_query." />
</Cards>

## Endpoint surface [#endpoint-surface]

| Method | Path   | Description                                    |
| ------ | ------ | ---------------------------------------------- |
| `POST` | `/mcp` | JSON-RPC 2.0 request handler (single or batch) |
| `GET`  | `/mcp` | SSE keepalive stream                           |

JSON-RPC methods on `POST /mcp`: `initialize`, `notifications/initialized`, `ping`,
`tools/list`, and `tools/call`. The `MCP-Protocol-Version` response header is always
`2025-11-25`, and `MCP-Session-Id` carries the session returned by `initialize`. See
the [endpoints reference](/aiway/mcp/reference/endpoints) for full signatures.

## Discover the tools [#discover-the-tools]

The `tools/list` method returns every available tool with its `name`, `description`, and
`inputSchema`. It is the first call after `initialize` — it tells the model what KubeMQ
can do.

<Tabs groupId="language" items="['curl','C#','Go','Java','Kotlin','Python','Ruby','Rust','Swift','TypeScript']">
  <Tab value="curl">
    ```bash
    curl -X POST http://localhost:9090/mcp \
      -H "Content-Type: application/json" \
      -H "MCP-Protocol-Version: 2025-11-25" \
      -d '{
        "jsonrpc": "2.0",
        "id": 1,
        "method": "tools/list"
      }'
    ```
  </Tab>

  <Tab value="C#">
    ```csharp
    using ModelContextProtocol.Client;

    var url = Environment.GetEnvironmentVariable("KUBEMQ_MCP_URL") ?? "http://localhost:9090";
    var transport = new HttpClientTransport(new HttpClientTransportOptions { Endpoint = new Uri($"{url}/mcp") });
    await using var client = await McpClientFactory.CreateAsync(transport);

    var tools = await client.ListToolsAsync();
    foreach (var tool in tools)
    {
        Console.WriteLine($"{tool.Name}: {tool.Description}");
    }
    ```
  </Tab>

  <Tab value="Go">
    ```go
    package main

    import (
    	"context"
    	"fmt"
    	"log"
    	"os"

    	"github.com/mark3labs/mcp-go/client"
    	"github.com/mark3labs/mcp-go/mcp"
    )

    func main() {
    	url := os.Getenv("KUBEMQ_MCP_URL")
    	if url == "" {
    		url = "http://localhost:9090"
    	}

    	c, err := client.NewStreamableHttpClient(url + "/mcp")
    	if err != nil {
    		log.Fatal(err)
    	}
    	defer c.Close()

    	ctx := context.Background()
    	if err := c.Start(ctx); err != nil {
    		log.Fatal(err)
    	}

    	result, err := c.ListTools(ctx, mcp.ListToolsRequest{})
    	if err != nil {
    		log.Fatal(err)
    	}

    	for _, tool := range result.Tools {
    		fmt.Printf("%s: %s\n", tool.Name, tool.Description)
    	}
    }
    ```
  </Tab>

  <Tab value="Java">
    ```java
    import io.modelcontextprotocol.sdk.McpClient;
    import io.modelcontextprotocol.sdk.client.transport.HttpClientStreamableHttpTransport;

    public class ToolsList {
        public static void main(String[] args) {
            String url = System.getenv().getOrDefault("KUBEMQ_MCP_URL", "http://localhost:9090");
            var transport = HttpClientStreamableHttpTransport.builder(url).endpoint("/mcp").build();
            var client = McpClient.sync(transport).build();
            client.initialize();

            var tools = client.listTools();
            System.out.println(tools);

            client.closeGracefully();
        }
    }
    ```
  </Tab>

  <Tab value="Kotlin">
    ```kotlin
    import io.modelcontextprotocol.kotlin.sdk.Implementation
    import io.modelcontextprotocol.kotlin.sdk.client.Client
    import io.modelcontextprotocol.kotlin.sdk.client.StreamableHttpClientTransport
    import io.ktor.client.*
    import io.ktor.client.plugins.sse.*
    import kotlinx.coroutines.runBlocking

    fun main() = runBlocking {
        val url = System.getenv("KUBEMQ_MCP_URL") ?: "http://localhost:9090"

        val httpClient = HttpClient { install(SSE) }
        val transport = StreamableHttpClientTransport(client = httpClient, url = "$url/mcp")
        val client = Client(clientInfo = Implementation(name = "kubemq-mcp-kotlin-example", version = "1.0.0"))
        client.connect(transport)

        val tools = client.listTools()
        println(tools)

        client.close()
        httpClient.close()
    }
    ```
  </Tab>

  <Tab value="Python">
    ```python
    import asyncio
    import os

    from mcp.client.streamable_http import streamablehttp_client
    from mcp import ClientSession

    KUBEMQ_MCP_URL = os.environ.get("KUBEMQ_MCP_URL", "http://localhost:9090")


    async def main():
        async with streamablehttp_client(f"{KUBEMQ_MCP_URL}/mcp") as (read, write, _):
            async with ClientSession(read, write) as session:
                await session.initialize()

                tools = await session.list_tools()
                for tool in tools.tools:
                    print(f"{tool.name}: {tool.description}")


    if __name__ == "__main__":
        asyncio.run(main())
    ```
  </Tab>

  <Tab value="Ruby">
    ```ruby
    require "mcp"

    url = ENV.fetch("KUBEMQ_MCP_URL", "http://localhost:9090")

    client = MCP::Client.new(
      transport: MCP::Transport::StreamableHTTP.new("#{url}/mcp"),
      name: "kubemq-mcp-ruby-example",
      version: "1.0.0"
    )
    client.initialize_handshake

    tools = client.list_tools
    puts tools

    client.close
    ```
  </Tab>

  <Tab value="Rust">
    ```rust
    use rmcp::transport::streamable_http::StreamableHttpClientTransport;
    use rmcp::service::RunService;

    #[tokio::main]
    async fn main() -> anyhow::Result<()> {
        let url = std::env::var("KUBEMQ_MCP_URL")
            .unwrap_or_else(|_| "http://localhost:9090".to_string());

        let transport = StreamableHttpClientTransport::from_uri(format!("{url}/mcp"))?;
        let client = ().serve(transport).await?;

        let tools = client.list_tools(Default::default()).await?;
        println!("{tools:#?}");
        Ok(())
    }
    ```
  </Tab>

  <Tab value="Swift">
    ```swift
    import Foundation
    import MCP

    @main
    struct ToolsList {
        static func main() async throws {
            let url = ProcessInfo.processInfo.environment["KUBEMQ_MCP_URL"] ?? "http://localhost:9090"

            let transport = HTTPClientTransport(endpoint: URL(string: "\(url)/mcp")!, streaming: true)
            let client = Client(name: "kubemq-mcp-swift-example", version: "1.0.0")
            try await client.connect(transport: transport)

            let (tools, _) = try await client.listTools()
            for tool in tools {
                print("\(tool.name): \(tool.description ?? "")")
            }
        }
    }
    ```
  </Tab>

  <Tab value="TypeScript">
    ```typescript
    import { Client } from "@modelcontextprotocol/sdk/client/index.js";
    import { StreamableHTTPClientTransport } from "@modelcontextprotocol/sdk/client/streamableHttp.js";

    const KUBEMQ_MCP_URL = process.env.KUBEMQ_MCP_URL || "http://localhost:9090";

    async function main() {
      const transport = new StreamableHTTPClientTransport(
        new URL(`${KUBEMQ_MCP_URL}/mcp`)
      );
      const client = new Client({ name: "kubemq-mcp-ts-example", version: "1.0.0" });
      await client.connect(transport);

      const tools = await client.listTools();
      console.log(JSON.stringify(tools, null, 2));

      await client.close();
    }

    main().catch(console.error);
    ```
  </Tab>
</Tabs>

## Supported languages [#supported-languages]

Every operation has a `curl` example plus the official MCP SDK in nine languages. The
SDK wraps the Streamable HTTP transport — session IDs, request IDs, and JSON-RPC
serialization are handled for you.

| Language        | MCP SDK package                      | Source                |
| --------------- | ------------------------------------ | --------------------- |
| C#              | `ModelContextProtocol`               | NuGet                 |
| Go              | `github.com/mark3labs/mcp-go`        | Go modules            |
| Java            | `io.modelcontextprotocol:sdk`        | Maven Central         |
| Kotlin          | `io.modelcontextprotocol:kotlin-sdk` | Maven Central         |
| Python          | `mcp`                                | PyPI                  |
| Ruby            | `mcp`                                | RubyGems              |
| Rust            | `rmcp`                               | crates.io             |
| Swift           | `mcp-swift-sdk`                      | Swift Package Manager |
| TypeScript / JS | `@modelcontextprotocol/sdk`          | npm                   |

## Next steps [#next-steps]

<Cards>
  <Card title="Getting started" href="/aiway/mcp/getting-started" description="Run the initialize handshake, wire up Claude Desktop, and make your first tool call." />

  <Card title="Tools overview" href="/aiway/mcp/tools" description="Browse all 15 tools by category, with the tool-call response shape." />

  <Card title="Configuration" href="/aiway/mcp/configuration" description="McpConfig fields, the disable env var, and CORS headers." />

  <Card title="Reference" href="/aiway/mcp/reference/endpoints" description="Endpoints, the full tools catalog, and error codes." />
</Cards>
