TellWorldAI World Archive
Ask中文

Home›Practice›Practice

Practice

MCP transports: writing a custom transport on Azure messaging

MCP defines two standard transports. This piece explains when a custom transport on Azure Event Grid or Event Hubs makes sense, what the stateless 2026-07-28 rules require, and what it costs in interoperability.

Who this is for and what you can do after reading

This is for developers who already build MCP servers or clients and need to connect MCP to an existing enterprise messaging system. After reading, you can state what a custom transport must satisfy, design one on Azure messaging services that follows the stateless rules of MCP specification 2026-07-28, and see what interoperability you give up in return.

What a transport is and what a custom one means

The transport layer decides how JSON-RPC messages travel between a client and a server. MCP has two standard transports: stdio and Streamable HTTP[1]. A custom transport is optional. It is an implementation-specific mapping, and both endpoints must agree on it[1].

The usual motive in enterprises is reuse: an organization already runs messaging infrastructure and wants MCP to ride on it instead of building a second channel[1]. The cost is equally clear. Hosts and SDKs that implement only the standard transports may be unable to talk to a custom mapping, so interoperability drops[1]. Before you build one, ask whether Streamable HTTP already meets your needs. If it does, a custom transport adds nothing.

Azure Event Grid and Azure Event Hubs are architecture patterns in this context. They are not standard MCP transports[1]. The examples below use them, but the reasoning applies to other messaging systems as well.

What the 2026-07-28 specification requires of transports

The core of MCP specification 2026-07-28 is statelessness. The protocol has no sessions, every request must be self-contained, and no handshake exists to carry state between requests[1]. This matters a great deal for a custom transport. Whichever function instance or partition handles a message, the receiver can only understand it from the message itself. A custom transport therefore cannot depend on session affinity, and it cannot assume that messages from one session arrive in order[1].

The requirements reduce to a few rules:

  • Messages use JSON-RPC 2.0 with MCP extensions, and each response is matched to its request by JSON-RPC id[1].
  • The transport must handle connection failures gracefully and must support secure communication[1].
  • Each request carries the protocol version, capabilities and identity[1].

Standard Streamable HTTP requires an Mcp-Method header and, when needed, an Mcp-Name header. A non-HTTP transport that lets intermediaries route without decoding the JSON-RPC body needs an equivalent mapping, agreed in advance and written down[1].

Preparation: fix the mapping first, then pick the Azure service

Azure Event Grid is a serverless event routing service for event-driven MCP architectures[1]. Azure Event Hubs provides high-throughput, real-time streaming for scenarios that need low latency and high message volume[1]. They emphasize different things. Event Grid distributes events to subscribers, while Event Hubs supports continuous streams consumed by partition.

Settle two questions before choosing. First, is each MCP request a discrete event, or part of a continuous stream? Second, must each response return to the client that sent its request? The answers decide which service fits and how the receiver links responses back to requests.

You also need an Azure subscription, a chosen region and a check of service limits. Validate the design against your own requirements and those limits[1].

Steps

  1. Write the mapping down for both endpoints: how a message is placed into an event, which properties carry the method and the id, and what the event type is called. Both endpoints must match exactly, or they cannot interoperate[1].
  2. Implement the sender. The Event Grid sample wraps each message in an event with subject mcp/{clientId}, event type MCP.MessageReceived and data version 1.0[1]. The TypeScript sender method looks like this:
    async sendMessage(message: McpMessage): Promise<void> {
        const event = {
            id: crypto.randomUUID(),
            source: `mcp-client-${this.clientId}`,
            type: "MCP.MessageReceived",
            time: new Date(),
            data: message
        };
        
        await this.publisher.sendEvents([event]);
    }
  1. Set up the receiver. Event Grid is push-based. In the C# sample, ReceiveMessageAsync throws NotImplementedException, and its comment says receiving is handled by an Azure Functions Event Grid trigger[1].
  2. In the function, deserialize the event data, pass it to the MCP server, and send the response back through the same transport[1]. Confirm that the sender can match each response event back to its original request.

Event Hubs details

  • Each event carries properties. The C# sample sets MessageType, MessageId and Timestamp on every message so consumers can identify it[1].
  • Delivery semantics. The TypeScript sample calls updateCheckpoint after handling a message, for at-least-once delivery[1]. A message can therefore be processed twice, so the handler must be idempotent, for example by checking MessageId before acting.
  • Errors. The same sample catches processing errors and logs them with console.error[1]. The logged error is not rethrown and enters no retry or quarantine path. In production, pair this with a dead letter queue for failed messages, a standard practice in messaging systems[1].
  • Partitioning. One partitioning sample partitions by client ID with the comment "for session affinity"[1]. That directly conflicts with the stateless rule above. Decide deliberately whether partitions serve throughput or sessions, because the two should not be mixed up when you copy the code.

Keys and security

Use managed identity in production and avoid putting connection strings in code or configuration[1]. One sample reads secrets named EventGridAccessKey and EventGridTopic from Azure Key Vault and creates the Event Grid transport from them[1]. Keeping the values in Key Vault means the code receives only what it needs and no secret is hard-coded in source.

Testing

An integration test can start an EventHubsContainer from Testcontainers with a test event hub, send a message, and check that the received message id matches[1]. Such a test catches mapping and serialization errors. It does not replace checking the design against the specification line by line. Write the mapping document first, then use the test to verify it.

Common problems

  • Clients cannot connect: the mapping is usually misaligned. A host that implements only standard transports cannot read a custom mapping, which is a design cost rather than a configuration error[1].
  • Duplicate messages: at-least-once delivery produces duplicates, so deduplicate by message id or make handlers idempotent[1].
  • Do the samples run as written? They show structure. A real project still needs complete interface definitions, retries, monitoring and health checks[1].
  • Sends fail intermittently: a message must cross the network before it reaches the messaging service, so failures are normal. The specification requires graceful handling of connection failures, so the sender needs a retry policy. Retries create duplicates, which is why the idempotent handling described above matters[1].
  • Responses do not match requests: check that both endpoints handle the JSON-RPC id the same way. A response must be traceable to its request by id[1].

Next steps

For protocol behavior, the MCP 2026-07-28 specification is the reference[2]. For how to configure the Azure services, check the official Azure Event Grid and Azure Event Hubs documentation.

Adapted from lesson material in Microsoft's open-source course *MCP for Beginners*, covering custom transports in its advanced topics[1], released under the MIT License.

Sources

  1. 1
  2. 2
    MCP Specification 2026-07-28Model Context Protocol

Cite this page: MCP transports: writing a custom transport on Azure messaging. TellWorld, https://www.tellworld.net/practice/practice-mcp-transport. Updated 2026-11-14

Related news

View all