# JSON-RPC Protocol Used by the Codex App Server: Implementation and Message Specification

> Explore the JSON-RPC protocol powering the Codex App Server. Understand its strict 2.0 implementation, request/response objects, and notification messaging for efficient communication.

- Repository: [OpenAI/codex-plugin-cc](https://github.com/openai/codex-plugin-cc)
- Tags: api-reference
- Published: 2026-07-12

---

**The Codex App Server uses a strict JSON-RPC 2.0 protocol defined in [`app-server-protocol.d.ts`](https://github.com/openai/codex-plugin-cc/blob/main/app-server-protocol.d.ts), where clients send Request objects with unique IDs to receive typed Response objects, while Notifications enable fire-and-forget messaging without return values.**

The `openai/codex-plugin-cc` repository implements a lightweight yet type-safe communication layer between the Codex App Server and client applications like the Codex Companion CLI. This JSON-RPC protocol governs how commands such as `run`, `status`, and `cancel` are transmitted, validated, and routed across WebSocket and HTTP connections.

## JSON-RPC 2.0 Protocol Specification

The protocol strictly adheres to the JSON-RPC 2.0 specification, enforcing a version string of `"2.0"` on every message. Located at [`plugins/codex/scripts/lib/app-server-protocol.d.ts`](https://github.com/openai/codex-plugin-cc/blob/main/plugins/codex/scripts/lib/app-server-protocol.d.ts), the TypeScript definitions declare a discriminated union type `Message` that encompasses all valid communication patterns:

```typescript
export type Message = Request | Notification | Response | ErrorMessage;

export interface Request {
  jsonrpc: "2.0";
  id: number | string;
  method: string;
  params?: unknown;
}

export interface Notification {
  jsonrpc: "2.0";
  method: string;
  params?: unknown;
}

export interface Response {
  jsonrpc: "2.0";
  id: number | string;
  result?: unknown;
  error?: ErrorObject;
}

export interface ErrorObject {
  code: number;
  message: string;
  data?: unknown;
}

```

This schema ensures that every payload carries the mandatory `jsonrpc` field while differentiating between calls that require responses (Requests) and those that do not (Notifications).

## Core Message Types and Type Definitions

### Request Messages

**Request** objects represent the primary mechanism for clients to invoke server-side operations. Each Request must include a unique `id` (string or number) that the server echoes back in the corresponding Response, enabling asynchronous correlation. The `method` field specifies the command to execute—such as `run` for executing code or `status` for checking job progress—while `params` optionally carries method-specific arguments.

### Notification Messages

**Notifications** follow the same structure as Requests but omit the `id` field entirely. These fire-and-forget messages inform the server of events without expecting acknowledgment. In `plugins/codex/scripts/lib/app-server.mjs`, the dispatcher inspects incoming JSON to detect the presence of an `id` property, routing Notifications to handlers that do not generate return traffic.

### Response and Error Handling

**Response** objects map to previous Requests via matching `id` values. A valid Response contains either a `result` field with the operation output or an `error` field containing an `ErrorObject` with `code`, `message`, and optional `data`. The `app-server-broker.mjs` file manages these mappings, ensuring that results from worker processes reach the correct client connection.

## Server Architecture and Routing

The `app-server.mjs` file implements the core dispatch logic that parses incoming JSON strings into the `Message` union. Upon receiving a payload, the server validates the `jsonrpc` version, then branches based on message type:

- **Requests**: Routed to command handlers (e.g., `runCommand`) that generate asynchronous results, eventually wrapped in a `Response` object and sent back to the client.
- **Notifications**: Handled immediately by dedicated functions in `app-server-broker.mjs` without generating return values.

The broker file (`plugins/codex/scripts/app-server-broker.mjs`) manages multiple concurrent client connections, maintaining request ID mappings to ensure that Responses reach the initiators even when multiple clients interact with the server simultaneously.

## Client Implementation Examples

### Sending Commands from codex-companion.mjs

The Codex Companion CLI constructs JSON-RPC Requests to execute commands. Below is a TypeScript example demonstrating how to build and send a `run` request:

```typescript
import { Request } from "./app-server-protocol";

function sendRunCommand(socket: WebSocket, command: string): void {
  const request: Request = {
    jsonrpc: "2.0",
    id: Date.now(),              // Unique identifier for response matching
    method: "run",
    params: { command },
  };
  
  const payload = JSON.stringify(request);
  socket.send(payload);           // Transmitted to app-server.mjs
}

```

### Processing Results

Clients listen for incoming messages and correlate them with pending requests using the `id` field:

```javascript
socket.addEventListener("message", (event) => {
  const msg = JSON.parse(event.data);
  
  if (msg.id === pendingRequestId) {
    if (msg.result) {
      console.log("Execution successful:", msg.result);
    } else if (msg.error) {
      console.error(`Error ${msg.error.code}: ${msg.error.message}`);
    }
  }
});

```

### Server-Side Message Dispatch

The server implementation parses raw strings and routes them according to the protocol definition:

```typescript
import { Message, Request, Response } from "./app-server-protocol";

function handleMessage(raw: string, ws: WebSocket): void {
  const msg: Message = JSON.parse(raw);

  if ("id" in msg) {
    // Request: requires a Response
    const response: Response = {
      jsonrpc: "2.0",
      id: msg.id,
      result: executeMethod(msg.method, msg.params),
    };
    ws.send(JSON.stringify(response));
  } else {
    // Notification: fire-and-forget
    handleNotification(msg);
  }
}

```

## Summary

- The Codex App Server strictly implements **JSON-RPC 2.0** as defined in [`plugins/codex/scripts/lib/app-server-protocol.d.ts`](https://github.com/openai/codex-plugin-cc/blob/main/plugins/codex/scripts/lib/app-server-protocol.d.ts).
- **Requests** include unique `id` fields and expect `Response` objects containing either `result` or `error` data.
- **Notifications** lack `id` fields and execute without server acknowledgment, handled by `app-server-broker.mjs`.
- The server dispatcher in `app-server.mjs` validates the `jsonrpc` version and routes messages based on the presence of an `id` property.
- Client implementations like `codex-companion.mjs` serialize TypeScript objects into JSON-RPC payloads for commands such as `run`, `status`, and `cancel`.

## Frequently Asked Questions

### What version of JSON-RPC does the Codex App Server use?

The Codex App Server implements **JSON-RPC 2.0**, as enforced by the `jsonrpc: "2.0"` field requirement in the TypeScript interfaces defined in [`app-server-protocol.d.ts`](https://github.com/openai/codex-plugin-cc/blob/main/app-server-protocol.d.ts). This ensures compatibility with standard JSON-RPC clients and strict validation of incoming message structures.

### How does the server distinguish between requests and notifications?

The server checks for the presence of an `id` field in the parsed JSON object. According to the protocol definition in [`app-server-protocol.d.ts`](https://github.com/openai/codex-plugin-cc/blob/main/app-server-protocol.d.ts), **Requests** contain an `id` (string or number), while **Notifications** omit this field entirely. The dispatch logic in `app-server.mjs` uses this check to determine whether to generate a Response.

### Where are the protocol types defined?

All message type definitions—including `Request`, `Notification`, `Response`, and `ErrorObject`—are located in **[`plugins/codex/scripts/lib/app-server-protocol.d.ts`](https://github.com/openai/codex-plugin-cc/blob/main/plugins/codex/scripts/lib/app-server-protocol.d.ts)**. This file serves as the central schema reference for both server and client implementations in the repository.

### Can clients send multiple concurrent requests?

Yes, clients can send multiple concurrent requests by ensuring each **Request** carries a unique `id` value. The server maintains these IDs through the broker layer (`app-server-broker.mjs`), matching asynchronous responses to the correct client connections and original request identifiers.