An MCP server works as a lightweight adapter that exposes a defined set of capabilities, typically tools, resources and prompts, to any MCP client over a standardized JSON-RPC 2.0 message format. When a client such as Claude Desktop or an internal agent starts a session, it performs a capability negotiation handshake with the server, asking what tools it offers and receiving back a list of names, descriptions and JSON Schema definitions for their inputs. From there the language model decides, based on the user's request, which tool to call; the client sends that call to the server, the server executes the underlying logic, for example querying a database or hitting an internal REST API, and returns a structured result that gets fed back into the model's context. The server itself can run locally as a subprocess communicating over stdio, or remotely as a Streamable HTTP service reachable over a network, the pattern used for shared enterprise deployments. Nanobase AI builds these servers around existing internal APIs, handling authentication, input validation and error handling so the resulting tool calls stay safe to expose to a language model in production.

The method calls behind every MCP session

Every MCP interaction reduces to a small, fixed set of JSON-RPC methods, and knowing them makes debugging a misbehaving integration far easier than treating the server as a black box.

MethodPurposeWho calls it
initializeNegotiate protocol version and capabilitiesClient, once per session
tools/listDiscover available tools and their input schemasClient, at session start or on demand
tools/callInvoke a specific tool with argumentsClient, on the model's decision
resources/list / resources/readDiscover and fetch static or semi-static contextClient
prompts/list / prompts/getFetch reusable prompt templates the server definesClient
NotificationsPush updates, such as a tool list change, without a requestServer, asynchronously

A production server only needs to implement the subset of these methods that match what it actually exposes; a server with no resources simply never receives a resources/list call, and clients handle that gracefully by capability negotiation.

Why the tool description is doing more work than the code

The tools/list response is not just documentation, it is the only information the model has when deciding whether to call a tool at all. Two badly named tools like get_data and fetch_info with vague descriptions will cause a model to guess wrong or hesitate, no matter how correct the underlying implementation is. Effective server design treats the tool name, description and parameter names as a small, deliberate interface contract, often iterated on by testing real prompts against the server rather than written once and left alone.

What happens during a tools/call

  1. The client sends the tool name and a JSON object of arguments matching the schema the server advertised.
  2. The server validates those arguments against its own schema before touching any backend system, rejecting malformed calls early rather than passing them through.
  3. The server executes the underlying operation, for example a database query or an authenticated REST call to an internal API.
  4. The server returns a result object, which can include structured content, plain text, or an error indicator.
  5. The client inserts that result back into the model's context so the model can continue the conversation with the new information.

A well-built server treats step 2 as non-negotiable: schema validation and business-rule checks belong in the server, not left to the model to get right every time.

Stateful sessions and reconnection

Unlike a single stateless REST call, an MCP session over Streamable HTTP can stay open for a sequence of exchanges, including long-running tool calls that stream partial progress back before completing. This matters for tools like a report generation job or a multi-step database export, where the client needs to show the user something is happening rather than blocking silently. Servers that support this need to think about reconnection behavior: what happens if a client drops mid-call, and whether a retried call is safe to run twice, which pushes toward designing tools to be idempotent wherever the underlying operation allows it.

Frequently asked questions

Does the server know which end user is making the call?

Only if the transport and authentication setup pass that information through. With the OAuth-based flow used for remote servers, the access token attached to the request typically identifies the acting user, and a well-built server checks that identity's permissions on every call rather than trusting the client blindly.

What happens if a tool call fails?

The server returns an error result rather than throwing an unhandled exception at the transport level. A well-designed server returns enough detail in that error for the model to explain the failure to the user or retry with corrected arguments, without leaking internal stack traces or credentials.

Can a server change its available tools mid-session?

Yes, through a notification that tells the client the tool list has changed, prompting it to call tools/list again. This is useful for servers whose available operations depend on runtime state, such as a system where certain actions only become available after a prior step completes.

How Nanobase AI helps

Nanobase AI, an NVIDIA Inception Program member, builds MCP servers with this full lifecycle in mind: strict schema validation on every tools/call, structured error handling instead of raw exceptions, and session management that survives real network conditions rather than only a local demo. For teams building their first internal server, our solutions page outlines the engineering approach, and what-is-mcp-how-to-build-an-mcp-server covers the build process end to end.

Ready to discuss your project? Contact Nanobase AI or email hello@bumu.tech.