How the Codex Plugin Uses JSON-RPC to Communicate with the App Server

The Codex plugin communicates with the Codex app server through a type-safe JSON-RPC 2.0 protocol implemented by the CodexAppServerClient class, which sends HTTP POST requests to a broker endpoint and listens for asynchronous server notifications via WebSocket.

The openai/codex-plugin-cc repository implements a robust communication layer that bridges the Codex plugin with the app server using JSON-RPC. This architecture enables synchronous method calls with typed request/response payloads while supporting asynchronous server-initiated events through a dual-transport design.

The JSON-RPC 2.0 Architecture

The communication system rests on three core pillars: a typed method map that defines available RPC operations, a generic client that serializes and transmits requests, and a notification pipeline that handles server-pushed messages. This structure ensures type safety across the boundary between the plugin and the app server.

Typed Method Definitions with AppServerMethodMap

According to the openai/codex-plugin-cc source code, the protocol definitions reside in plugins/codex/scripts/lib/app-server-protocol.d.ts. This file exports the AppServerMethodMap interface, which acts as a central registry of every RPC method the server supports.

Each entry in the map specifies the exact shape of request parameters and response payloads. For example, the thread/start method expects parameters matching the ThreadStartParams type and returns a response containing a threadId. These generated TypeScript definitions ensure compile-time validation of all JSON-RPC calls.

The CodexAppServerClient Implementation

The concrete implementation lives in plugins/codex/scripts/lib/app-server-client.ts. The CodexAppServerClient class consumes the type definitions to provide a developer-friendly API over raw JSON-RPC.

Initializing the Client

To instantiate the client, pass a configuration object satisfying the CodexAppServerClientOptions interface:

import {
  CodexAppServerClient,
  CodexAppServerClientOptions,
} from "./app-server-protocol";

const opts: CodexAppServerClientOptions = {
  brokerEndpoint: "http://localhost:3000/broker",
  clientInfo: { name: "my-codex-plugin", version: "1.0.0" },
};

const client = new CodexAppServerClient(opts);

The brokerEndpoint determines where the client posts JSON-RPC payloads. When the broker is disabled, the client communicates directly with the app server's HTTP endpoint.

Making Typed RPC Requests

The request method on CodexAppServerClient accepts a method name defined in AppServerMethodMap and its corresponding parameters. It returns a Promise resolving to the typed response.

import { ThreadStartParams } from "./app-server-protocol";

const startParams: ThreadStartParams = {
  // Parameters matching the generated type definition
};

client
  .request("thread/start", startParams)
  .then((response) => {
    console.log("Thread started:", response.threadId);
  })
  .catch((err) => console.error("RPC error:", err));

Internally, the client constructs a JSON-RPC 2.0 payload:

{
  "jsonrpc": "2.0",
  "id": "a1b2c3d4",
  "method": "thread/start",
  "params": {
    // Fields from ThreadStartParams
  }
}

The client POSTs this payload to the configured broker or app server endpoint, then awaits the response, mapping it back to the TypeScript return type defined in the method map.

Handling Asynchronous Server Notifications

Beyond request-response cycles, the app server pushes asynchronous notifications to the client. These messages follow the JSON-RPC notification specification—they omit the id field because they do not require a response.

Registering Notification Handlers

The CodexAppServerClient exposes an onNotification method that accepts an AppServerNotificationHandler callback. The handler receives ServerNotification objects defined in plugins/codex/scripts/lib/app-server-protocol.d.ts.

client.onNotification((msg) => {
  switch (msg.method) {
    case "turn/start":
      console.log("Turn started:", msg.params);
      break;
    case "review/start":
      console.log("Review started:", msg.params);
      break;
    // Handle other server notifications
  }
});

The client maintains a WebSocket or Server-Sent Events connection to receive these notifications in real-time, enabling the plugin to react to server-side events like conversation turns or review cycles without polling.

Transport Layer Implementation

The JSON-RPC client abstracts two distinct transport mechanisms under a unified interface.

HTTP POST for Synchronous Calls

For method calls requiring immediate responses, the client serializes the request to JSON and POSTs it to the broker endpoint. The broker forwards the request to the app server and returns the JSON-RPC response to the client.

WebSocket for Real-Time Events

For notifications, the client establishes a persistent WebSocket connection. This bidirectional channel allows the server to push turn/start or review/start events to the plugin immediately as they occur, maintaining an active communication channel alongside the HTTP request flow.

Summary

  • The JSON-RPC 2.0 protocol in openai/codex-plugin-cc provides type-safe communication between the Codex plugin and app server.
  • The AppServerMethodMap in plugins/codex/scripts/lib/app-server-protocol.d.ts defines all available RPC methods with complete TypeScript typings.
  • The CodexAppServerClient class handles serialization of requests, HTTP POST transmission to the broker endpoint, and response deserialization.
  • Notifications flow through a separate WebSocket channel, handled by the AppServerNotificationHandler to process server-initiated events like turn/start and review/start.
  • The architecture separates synchronous method calls from asynchronous events while maintaining strict type safety through generated TypeScript definitions.

Frequently Asked Questions

What is the default broker endpoint for the Codex plugin?

By default, the CodexAppServerClient targets http://localhost:3000/broker when the brokerEndpoint option is not explicitly configured in CodexAppServerClientOptions. This endpoint acts as a proxy between the plugin and the Codex app server, though the client can connect directly to the app server when broker mode is disabled.

How does the CodexAppServerClient handle server-initiated notifications?

The client opens a persistent WebSocket connection to receive JSON-RPC notifications—messages without an id field. It dispatches these to registered handlers via the onNotification method, allowing the plugin to respond to events like turn/start or review/start asynchronously without polling the server.

Where are the JSON-RPC method types defined in the codebase?

All type definitions for the JSON-RPC protocol reside in plugins/codex/scripts/lib/app-server-protocol.d.ts. This includes the AppServerMethodMap interface mapping method names to their parameter and return types, as well as the ServerNotification type for incoming events.

What JSON-RPC version does the Codex plugin implement?

The Codex plugin uses JSON-RPC 2.0, as evidenced by the "jsonrpc": "2.0" field present in every request payload constructed by the CodexAppServerClient. This version supports both standard request-response cycles and notification messages that require no response.

Have a question about this repo?

These articles cover the highlights, but your codebase questions are specific. Give your agent direct access to the source. Share this with your agent to get started:

Share the following with your agent to get started:
curl -s "https://instagit.com/install.md"

Works with
Claude Codex Cursor VS Code OpenClaw Any MCP Client

Maintain an open-source project? Get it listed too →