ScreenshotNeo

BlogAI agents

MCP Client vs. MCP Server With Example

An MCP client connects and requests capabilities; an MCP server exposes tools, resources, and prompts. See the complete request flow and TypeScript example.

By the ScreenshotNeo team1 October 20267 min read

Short answer: an MCP client connects to an MCP server and sends protocol requests. The MCP server advertises capabilities and handles those requests. An AI host usually contains the client connection, while the server provides tools, resources, and prompts.

Think of the client as the connector and requester, and the server as the capability provider. The roles stay the same whether the connection uses local stdio or remote Streamable HTTP.

What is an MCP client?

An MCP client is the protocol component that opens a connection to a server, performs the initialization handshake, discovers available capabilities, and invokes them. An AI application such as a desktop assistant, coding agent, or chat product commonly acts as the host; the host creates or contains one MCP client for each server connection.

Typical client operations include:

  • Connect and negotiate protocol capabilities.
  • List tools, resources, and prompts.
  • Call a tool with structured arguments.
  • List and read resources.
  • Retrieve a prompt template.
  • Handle server notifications and errors.

What is an MCP server?

An MCP server is a process or service that exposes capabilities through MCP. It registers tools, resources, and prompts, validates incoming arguments, runs the underlying operation, and returns structured results.

The official server documentation describes servers as exposing tools, resources, and prompts. See the MCP server specification and the TypeScript SDK v2 overview.

MCP client vs. MCP server

Aspect MCP client MCP server
Main responsibility Connects and sends protocol requests Advertises and implements capabilities
Typical operations List and call tools; list and read resources; get prompts Register capabilities and handle requests
Example Calls lookup-order with an order ID Implements lookup-order and returns order data
Where it runs Usually inside an AI host application A local process or remote service providing access to data and actions

Host, client, and server: the terms that get mixed up

The host is the application context, such as an AI assistant. The host usually creates an MCP client, and that client maintains the protocol connection to an MCP server. Calling the host “the client” can be convenient in casual conversation, but it hides the implementation boundary.

For MCP Apps, the host can also load an embedded view. The host keeps its protocol connection to the server and communicates separately with that view. The view is not the MCP client connection; see the MCP Apps architecture overview.

The three MCP capability types

Tools

Tools are executable functions. The model can ask the client to call a server tool with JSON arguments. Examples include looking up an order, exporting records, or taking a screenshot.

Resources

Resources provide contextual data identified by a URI such as orders://recent. The client lists or reads a resource and supplies the returned content to the host or model according to the host’s policy.

Prompts

Prompts are user-controlled templates exposed by the server. A client can retrieve a prompt and its arguments, then present or use the resulting messages.

These capability categories and their control boundaries are described in the server specification.

Complete orders example: server and client flow

The official SDK example uses an illustrative order service. The server exposes tools including lookup-order, order-total, and export-orders, an orders://recent resource, and a prompt. The client discovers the tools, calls lookup-order with { id: "A-1041" }, and receives A-1041: 3 items, shipped. The resource example contains A-1041 and A-1042. These values are documentation examples, not a live order system.

Server (TypeScript SDK v2 pattern)

import { McpServer } from "@modelcontextprotocol/server";
import { StdioServerTransport } from "@modelcontextprotocol/server/stdio";
import { z } from "zod";

const server = new McpServer({ name: "orders", version: "1.0.0" });

server.tool(
  "lookup-order",
  "Look up one order by ID",
  { id: z.string().min(1) },
  async ({ id }) => {
    const orders: Record<string, string> = {
      "A-1041": "A-1041: 3 items, shipped",
      "A-1042": "A-1042: 1 item, processing"
    };
    const result = orders[id] ?? `No order found for ${id}`;
    return { content: [{ type: "text", text: result }] };
  }
);

server.resource("recent-orders", "orders://recent", async () => ({
  contents: [{
    uri: "orders://recent",
    mimeType: "text/plain",
    text: "A-1041\\nA-1042"
  }]
}));

const transport = new StdioServerTransport();
await server.connect(transport);

Install the package versions that match the SDK v2 documentation. The v2 documentation identifies @modelcontextprotocol/server as the server package. Do not mix v1 imports from the older monolithic @modelcontextprotocol/sdk package with v2 instructions.

Client (TypeScript SDK v2 pattern)

import { Client } from "@modelcontextprotocol/client";
import { StdioClientTransport } from "@modelcontextprotocol/client/stdio";

const client = new Client({ name: "orders-host", version: "1.0.0" });
const transport = new StdioClientTransport({
  command: "node",
  args: ["dist/orders-server.js"]
});

await client.connect(transport);

const tools = await client.listTools();
console.log("Tools:", tools.tools.map((tool) => tool.name));

const order = await client.callTool({
  name: "lookup-order",
  arguments: { id: "A-1041" }
});
console.log(order);

const recent = await client.readResource({ uri: "orders://recent" });
console.log(recent);

Method names and import paths can change between SDK lines. Pin one SDK version, follow its matching client guide, and verify the current package exports before publishing production code. The SDK’s client operations example is at Calling tools and reading resources.

