How the MCP Server Handles JSON-RPC 2.0 Requests and Tool Dispatching in codebase-memory-mcp
The MCP server uses a single-threaded event loop with YYJSON parsing and a strcmp-based method dispatcher in 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, 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, 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:
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 (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 (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. 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:
{
"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:
{
"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, 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_errorwhencbm_jsonrpc_parsefails to decode the request. - Method not found (-32601): Generated in the final
elsebranch ofcbm_mcp_server_handlewhen 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:
{
"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_parseinsrc/mcp/mcp.c, which validates JSON-RPC 2.0 structure using YYJSON and handles both numeric and string IDs. - Method dispatching uses a linear
strcmpchain incbm_mcp_server_handleto route requests toinitialize,ping,tools/list, ortools/callhandlers. - Tool execution relies on the static
TOOLS[]registry andcbm_mcp_handle_toolto dispatch to concrete implementations likehandle_search_graph. - Response formatting through
cbm_jsonrpc_format_responseensures 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. 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.
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:
curl -s "https://instagit.com/install.md" Maintain an open-source project? Get it listed too →