MCP
Expose KubeMQ messaging and the A2A agent bridge as Model Context Protocol tools that Claude and other AI models can discover and invoke.
The MCP connector exposes KubeMQ messaging operations as
Model Context Protocol 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.
Part of Aiway. MCP is one of the two doors into KubeMQ Aiway, the AI Agents Fabric. New here? Start with the Aiway overview, or follow the end-to-end Aiway tutorial.
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
- 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 /mcpfor JSON-RPC requests (single or batch), plusGET /mcpfor a keepalive SSE stream, both on the shared HTTP port9090. - 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 through the same tool interface.
- Enabled by default — start kubemq-server and
/mcpis live; there is no flag to turn it on.
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.
The MCP connector turns JSON-RPC tool calls into KubeMQ operations and bridges to A2A agents.
The connector runs on the shared HTTP server and
inherits its middleware, authentication,
and observability. The reserved _AGENTS_. channel
prefix is rejected for direct messaging tools — use the agent-bridge tools to reach
agents.
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 |
Queue tools
Point-to-point messaging — queue_send, queue_receive, queue_peek.
Events tools
Pub/sub and persistent events — events_publish and the events-store tools.
Command & query tools
Synchronous request/reply — command_send and query_send.
Channel tools
Introspect channels — channel_list and channel_info.
Agent-bridge tools
Reach A2A agents — agent_list, agent_info, agent_send, agent_query.
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 for full signatures.
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.
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"
}'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}");
}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)
}
}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();
}
}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()
}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())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.closeuse 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(())
}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 ?? "")")
}
}
}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);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
Getting started
Run the initialize handshake, wire up Claude Desktop, and make your first tool call.
Tools overview
Browse all 15 tools by category, with the tool-call response shape.
Configuration
McpConfig fields, the disable env var, and CORS headers.
Reference
Endpoints, the full tools catalog, and error codes.
Was this page helpful?