What happens during a request?

  1. Start: the host starts a local server process or opens a remote connection.
  2. Initialize: client and server negotiate protocol and implementation information.
  3. Discover: the client lists tools, resources, or prompts.
  4. Request: the host asks the client to call a tool or read a resource.
  5. Handle: the server validates input and executes its handler.
  6. Return: the server sends structured content or an MCP error.
  7. Present: the host decides how to show the result to the user or model.

Transport: stdio vs. Streamable HTTP

Transport Best fit Operational notes
stdio Local integrations where the host starts the server process Simple process boundaries; keep stdout reserved for protocol messages and send logs to stderr
Streamable HTTP Remote or shared servers Use normal HTTP deployment controls, authentication, timeouts, and observability
HTTP plus SSE Backward-compatible deployments Supported in older documentation; confirm compatibility before selecting it

Transport changes how bytes move; it does not change which side is the client or which side provides capabilities. The v1 SDK overview discusses stdio, Streamable HTTP, and HTTP plus SSE compatibility.

Common implementation mistakes

  • Calling the AI model the server: the model may choose a tool, but the MCP server implements it.
  • Putting business logic in the client: keep capability implementation and authorization on the server side.
  • Mixing SDK generations: v1 and v2 package names and APIs differ.
  • Writing logs to stdout over stdio: protocol parsers can fail; write diagnostics to stderr.
  • Skipping input validation: validate tool arguments with a schema before performing side effects.
  • Returning unbounded data: paginate or limit resource results to protect context windows and memory.
  • Assuming discovery grants permission: listing a tool does not authorize every user or argument; enforce authorization when handling calls.

Troubleshooting MCP connections

Symptom Likely cause Fix
Server starts, then client disconnects Process exited or wrote non-protocol text to stdout Check the exit code, send logs to stderr, and run the server command directly.
No tools appear Tool registration did not run or the client is connected to another server Log registration during startup, confirm the command/path, then call listTools.
Invalid arguments Client omitted a required field or used the wrong type Inspect the advertised input schema and send JSON matching it.
Resource URI not found URI mismatch or resource handler not registered List resources and copy the exact URI, including casing and encoding.
Remote requests time out Network, proxy, server overload, or a handler waiting on an external API Set bounded timeouts, add cancellation, inspect server logs, and retry only idempotent operations.
Works on v1, fails on v2 Mixed package or import instructions Choose one SDK line and use its matching install, imports, and examples.

Reliability, security, and performance checklist

  • Use least-privilege credentials for every server.
  • Authenticate remote clients and authorize each tool call.
  • Validate and constrain URLs, file paths, SQL, and shell arguments exposed through tools.
  • Apply request, output-size, and execution-time limits.
  • Make side-effecting tools explicit and require confirmation in the host.
  • Use cancellation and idempotency keys for operations that may be retried.
  • Keep resource payloads small; return summaries or paginated data where possible.
  • Measure handler latency separately from network and model latency.
  • Cache safe, immutable resources, but never cache secrets or user-specific data without an isolation plan.

Or skip the browser setup

If your MCP server or agent needs screenshots, ScreenshotNeo provides a website screenshot API and MCP server. One GET request returns PNG, JPEG, WebP, or PDF output. Cookie and consent banners are accepted like a visitor and more than 60 known consent platforms, newsletter popups, and chat widgets are removed before capture; each step can be turned off. Bot checks, blank pages, timeouts, failed loads, and cache hits are not billed, and response headers identify the page verdict and billing result.

curl -G "https://api.screenshotneo.com/v1/shot" -d access_key=YOUR_API_KEY --data-urlencode url=https://stripe.com -o shot.webp
import requests
r = requests.get("https://api.screenshotneo.com/v1/shot", params={"access_key": "YOUR_API_KEY", "url": "https://stripe.com"}, timeout=90)
open("shot.webp", "wb").write(r.content)
const q = new URLSearchParams({ access_key: 'YOUR_API_KEY', url: 'https://stripe.com' });
const res = await fetch(`https://api.screenshotneo.com/v1/shot?${q}`);

See the ScreenshotNeo API and MCP documentation for the MCP tools take_screenshot, get_page_info, and capture_pdf. AI agents can use the MCP server directly. Free usage includes 1,000 screenshots a month with no card; paid plans start at $5 for 3,000 shots. Create a free ScreenshotNeo account.

FAQ

Can one application be both an MCP client and an MCP server?

Yes. A host can connect as a client to one server while exposing its own capabilities through a server connection for another application.

Does MCP require a large language model?

No. MCP defines the connection and capability protocol. An AI model is common in the host, but a regular program can also operate as a client.

Are tools safer than resources?

They have different semantics. Tools execute functions and may cause side effects; resources provide data. Apply authentication, authorization, validation, and output limits to both.

Which transport should a beginner choose?

Use stdio for a local host that launches the server. Use Streamable HTTP when the server is remote or shared, then add normal HTTP authentication and observability.

Where should I check for current SDK syntax?

Use the versioned TypeScript SDK v2 documentation and its client calling guide. Keep v1 and v2 examples separate.