# How the MCP Server Handles JSON-RPC 2.0 Requests and Tool Dispatching in codebase-memory-mcp

> Learn how the MCP server in codebase-memory-mcp handles JSON-RPC 2.0 requests using a single-threaded event loop and strcmp dispatcher for efficient tool routing.

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

---

**The MCP server uses a single-threaded event loop with YYJSON parsing and a strcmp-based method dispatcher in [`src/mcp/mcp.c`](https://github.com/DeusData/codebase-memory-mcp/blob/main/src/mcp/mcp.c) to route JSON-RPC 2.0 requests to concrete tool handlers like `handle_search_graph` and `handle_index_repository`.**

The DeusData/codebase-memory-mcp repository implements a lightweight MCP (Model Context Protocol) server that communicates via JSON-RPC 2.0 over standard I/O. Written in C and centered in [`src/mcp/mcp.c`](https://github.com/DeusData/codebase-memory-mcp/blob/main/src/mcp/mcp.c), the implementation handles request parsing, method dispatching, and tool execution through a synchronous, single-threaded architecture. This article examines how the server processes incoming JSON-RPC 2.0 requests and manages the dispatching of tool calls to graph-analysis functions.

## Parsing JSON-RPC 2.0 Requests

The server begins processing by reading raw lines from standard input and converting them into structured request objects.

### The cbm_jsonrpc_parse Function

Located at lines 21–67 of [`src/mcp/mcp.c`](https://github.com/DeusData/codebase-memory-mcp/blob/main/src/mcp/mcp.c), the `cbm_jsonrpc_parse` function uses the YYJSON library to validate and extract fields from incoming JSON. It constructs a `cbm_jsonrpc_request_t` structure containing the mandatory `jsonrpc`, `method`, and `id` fields, along with optional `params`. The function returns specific error codes if the document fails to parse, ensuring strict adherence to the JSON-RPC 2.0 specification.

### Handling Request Identifiers

The parser preserves both numeric and string identifiers exactly as received, a detail critical for compliance with JSON-RPC 2.0. This preservation allows the response formatter to echo the correct `id` back to the client, even when the identifier contains non-numeric characters or complex string values.

## Method Dispatching and Routing

Once parsed, requests flow through a centralized dispatcher that routes method calls to appropriate handlers.

### The cbm_mcp_server_handle Dispatcher

The `cbm_mcp_server_handle` function serves as the core routing logic within the server's event loop. This implementation distinguishes between **notifications** (requests without an `id` field) and standard method calls, processing them through a linear chain of `strcmp` comparisons.

### Routing Logic with strcmp

The dispatcher uses explicit string comparisons to route methods:

```c
if (strcmp(req.method, "initialize") == 0) { … }
else if (strcmp(req.method, "ping") == 0) { … }
else if (strcmp(req.method, "tools/list") == 0) { … }
else if (strcmp(req.method, "tools/call") == 0) { … }
else { … }   // Method-not-found error

```

This straightforward approach in [`src/mcp/mcp.c`](https://github.com/DeusData/codebase-memory-mcp/blob/main/src/mcp/mcp.c) (lines 4832–4839) ensures predictable, deterministic dispatching for the four primary MCP endpoints: `initialize`, `ping`, `tools/list`, and `tools/call`.

### Handling Notifications vs Calls

Notifications arrive without an `id` field and receive no response, while standard calls trigger full response generation. The dispatcher checks for the presence of `id` before entering the response formatting phase, adhering to JSON-RPC 2.0 semantics regarding one-way versus two-way communication.

## Tool Invocation and Execution

The `tools/call` method requires special handling to map tool names to concrete implementations.

### The TOOLS Array Registry

The server maintains a static array named `TOOLS[]` near the top of [`src/mcp/mcp.c`](https://github.com/DeusData/codebase-memory-mcp/blob/main/src/mcp/mcp.c) (lines 73–94). Each entry contains the tool name, description, and JSON Schema definition for arguments, serving as the authoritative registry of available capabilities.

### The cbm_mcp_handle_tool Implementation

When processing `tools/call`, the dispatcher extracts the tool name and arguments using `cbm_mcp_get_tool_name` and `cbm_mcp_get_arguments`. It then records execution timing for diagnostics and forwards the request to `cbm_mcp_handle_tool`. This function iterates through the `TOOLS[]` array to locate the matching implementation.

### Concrete Tool Handlers

Individual tools such as `handle_index_repository`, `handle_search_graph`, and `handle_manage_adr` reside in [`src/mcp/mcp.c`](https://github.com/DeusData/codebase-memory-mcp/blob/main/src/mcp/mcp.c). Each handler receives the parsed arguments, performs graph-analysis operations, and returns a JSON string that becomes the `result` field in the JSON-RPC response.

The following example demonstrates a `tools/call` request for the `search_graph` tool:

```json
{
  "jsonrpc": "2.0",
  "id": "search-42",
  "method": "tools/call",
  "params": {
    "name": "search_graph",
    "arguments": {
      "project": "my-project",
      "query": "update settings"
    }
  }
}

```

The response produced by `handle_search_graph` contains the search results:

```json
{
  "jsonrpc": "2.0",
  "id": "search-42",
  "result": {
    "total": 128,
    "has_more": false,
    "results": [ /* array of matched graph nodes */ ]
  }
}

```

## Response Formatting and Error Handling

The server constructs compliant responses using dedicated formatting functions.

### The cbm_jsonrpc_format_response Function

Defined at lines 84–120 in [`src/mcp/mcp.c`](https://github.com/DeusData/codebase-memory-mcp/blob/main/src/mcp/mcp.c), `cbm_jsonrpc_format_response` creates a mutable YYJSON document. It always inserts the `"jsonrpc":"2.0"` member, preserves the request ID (handling both numeric and string types), and embeds either a `result` or `error` payload. The function returns the final JSON string ready for transmission over standard output.

### Standard Error Codes

The implementation uses specific JSON-RPC 2.0 error codes for failure conditions:

- **Parse error (-32700)**: Returned by `cbm_jsonrpc_format_error` when `cbm_jsonrpc_parse` fails to decode the request.
- **Method not found (-32601)**: Generated in the final `else` branch of `cbm_mcp_server_handle` when the method name matches no known endpoint.

The error response preserves the original request `id` even when it is a string, as implemented in the error handling logic at lines 4810–4824.

Example error response for an unknown method:

```json
{
  "jsonrpc": "2.0",
  "id": 99,
  "error": { "code": -32601, "message": "Method not found" }
}

```

## Lifecycle and Resource Management

The server includes mechanisms to maintain bounded memory usage during idle periods.

### Idle Store Eviction

The event loop monitors for inactivity using `STORE_IDLE_TIMEOUT_S`. When no requests arrive within the configured timeout, the server invokes `cbm_mcp_server_evict_idle` to release the cached SQLite store. This behavior ensures predictable memory consumption while maintaining full JSON-RPC 2.0 compliance for active connections.

## Summary

- **Request parsing** occurs via `cbm_jsonrpc_parse` in [`src/mcp/mcp.c`](https://github.com/DeusData/codebase-memory-mcp/blob/main/src/mcp/mcp.c), which validates JSON-RPC 2.0 structure using YYJSON and handles both numeric and string IDs.
- **Method dispatching** uses a linear `strcmp` chain in `cbm_mcp_server_handle` to route requests to `initialize`, `ping`, `tools/list`, or `tools/call` handlers.
- **Tool execution** relies on the static `TOOLS[]` registry and `cbm_mcp_handle_tool` to dispatch to concrete implementations like `handle_search_graph`.
- **Response formatting** through `cbm_jsonrpc_format_response` ensures strict JSON-RPC 2.0 compliance with proper ID preservation and error code usage.
- **Resource management** includes idle timeout eviction to prevent memory growth during inactive periods.

## Frequently Asked Questions

### What JSON library does the MCP server use?

The MCP server uses **YYJSON**, a high-performance JSON library located in [`vendored/yyjson/yyjson.c`](https://github.com/DeusData/codebase-memory-mcp/blob/main/vendored/yyjson/yyjson.c). All parsing in `cbm_jsonrpc_parse` and response formatting in `cbm_jsonrpc_format_response` utilize this library for efficient document manipulation.

### How does the server distinguish between JSON-RPC notifications and regular calls?

The server checks for the presence of the `id` field in the request structure. Notifications lack an `id` and receive no response, while standard calls require a full JSON-RPC response with the same `id` value, as handled in the `cbm_mcp_server_handle` dispatch logic.

### What happens when the server receives an unknown method name?

When `cbm_mcp_server_handle` encounters a method not matching `initialize`, `ping`, `tools/list`, or `tools/call`, it generates a JSON-RPC error response with code `-32601` (Method not found) and preserves the original request identifier in the response.

### How does the MCP server manage memory for the SQLite cache?

The server implements an idle eviction mechanism using `STORE_IDLE_TIMEOUT_S`. After periods of inactivity detected in the main event loop, `cbm_mcp_server_evict_idle` releases the cached SQLite store, ensuring memory usage remains bounded while the server continues accepting new JSON-RPC 2.0 connections.