new·The score now tells you which way it movedA brain's exam only ever grows: its own material writes questions, and so does every question a real caller asked and did not get answered. The score is a percentage over that growing set, so a brain that learned more could post a smaller number — and this week three did. One of them answered two MORE questions than the week before and showed eighteen points less. Printed as a single percentage, that reads as decline to a reader and as punishment to anyone who contributes material.all news →
mozg.beta
Sign in

MCP · Building servers and clients · all subjects

client implementation

56 notes, read out of this brain and free to use. Each one was extracted from a source and is re-checked against its exam.

ttlMs and cacheScope hints on list, server/discover and resources/read results

Each list result (such as `tools/list`), as well as each `server/discover` and `resources/read` result, carries `ttlMs` and `cacheScope` hints that clients should follow per the specification's caching utility. A cached list must be treated as stale as soon as a `list_changed` notification arrives, even before its TTL expires.

Claude Custom Connectors are the mechanism for connecting to remote MCP servers

In Claude, remote MCP servers are added as 'Custom Connectors'. The flow is: open Settings (Desktop: Ctrl+Comma, or menu icon > File > Settings; Browser: Cmd+Shift+Comma, or profile icon > Settings), click 'Connectors' in the sidebar, click 'Add' at the top-right, choose 'Add custom connector', paste the server URL, then click 'Add'.

Elicitation has two modes: form and URL

Elicitation supports two modes. Form mode: the server asks the client to collect structured data, and the request includes a schema the client uses to build an input form and validate the response. URL mode: the server provides a URL for the user to open, the interaction happens out of band and its data never passes through the client, making it suitable for sensitive flows such as credential entry or third-party OAuth authorization.

Elicitation uses the MRTR pattern with InputRequiredResult

Elicitation follows the Multi Round-Trip Requests (MRTR) pattern. When a server needs user input while processing a request such as tools/call, it responds with an InputRequiredResult whose inputRequests field carries one or more elicitation/create requests. The client gathers the input and retries the original request (with a new request id), attaching the collected inputResponses and echoing back any requestState the server included.

elicitation/create request shape example

An elicitation request delivered inside InputRequiredResult.inputRequests has method "elicitation/create" and params containing mode (e.g. "form"), message (e.g. "Please confirm your Barcelona vacation booking details:"), and requestedSchema. requestedSchema is a JSON Schema object with type "object", a properties map (fields typed boolean or string, string fields may use enum lists such as ["window", "aisle", "no preference"], each with a description and optional default), and a required array listing mandatory field names.

Elicitation client response options: provide, decline, cancel

Users responding to an elicitation can provide the requested information through UI controls (text fields, dropdowns, checkboxes), decline to provide information with an optional explanation, or cancel the entire operation. Clients validate responses against the provided schema before returning them to servers, and display which server is asking and why.

Roots are deprecated in 2026-07-28; use tool params or resource URIs

Roots are deprecated as of protocol version 2026-07-28 and scheduled for removal. New implementations should pass directories or files via tool parameters, resource URIs, or server configuration instead.

Root object structure and file:// scheme

A root is a JSON object with a "uri" and a "name", for example {"uri": "file:///Users/agent/travel-planning", "name": "Travel Planning Workspace"}. Roots are exclusively filesystem paths and always use the file:// URI scheme.

Roots list changes are picked up on the next roots/list request

The roots list can change as users work with different projects or folders; for example if a user opens an archive folder the client adds it to the roots list. Servers see the new boundary the next time they issue a roots/list request. Servers typically access files within roots using relative paths from the root directories or file search tools that respect root boundaries.

Sampling is deprecated in 2026-07-28; integrate LLM APIs directly

Sampling is deprecated as of protocol version 2026-07-28 and scheduled for removal. New implementations should integrate directly with LLM provider APIs instead of asking the client for completions.

Sampling flow uses InputRequiredResult with sampling/createMessage

Sampling follows the same Multi Round-Trip Requests flow as elicitation: the server responds to a request such as tools/call with an InputRequiredResult carrying a sampling/createMessage request; the client presents it to the user for approval, forwards the approved request to the LLM, optionally has the user review the generation, then retries the original tools/call with inputResponses containing the approved response.

Sampling request parameters: messages, modelPreferences, systemPrompt, maxTokens

