ScreenshotNeo

BlogAI agents

What Is an MCP Server? Explanation and Working Example

Learn what an MCP server does, how tools, resources and prompts work, and how to build and connect a working server.

By the ScreenshotNeo team1 October 20269 min read

Direct answer: An MCP server is software that exposes capabilities—tools, resources and prompts—through the Model Context Protocol (MCP) to an MCP client or host. The host connects the server to an AI application; the server supplies the declared interface and performs an operation or provides requested context. MCP is an open standard that connects AI applications to the systems where your data and tools live.

An MCP server is the server-side component of that connection. It is not the language model and does not have to be a complete AI application. A server might run locally as a child process, or remotely as a network service. The client discovers what the server offers, then sends structured requests that match the advertised schemas.

What an MCP server provides

MCP defines three core server primitives. They have different jobs and should not be treated as interchangeable.

Primitive Purpose Typical examples Who usually chooses it
Tool Lets the model request an action or retrieval. Query a database, create an issue, fetch weather, take a screenshot. The model, through the host’s tool-calling loop.
Resource Exposes contextual data managed by the application. Documents, records, configuration, generated reports. The host or user, depending on the client.
Prompt Provides a reusable prompt template normally surfaced for user choice. Code-review template, incident-summary template, research workflow. The user or host interface.

The official server overview describes these control roles. A server can implement one primitive or all three. Keep side effects in tools, keep reference material in resources, and use prompts for repeatable instructions.

How the connection works

  1. The host starts or connects to an MCP server.
  2. The MCP client negotiates the protocol and learns the server’s declared capabilities.
  3. The host presents available tools, resources or prompts to the AI application.
  4. The model selects a tool or the user selects a resource or prompt.
  5. The client sends a schema-conforming request.
  6. The server validates the input, performs the operation, and returns content or structured output.
  7. The host gives the result back to the model or displays it to the user.

For example, a weather server can declare a get_weather tool with a required city string. The model supplies the city, the handler calls a weather service, and the server returns text or structured weather data. The model never needs to know the weather provider’s internal API details.

Transport choices: stdio and Streamable HTTP

Transport Best fit Operational shape
stdio Local integrations launched by a desktop host or editor. The host spawns the server process and exchanges protocol messages over standard input and output.
Streamable HTTP Remote or shared deployments. The client reaches a server over HTTP; deployment, authentication and network policy are managed separately.
HTTP plus SSE Compatibility with older implementations. The v1 TypeScript SDK documents this as a backward-compatibility path.

Choose the transport your specific host supports. A local process integration generally points to stdio; a service reached over a network generally points to Streamable HTTP. The TypeScript SDK v1 guide documents these transport options and a matching server/client quickstart.

Working example: a TypeScript MCP server

The following example targets the TypeScript SDK v2 and the 2026-07-28 specification baseline described in the official v2 documentation. It registers a tool, defines its input schema, and returns structured content. Check the current SDK guide before starting a new project because package APIs and protocol revisions can change.

1. Create the project

mkdir mcp-weather-server
cd mcp-weather-server
npm init -y
npm install @modelcontextprotocol/sdk zod
npm install --save-dev typescript tsx @types/node

Add an npm script:

npm pkg set scripts.start='tsx src/server.ts'
mkdir src

2. Register a tool

import { McpServer } from '@modelcontextprotocol/sdk/server/mcp.js';
import { StdioServerTransport } from '@modelcontextprotocol/sdk/server/stdio.js';
import { z } from 'zod';

const server = new McpServer({
  name: 'weather-example',
  version: '1.0.0'
});

server.registerTool(
  'get_weather',
  {
    title: 'Get weather',
    description: 'Return a small weather summary for a city.',
    inputSchema: {
      city: z.string().min(1).describe('City name, such as London')
    }
  },
  async ({ city }) => {
    // Replace this deterministic example with your weather provider call.
    const summary = `Weather lookup requested for ${city}.`;
    return {
      content: [{ type: 'text', text: summary }],
      structuredContent: { city, summary }
    };
  }
);

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

Save it as src/server.ts and start it:

npm start

With stdio, the process waits for an MCP client. Do not write diagnostic logs to standard output; stdout carries protocol messages. Send logs to stderr instead.

