Building Applications & Examples

Shipped examples and step-by-step patterns for building your own services with send/recv, MCP, and A2A, plus patterns for building your own applications on top of it.

Overview

AXL is a peer-to-peer networking layer that lets you build distributed applications over a mesh of connected nodes.

For more on the internals of AXL, check out How it Works.

It provides low-level messaging primitives along with higher-level protocol support for MCP and A2A, so you can go from simple fire-and-forget communication to fully discoverable agent services with minimal setup.

Building your Own Application

Building an application using AXL means picking a starting point. In this case, that starting point can be a building pattern which makes use of AXL's low-level functionalities in a particular way.

These patterns include [1] fire-and-forget (using send/recv), [2] MCP services (request/response), and [3] A2A (agent-to-agent).

Pattern 1: Send/Recv (Fire-and-Forget)

This is the simplest pattern. Your application sends raw bytes and polls for incoming messages.

import requests, json, time

AXL = "http://127.0.0.1:9002"
PEER = "1ee862344fb283395143ac9775150d2e5936efd6e78ed0db83e3f290d3d539ef"

def send(message):
    requests.post(f"{AXL}/send",
        headers={"X-Destination-Peer-Id": PEER},
        data=json.dumps(message))

def recv_loop():
    while True:
        resp = requests.get(f"{AXL}/recv")
        if resp.status_code == 200:
            sender = resp.headers.get("X-From-Peer-Id")
            print(f"From {sender[:8]}...: {resp.text}")
        time.sleep(0.2)
  • When to use: Simple messaging, notifications, data streaming, custom protocols where you control both sides.

  • Limitation: No built-in acknowledgment. If you need request-response, use MCP/A2A or build correlation over send/recv.

Pattern 2: MCP Services (Request-Response)

MCP (Model Context Protocol) gives you structured JSON-RPC request-response. You expose a named service on your node, and other nodes call it remotely.

The requests flow like this:

Step 1: Write Your Service

You can start by configuring a basic HTTP server:

Step 2: Start the MCP Router

Step 3: Register your Service w/ Router

Don't forget to deregister on shutdown using this command:

requests.delete("http://127.0.0.1:9003/register/sentiment")

Step 4: Enable MCP (Node Config)

If you run this command, any node on the network can call your service by your public key and service name:

If you want to calling a remote MCP service (from another node), you'd run this:

Replace {peer_id} with the remote node's 64-character hex public key.

Both nodes must share at least one common peer but they don't need direct connectivity.

MCP Router Endpoints

Use this list of router endpoints.

Endpoint

Description

POST /route

Forward a request to a registered service (called by the node)

POST /register

Register a service: {"service": "...", "endpoint": "..."}

DELETE /register/{service}

Remove a service

GET /services

List registered services

GET /health

Health check

Pattern 3: A2A (Agent-to-Agent)

A2A wraps your MCP services as A2A skills, making them discoverable by A2A-compatible agents.

Run this command:

Then add it to your node configuration file:

The A2A server auto-discovers services from the MCP router and advertises them at /.well-known/agent.json.

Remote nodes can interact with your A2A server like this:

The messageId is a client-assigned correlation ID. The text part must be a JSON-stringified MCP request matching the format the A2A server expects.

A2A Test Client

A convenience script is included at examples/python-client/a2a_client.py:

Adding a Custom Protocol

If MCP and A2A don't fit your needs, you can add your own protocol by implementing the Stream interface:

Register it in internal/tcp/listen/listener.go alongside the MCP and A2A streams. Messages matching your discriminator will be routed to your handler instead of the default queue.

Sharing Your Service

Once running, other nodes need two things: [1] your public key (so other nodes can find and connect to yours) and [2] your service name, so they know what to call.

You can share your public key and service name however you like.

e.g., "I'm 37227e... and I run a sentiment MCP service."

Built-in Examples

There are several example applications that are built into the AXL repository itself, each demonstrating an angle of the technology. You can find them here.

1. Tensor Exchange

Send and receive PyTorch tensors between nodes using msgpack serialization.

File: examples/python-client/client.py

Modes:

  • recv: listen for incoming tensors

  • tensor: send a tensor to a peer

  • bandwidth: bandwidth test

2. Remote MCP Server

Connect two nodes so one can call MCP tools hosted on the other. A2A is not required. The node's /mcp/ endpoint talks directly to a remote peer's MCP router.

  1. Remote Machine (Sender)

  1. Local Machine (Receiver)

Both nodes must be able to reach at least one common peer (configured in Peers). They don't need direct connectivity.

3. Remote A2A

Optimize integration by transforming MCP services into A2A skills using the optional A2A extension.

  1. Remote Machine (Sender):

  1. Local Machine (Receiver):

The A2A server automatically detects and registers MCP services as skills, making access easy for agents that are already A2A-compatible.

4. GossipSub

GossipSub-style pub/sub message propagation with IHAVE/IWANT lazy forwarding, built on send/recv.

File: examples/python-client/gossipsub/gossipsub.py

5. Convergecast

Tree-based data aggregation using the network's spanning tree. Nodes derive their position from /topology and aggregate results upward toward the root.

File: examples/python-client/convergecast.py

Last updated