Volley / Templates / MCP tool call

AI agents template

MCP tool call sequence diagram

An agent connects to a remote MCP server, lists its tools and calls one when the model asks for it. Each JSON-RPC request and response is on its arrow, along with the session header the server hands out.

Sequence diagram of a Model Context Protocol tool call across User, Agent, Model and MCP Server: POST /mcp initialize with an Mcp-Session-Id in the response, notifications/initialized with 202, tools/list, the model choosing search_issues, tools/call and a text result, then the final answer.

Click any arrow in the editor to see its request and response as a table or the raw body. Change the hosts, ids and fields to match your integration, then share a link or embed it in your README.

Step by step

  1. The agent sends initialize as a JSON-RPC 2.0 POST to /mcp, with protocolVersion, its capabilities and clientInfo.
  2. The server answers with its own capabilities and an Mcp-Session-Id header. The agent sends that header and MCP-Protocol-Version on every request after this.
  3. The agent sends notifications/initialized. It is a notification with no id, so the server answers 202 with no body.
  4. The agent calls tools/list and gets each tool's name, description and inputSchema.
  5. The model picks a tool. The agent passes the user's question and the tool definitions to the model, which asks for search_issues with arguments.
  6. The agent sends tools/call, gets back content with text, and gives it to the model for the final answer.

Easy to get wrong

  • Send Accept: application/json, text/event-stream. The server may answer any request as a stream of server-sent events instead of plain JSON.
  • A tool that fails returns a normal result with isError: true, not a JSON-RPC error. Check both.
  • If the server answers 404 to a request with your Mcp-Session-Id, the session is gone. Start again with initialize.

The source

The whole diagram is this plain text. Copy it into your repo, or open it in the editor.

mcp-tool-call.volley
title: MCP tool call over Streamable HTTP
order: User, Agent, Model, MCP Server

note Agent, MCP Server: The agent is the MCP client. Every message to the server is a JSON-RPC 2.0 POST to one endpoint, here `/mcp`.

=: {fas-plug} Connecting

Agent -> MCP Server: POST /mcp (initialize)
in: Request
```http
POST /mcp HTTP/1.1
Content-Type: application/json
Accept: application/json, text/event-stream
Authorization: Bearer <redacted>

{
  "jsonrpc": "2.0",
  "id": 1,
  "method": "initialize",
  "params": {
    "protocolVersion": "2025-06-18",
    "capabilities": { "roots": { "listChanged": true } },
    "clientInfo": { "name": "example-agent", "version": "1.4.0" }
  }
}
```

MCP Server --> Agent: 200 OK
out: Response
```http
HTTP/1.1 200 OK
Content-Type: application/json
Mcp-Session-Id: 1868a90c-4f2b-4c6e-9d3a-7b5e2f8c1a04

{
  "jsonrpc": "2.0",
  "id": 1,
  "result": {
    "protocolVersion": "2025-06-18",
    "capabilities": { "tools": { "listChanged": true } },
    "serverInfo": { "name": "issue-tracker", "version": "2.1.0" }
  }
}
```
note: Send `Mcp-Session-Id` and `MCP-Protocol-Version: 2025-06-18` on every request after this one.

Agent -> MCP Server: POST /mcp (notifications/initialized)
in: Request
```http
POST /mcp HTTP/1.1
Content-Type: application/json
Accept: application/json, text/event-stream
Mcp-Session-Id: 1868a90c-4f2b-4c6e-9d3a-7b5e2f8c1a04
MCP-Protocol-Version: 2025-06-18

{ "jsonrpc": "2.0", "method": "notifications/initialized" }
```

MCP Server --> Agent: 202 Accepted
note: A notification has no `id`, so there is nothing to answer and the body is empty.

Agent -> MCP Server: POST /mcp (tools/list)
in: Request
```json
{ "jsonrpc": "2.0", "id": 2, "method": "tools/list" }
```

MCP Server --> Agent: 200 OK
out: Tools
```json
{
  "jsonrpc": "2.0",
  "id": 2,
  "result": {
    "tools": [
      {
        "name": "search_issues",
        "description": "Search issues by text and state",
        "inputSchema": {
          "type": "object",
          "properties": {
            "query": { "type": "string" },
            "state": { "type": "string", "enum": ["open", "closed"] }
          },
          "required": ["query"]
        }
      }
    ]
  }
}
```

=: {fas-robot} The model picks a tool

User -> Agent: Which open issues mention the login timeout?

Agent -> Model: The question and the tool definitions
in: Tools offered
  search_issues: Search issues by text and state

Model --> Agent: Call search_issues
out: Tool call
```json
{ "name": "search_issues", "arguments": { "query": "login timeout", "state": "open" } }
```
note: The model only asks for the call. The agent decides whether to run it, and may ask the user first.

Agent -> MCP Server: POST /mcp (tools/call)
in: Request
```json
{
  "jsonrpc": "2.0",
  "id": 3,
  "method": "tools/call",
  "params": { "name": "search_issues", "arguments": { "query": "login timeout", "state": "open" } }
}
```

MCP Server --> Agent: 200 OK
out: Result
```json
{
  "jsonrpc": "2.0",
  "id": 3,
  "result": {
    "content": [
      { "type": "text", "text": "2 open issues: #812 Login times out after 30 seconds on Safari. #837 Session timeout ignores Remember me." }
    ],
    "isError": false
  }
}
```

Agent -> Model: Tool result
Model --> Agent: Final answer
Agent --> User: Two open issues mention it: #812 and #837

Related

Make this MCP tool call diagram yours.

Open it in the editor, change it to match your integration and share the link. Free, with no account.