Beyond prompt engineering: A first look at MCP

Beyond prompt engineering: A first look at MCP

Sooner or later, most of the software we touch will have some AI wired into it. Once you go past prompt engineering, custom instructions, and skills, you hit a new wall: the model knows a lot in general, but it knows nothing about your domain or your systems. That’s where MCP comes into the picture. It lets an agent reach the outside world in real time and pull in domain-specific knowledge.

In this article we go through the concept of MCP, the client and server split, and the components an MCP server can expose.

What’s MCP?

MCP stands for Model Context Protocol. It’s a specification for what a server should expose, and how, so that an AI client can discover those capabilities and let a model use them.

One thing to get right early, because plenty of introductions get it wrong: MCP is not REST. Every message between a client and a server is JSON-RPC 2.0. The spec defines two standard transports, stdio (the client launches the server as a subprocess and they talk over stdin/stdout) and Streamable HTTP (for remote servers). An older HTTP+SSE transport existed and has since been superseded by Streamable HTTP, which is worth knowing if you run into it in older tutorials.

Assume we have a weather app or a user management application already exposing REST APIs. Now we want to bring that app into our AI workflow, into Claude for example. We need to be able to run operations against it: get the list of users, get today’s weather, and so on. Those REST endpoints don’t disappear. We wrap them, and the wrapper speaks MCP.

You can implement the protocol yourself by following the specification. In practice you probably shouldn’t. The official SDKs cover most languages, and on the Java side there’s MCP Server Boot Starter and MCP Client Boot Starter.

MCP client and MCP server

Like most internet technology, MCP has two sides.

An MCP client is the application that hosts the model: Claude, an IDE, a CLI tool. The distinction that trips people up is that the client is not the model. The model reads the list of available tools and decides that one of them should be called. The client is the code that actually opens the connection, sends the JSON-RPC request, and hands the result back to the model.

An MCP server is the application or service of interest, wrapped so it can be asked. In our example, the user app or the weather app is the MCP server. It advertises what it can do and waits.

MCP components

An MCP server can expose several kinds of things. Very few servers implement all of them, and that’s fine. Most useful servers in the wild are a handful of tools and nothing else.

Tools

Tools are the main instrument through which a model acts on an MCP server. A tool is the verb: create a user, fetch the forecast, restart a job.

Each tool comes with a name, a description, and a JSON Schema for its parameters. The model picks the right one from that metadata alone, which is why the description matters more than people expect. A badly named tool with a vague description simply won’t get called.

Here’s what a tool declaration looks like on the wire, in the response to a tools/list request:

{
  "name": "get_forecast",
  "description": "Get the weather forecast for a city, up to 7 days ahead.",
  "inputSchema": {
    "type": "object",
    "properties": {
      "city": { "type": "string", "description": "City name, e.g. Munich" },
      "days": { "type": "integer", "minimum": 1, "maximum": 7 }
    },
    "required": ["city"]
  }
}

And the call itself:

{
  "jsonrpc": "2.0",
  "id": 3,
  "method": "tools/call",
  "params": {
    "name": "get_forecast",
    "arguments": { "city": "Munich", "days": 3 }
  }
}

No paths, no HTTP verbs, no resource URLs. tools/call is a JSON-RPC method name, and it looks the same whether the message arrived over stdio or over HTTP. That’s the part worth internalizing before you start building.

Resources

Resources are data a client can read from a server without triggering computation. Each one is identified by a URI. A log file, a config file, a database schema, a product manual all fit here.

The distinction against tools is that a tool does something, a resource is there to be read. Resources are also application-controlled rather than model-controlled, meaning the client decides what to pull in, not the model.

Prompts

Prompts are predefined templates or workflows for a specific task, often surfaced in the client as commands starting with /. They can take parameters, so the same template gets reused with different inputs. The point is to standardize the model’s output and behavior, which makes it more predictable.

Completion

Autocompletion, similar to what an IDE gives you. When a user fills in an argument for a prompt or a tool, the server can suggest valid values as they type. Instead of guessing the exact spelling of a project ID, the user picks it from a list the server already knows.

Progress

The client sends a progress token with a request, and the server sends back updates as the work moves along. Without it, a task that takes two minutes looks identical to a task that has crashed.

Sampling

Sampling reverses the direction. The server asks the client’s model to perform a task. A server that needs a summary, a classification, or a short piece of generated text doesn’t have to ship its own model. It asks the client’s model instead, and the client stays in control of what actually gets sent, including whether to send it at all.

Elicitation

Elicitation is how a server asks the end user for information it doesn’t have. The server sends a request with a JSON Schema describing what it needs, and the client renders that as a form or a prompt. The user can fill it in, decline, or cancel. This covers the case where a tool call is missing a required piece of context and the model has no way to invent it.

Logging

A mechanism for a server to surface its logs to the client, at standard syslog severity levels. It’s usually not shown to the end user. The purpose is to give the client, and through it the model, more context about what happened behind the scenes.

Conclusion

MCP standardizes how an AI agent talks to a service: JSON-RPC 2.0 over stdio or Streamable HTTP, with a defined set of things a server can expose. Tools are the backbone of that communication, and the other components exist for the moments you actually need them.

If you’re building your own server, don’t start with all of it. Start with one tool that doesIf you’re building your own server, don’t start with all of it. Start with one tool that does one thing you already do by hand, wire it up, and watch the model call it. You’ll know when you need the rest. one thing you already do by hand, wire it up, and watch the model call it. You’ll know when you need the rest.

Inline/featured images credits