Source: docs/mcp-api.md

MCP client API

This document describes the reusable C++ Model Context Protocol (MCP) client library in this repository. It covers Streamable HTTP clients and the modern-only local stdio client.

For the std_slop mcp ... command-line workflow, see mcp-slop-userguide.md.

Scope

The outbound client supports Streamable HTTP servers and local stdio subprocesses. Stdio supports modern MCP 2026-07-28 only; classic revision selection remains available over HTTP. The deprecated HTTP+SSE transport is not supported. Inbound stdio server support is a separate package.

Core package:

mcp/
  protocol.h, types.h          shared protocol definitions and public data types
  json_rpc.*                   shared JSON-RPC build/parse helpers
  json_schema.*                JSON Schema validation
  client/
    client.h                   high-level client connection helper
    session.h                  typed MCP client session API
    streamable_http_transport.h
    stdio_transport.h, modern_stdio.h
    oauth_discovery.h, authorization.h, oauth_client.h
    token_store.h, registry.h, runtime.h

The public API uses absl::Status and absl::StatusOr<T> for fallible operations.

Local stdio client

ConnectStdioMcp(StdioTransportOptions, ClientOptions) starts the configured executable with a direct argument vector, then uses modern discovery and the modern client. It does not start a shell, expand command or argument strings, use HTTP authentication, or fall back to the classic revision. The child inherits the agent's current directory, environment, and operating-system permissions. Use only trusted executables. No HttpClient is required.

#include <utility>

slop::mcp::StdioTransportOptions process;
process.command = "/absolute/path/to/mcp-server";
process.args = {"--root", "/work/project"};

slop::mcp::ClientOptions options;
options.client_info.name = "my-client";
options.client_info.version = "1.0";
auto client = slop::mcp::ConnectStdioMcp(std::move(process), options);

ConnectStdioMcp rejects SelectionPolicy::kClassicOnly. The stdio exchange validates response IDs, bounds messages, serializes one outstanding request per server, and closes the child on timeout or protocol failure.

Classic methods:

  • ping
  • tools/list
  • tools/call
  • resources/list
  • resources/read
  • prompts/list
  • prompts/get

Classic server notification parsing:

  • progress notifications
  • logging notifications
  • tools/resources/prompts list-change notifications

Unsupported or host-policy dependent features:

  • classic stdio transport
  • deprecated HTTP+SSE transport
  • automatic sampling approval
  • automatic roots approval
  • automatic elicitation approval
  • complete validation of every JSON Schema feature (the modern client validates its supported subset)

Connect with automatic protocol selection

Use ConnectMcp() for normal operation. It returns a common Client interface and applies the selection policy described above.

#include "core/http_client.h"
#include "mcp/client/client.h"
#include "mcp/types.h"

slop::mcp::StreamableHttpConfig config;
config.endpoint_url = "https://example.com/mcp";

slop::mcp::ClientOptions options;
options.selection = slop::mcp::SelectionPolicy::kPreferLatest;
options.client_info.name = "my-client";
options.client_info.version = "1.0";

slop::HttpClient http_client;
auto client = slop::mcp::ConnectMcp(config, options, &http_client);
if (!client.ok()) return client.status();

auto tools = (*client)->ListTools();
if (!tools.ok()) return tools.status();

Call (*client)->revision() to check which protocol revision was selected. Client also exposes CallTool() and ContinueToolCall(); continuations require modern MCP.

Bearer token clients

For static bearer authentication, put the token into StreamableHttpConfig::bearer_token before connection:

slop::mcp::StreamableHttpConfig config;
config.endpoint_url = "https://example.com/mcp";
config.bearer_token = "YOUR_TOKEN";

The transport injects:

Authorization: Bearer YOUR_TOKEN

Do not log token values. If you persist tokens with SaveOAuthTokens(), the token store rejects access tokens with HTTP header control characters so they cannot create malformed Authorization headers.

Error model

Use status codes to distinguish failures:

  • malformed JSON-RPC or response shape: InvalidArgument
  • unsupported MCP protocol version: Unimplemented
  • HTTP 401: Unauthenticated
  • HTTP 403: PermissionDenied
  • other HTTP failure: Unavailable
  • no queued response available: Unavailable
  • closed or uninitialized session: FailedPrecondition

Callers should add host-specific remediation text at their boundary. For example, std::slop adds messages that tell users to run std_slop mcp add ... --auth bearer --token ..., std_slop mcp oauth-login, or std_slop mcp oauth-refresh.

Security notes

  • Treat all server messages as untrusted.
  • Validate JSON-RPC shape before session side effects.
  • Validate tool result content before converting it to host output.
  • Do not execute server-provided data.
  • Do not log bearer tokens or Authorization headers.
  • Do not fetch server-provided icons with credentials unless the host policy allows it.
  • Require explicit host callbacks for sampling, roots, and elicitation.
  • Roots are not a security boundary; use OS sandboxing or file permissions for enforcement.

Content is generated from the repository sources listed above. See the source files for the complete reference.