A sampling request includes messages (array of {role, content:{type:"text", text}}), modelPreferences with hints (e.g. [{name: "claude-sonnet-4-20250514"}]) plus costPriority, speedPriority and intelligencePriority values between 0 and 1 (example values 0.3, 0.2, 0.9), a systemPrompt string, and maxTokens (example 1500).

Three client features available to servers: elicitation, roots, sampling

Beyond consuming server context, MCP clients may offer three features to servers: Elicitation (servers request specific information from users during interactions), Roots (clients specify which directories servers should focus on), and Sampling (servers request LLM completions through the client). As of protocol version 2026-07-28, both Roots and Sampling are deprecated; Elicitation is not.

server/discover RPC for up-front version selection

`server/discover` is a mandatory MCP RPC that returns the server's supported protocol versions, capabilities, and identity in a single request. Clients may call it to select a version up front, but calling it is optional — a client may send any request directly and handle an UnsupportedProtocolVersionError if one comes back.

Required _meta fields on every MCP request

Every MCP request must carry `io.modelcontextprotocol/protocolVersion` and `io.modelcontextprotocol/clientCapabilities` in its `_meta`; clients should also include `io.modelcontextprotocol/clientInfo`. A request missing either required field is rejected with error code -32602 (Invalid params), the same code returned for many other malformed inputs.

MCP OAuth flow: 401 + WWW-Authenticate to token exchange

The end-to-end MCP authorization flow that a client must implement has six steps: (1) connect to the server URL and receive a 401 whose WWW-Authenticate header points at the protected-resource metadata URL via the `resource_metadata` parameter and optionally lists required scopes; (2) fetch the protected-resource and authorization-server metadata to discover endpoints and supported grants; (3) identify the client via dynamic client registration, a pre-registered static client id/secret, a Client ID Metadata Document URL, or an enterprise-managed IdP; (4) open the authorization URL in a browser for sign-in and consent; (5) receive the redirect to the client's callback URL carrying the authorization code; (6) exchange the code for tokens, persist them, and automatically retry the original request.

Mid-session 401 re-authorization and 403 insufficient_scope step-up

A server can refuse a single request mid-session with a `401` (token expired or revoked) or a `403 insufficient_scope` (token lacks required scopes) without the connection being dropped. On 401 the client parses the WWW-Authenticate challenge, re-runs the authorization flow, and retries the failed request. On insufficient_scope the client performs a step-up: it re-authorizes for the union of the currently held scopes and the newly required scopes, so the new token covers everything the old one did plus the new scopes.

Inspector OAuth client flags (CLI and TUI only)

Five OAuth flags are defined only by the Inspector CLI and TUI; the web client gets the same settings through its Client Settings dialog. They are `--client-config <path>` (install-level client config, env `MCP_CLIENT_CONFIG_PATH`, default `~/.mcp-inspector/storage/client.json`), `--client-id <id>` (static OAuth client ID, overrides client.json), `--client-secret <secret>` (for confidential clients, overrides client.json), `--client-metadata-url <url>` (CIMD metadata URL, overrides client.json), and `--callback-url <url>` (env `MCP_OAUTH_CALLBACK_URL`, default `http://127.0.0.1:6276/oauth/callback`).

server/discover result contents on a modern connection

On a modern (2026-07-28) connection, `server/discover` supplies `capabilities` (including `extensions`), `instructions`, and the list of `supportedVersions`. The server's name and version arrive in the result `_meta` under the key `io.modelcontextprotocol/serverInfo`.

Dynamic Client Registration request body for MCP clients

An MCP client that uses Dynamic Client Registration POSTs to the authorization server's `registration_endpoint` with JSON such as {"client_name": "My MCP Client", "redirect_uris": ["http://localhost:3000/callback"], "grant_types": ["authorization_code", "refresh_token"], "response_types": ["code"]}, and receives client registration information back.

Client must offer manual client-info entry when DCR is unsupported

If an MCP client connects to a server whose authorization server does not support Dynamic Client Registration and the client is not pre-registered, it is the client developer's responsibility to provide an affordance for the end user to enter client registration information manually. Without this, the connection cannot complete.

Auth server metadata fields the client needs

