CertSafari
    Anthropic Claude Certified Developer – Foundations (CCDV-F)· Lessons

    Domain 8 · Lesson 24/25

    MCP Server Primitives: Tools, Resources, and Prompts

    MCP Server Development

    12 min read
    3.53% of exam
    8 sources
    Published 4 Oct 2026
    Docs as of 30 Sep 2026

    What you will be able to do

    • Describe the roles of host, client, and server in the MCP architecture
    • Explain how a server advertises its features through capability declaration
    • Define a tool with a valid inputSchema and return text or structured results
    • Expose resources and resource templates, and secure file:// resources
    • Publish parameterised prompts and return the correct error codes
    • Choose between the stdio and Streamable HTTP communication patterns and keep a stdio server's stdout clean

    Key concept

    MCP server primitives — An MCP server is a small, focused program that offers three kinds of capability to a host application: tools the model can call, resources that supply context, and prompts that act as reusable message templates. The host keeps control of the conversation, and the server only answers the requests it receives.

    1.Host, client, and server

    MCP involves three roles, and it helps to keep them apart. The host is the application the user works in, such as Claude Code or your own agent. It creates and manages several client instances, enforces security policies and consent, handles authorization decisions, and coordinates the LLM integration. Each client lives inside the host and holds exactly one connection to one server. It attaches the protocol version and capabilities to every request, routes messages in both directions, and keeps servers isolated from each other. The server exposes tools, resources, and prompts, and it can run as a local process or as a remote service.

    The spec gives a few design principles for this split. Servers should be extremely easy to build, because the host does the complex orchestration. They should be composable, so several focused servers can be combined. And they should not be able to read the whole conversation or see into other servers. A server receives only the context it needs, and the full conversation history stays with the host.

    Checkpoint 1 of 5· Match them up

    Match each responsibility to the MCP role that owns it

    Tap a term, then the definition that fits it.

    Sources1

    2.Declaring capabilities

    Features are negotiated, not assumed. A server declares capabilities such as tool support, resource subscriptions, and prompt templates. A client declares its own capabilities, such as support for sampling and elicitation. Both sides must then respect what was declared for the rest of the interaction. In practice, any feature your server implements has to be advertised in its capabilities. A server that registers tool handlers but never declares tools cannot have those tools invoked.

    A server declaring tool support and promising list-change notificationsjson
    {
      "capabilities": {
        "tools": {
          "listChanged": true
        }
      }
    }

    With listChanged: true, the server is promising to send notifications/tools/list_changed when its tool set changes, so the client knows to fetch the list again. Resources and prompts use the same pattern under their own capability keys.

    Checkpoint 2 of 5· Check yourself

    A server implements a tools/call handler but leaves tools out of its capabilities. What does the spec say?

    Capabilities describe what a server offers. The communication pattern describes how its messages travel, and the two are independent. The first pattern is stdio, used for local servers. The client launches the server as a child process, and the server reads JSON-RPC messages from stdin and writes JSON-RPC messages to stdout. Each message is a single JSON-RPC request, notification, or response. Messages are delimited by newlines and must not contain embedded newlines. Claude Code connects this way, as in claude mcp add --transport stdio airtable -- npx -y airtable-mcp-server. There the command after -- is the process Claude Code spawns. An SDK server does the same by connecting a StdioServerTransport.

    Because stdout carries the protocol, a stdio server must never print anything else to it, and the client must never send anything to stdin that is not a valid MCP message. A stray print or console.log corrupts the stream. Log to stderr instead, which the spec allows for any logging purposes. The client may capture, forward, or ignore that output, and it should not assume stderr output means an error. To shut down, the client closes the input stream to the child process and waits for the server to exit. If the server does not exit in a reasonable time, the client forcibly terminates it.

    The second pattern is Streamable HTTP, used for remote servers. Here the server is a standalone service that exposes a single HTTP endpoint accepting POST, and the client sends every JSON-RPC request or notification as its own POST. The server answers with either one JSON object or an SSE stream. Claude Code reaches such a server with claude mcp add --transport http <name> <url>. The older sse transport and a ws WebSocket entry are also accepted in Claude Code configuration. In both patterns the client opens the connection and the server answers requests. The difference is whether the client starts the server process (stdio) or connects to one that is already running (HTTP).

    Sources12345

    3.Tools: model-callable functions

    A tool definition has a unique name, an optional display title, a description, an inputSchema, an optional outputSchema, and optional annotations and icons. Tool names should be 1–128 characters, are treated as case-sensitive, should use only ASCII letters, digits, _, -, and ., and should be unique within a server. getUser, DATA_EXPORT_v2 and admin.tools.list are all valid names.

    inputSchema defaults to JSON Schema 2020-12 when no $schema field is present. For a tool with no parameters, the recommended schema is { "type": "object", "additionalProperties": false }. Clients find tools with tools/list, which is paginated with a cursor, and run them with tools/call, passing name and arguments. A result carries a content array, which can hold text, image, audio, resource_link, or embedded resource items, plus an isError flag. If you declare an outputSchema, the server must also return structuredContent that conforms to it.

    A successful tools/call resultjson
    {
      "jsonrpc": "2.0",
      "id": 2,
      "result": {
        "resultType": "complete",
        "content": [
          {
            "type": "text",
            "text": "Current weather in New York:\nTemperature: 72°F\nConditions: Partly cloudy"
          }
        ],
        "isError": false
      }
    }

    Some tools create state that later calls refer to by handle, for example a create_basket call that returns a basket_id. For these tools, state the retention policy in the creation tool's description. When a call uses an expired or unknown handle, return a tool execution error so the model can recover. On the host side, the spec expects a human in the loop: the UI should make exposed tools visible, show when a tool is invoked, and ask the user to confirm operations.

    Checkpoint 3 of 5· Fill the gap

    Which method name completes this request to run a tool?

    {
      "jsonrpc": "2.0",
      "id": 2,
      "method": " ? ",
      "params": {
        "name": "get_weather",
        "arguments": {
          "location": "New York"
        }
      }
    }

    Sources6

    4.Resources: context identified by URI

    A resource is data identified by a uri. It also has a name and, optionally, a title, description, mimeType, size, and icons. Clients list resources with resources/list and fetch them with resources/read. Each item in the returned contents holds either text or base64 blob data. For parameterised access, resources/templates/list returns URI templates such as file:///{path}. Annotations tell the client how to use a resource: audience (user and/or assistant), priority from 0.0 to 1.0, and lastModified.

    Reading a resource by URIjson
    {
      "jsonrpc": "2.0",
      "id": 2,
      "method": "resources/read",
      "params": {
        "uri": "file:///project/src/main.rs"
      }
    }

    The resources capability has two optional flags. listChanged means the server will send a notification when the set of resources changes. subscribe means it supports update notifications for individual resources requested through subscriptions/listen. Security falls on the server. It must validate every resource URI, must encode binary data properly, should apply access controls to sensitive resources, and must sanitize file paths when serving file:// resources. If a resource does not exist, the server returns error -32602 with the URI in data.

    Checkpoint 4 of 5· Check yourself

    Your server exposes project files through the template file:///{path}. Which requirement does the spec make specifically for this?

    Sources7

    5.Prompts: reusable message templates

    A prompt is a named template with optional arguments, each of which has a name, a description, and a required flag. A client lists prompts with prompts/list and fills one in with prompts/get. The server returns a list of messages. Each message has a role of user or assistant and content that can be text, image, audio, a resource link, or an embedded resource.

    Filling in the code_review prompt with an argumentjson
    {
      "jsonrpc": "2.0",
      "id": 2,
      "method": "prompts/get",
      "params": {
        "name": "code_review",
        "arguments": {
          "code": "def hello():\n    print('world')"
        }
      }
    }

    Servers should validate prompt arguments before processing them. An unknown prompt name or a missing required argument returns -32602 (Invalid params), and internal failures return -32603. The table below puts the three primitives side by side.

    The three server primitives compared
    PrimitiveDiscoverUseChange notification
    Toolstools/listtools/callnotifications/tools/list_changed
    Resourcesresources/list, resources/templates/listresources/readnotifications/resources/list_changed, notifications/resources/updated
    Promptsprompts/listprompts/getnotifications/prompts/list_changed

    Checkpoint 5 of 5· Check yourself

    A client calls prompts/get for code_review but leaves out the required code argument. Which error should the server return?

    Sources8

    Exam traps

    Each one states something that sounds right. Open it to see what is actually true.

    1. 1.A tool with no parameters can set inputSchema to null or leave it out.Why is that wrong?

      inputSchema must always be a valid JSON Schema object. For a tool with no parameters, the recommended form is an object type with additionalProperties: false.

      Covered in Tools: model-callable functions

    2. 2.Implementing a handler is enough for clients to use a feature, so capability declaration is optional.Why is that wrong?

      Server features must be advertised in the server's capabilities, and tool invocation specifically requires the tools capability to be declared.

      Covered in Declaring capabilities

    3. 3.A stdio server can print debug output to stdout, since the client simply ignores text it does not recognise.Why is that wrong?

      stdout carries the protocol, so anything that is not a valid MCP message breaks the stream. Logging belongs on stderr.

      Covered in Declaring capabilities

    Sources

    Every claim above is drawn from one of these pages, quoted as it was written on the date shown.

    1. 1.
      “Full conversation history stays with the host”
      ↩︎ Host, client, and server
      “Can be local processes or remote services”
      ↩︎ Host, client, and server
      “Servers declare capabilities like tool support, resource subscriptions, and prompt templates”
      ↩︎ Declaring capabilities
      “Expose resources, tools and prompts via MCP primitives”
      ↩︎ Key concept
      “Tool invocation requires the server to declare tool capabilities”
      ↩︎ Exam trap 2
      “Communicates with exactly one server”
      ↩︎ Checkpoint
      “Tool invocation requires the server to declare tool capabilities”
      ↩︎ Checkpoint
    2. 2.
      “The server reads JSON-RPC messages from stdin and writes JSON-RPC messages to stdout.”
      ↩︎ Declaring capabilities
      “Messages are delimited by newlines, and MUST NOT contain embedded newlines.”
      ↩︎ Declaring capabilities
      “The server MAY write UTF-8 strings to stderr for any logging purposes including informational, debug, and error messages.”
      ↩︎ Declaring capabilities
      “Closing the input stream to the child process (the server).”
      ↩︎ Declaring capabilities
      “The server MUST NOT write anything to its stdout that is not a valid MCP message.”
      ↩︎ Exam trap 3
    3. 3.
      “The server exposes a single HTTP endpoint (the MCP endpoint) that accepts POST.”
      ↩︎ Declaring capabilities
    4. 4.
      “Stdio connection: connects to Claude Code over stdin/stdout. This is standard for any MCP server.”
      ↩︎ Declaring capabilities
    5. 5.
      “claude mcp add --transport http <name> <url>”
      ↩︎ Declaring capabilities
    6. 6.
      “Servers MUST provide structured results that conform to this schema.”
      ↩︎ Tools: model-callable functions
      “should return a tool execution error that says so, so the model can recover by creating a new one”
      ↩︎ Tools: model-callable functions
      “Present confirmation prompts to the user for operations, to ensure a human is in the loop”
      ↩︎ Tools: model-callable functions
      “MUST be a valid JSON Schema object (not null)”
      ↩︎ Exam trap 1
      “MUST be a valid JSON Schema object (not null)”
      ↩︎ Prediction
    7. 7.
      “whether the server supports resource-specific update notifications for resources requested through subscriptions/listen using the resourceSubscriptions filter”
      ↩︎ Resources: context identified by URI
      “uri: Unique identifier for the resource”
      ↩︎ Resources: context identified by URI
      “Servers MUST sanitize file paths to prevent directory traversal attacks when serving file:// resources”
      ↩︎ Checkpoint
    8. 8.
      “arguments: Optional list of arguments for customization”
      ↩︎ Prompts: reusable message templates
      “Servers SHOULD validate prompt arguments before processing”
      ↩︎ Prompts: reusable message templates
      “Missing required arguments: -32602 (Invalid params)”
      ↩︎ Checkpoint

    Continue to page 2 of 2

    MCP Transports and Connecting Servers to Claude Code and the Agent SDK

    Spotted a mistake, or was something unclear? Tell us.