Tuesday, 11 August 2026

MCP Server

 

What is an MCP server and why is it different from wiring a tool directly?

When wiring a tool directly into an application, you are responsible for defining the tool’s schema and its functionality. Both live in that application’s code. If three different applications need access to the same external service, each one maintains its own integration. Model Context Protocol, or MCP, separates tool definitions from individual applications and turns them into a process called a server.

An MCP server is a process that exposes tools, resources, and prompts that MCP clients can use. 

The practical difference: a tool is the model reaching out to get something when it decides it needs it. A resource is the client pulling known data in before the model even starts. A prompt is packaging expert-level instructions so every developer on your team gets the same quality output without having to know how to write that instruction themselves.

Three things an MCP server exposes — you already know tools, here are the other two.

Resources — read-only data fetched directly into context

A resource is data the server exposes at an address. The client fetches it and places it into context directly — no tool call, no model decision involved. Think of it as a GET request to a known endpoint.

Two forms:

  • Direct resource — fixed address, no parameters. The data is always at that address.
  • Templated resource — address contains a parameter, resolved at fetch time.

When to use it over a tool: When you know upfront what data you need in context before the turn starts. A tool call is dynamic — the model decides when and whether to call it. A resource is deterministic — the client fetches it directly. Cheaper and more predictable when the data is known.

Practical examples:

# Direct resource — fixed address
mcp://java-tools/conventions/spring-boot-standards
→ Returns your team's Spring Boot coding standards
→ Client fetches this at session start, always in context

# Templated resource — parameterized address  
mcp://java-tools/schema/{tableName}
→ mcp://java-tools/schema/orders
→ Returns the DDL for the orders table
→ Client fetches by passing the table name as parameter

Other real-world examples:

  • mcp://jira/project/OMS/open-tickets — current sprint tickets loaded into context
  • mcp://confluence/runbooks/{serviceName} — runbook for a specific service
  • mcp://github/repo/accenture-oms/pull-requests/open — open PRs fetched directly

Prompts — pre-written instruction templates invoked by name

A prompt is a vetted instruction template the server exposes so any client can invoke it by name instead of writing their own version. The server maintains it in one place, every connected client gets the same quality.

When a prompt is worth it over just asking Claude: When specific wording materially changes the output quality. For routine questions the user's own words are fine. For specialized tasks — a security review, a database migration audit, an API contract check — a carefully constructed prompt produces consistently better results than whatever each developer would type on the fly.

Practical examples for your Spring Boot context:

# Invoked by name in the client
/prompt: review-db-migration

# What the server actually sends to the model
"Review this Flyway migration file against these criteria:
1. Does it have a matching rollback script in db/rollbacks/?
2. Are all foreign key columns indexed?
3. Does it use CREATE OR REPLACE anywhere (not allowed)?
4. Are all VARCHAR columns explicitly sized?
5. Is the version number in the correct format V{date}_{seq}?
Return findings as: PASS / WARN / FAIL with specific line references."
# Another example
/prompt: api-contract-review

# Server sends
"Review this REST controller against our API standards:
1. Are all endpoints using method-specific annotations (@GetMapping etc)?
2. Are all response bodies Java records, never raw entities?
3. Is business logic absent from the controller?
4. Are all error responses using ProblemDetail (RFC 9457)?
5. Does every endpoint have @Operation and @ApiResponse annotations?
Return a checklist with PASS/FAIL per item."

How all three fit together

MechanismWhat it isWhen to reach for it
ToolAction the model calls dynamicallyWhen the model needs to decide whether and when to fetch or act
ResourceRead-only data fetched directly into contextWhen you know upfront what data you need, before the turn starts
PromptPre-written instruction template invoked by nameWhen specific wording produces materially better results than freeform input


Three transports, each for a different deployment topology.

The MCP transport (stdio, HTTP, SSE) just carries JSON-RPC envelopes


stdio — server runs as a child process on the same machine

The client launches the server as a subprocess and communicates via stdin/stdout. One line in, one line out — JSON-RPC over pipes. This is exactly what your ClaudeMCPServer.java uses. No network, no port, no authentication needed. The process lives and dies with the client session.

Use it when: the server runs locally alongside Claude Code on the same machine.


HTTP — server runs as a standalone process, local or remote

The client sends HTTP POST requests to a fixed URL. The server is a normal HTTP service — could be on localhost, could be on a remote host. Stateless request/response, same as any REST API. Each request is independent.

Use it when: the server needs to be shared across multiple clients, runs on a remote machine, or needs to persist beyond a single session.


SSE (Server-Sent Events) — HTTP with a persistent stream back

An extension of HTTP transport. The client POSTs requests normally, but the server holds the connection open and streams responses back as events rather than closing after each response. Useful when the server needs to push notifications or stream partial results.

Use it when: the server needs to send unsolicited updates to the client, or results arrive incrementally.


The practical decision

Server on same machine, local dev    →  stdio
Server shared across team / remote   →  HTTP
Server needs to push events          →  SSE

Your ClaudeMCPServer.java is stdio — that's why System.out is the protocol wire and System.err is the only safe place to log. Switching to HTTP would mean replacing stdin/stdout with an HTTP listener, but the JSON-RPC message structure stays identical.



No comments:

Post a Comment