Skip to content

Model Context Protocol (MCP): Hosts, Clients and Servers

Why every AI app rewriting the same tools does not scale, and how MCP fixes it. Hosts, clients and servers, tools/list and tools/call, and a task server with an LLM client in Spring AI, Node.js and Python.

Builds on Introduction to AI Agents: Tools, Tool Calling and the Agent Loop

Stage 6core17 min read
Code35

These notes explain MCP in simple English, with practical examples, diagrams, code snippets, interview answers, and revision points. They follow the uploaded chapter's core concepts and terminology.

1. Why do we need MCP?

Imagine a company has a task-tracking system and wants to add AI features to five applications:

  • A customer-support chatbot
  • A Slack bot
  • An internal admin assistant
  • A code-editor plugin
  • A command-line AI assistant

All five applications need to create, list, and complete tasks.

Without MCP, each application builds its own integration with the task service.

Without MCP

Loading diagram…

Each app maintains its own integration, validation and error handling.

Suppose the task service introduces a new required field called dueDate. Every application must update its integration. If one team forgets, its integration breaks.

This is a traditional software integration problem, not a problem unique to AI.

The N × M integration problem

Assume there are:

  • N AI applications
  • M external systems

Without a shared protocol, the number of integrations can grow to N × M.

For example, five applications accessing ten systems may require:

5 × 10 = 50 integrations

With MCP, each app learns one common protocol, and each system exposes its capabilities through an MCP server.

N × M  →  N + M

In this example, that means roughly 15 integration components instead of 50, assuming one reusable connection per app and one MCP wrapper per system.

Memory trick: MCP is like USB. Instead of building a different connector for every device, you use a common standard.

2. What is MCP?

Model Context Protocol (MCP) is a standard protocol that allows AI applications to discover and use external tools and data through a common interface.

An AI application can use MCP to connect to systems such as:

  • GitHub
  • Jira
  • Slack
  • Task-management services
  • Databases
  • File systems
  • Calendar APIs
  • Internal company services

MCP does not create these capabilities. It standardizes how AI applications discover and access them.

MCP uses JSON-RPC

MCP messages use JSON-RPC 2.0, a format for sending requests and receiving results between programs.

A simplified request looks like this:

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

Meaning:

  • jsonrpc: the protocol format version
  • id: identifies the request so the response can be matched
  • method: the operation being requested
  • params: optional input arguments for the method

The server responds with the same request ID and either a result or an error.

3. The three main components of MCP

This is the most important concept in the chapter.

1. Host: the AI application

Examples: an AI assistant, a code editor with AI, or your own Spring AI application.

The host manages the model, conversation, permissions and approval rules.

2. MCP Client: the connector

It communicates with one MCP server, discovers available tools and sends tool-call requests.

3. MCP Server: the capability provider

It exposes tools and potentially resources and prompts. It runs ordinary code to perform the requested operation.

Example: the server calls an existing task service or database.

3.1 Host

The host is the application that the user interacts with.

Responsibilities:

  • Receives the user's message.
  • Sends the message and available tool definitions to the LLM.
  • Receives the model's proposed tool call.
  • Checks permissions and whether approval is needed.
  • Tells the MCP client to execute allowed calls.
  • Returns results to the model and eventually responds to the user.

Important: The model can request a tool, but the host decides whether the tool is allowed to run.

3.2 MCP client

The MCP client is a component inside the host.

Responsibilities:

  • Connects to an MCP server.
  • Discovers tools using tools/list.
  • Sends tool requests using tools/call.
  • Receives tool results.
  • Handles protocol communication.

A host connected to three MCP servers generally maintains three client connections, one per server.

Analogy: If the host is your Java application and an MCP server is a database, the MCP client plays a role similar to a database driver.

3.3 MCP server

The MCP server exposes capabilities through MCP.

For example, a task server may provide:

create_task(title)
list_tasks()
complete_task(title)

Internally, these tools can call existing business logic, REST APIs, databases, files or message queues.

The server controls which capabilities it exposes. A database MCP server could provide a read-only query tool without exposing a destructive operation such as dropping a table.

