# How the MCP JSON-RPC 2.0 Protocol Handles Tool Calling: A Complete Technical Guide

> Explore how the MCP JSON-RPC 2.0 protocol handles tool calling via the tools/call method. This guide details request parsing, dispatching, permission validation, and error handling within the DeusData codebase.

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

---

**The MCP JSON-RPC 2.0 protocol executes tool calls through the `tools/call` method, which parses requests in `cbm_jsonrpc_parse()`, dispatches them via `cbm_mcp_server_handle()` in [`src/mcp/mcp.c`](https://github.com/DeusData/codebase-memory-mcp/blob/main/src/mcp/mcp.c), validates permissions against a static `TOOLS[]` array, and returns structured responses with strict error handling.**

The DeusData/codebase-memory-mcp repository implements a memory-code-portal server that exposes graph-analysis capabilities through a JSON-RPC 2.0 interface. Understanding how the MCP JSON-RPC 2.0 protocol handles tool calling is essential for integrating with its 14 self-describing graph tools, which range from `search_graph` to `trace_path` and execute through a unified `tools/call` endpoint.

## The Three-Stage Tool Execution Flow

The `tools/call` implementation follows a strict pipeline defined in [`src/mcp/mcp.c`](https://github.com/DeusData/codebase-memory-mcp/blob/main/src/mcp/mcp.c), splitting execution into parsing, dispatch, and validation phases.

### Stage 1: Request Parsing with cbm_jsonrpc_parse()

Every tool call begins with `cbm_jsonrpc_parse()` (lines 1082‑1085), which reads the incoming line from stdin or HTTP and extracts the `jsonrpc` version, `method` name, request `id`, and raw `params` JSON string. The parser supports string-based identifiers as per RFC §4, handling both numeric and string values for the `v_id` field to ensure compatibility with diverse JSON-RPC clients.

### Stage 2: Method Dispatch in cbm_mcp_server_handle()

Inside the main server loop `cbm_mcp_server_handle`, the protocol compares the method string against known verbs. The critical branch for tool invocation appears at line 10851:

```c
else if (strcmp(req.method, "tools/call") == 0) { … }

```

This block extracts the tool name from the `params` payload and routes the request toward validation. The dispatch mechanism treats `tools/call` as a first-class RPC method while maintaining separation between transport logic and business logic.

### Stage 3: Tool Validation and Invocation

Validation occurs through multiple layers before execution:

- **Tool Discovery**: The static `TOOLS[]` array (line 47) holds every tool definition including name, title, description, and input schema.
- **Profile Checking**: `mcp_tool_allowed()` (lines 10830‑10857) verifies the requested tool is permitted for the current MCP profile (`analysis`, `scout`, or `all`).
- **Annotation Lookup**: `mcp_tool_annotations()` (lines 10888‑10895) provides behavior hints such as `readOnlyHint` or `destructiveHint`.
- **Execution**: Once validated, the server invokes concrete implementations like `cbm_search_graph()` or `cbm_trace_path()`.

Errors during any phase convert to JSON-RPC error objects via `cbm_jsonrpc_format_error()` (lines 10846‑10858).

## Tool Discovery and Schema Definition

The protocol implements self-describing APIs through unified schema definitions. Each tool advertises its `inputSchema` derived from the `tool_def_t` structure and a generic `outputSchema` defined by `MCP_TOOL_OUTPUT_SCHEMA`.

The function `mcp_add_tool_def()` (lines 10810‑10818) attaches these schemas to the tool JSON object, enabling clients to query `tools/list` and discover exact parameter requirements before invocation. For large toolsets, pagination occurs via the `MCP_TOOLS_PAGE_SIZE` constant (line 10836), with cursor logic implemented in `mcp_tools_cursor_offset()` (lines 10887‑10923) to support incremental fetching without overwhelming the transport layer.

## Profile-Based Access Control and Annotations

Security enforcement happens at the protocol layer through profile-based restrictions. The `mcp_tool_allowed()` function checks whether the current session profile permits access to the requested tool, preventing unauthorized access to destructive operations in restricted modes like `scout` or `analysis`.

Behavioral metadata comes from `mcp_tool_annotations()`, which supplies boolean hints describing tool side effects. These annotations allow clients to display warnings for destructive operations or optimize read-only queries without executing the tool.

## Strict JSON-RPC 2.0 Error Handling

The implementation adheres strictly to the JSON-RPC 2.0 specification with standardized error codes generated by `cbm_jsonrpc_format_error()`:

- **Parse error** (-32700): Returned when the request JSON is malformed or cannot be parsed.
- **Method not found** (-32601): Triggered when the method string (including misspelled tool names) does not match any registered handler.
- **Invalid params** (-32602): Raised when required fields are missing from the tool's input schema or parameter types mismatch.

This strict error taxonomy ensures predictable client behavior and simplifies debugging across different transport implementations.

## Transport-Agnostic Implementation

The core logic remains transport-neutral, functioning identically across stdio and HTTP interfaces. The HTTP server ([`src/ui/http_server.c`](https://github.com/DeusData/codebase-memory-mcp/blob/main/src/ui/http_server.c), line 1595) extracts POST request bodies and forwards them directly to `cbm_mcp_server_handle`, allowing the same `tools/call` processing pipeline to serve both local subprocesses and remote HTTP clients without code duplication.

## Practical Code Examples

Requesting the tool catalog requires no parameters:

```json
{
  "jsonrpc": "2.0",
  "id": 1,
  "method": "tools/list"
}

```

Invoking a specific tool uses the `tools/call` method with the tool name in the params:

```json
{
  "jsonrpc": "2.0",
  "id": 2,
  "method": "tools/call",
  "params": {
    "name": "search_graph",
    "project": "my-repo",
    "query": "update settings",
    "limit": 20,
    "format": "json"
  }
}

```

A minimal C client implementation:

```c
#include "mcp/mcp.h"

int main(void) {
    const char *req = "{\"jsonrpc\":\"2.0\",\"id\":42,\"method\":\"tools/call\","
                     "\"params\":{\"name\":\"search_graph\",\"project\":\"demo\","
                     "\"query\":\"cache\",\"limit\":5}}";

    cbm_mcp_server_t *srv = cbm_mcp_server_new();
    char *resp = cbm_mcp_server_handle(srv, req);
    printf("%s\n", resp);
    free(resp);
    cbm_mcp_server_free(srv);
    return 0;
}

```

## Summary

- The **MCP JSON-RPC 2.0 protocol** handles tool calling through the dedicated `tools/call` method implemented in [`src/mcp/mcp.c`](https://github.com/DeusData/codebase-memory-mcp/blob/main/src/mcp/mcp.c).
- Execution follows a **three-stage pipeline**: parsing via `cbm_jsonrpc_parse()`, dispatch through `cbm_mcp_server_handle()`, and validation using `mcp_tool_allowed()` against the static `TOOLS[]` array.
- **Self-describing schemas** enable automatic tool discovery through `tools/list`, with pagination support via `mcp_tools_cursor_offset()`.
- **Profile-based access control** restricts tool availability based on `analysis`, `scout`, or `all` profiles, supplemented by behavioral annotations from `mcp_tool_annotations()`.
- **Strict RFC-compliant error handling** returns standard JSON-RPC error codes (-32700, -32601, -32602) for parse, method, and parameter failures.
- The architecture is **transport-agnostic**, supporting both stdio and HTTP interfaces through the same core logic in `cbm_mcp_server_handle()`.

## Frequently Asked Questions

### What JSON-RPC method invokes tools in the MCP protocol?

Tools are invoked through the **`tools/call`** method. This single endpoint handles all 14 graph-analysis tools (such as `search_graph` and `trace_path`) by extracting the specific tool name from the `params` object and routing to the appropriate implementation after validation checks.

### How does the MCP server validate tool permissions before execution?

Validation occurs via **`mcp_tool_allowed()`** (lines 10830‑10857), which checks the requested tool against the current session profile. The server maintains a static `TOOLS[]` array at line 47 containing all tool definitions, and only executes tools permitted for the active profile (`analysis`, `scout`, or `all`).

### What error codes does the MCP protocol return for invalid tool calls?

The server returns standard JSON-RPC 2.0 error codes: **-32700** for parse errors (malformed JSON), **-32601** for method not found (unknown tool names), and **-32602** for invalid parameters (missing required fields or schema violations). These are generated by `cbm_jsonrpc_format_error()` at lines 10846‑10858.

### Can the MCP tool calling mechanism work over HTTP or only stdio?

The implementation is **transport-agnostic**. While designed primarily for stdin/stdout communication, the same `tools/call` logic supports HTTP transport through [`src/ui/http_server.c`](https://github.com/DeusData/codebase-memory-mcp/blob/main/src/ui/http_server.c) (line 1595), which extracts POST bodies and forwards them to `cbm_mcp_server_handle()` without modifying the core execution flow.