# JSON-RPC 2.0 Protocol Implementation for MCP Communication in codebase-memory-mcp

> Implement the JSON-RPC 2.0 protocol for MCP communication in codebase-memory-mcp. This TypeScript client simplifies backend interaction via HTTP POST requests using the callTool function.

- Repository: [Martin Vogel/codebase-memory-mcp](https://github.com/DeusData/codebase-memory-mcp)
- Tags: api-reference
- Published: 2026-07-11

---

**The codebase-memory-mcp repository implements a lightweight JSON-RPC 2.0 client in TypeScript that communicates with the Memory-Control-Panel backend via HTTP POST requests to the `/rpc` endpoint, handling request serialization, error propagation, and result unmarshalling through a single `callTool()` function.**

The `codebase-memory-mcp` project provides a complete JSON-RPC 2.0 client implementation that enables the frontend graph interface to communicate with the MCP (Memory-Control-Panel) backend. Located in [`graph-ui/src/api/rpc.ts`](https://github.com/DeusData/codebase-memory-mcp/blob/main/graph-ui/src/api/rpc.ts), this implementation manages the full request lifecycle from payload construction to response parsing while maintaining strict compliance with the JSON-RPC 2.0 specification.

## Request Structure and Payload Construction

In [`graph-ui/src/api/rpc.ts`](https://github.com/DeusData/codebase-memory-mcp/blob/main/graph-ui/src/api/rpc.ts), the `callTool` function constructs JSON-RPC 2.0 requests according to the protocol specification. Each request includes four required fields: the protocol version, a unique identifier, the method name, and parameters.

### Protocol Version and Method Specification

The implementation explicitly sets the `jsonrpc` field to `"2.0"` to ensure compliance with the JSON-RPC 2.0 specification. Method names follow MCP-specific conventions, such as `"tools/call"`, which the backend recognizes as tool invocation requests.

```typescript
body: JSON.stringify({
  jsonrpc: "2.0",               // Protocol version identifier
  id: _nextId++,                // Auto-incrementing request ID
  method: "tools/call",         // MCP-specific method endpoint
  params: { name, arguments: args },
})

```

### Request ID Management

The client maintains an internal counter `_nextId` that auto-increments for each request, ensuring every JSON-RPC message carries a unique identifier. This enables the client to match responses to specific requests when handling concurrent operations.

### HTTP Transport Configuration

Requests are transmitted via HTTP POST to the `/rpc` endpoint with a `Content-Type: application/json` header. This transport mechanism bridges the JSON-RPC protocol over standard HTTP, allowing the frontend to communicate with the backend service.

## Error Handling and Response Validation

The implementation distinguishes between transport-level failures and JSON-RPC protocol errors through a two-stage validation process defined in lines 30-38 of [`rpc.ts`](https://github.com/DeusData/codebase-memory-mcp/blob/main/rpc.ts).

### HTTP Status Verification

After executing the fetch request, the client first checks the HTTP response status. If the status indicates failure (not OK), the client throws an `RpcError` with a generic code of `-1`, signaling a network or transport layer problem.

### JSON-RPC Error Processing

For successful HTTP responses, the client parses the JSON body and checks for the presence of an `error` object. When present, the client throws an `RpcError` populated with the specific `code` and `message` supplied by the server, preserving the backend's error context.

```typescript
// Error handling pattern from rpc.ts
if (!response.ok) {
  throw new RpcError("HTTP error", -1);
}
const data = await response.json();
if (data.error) {
  throw new RpcError(data.error.message, data.error.code);
}

```

### RpcError Class Architecture

The `RpcError` class extends JavaScript's native `Error` to include an RPC-specific error code property. This design allows calling code to distinguish between protocol-level failures, application errors, and network interruptions programmatically.

## Result Unmarshalling and Data Extraction

MCP tool results arrive wrapped in a nested structure containing a `content` array with text elements. According to lines 40-47 of [`rpc.ts`](https://github.com/DeusData/codebase-memory-mcp/blob/main/rpc.ts), the client extracts the first text field from `result.content[0].text` and automatically parses it as JSON when present, otherwise returning the raw result object.

```typescript
// Result extraction logic from lines 40-47 of rpc.ts
const text = data.result?.content?.[0]?.text;
if (text !== undefined) {
  return JSON.parse(text);
}
return data.result;

```

This unmarshalling strategy handles MCP's convention of wrapping tool outputs in content objects while providing developers with clean, parsed data structures.

## Practical Implementation Examples

The following examples demonstrate how to interact with the JSON-RPC 2.0 implementation using the `callTool` function.

### Fetching Structured Data

Call a tool that returns a plain JSON object by specifying the expected TypeScript interface:

```typescript
interface ProjectList {
  projects: string[];
}
const projects = await callTool<ProjectList>("projects/list");
console.log(projects.projects);

```

### Handling Stringified JSON Payloads

When tools return stringified JSON within the text content field, the client automatically parses the inner payload:

```typescript
type Summary = { title: string; body: string };
const summary = await callTool<Summary>("summary/generate", { 
  text: "Explain JSON-RPC" 
});
console.log(`${summary.title}: ${summary.body}`);

```

Supporting hooks like [`useProjects.ts`](https://github.com/DeusData/codebase-memory-mcp/blob/main/useProjects.ts) and [`useGraphData.ts`](https://github.com/DeusData/codebase-memory-mcp/blob/main/useGraphData.ts) demonstrate production usage patterns for populating UI state with RPC data.

## Summary

- The **JSON-RPC 2.0 protocol implementation** in `codebase-memory-mcp` centers on the `callTool` function in [`graph-ui/src/api/rpc.ts`](https://github.com/DeusData/codebase-memory-mcp/blob/main/graph-ui/src/api/rpc.ts).
- **Request construction** follows strict JSON-RPC 2.0 standards with auto-incrementing IDs and proper method naming conventions.
- **Error handling** differentiates HTTP transport failures from JSON-RPC protocol errors using the `RpcError` class.
- **Result unmarshalling** automatically extracts and parses JSON content from MCP's nested response structure.
- The implementation provides **type-safe integration** between the frontend graph interface and the MCP backend.

## Frequently Asked Questions

### How does the codebase-memory-mcp client ensure JSON-RPC 2.0 compliance?

The client enforces compliance by explicitly setting the `jsonrpc` field to `"2.0"`, including unique request IDs through auto-incrementing counters, and structuring requests with the required `method` and `params` fields. This implementation adheres to the official JSON-RPC 2.0 specification for single-request messaging.

### What error codes does the JSON-RPC implementation use?

The implementation uses code `-1` for HTTP transport failures (non-OK responses), while server-side JSON-RPC errors pass through with their original codes as defined in the MCP backend. The `RpcError` class captures both scenarios, allowing applications to handle network issues separately from business logic errors.

### Where is the JSON-RPC client code located in the repository?

The core implementation resides in [`graph-ui/src/api/rpc.ts`](https://github.com/DeusData/codebase-memory-mcp/blob/main/graph-ui/src/api/rpc.ts), which contains the `callTool` function and `RpcError` class. Supporting type definitions appear in [`graph-ui/src/lib/types.ts`](https://github.com/DeusData/codebase-memory-mcp/blob/main/graph-ui/src/lib/types.ts), while usage examples exist in [`graph-ui/src/hooks/useProjects.ts`](https://github.com/DeusData/codebase-memory-mcp/blob/main/graph-ui/src/hooks/useProjects.ts) and [`graph-ui/src/hooks/useGraphData.ts`](https://github.com/DeusData/codebase-memory-mcp/blob/main/graph-ui/src/hooks/useGraphData.ts).

### How does the client handle MCP tool results that contain stringified JSON?

The client automatically inspects the `result.content[0].text` field when present, parsing the string as JSON and returning the resulting object. If the text field is undefined, the client returns the raw `result` object, providing flexibility for tools that return different payload structures.