The authorization server metadata JSON that an MCP client fetches contains at least `issuer`, `authorization_endpoint`, `token_endpoint` and `registration_endpoint`, for example {"issuer": "https://auth.your-server.com", "authorization_endpoint": "https://auth.your-server.com/authorize", "token_endpoint": "https://auth.your-server.com/token", "registration_endpoint": "https://auth.your-server.com/register"}. If the PRM lists multiple authorization servers, the client chooses one.

Consent requirements for one-click local MCP server configuration

An MCP client that supports one-click local server configuration MUST show a consent dialog before executing commands that displays the exact command including all arguments without truncation, clearly labels it as a potentially dangerous operation that runs code on the user's system, requires explicit approval, and allows cancellation. Clients SHOULD additionally highlight dangerous patterns (sudo, rm -rf, network operations, file access outside expected directories), warn about access to home directory/SSH keys/system directories, warn that servers run with the client's privileges, and run servers sandboxed (containers, chroot, application sandboxes) with least privilege and opt-in grants for extra file system or network access.

Validate OAuth authorization URL schemes received from servers

MCP clients MUST validate authorization URLs supplied by MCP servers: only http:// and https:// schemes are allowed, with http:// acceptable only for loopback addresses (localhost, 127.0.0.1, ::1) during local development while production authorization servers MUST use https://. Clients MUST reject javascript:, data:, file:, vbscript: and other dangerous schemes, and SHOULD use allowlist-based rather than blocklist-based validation. Passing a javascript: URL straight to window.open() gives the malicious server XSS inside the client.

Never open URLs via a shell in an MCP client

MCP clients MUST NOT use shell commands (cmd.exe, sh, PowerShell) to open authorization URLs, because the shell can interpret parts of an attacker-supplied URL as extra commands, yielding remote code execution. Clients SHOULD use platform-specific, non-shell URL opening mechanisms, reject URLs containing special characters that shells could interpret, use dedicated URL sanitization libraries, and log suspicious authorization URLs.

CSP settings for web-based MCP clients

Web-based MCP clients SHOULD send Content Security Policy headers to prevent JavaScript execution from untrusted sources: set script-src 'self' to block inline JavaScript, default-src 'self' to restrict resource loading, and consider script-src 'nonce-<random>' for dynamic content that genuinely needs inline scripts.

Client scope fallback when WWW-Authenticate carries no scope parameter

Clients should begin with only baseline scopes or those given in the initial WWW-Authenticate challenge, and cache recent failures to avoid repeated elevation loops for denied scopes. When the initial WWW-Authenticate challenge carries no scope parameter, the Scope Selection Strategy directs clients to fall back to requesting all scopes listed in scopes_supported, letting the authorization server and end user decide during consent. Scope accumulation is a client-side responsibility: clients SHOULD request the union of previously requested and newly challenged scopes when re-authorizing, so servers stay stateless about client scope sets; hierarchical redundancy need not be deduplicated because authorization servers normalize it, though servers must account for hierarchy when judging token sufficiency.

App class: connect, ontoolresult, callServerTool

In the UI, `import { App } from "@modelcontextprotocol/ext-apps"` and create `new App({ name, version })`. `app.connect()` establishes communication with the host and must be called once at app initialization. `app.ontoolresult = (result) => {...}` fires when the host pushes a tool result (e.g. the initial call that rendered the UI). `await app.callServerTool({ name, arguments })` lets the UI proactively call server tools; each call is a round-trip to the server so the UI should handle latency gracefully. The App class also provides methods for logging, opening URLs, and updating the model's context with structured data.

Adding MCP Apps support to a client: mcp-ui or App Bridge

A client that wants to support MCP Apps has two options: (1) use the `@mcp-ui/client` package, which provides React components for rendering and interacting with MCP Apps views; or (2) build on the SDK's App Bridge module, which handles rendering apps in sandboxed iframes, message passing, tool call proxying, and security policy enforcement — the `basic-host` example in the ext-apps repo shows the integration.

Client declares extension support in _meta clientCapabilities

An MCP client declares support for an extension per-request by including in the request `params._meta` a key `io.modelcontextprotocol/clientCapabilities` whose value is an object with an `extensions` map; e.g. `"_meta": {"io.modelcontextprotocol/clientCapabilities": {"extensions": {"io.modelcontextprotocol/enterprise-managed-authorization": {}}}}`. The request itself is normal JSON-RPC 2.0 with `jsonrpc`, `id`, `method`, `params`.

