Understanding the True Nature of MCP: From the Agent Loop of Tool Use to Two-Layer Error Handling in JSON-RPC 2.0

Understanding the True Nature of MCP: From the Agent Loop of Tool Use to Two-Layer Error Handling in JSON-RPC 2.0

Starting from Claude API's Tool Use, we explore the true nature of MCP. We explain in a chain of connected questions: how LLMs are unaware of MCP's existence, how client applications handle the routing, and the mechanism of two-layer error handling via JSON-RPC 2.0.
2026.07.10

This page has been translated by machine translation. View original

Introduction

While implementing an agent using Tool Use with the Claude API, a question suddenly came to mind.

"What exactly is MCP (Model Context Protocol)? What's the difference from Tool Use?"

As I researched, I arrived at the fact that LLMs don't even know MCP exists, and from there, a chain of questions resolved themselves — the architectural philosophy of MCP, and further, the mechanism of JSON-RPC 2.0 which serves as its communication foundation.

This article shares that journey of exploration.

The Correct Message Structure for the Tool Use Agent Loop

Starting with the basics. When implementing an agent with tool use enabled via the Claude API, you need to understand the correct design of the agent loop.

The Loop Flow

When Claude returns stop_reason: "tool_use", the developer needs to execute the tool locally and return the result to the API. The rules to follow are clear.

Send the entire conversation history including the immediately preceding assistant message, along with a new user message containing a tool_result content block with the corresponding tool_use_id.

cb4027ca-5b75-4d30-a41b-59fdb08ba4b0

{
  "messages": [
    {
      "role": "user",
      "content": "Check the current weather in Tokyo."
    },
    {
      "role": "assistant",
      "content": [
        {
          "type": "tool_use",
          "id": "toolu_xyz123",
          "name": "get_weather",
          "input": { "city": "Tokyo" }
        }
      ]
    },
    {
      "role": "user",
      "content": [
        {
          "type": "tool_result",
          "tool_use_id": "toolu_xyz123",
          "content": "Sunny, temperature 22 degrees"
        }
      ]
    }
  ]
}

Why the user Role?

You might wonder, "The assistant called the tool, so why is the result returned as user?"

In the Claude API, role represents the direction data flows.

Role Meaning
assistant Data coming from the model (including tool call instructions)
user Data being sent to the model (including tool execution results)

The application code acts as the user's "proxy (agent)", playing the role of conveying facts obtained from the external world to the model.

852c765b-8439-4d4a-a963-6eddfa5583cb

Handling Errors

Even when tool execution fails due to a timeout or similar issue, sending the tool_result cannot be omitted. Omitting it results in an API error (400 Bad Request). On error, set is_error: true and describe the error details in content.

{
  "type": "tool_result",
  "tool_use_id": "toolu_01A2B3C4D5",
  "content": "Error: The external API request timed out after 10 seconds.",
  "is_error": true
}

This allows Claude to recognize the fact of the error and autonomously decide how to explain it to the user or whether to retry.

MCP Does Not Exist for the LLM

Here is the main topic. The Tool Use rules described above are exactly the same even when using MCP.

That's because Claude has absolutely no knowledge of MCP's existence.

The Client App as "Illusionist"

In MCP's architecture, a client app (Claude Desktop, Claude Code, a custom agent, etc.) stands in the middle and performs the following processing.

Phase 1: Consolidating the Tool List

The client app queries the connected MCP servers asking "what tools do you have?", then collects the retrieved tool definitions into a standard tools array and sends it to the Claude API.

"tools": [
  { "name": "github_create_issue", "description": "..." },
  { "name": "postgres_query", "description": "..." },
  { "name": "slack_post_message", "description": "..." }
]

As far as Claude is concerned, there is no way to distinguish whether these came from MCP servers or were locally written functions.

Phase 2: Claude Simply Calls Standard Tool Use

{
  "type": "tool_use",
  "name": "postgres_query",
  "input": { "query": "SELECT * FROM users WHERE active = true" }
}

Claude doesn't know "how it will be executed". It simply outputs structured JSON intent and stops.

Phase 3: The Client App Determines Routing

The client app looks at the name in tool_use and decides.

  • If it's a local function → execute directly
  • If it's an MCP server tool → forward to the relevant server via JSON-RPC

Phase 4: Return the Result with tool_result

The result received from the MCP server is wrapped in a standard tool_result message block and returned to Claude.

mcp-tool-use-json-rpc-architecture-deep-dive-mcp-architecture

MCP = HTTP for the AI Era, Microservices for LLMs

So if the LLM doesn't know about MCP, why did Anthropic create MCP?

The answer is decoupling. Just as HTTP separates web browsers from web servers, MCP separates AI clients from tools and data sources.

Structural Similarity to HTTP

Perspective HTTP MCP
What doesn't the client need to know? Server implementation language, DB type Tool implementation language, authentication flow
What doesn't the server need to know? Client's OS, device Which LLM is calling
Common contract HTTP methods, status codes JSON-RPC 2.0, three primitives

The Microservices Analogy

In traditional system design, a large application is split into microservices (authentication service, payment service, shipping service, etc.), and the main app uses the necessary features via network calls.

MCP is doing exactly the same thing in the world of AI. The only difference is that the "boss" calling the services is not a hardcoded application but an LLM.

MCP is similar to microservices. If microservices are for applications, MCP is for LLMs.