3.4 Does an MCP server need an LLM?

No. An MCP server does not need an LLM or an AI API key.

It can be an ordinary Spring Boot, Node.js or Python application. The model normally lives in the host; the server simply executes the requested business logic.

4. Tool calling vs MCP

These two concepts work together, but they solve different problems.

ConceptMain questionResponsibility
Tool callingWhich tool should run, and with what arguments?The model proposes the call
MCPWhere do the tools come from, and how does the app reach them?The protocol standardizes discovery and execution

Consider the request:

"Remind me to renew my car insurance."

The model may choose:

{
  "name": "create_task",
  "arguments": {
    "title": "Renew car insurance"
  }
}

Tool calling determines that create_task is appropriate and supplies its arguments.

MCP allows the host to send that request to the remote task server through tools/call.

Interview-ready answer: Tool calling decides which capability to use. MCP provides a standard way to discover and access that capability. MCP does not replace tool calling.

5. How does MCP work end to end?

Let's follow the complete request:

User: "Remind me to renew my car insurance."

  1. Discover tools: The MCP client asks the task server for its available tools using tools/list.
  2. Send tools to the model: The host converts the tool definitions into the format expected by its model API.
  3. Choose a tool: The LLM selects create_task and supplies the title argument.
  4. Check permissions: The host checks whether the requested operation is allowed and whether approval is required.
  5. Execute the tool: The MCP client sends tools/call to the task server.
  6. Run business logic: The server validates the title and creates the task.
  7. Return the result: The result returns to the host, which provides it to the LLM.
  8. Respond to the user: The model generates a natural-language response.
Loading diagram…

The tool discovery step generally happens at connection or startup and can be cached. It does not have to happen before every user message.

A critical distinction

  • The LLM does not directly connect to the MCP server.
  • The MCP server does not need to know which LLM selected the tool.
  • The host coordinates the interaction.
  • The server executes code; the model interprets the result.

6. tools/list: Discovering tools

tools/list asks an MCP server which tools it offers.

Example request:

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

A simplified response:

{
  "jsonrpc": "2.0",
  "id": 1,
  "result": {
    "tools": [
      {
        "name": "create_task",
        "description": "Create a pending task.",
        "inputSchema": {
          "type": "object",
          "properties": {
            "title": {
              "type": "string",
              "minLength": 1,
              "maxLength": 120
            }
          },
          "required": ["title"]
        }
      }
    ]
  }
}

Each tool definition contains three key parts:

  1. Name: The identifier used to call the tool.
  2. Description: What the tool does and when it should be used.
  3. Input schema: The structure and constraints of its arguments.

The host learns these definitions dynamically rather than having to hardcode every tool.

Why do tool descriptions matter?

Suppose a model needs to complete a task but does not know its exact title.

A good description might say:

"Call list_tasks first if you are unsure of the exact task title."

The model can then list the tasks before attempting to complete one.

Treat tool descriptions like public API documentation: unclear descriptions can cause incorrect tool selection.

7. Schemas: a contract between programs

A tool's input schema defines the arguments the tool expects.

For example:

{
  "type": "object",
  "properties": {
    "title": {
      "type": "string",
      "minLength": 1,
      "maxLength": 120
    }
  },
  "required": ["title"]
}

This describes the expected structure, but it does not guarantee that a task title is unique or that the user has permission to create a task.

The server must still validate business rules.

This is similar to structured output from an LLM:

  • Structured output schema: Defines the shape of the model's response.
  • Tool input schema: Defines the shape of the model's tool arguments.
  • Business validation: Checks whether the requested action is actually valid.

8. tools/call: Executing a tool

After the model selects a tool, the host instructs the MCP client to call it.

Example request:

{
  "jsonrpc": "2.0",
  "id": 2,
  "method": "tools/call",
  "params": {
    "name": "create_task",
    "arguments": {
      "title": "Renew car insurance"
    }
  }
}

A simplified response:

{
  "jsonrpc": "2.0",
  "id": 2,
  "result": {
    "content": [
      {
        "type": "text",
        "text": "Task created: Renew car insurance"
      }
    ],
    "isError": false
  }
}