Client requirements for enterprise-managed authorization

A client supporting Enterprise-Managed Authorization must: (1) declare support in per-request capabilities via _meta; (2) support SSO login against the enterprise IdP and save the Identity Assertion (ID Token or SAML assertion); (3) handle ID-JAGs by exchanging them for MCP access tokens; (4) let administrators configure the enterprise IdP endpoints at organization level rather than per-user; (5) respect token scopes, since enterprise IdP tokens may carry scope restrictions differing from standard MCP authorization, and handle scope errors gracefully.

Client steps for client-credentials auth

To use OAuth client credentials, an MCP client must: (1) declare the extension in per-request capabilities under _meta, (2) obtain an access token from the authorization server using the client credentials grant before connecting to the MCP server, (3) send the token as `Authorization: Bearer <access_token>` on HTTP requests to the MCP server, and (4) implement token refresh, since client-credentials tokens typically have shorter lifetimes than user-delegated tokens.

Client declares oauth-client-credentials in per-request _meta capabilities

An MCP client declares support for the extension in its per-request capabilities, inside params._meta under the key "io.modelcontextprotocol/clientCapabilities" with {"extensions": {"io.modelcontextprotocol/oauth-client-credentials": {}}} on the JSON-RPC 2.0 request.

Extension negotiation: clients declare in _meta clientCapabilities, servers in server/discover

MCP extensions use a negotiation mechanism where clients declare support in the `extensions` field of the `io.modelcontextprotocol/clientCapabilities` object they send in each request's `_meta`, and servers advertise their supported extensions in the capabilities returned by `server/discover`.

Where a client declares extension support: clientCapabilities in request _meta

To add extension support to an MCP client, declare it in the `extensions` field of the `io.modelcontextprotocol/clientCapabilities` object that the client sends in each request's `_meta`, and read the server's `extensions` from the server's `server/discover` response.

Steps to implement an MCP extension in a client

The recommended process for adding extension support to an MCP client is: (1) review the extension specification in the relevant repository (ext-auth for auth extensions, ext-apps for MCP Apps), (2) declare support in the `extensions` field of `io.modelcontextprotocol/clientCapabilities` sent in each request's `_meta` and read the server's `extensions` from its `server/discover` response, (3) implement the extension's protocol requirements, and (4) submit a pull request to update the community-maintained support matrix.

Client capability JSON for Tasks extension

Example client request declaring Tasks support: {"jsonrpc":"2.0","id":1,"method":"...","params":{"_meta":{"io.modelcontextprotocol/clientCapabilities":{"extensions":{"io.modelcontextprotocol/tasks":{}}}}}}. The extension value is an empty object.

Handling input_required tasks mid-flight

If a task moves to `input_required`, the `tasks/get` response includes an `inputRequests` map containing elicitations or other server requests. The client presents them to the user or model and submits answers via `tasks/update` with `inputResponses`. This avoids needing a second connection or unsolicited server-to-client messages.

Clients must handle polymorphic tools/call results

A client that opts into Tasks must be prepared for a supported request such as `tools/call` to return either the standard result or a `CreateTaskResult` with `resultType: "task"`, and branch on `resultType`. Clients opt in once via the extension capability rather than per tool.

Polling loop rules for task clients

After receiving a taskId, call `tasks/get` respecting the server-supplied `pollIntervalMs`, and keep polling until a terminal status (`completed`, `failed`, or `cancelled`). Persist task IDs durably so polling can resume after a client crash or restart.

Required _meta keys on every MCP request

Each client request's params._meta carries three namespaced keys: `io.modelcontextprotocol/protocolVersion` (e.g. "2026-07-28"), `io.modelcontextprotocol/clientInfo` (an object with `name` and `version`, e.g. {"name": "example-client", "version": "1.0.0"}), and `io.modelcontextprotocol/clientCapabilities` (e.g. {"elicitation": {}}). protocolVersion and clientCapabilities are mandatory on every request; clientInfo should normally be included unless the client is configured not to.

server/discover is optional and its result is cacheable