6652d830-f78c-4aa3-a591-183a917aa141

The Problem Before MCP

In the days before MCP, if five different AI coding assistants (Cursor, Claude Desktop, Continue.dev, Aider, an in-house agent, etc.) each wanted to implement GitHub integration, each one had to reinvent the same wheel five times. And each implementation was incompatible with the others.

With MCP, if one developer creates an excellent GitHub MCP server, all AI client apps can immediately use it.

The Reality of the Ecosystem

However, MCP cannot prevent "100 developers creating 100 MCP servers for the same app". It's the same as having 50 packages on npm for string padding.

What matters is that where effort is directed has changed. Instead of "each app developer rewriting the same basic tools privately", it has become "the community competing to create the best public MCP servers".

JSON-RPC 2.0: Schema Enforcement for Communication Protocols

What underpins MCP's communication foundation is JSON-RPC 2.0.

The Difference Between JSON and JSON-RPC 2.0

JSON is a data format; JSON-RPC 2.0 is a strict contract. If JSON is an "alphabet", JSON-RPC 2.0 is like a "legal contract" written in that alphabet.

JSON only defines syntax; there are no rules about meaning.

{ "coffee": "iced", "temperature": 2, "is_good": true }

JSON-RPC 2.0, on the other hand, enforces a strict structure for remote procedure calls (RPC).

The Request Contract

{
  "jsonrpc": "2.0",
  "method": "tools/call",
  "params": { "name": "fetch_file", "path": "./src/main.ts" },
  "id": "request-abc-123"
}

Three required keys: jsonrpc (version), method (function name to execute), id (request identifier). params (arguments) is optional, but is typically included in MCP.

The Response Contract

{
  "jsonrpc": "2.0",
  "result": { "content": "console.log('hello world');" },
  "id": "request-abc-123"
}

The Error Contract

{
  "jsonrpc": "2.0",
  "error": { "code": -32602, "message": "File not found at specified path" },
  "id": "request-abc-123"
}

Automatic Rejection of Schema Violations

JSON-RPC 2.0 automatically detects and rejects schema violations.

Type of Violation Error Code Condition
Parse error -32700 JSON syntax error (missing closing bracket, etc.)
Invalid Request -32600 Missing required key (jsonrpc or method absent)
Method not found -32601 Calling a non-existent method
Invalid params -32602 Parameter type or structure is invalid

Why It Matters for LLMs

Because LLMs dynamically generate tool parameters, tool name hallucinations or missing parameters can occur. With JSON-RPC 2.0's schema enforcement, MCP servers don't crash and return standardized error codes. The client app feeds those errors back to Claude, and Claude self-corrects and re-requests — creating a robust loop.

The Two-Layer Structure of HTTP Status Codes and JSON-RPC Error Codes

JSON-RPC 2.0 coexists with HTTP status codes (400, 500, etc.) rather than replacing them.

The Two-Layer Security Model

An armored truck analogy makes this easy to understand.

  • HTTP status codes → Manage the truck itself (did delivery physically succeed?)
  • JSON-RPC error codes → Manage the safe inside the truck (did the contents pass inspection?)

dcfe0a98-c739-4469-b7c8-749e0eb6c666

Pattern 1: Network Success + Tool Execution Success

HTTP/1.1 200 OK

{
  "jsonrpc": "2.0",
  "result": { "status": "Slack message sent successfully!" },
  "id": "mcp-msg-99"
}

Pattern 2: Network Success + Tool Execution Failure

HTTP returns 200 OK, yet internally it's an error. This is the case where network delivery succeeded, but the contents failed inspection.

HTTP/1.1 200 OK

{
  "jsonrpc": "2.0",
  "error": { "code": -32602, "message": "Invalid params: 'path' must be an absolute string." },
  "id": "claude-bad-request-1"
}

Pattern 3: Network Itself Fails

When the MCP server crashes, it can't even return a JSON-RPC response.

HTTP/1.1 504 Gateway Timeout

mcp-tool-use-json-rpc-architecture-deep-dive-dual-layer-error

Layer What It Means Example
HTTP (4xx, 5xx) The pipe is broken Server unreachable, timeout
JSON-RPC (-32xxx) The pipe is fine, but the data sent failed inspection Method absent, invalid parameters

Summary

Here is a summary of the understanding gained through this exploration.

Concept Essence
Tool Use agent loop A strict alternating pattern of assistant: tool_useuser: tool_result. Complete preservation of conversation history is mandatory
The relationship between MCP and LLMs The LLM doesn't know about MCP. The client app decides the routing
The value of MCP HTTP for the AI era. A decoupling standard regardless of platform or language
JSON-RPC 2.0 A schema enforcement layer for communication protocols. Coexists on a separate layer from HTTP status codes

As a practical judgment criterion, thinking of MCP as "microservices for LLMs" is the most useful framing. If traditional microservices are for applications, MCP is for LLMs. JSON-RPC 2.0 as a contract is layered on top of HTTP, composed of three primitives (Prompts, Resources, Tools). With this understanding, you should rarely find yourself lost when making MCP design decisions.


Claudeならクラスメソッドにお任せください

クラスメソッドは、Anthropic社とリセラー契約を締結しています。各種製品ガイドから、業種別の活用法、フェーズごとのお悩み解決などサービス支援ページにまとめております。まずはご覧いただき、お気軽にご相談ください。

サービス詳細を見る

Share this article