3. What happens during a tool call

  1. The client lists the server’s tools and sees get_weather.
  2. The host gives the model the tool name, description and input schema.
  3. The model requests { "city": "London" }.
  4. The SDK validates the argument against the Zod schema.
  5. The callback performs the operation and returns content plus optional structured data.
  6. The host supplies the result to the model.

The callback should validate all untrusted input, enforce authorization before side effects, apply timeouts to outbound calls, and return useful errors. A tool description should state what the operation does and any destructive consequences so the model can choose it safely.

Connecting a client

The exact client configuration belongs to the host. A typical local configuration points the host at the command that starts your server:

{
  "mcpServers": {
    "weather-example": {
      "command": "npm",
      "args": ["start"],
      "cwd": "/absolute/path/to/mcp-weather-server"
    }
  }
}

For a remote deployment, configure the host with the Streamable HTTP endpoint and the authentication method supported by that host and server. Verify current host documentation rather than assuming every MCP client supports every transport or authentication scheme.

Calling an MCP HTTP endpoint with cURL

HTTP request shapes depend on the MCP specification version and server framework. Use the endpoint and protocol version documented by your server. A generic JSON POST looks like this:

curl -i https://example.com/mcp \
  -H 'Content-Type: application/json' \
  -H 'Accept: application/json, text/event-stream' \
  -d '{"jsonrpc":"2.0","id":1,"method":"tools/list","params":{}}'

This illustrates an HTTP transport request; it is not a universal replacement for a host’s connection flow. Older examples may include initialization messages or an Mcp-Session-Id header.

Calling an MCP server from Python

For a remote server, use an MCP-compatible Python client library and follow that library’s current transport instructions. The low-level shape below shows the kind of JSON-RPC request an HTTP client might send when the server documents direct HTTP access:

import requests

endpoint = 'https://example.com/mcp'
payload = {
    'jsonrpc': '2.0',
    'id': 1,
    'method': 'tools/list',
    'params': {}
}
response = requests.post(
    endpoint,
    json=payload,
    headers={'Accept': 'application/json, text/event-stream'},
    timeout=30,
)
response.raise_for_status()
print(response.text)

For stdio, let the MCP Python client launch the command and speak the protocol; do not attempt to parse the server’s stdout as ordinary log text.

Calling an MCP server from Node.js

const response = await fetch('https://example.com/mcp', {
  method: 'POST',
  headers: {
    'content-type': 'application/json',
    'accept': 'application/json, text/event-stream'
  },
  body: JSON.stringify({
    jsonrpc: '2.0',
    id: 1,
    method: 'tools/list',
    params: {}
  })
});

if (!response.ok) {
  throw new Error(`MCP request failed: ${response.status}`);
}
console.log(await response.text());

Use an SDK client for production connections so transport negotiation, streaming and version details are handled consistently.

Protocol versions matter

The official announcement for the 2026-07-28 specification describes substantial changes, including retirement of the initialize/initialized exchange and the Mcp-Session-Id header, an optional server/discover RPC, and self-contained requests. It also describes ttlMs and cacheScope metadata on list and resource-read responses.

Those are claims about that specification version. Older clients and SDK examples can target different revisions. Do not mix a v1 package, a v2 package and protocol assumptions from different documents without checking the migration guidance. Record the SDK and protocol version in your project documentation.

Designing tools, resources and prompts

Tool design checklist

  • Use a stable, descriptive name such as search_issues or create_invoice.
  • Describe required and optional fields with a machine-readable schema.
  • State side effects, permissions and expected latency in the description.
  • Validate arguments again inside the handler.
  • Return concise human-readable content and structured data when callers need fields.
  • Use idempotency keys for operations that might be retried.

Resource design checklist

  • Use resources for context that the host can read, rather than actions.
  • Choose stable URIs and document their content type.
  • Control access per resource and avoid exposing secrets in resource bodies.
  • Define refresh and cache behavior where stale data matters.

Prompt design checklist

  • Make prompts reusable and parameterized.
  • Keep user choice visible for workflows with meaningful consequences.
  • Do not hide authorization decisions inside a prompt template.