Calling `server/discover` is optional: because every request carries the same `_meta` fields, a client may send any request directly and handle a version error if one comes back. The discovery response is typically cacheable (it carries ttlMs and cacheScope), so the discovery flow does not need to be repeated for every request.

Subscription acknowledgment message

The server acknowledges a subscription with the notification `notifications/subscriptions/acknowledged`, which is the first message carrying that subscription's ID in `_meta.io.modelcontextprotocol/subscriptionId`; no other notification for that subscription is sent before it. Its `notifications` field reflects the subset of the requested filter the server agreed to honor, with unsupported notification types omitted — so clients must check which filters were actually accepted.

Notifications carry subscriptionId and have no id

MCP notifications are JSON-RPC 2.0 notification messages with no `id` field, so no response is expected or sent. Every notification on a subscription stream carries `io.modelcontextprotocol/subscriptionId` in `params._meta`, whose value is the JSON-RPC ID of the `subscriptions/listen` request that opened the stream, letting clients correlate notifications with subscriptions. Example: {"jsonrpc":"2.0","method":"notifications/tools/list_changed","params":{"_meta":{"io.modelcontextprotocol/subscriptionId":4}}}.

Client refresh cycle after a list_changed notification

On receiving `notifications/tools/list_changed`, a client typically reacts by re-sending `tools/list` (with a new JSON-RPC id) and updating its tool registry, then notifying the LLM of the new capabilities if a conversation is active. Pseudo-code pattern: `async with client.listen(tools_list_changed=True) as sub: async for _event in sub: tools_response = await client.list_tools(); app.update_available_tools(client, tools_response.tools)`.

Client advertises extensions in _meta io.modelcontextprotocol/clientCapabilities

Clients advertise extension support inside `_meta["io.modelcontextprotocol/clientCapabilities"]` on each request, under an `extensions` object keyed by extension identifier. Example of a `tools/call` request params: `"_meta": {"io.modelcontextprotocol/protocolVersion": "2026-07-28", "io.modelcontextprotocol/clientCapabilities": {"extensions": {"io.modelcontextprotocol/ui": {"mimeTypes": ["text/html;profile=mcp-app"]}}}, "io.modelcontextprotocol/clientInfo": {"name": "ExampleClient", "version": "1.0.0"}}`.

Client-side completion implementation best practices

Clients SHOULD: debounce rapid completion requests, cache completion results where appropriate, and handle missing or partial results gracefully.

Clients MUST support at least JSON Schema 2020-12

Clients are required to validate schemas according to their declared or default dialect. All clients must support at least JSON Schema 2020-12.

Client response to out-of-band server requests

Clients receiving server-to-client requests with no associated outbound request SHOULD respond with a `-32602` (Invalid Params) error.

Client implementers should expose server instructions to users

MCP clients that support server instructions should expose instructions to users and provide transparency about what servers are injecting into context. Users should be able to see exactly what instructions are being sent to the model in chat logs or similar interfaces.

Client implementers should give users control over server instructions

MCP clients should allow users to review, enable, or disable server instructions to help users customize server usage and minimize conflicts or remove suboptimal instructions.

Client implementers should document their server instructions approach

MCP clients should be clear about how they handle and apply server instructions so users understand the behavior.

Recommended annotation practices for client authors

Client authors should treat annotations from untrusted servers as informational and use them for UX purposes, but keep actual safety guarantees in deterministic controls like network restrictions or sandboxing.

MCP client discovery behavior for authorization server location

MCP clients MUST support both discovery mechanisms. Clients MUST use the resource metadata URL from parsed WWW-Authenticate headers when present; otherwise, they MUST fall back to constructing and requesting well-known URIs in the order listed: first the path-specific well-known URI, then the root well-known URI.

MCP client authorization server metadata discovery interoperability

To handle different issuer URL formats and ensure interoperability with both OAuth 2.0 Authorization Server Metadata and OpenID Connect Discovery 1.0 specifications, MCP clients MUST attempt multiple well-known endpoints when discovering authorization server metadata.

MCP OAuth 2.0 metadata discovery with WWW-Authenticate header

When a client receives an HTTP 401 Unauthorized response from an MCP server, it MUST check for a WWW-Authenticate header. If the header includes a resource_metadata parameter, the client MUST use the URL from that parameter to locate the OAuth 2.0 protected resource metadata.

Give your agent this brain