The response contains content blocks, such as text, and an isError flag indicating whether the tool reported an execution error.

The client converts the returned content into tool output for the host and model.

9. Handling errors and retries

MCP distinguishes between two kinds of failure.

A. Tool execution error

The server ran the tool, but the operation could not be completed.

Example: the user asks to complete a task named Car Insurance, but the actual title is Renew car insurance.

The server returns a tool result with isError: true and a useful message. The model may then call list_tasks and retry with the correct title.

B. Protocol or transport error

The request could not be handled properly, such as when the server is unavailable, the request names an unknown tool, or a call times out.

The host or client must handle this failure, log it and decide what to communicate to the user.

Why blind retries are dangerous

Imagine a payment tool times out. The payment might have succeeded even though the client never received the response.

Retrying without protection could charge the customer twice.

Use an idempotency key: a unique identifier that lets the server recognize repeated requests and avoid repeating the same side effect.

For task creation, the example server also rejects duplicate pending titles, which helps make a retry safe for that specific operation. This is not a general replacement for idempotency keys.

10. MCP transports: stdio vs Streamable HTTP

A transport determines how MCP messages travel between the client and server.

FeaturestdioStreamable HTTP
ConnectionHost starts a child processServer runs on a port
Typical useLocal editor tools and file accessShared or deployed services
Network accessNormally local to the host processAccessible to clients that can reach the URL
AuthenticationOften not needed for a trusted local process, but permissions still matterRequired for shared or remotely reachable services
Main concernServer output must not corrupt the protocol streamAuthentication, network security and local-host protections

stdio example

An AI code editor starts an MCP server as a local process. The client writes requests to the process's standard input and reads responses from standard output.

Be careful: a local MCP server may run with your user permissions, potentially allowing access to local files or credentials.

Streamable HTTP example

Your Spring Boot task server listens at an endpoint such as:

http://localhost:8081/mcp

The host sends MCP requests over HTTP.

For production, the server needs appropriate authentication, authorization, secure deployment and network protections.

11. MCP and REST API: Do they replace each other?

No. MCP and REST solve different integration needs and can work together.

Loading diagram…

A web frontend or mobile app can continue using the same REST API directly.

REST APIMCP server
Exposes HTTP endpointsExposes capabilities through MCP
Commonly used by application codeDesigned for AI applications and their hosts
Often documents endpoints with OpenAPIProvides tool discovery through tools/list
May expose lower-level operationsCan expose higher-level actions with model-oriented descriptions

An MCP server can act as an AI-friendly layer over an existing REST API. You do not need to rewrite the business logic.

12. Tools, resources and prompts

MCP can expose more than executable tools.

CapabilityPurposeExample
ToolsPerform actionscreate_task, complete_task
ResourcesProvide information or contextA policy document or project README
PromptsProvide reusable instructions or workflowsA template for planning the day

A useful way to remember this:

  • Tools: Do something.
  • Resources: Provide something to know or read.
  • Prompts: Provide reusable instructions.

These are distinct concepts. A resource is not the same as RAG (Retrieval-Augmented Generation). A resource can be fetched by its address, while RAG typically retrieves relevant chunks from a larger collection. An MCP tool can itself run a RAG pipeline.

13. Security: the host is still responsible

MCP standardizes communication. It does not automatically make a tool safe.

The host should enforce security rules before allowing tool execution.

Important security practices

  1. Allow-list tools. Expose only the tools the application needs.
  2. Require approval for risky actions. For example, deleting a repository, sending an email or making a payment.
  3. Authenticate shared servers. Use appropriate credentials and per-user authorization.
  4. Use least privilege. A server should receive only the permissions required for its work.
  5. Treat tool output as untrusted data. A tool result might contain prompt-injection text instructing the model to ignore its rules.
  6. Review changes to tool definitions. A server could introduce a new destructive tool or change an existing tool's behavior.
  7. Protect local servers. Bind them to loopback when they are meant to be local and apply the relevant host-header protections.

Example: a destructive tool

Suppose an MCP server offers:

delete_repository(repositoryName)