Security and reliability

  • Authentication: authenticate remote clients and authorize each tool or resource separately.
  • Least privilege: give the server only the credentials and filesystem access it needs.
  • Input validation: treat model-generated arguments as untrusted input.
  • Side effects: require confirmation or an explicit policy for deletes, payments and external messages.
  • Timeouts: bound database and HTTP calls so one tool cannot stall the host indefinitely.
  • Retries: retry only safe or idempotent operations, with exponential backoff.
  • Redaction: remove tokens and personal data from logs and error messages.
  • Observability: log request IDs, tool names, latency and outcome to stderr or your logging system.
  • Concurrency: protect shared state and set limits for expensive tools.

Performance, caching and cost

Protocol overhead is usually small compared with the operation a tool performs. Measure the handler: network latency, database time, serialization and model time can dominate. Keep tool results focused; returning a large document increases transfer and context costs.

Cache read-only resources when their freshness policy permits it. For the 2026-07-28 specification, inspect the server’s ttlMs and cacheScope metadata instead of inventing a cache duration. Avoid caching authorization-sensitive responses across users.

For remote servers, budget for hosting, outbound API calls and any model or host charges. MCP itself does not set a universal price. Track usage by tool and tenant so expensive operations are visible.

Common errors and fixes

Symptom Likely cause Fix
Client cannot start the server Wrong command, working directory or runtime. Run the exact command manually, use an absolute path, and confirm dependencies are installed.
JSON parse errors on stdio Logs or banners were written to stdout. Send diagnostics to stderr and reserve stdout for MCP messages.
Tool is missing Registration failed or the client cached an old tool list. Check startup errors, confirm registration runs before connect, then reconnect the client.
Invalid arguments Model input does not match the declared schema. Improve the schema description, validate inside the handler, and return a useful error.
HTTP 404 or 405 Wrong endpoint or method for the deployed transport. Use the server’s documented MCP endpoint and request method.
Session or initialize errors Client and server target different protocol revisions. Align SDK and protocol versions; do not copy initialization behavior from an older example into a newer server.
Requests hang Handler has no timeout or the transport stream is not consumed. Add operation timeouts, inspect server logs, and use an SDK transport implementation.
Works locally but not remotely Firewall, TLS, proxy or authentication configuration. Verify network reachability, certificates, proxy streaming support and authorization headers.

Or skip the browser setup

If your MCP tool needs website images, ScreenshotNeo provides an MCP server with take_screenshot, get_page_info and capture_pdf tools for Claude, Cursor and other MCP clients. It also offers a direct screenshot API, so you can call one endpoint instead of installing and maintaining a browser.

Cookie and consent banners, newsletter popups and chat widgets are removed before the shot. Bot checks, blank pages and failed loads are never billed, and each response reports its page verdict and billing status in X-Page-Verdict and X-Billed headers. You can use full-page capture, element selectors, custom CSS and JavaScript, device presets, dark mode, waits, request blocking, cookies, headers, caching, signed links, async jobs and bulk capture.

Example request (see the ScreenshotNeo API documentation):

cURL

curl -G "https://api.screenshotneo.com/v1/shot" -d access_key=YOUR_API_KEY --data-urlencode url=https://stripe.com -o shot.webp

Python

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)

Node.js

const q = new URLSearchParams({ access_key: 'YOUR_API_KEY', url: 'https://stripe.com' }); const res = await fetch(`https://api.screenshotneo.com/v1/shot?${q}`);

ScreenshotNeo includes 1,000 screenshots a month free with no card. Paid plans start at $5 for 3,000 screenshots. Create a free ScreenshotNeo account.

FAQ

Is an MCP server an AI model?

No. It is a protocol server that exposes capabilities to an AI host and client.

Can one server expose tools and resources together?

Yes. Implement the primitives your integration needs and apply separate authorization and validation rules to each.

Should I use stdio or HTTP?

Use stdio for a host that launches a local process. Use Streamable HTTP for a remotely reachable service, subject to host support.

Do all MCP clients use the same initialization flow?

No. Protocol and SDK versions differ. Match the client, server and documentation versions.

Where can I find the canonical specification?

Start with the server overview, then check the SDK guide and the specification version your deployment targets.