Even if the model requests this tool, the host should check its policy and potentially require user confirmation before sending tools/call.

The model's choice is a request, not authorization.

14. Performance and production considerations

MCP adds a connection layer, so it comes with operational costs.

14.1 Cache the tool list

The server's available tools do not usually change with every user message.

A host can cache tools/list and refresh it periodically or when the server signals that the list changed.

Benefits:

  • Fewer discovery round trips
  • Lower latency
  • Reduced overhead

But caching has a trade-off: newly added tools might not appear until the cache refreshes.

14.2 Avoid exposing every tool

Every tool definition sent to the model consumes input tokens. Too many tools can increase costs and make it harder for the model to choose the correct one.

Expose the tools relevant to the host's task instead of blindly passing through every capability from every server.

14.3 Handle name collisions

Two connected servers might both offer a tool called search.

The host needs a naming strategy, such as server prefixes, so it can identify the correct tool.

14.4 Use timeouts and step limits

A slow tool can delay the entire response. Configure sensible timeouts and stop the model-tool loop after a maximum number of steps to prevent runaway loops.

14.5 Treat tool definitions as a public API

Changing a tool name or making an optional field required may break clients.

Prefer backward-compatible changes: introduce the new interface, migrate clients and remove the old interface only when it is safe.

15. Building an MCP task assistant with Spring Boot

The chapter's example has two applications:

Task client: port 8080

  • Receives the user's request.
  • Calls the LLM.
  • Uses an MCP client to discover and call remote tools.
  • Returns the final answer.

Task server: port 8081

  • Exposes create_task, list_tasks and complete_task.
  • Validates inputs.
  • Runs the task store's business logic.
  • Does not need an LLM.

The example exposes these client endpoints:

EndpointPurpose
POST /api/askAccepts a message and runs the assistant loop
GET /api/toolsReturns the discovered tool list without making a model call

The chapter specifies a 400 response for invalid messages, such as an empty message or one exceeding the configured length, and a 502 when the model or task server fails. These are behaviors of the example application, not universal MCP status-code requirements.

15.1 Defining a tool in Spring AI

The example uses annotations to expose Java methods as MCP tools:

@McpTool(
    name = "create_task",
    description = "Add a new pending task. Titles must be unique among pending tasks."
)
public String createTask(
    @McpToolParam(
        description = "Short title of the new task",
        required = true
    ) String title
) {
    return "Task created: " + store.create(title);
}

Conceptually:

  • @McpTool exposes the method as a tool.
  • name identifies the tool.
  • description helps the model understand when to use it.
  • @McpToolParam describes the argument.
  • The method calls ordinary business logic in store.create(title).

The Spring AI MCP server integration uses method signatures and annotations to construct the tool definition.

15.2 Configuring the MCP client

The example configures a Streamable HTTP connection in YAML:

spring:
  ai:
    mcp:
      client:
        request-timeout: 20s
        streamable-http:
          connections:
            task-server:
              url: ${TASK_SERVER_URL:http://localhost:8081}
              endpoint: /mcp
        toolcallback:
          enabled: true

This tells the client where the MCP server is and configures the tool-callback integration. The starter handles the protocol details, including discovery and remote calls.

15.3 Connecting remote tools to the LLM

The key idea in the example is that the model receives callbacks created from remote MCP tool definitions.

public TaskAssistant(
    ChatClient.Builder builder,
    ToolCallbackProvider mcpTools
) {
    this.chatClient = builder
        .defaultSystem(SYSTEM_PROMPT)
        .build();

    this.mcpTools = mcpTools;
}

public String reply(String message) {
    String reply = chatClient.prompt()
        .user(message)
        .toolCallbacks(mcpTools.getToolCallbacks())
        .call()
        .content();

    if (reply == null || reply.isBlank()) {
        throw new IllegalStateException(
            "The model returned an empty reply"
        );
    }

    return reply;
}

The important line is:

.toolCallbacks(mcpTools.getToolCallbacks())

The model can use the discovered remote tools without the client application hardcoding each tool's definition.

Remember: The business logic belongs to the server. The host owns the model and the decision loop. The MCP client connects the two.

16. When should you use MCP?

Use MCP when:

  • Multiple AI applications need the same tools.
  • You want your service to be usable by AI hosts you do not control.
  • You want a standard way to discover and invoke external capabilities.

Avoid adding MCP when:

  • Only one application needs a few local tools.
  • The workflow is a fixed pipeline and the model does not choose tools.
  • An extra network hop would violate a strict latency requirement.
  • Several operations must succeed or fail as one atomic transaction.
  • You cannot secure the MCP server properly.

For a single application with a few tools, local functions are often simpler. For multiple AI clients sharing many capabilities, MCP can reduce duplicated integration work.

17. Quick revision notes

TermMeaning
MCPA standard protocol for discovering and accessing external capabilities.
HostThe AI app that owns the model, conversation and permission decisions.
MCP clientThe component that communicates with one MCP server.
MCP serverA program that exposes tools and other capabilities.
tools/listDiscovers tool names, descriptions and input schemas.
tools/callRequests execution of a named tool with arguments.
Tool callingThe model proposes which tool to use and supplies its arguments.
stdioA local process communication transport.
Streamable HTTPA network transport for communicating with an MCP server over HTTP.
Idempotency keyA unique request identifier that helps prevent duplicate side effects on retries.

The entire chapter in three lines

  1. Tool calling: The model chooses a capability and proposes its arguments.
  2. MCP: The host discovers and accesses capabilities through a common protocol.
  3. Security: The host still decides what is allowed; the server validates and executes the operation.

18. Interview questions and answers

"What problem does MCP solve?"

MCP reduces duplicated integrations between AI applications and external systems. Each app can use a common protocol, while each system exposes its capabilities through an MCP server.

"What is the difference between an MCP host, client and server?"

The host manages the model and permissions. The client handles MCP communication with a server. The server exposes tools and runs their business logic.

"Does an MCP server require an LLM?"

No. It can be an ordinary application that exposes functions and executes them. The LLM generally lives in the host.

"Explain tools/list and tools/call."

tools/list discovers the available tools and their schemas. tools/call requests execution of a particular tool with its arguments.

"How is MCP different from tool calling?"

Tool calling determines which tool the model wants to use. MCP provides the standardized mechanism for discovering and reaching the tool.

"How does MCP work with REST APIs?"

An MCP server can wrap an existing REST API and expose AI-friendly tools. Other applications can continue using the REST API directly.

"How should tool errors be handled?"

Return a clear tool error so the model can potentially recover. Protocol or transport errors must be handled by the client or host. Retry operations with side effects carefully, using idempotency where appropriate.

"How do you secure MCP?"

Authenticate shared servers, enforce per-user permissions, allow-list tools, require approval for risky actions and treat tool output as untrusted data.

"When would you not use MCP?"

When one application uses a few local tools, the workflow is fixed, latency is extremely tight, operations require a single atomic transaction, or the server cannot be secured.

19. Self-test

Check your understanding

  1. Which component decides whether a requested tool is allowed to execute?
    • The MCP server only
    • The host
    • The model alone
    • The JSON-RPC transport
  2. Which method discovers available tools?
    • tools/call
    • server/execute
    • tools/list
    • resources/read
  3. Does an MCP server need an LLM?
    • Always
    • Only with HTTP
    • No
    • Only in Spring Boot
  4. What does tool calling do?
    • Authenticates the MCP server
    • Chooses a tool and its arguments
    • Replaces REST APIs
    • Creates the transport
  5. Why can blind retries be dangerous for a payment tool?
    • They change the schema
    • They can repeat a successful charge
    • They disable discovery
    • They always cause JSON-RPC errors
  6. Which transport is commonly suited to a local editor plugin?
    • stdio
    • SMTP
    • SQL
    • GraphQL

Suggested revision order: First understand the three roles, then the difference between tool calling and MCP, then tools/list and tools/call, followed by security, transports and the Spring Boot example.

In this topic

Done with this topic?

How well do you know it?

PreviousStructured Output: Typed JSON From an LLM
Practise 17 questions