Skip to content

ArcadeAI/mcpp

Folders and files

NameName
Last commit message
Last commit date

Latest commit

Β 

History

7 Commits
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 

Repository files navigation

mcpp

A modern C++20 client library for the Model Context Protocol (MCP).

Features

  • Full MCP Protocol Support - Tools, resources, prompts, completions, subscriptions
  • Multiple Transports - Process (stdio), HTTP with SSE
  • Sync & Async APIs - Blocking McpClient and coroutine-based AsyncMcpClient
  • Production Ready - Circuit breaker, URL validation, session management, retry logic
  • Modern C++ - C++20 coroutines, concepts, std::expected-style error handling
  • Comprehensive Tests - 495+ tests covering unit, integration, and real server scenarios

Architecture Overview

β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
β”‚                            Your Application                                  β”‚
β”œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€
β”‚                                                                              β”‚
β”‚   β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”    β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”       β”‚
β”‚   β”‚        McpClient            β”‚    β”‚      AsyncMcpClient         β”‚       β”‚
β”‚   β”‚      (synchronous)          β”‚    β”‚      (coroutines)           β”‚       β”‚
β”‚   β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜    β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜       β”‚
β”‚                  β”‚                                   β”‚                       β”‚
β”‚   β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”΄β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”΄β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”      β”‚
β”‚   β”‚                        Transport Layer                           β”‚      β”‚
β”‚   β”‚  β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”        β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”         β”‚      β”‚
β”‚   β”‚  β”‚  ProcessTransport   β”‚        β”‚    HttpTransport    β”‚         β”‚      β”‚
β”‚   β”‚  β”‚  (stdio to subprocess)       β”‚   (HTTP + SSE)      β”‚         β”‚      β”‚
β”‚   β”‚  β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜        β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜         β”‚      β”‚
β”‚   β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜      β”‚
β”‚                                                                              β”‚
β”‚   β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”      β”‚
β”‚   β”‚                      Resilience & Security                        β”‚      β”‚
β”‚   β”‚  β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”  β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”  β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”    β”‚      β”‚
β”‚   β”‚  β”‚Circuit Breakerβ”‚  β”‚ URL Validator β”‚  β”‚ Session Manager   β”‚    β”‚      β”‚
β”‚   β”‚  β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜  β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜  β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜    β”‚      β”‚
β”‚   β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜      β”‚
β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜
                                     β”‚
                                     β–Ό
β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
β”‚                              MCP Server                                      β”‚
β”‚  (filesystem, GitHub, Slack, custom AI agents, etc.)                        β”‚
β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜

Quick Start

Requirements

  • C++20 compiler (GCC 11+, Clang 14+, MSVC 2022+)
  • CMake 3.20+

Building

git clone https://github.com/your-org/mcpp.git
cd mcpp
mkdir build && cd build
cmake ..
make -j$(nproc)

Basic Usage

#include <mcpp/transport/process_transport.hpp>
#include <mcpp/client/mcp_client.hpp>

using namespace mcpp;

int main() {
    // Connect to an MCP server via stdio
    ProcessTransportConfig config;
    config.command = "npx";
    config.args = {"-y", "@modelcontextprotocol/server-filesystem", "/tmp"};
    
    auto transport = std::make_unique<ProcessTransport>(config);
    transport->start();
    
    McpClient client(std::move(transport));
    client.connect();
    client.initialize();
    
    // List available tools
    auto tools = client.list_tools();
    if (tools) {
        for (const auto& tool : tools->tools) {
            std::cout << "Tool: " << tool.name << "\n";
        }
    }
    
    // Call a tool
    auto result = client.call_tool("read_file", {{"path", "/tmp/test.txt"}});
    if (result) {
        for (const auto& content : result->content) {
            if (content.type == "text") {
                std::cout << content.text.value_or("") << "\n";
            }
        }
    }
    
    client.disconnect();
    return 0;
}

Request/Response Flow

β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”                                    β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
β”‚   Client   β”‚                                    β”‚   Server   β”‚
β””β”€β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”€β”˜                                    β””β”€β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”€β”˜
      β”‚                                                 β”‚
      β”‚  ──────────── initialize ──────────────────►   β”‚
      β”‚  ◄─────────── InitializeResult ────────────    β”‚
      β”‚                                                 β”‚
      β”‚  ──────────── notifications/initialized ───►   β”‚
      β”‚                                                 β”‚
      β”‚  ──────────── tools/list ──────────────────►   β”‚
      β”‚  ◄─────────── ListToolsResult ─────────────    β”‚
      β”‚                                                 β”‚
      β”‚  ──────────── tools/call ──────────────────►   β”‚
      β”‚  ◄─────────── CallToolResult ──────────────    β”‚
      β”‚                                                 β”‚
      β”‚  ◄─────────── notifications/progress ──────    β”‚  (optional)
      β”‚                                                 β”‚
      β”‚  ──────────── ping ────────────────────────►   β”‚
      β”‚  ◄─────────── pong ────────────────────────    β”‚
      β”‚                                                 β”‚
      β–Ό                                                 β–Ό

Examples

See the examples/ directory for complete working examples:

Example Description
01_basic_sync Synchronous client basics
02_basic_async Async/coroutine client
03_filesystem_server File operations
04_http_transport Remote HTTP servers
05_custom_handlers Elicitation, sampling, roots
06_circuit_breaker Resilience patterns
07_arcade_toolkit Arcade AI integration

MCP Protocol Coverage

Feature Status Description
Initialize/Shutdown βœ… Session lifecycle
Tools (list, call) βœ… Execute server-provided tools
Resources (list, read, subscribe) βœ… Access server resources
Resource Templates βœ… URI template discovery
Prompts (list, get) βœ… Prompt templates
Completions βœ… Autocompletion API
Ping βœ… Health checks
Cancellation βœ… Cancel in-progress operations
Progress Notifications βœ… Track long-running ops
Logging Control βœ… Server log level
Elicitation Handler βœ… User input requests
Sampling Handler βœ… LLM completion requests
Roots Handler βœ… Filesystem root exposure

Transports

ProcessTransport (stdio)

β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”     stdin      β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
β”‚    Client    │───────────────►│    Server    β”‚
β”‚              │◄───────────────│   (process)  β”‚
β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜     stdout     β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜
ProcessTransportConfig config;
config.command = "python";
config.args = {"-m", "my_mcp_server"};
config.use_content_length_framing = false;  // or true for framed mode
config.working_directory = "/path/to/server";
config.environment = {{"API_KEY", "secret"}};

HttpTransport (HTTP + SSE)

β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”   POST /message   β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
β”‚    Client    │──────────────────►│    Server    β”‚
β”‚              │◄──────────────────│    (HTTP)    β”‚
β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜   SSE /sse        β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜
HttpClientConfig config;
config.base_url = "https://api.example.com/mcp/";
config.headers = {{"Authorization", "Bearer token"}};
config.timeout = std::chrono::seconds(30);

Error Handling

Uses tl::expected for explicit error handling without exceptions:

auto result = client.call_tool("my_tool", args);
if (!result) {
    switch (result.error().code) {
        case ClientErrorCode::NotConnected:
            // Handle connection error
            break;
        case ClientErrorCode::TransportError:
            // Handle transport failure
            break;
        case ClientErrorCode::ProtocolError:
            // Handle protocol error
            break;
    }
    return;
}
// Use result.value()

Circuit Breaker

     CLOSED ──────► OPEN ──────► HALF-OPEN
        β–²            β”‚               β”‚
        β”‚            β”‚   success     β”‚
        β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”΄β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜
              failure: back to OPEN
McpClientConfig config;
config.enable_circuit_breaker = true;
config.circuit_breaker.failure_threshold = 5;
config.circuit_breaker.recovery_timeout = std::chrono::seconds(30);

McpClient client(std::move(transport), config);

if (client.is_circuit_open()) {
    // Fast-fail, don't wait for timeout
}

CLI Tool

# List tools
./mcpp-cli -c 'npx' -a '-y' -a '@modelcontextprotocol/server-filesystem' -a '/tmp' --list-tools

# Call a tool
./mcpp-cli -c 'python' -a 'server.py' --call-tool read_file --tool-args '{"path":"/tmp/test.txt"}'

# Interactive mode
./mcpp-cli -c 'node' -a 'server.js' --interactive

# JSON output
./mcpp-cli -c 'python' -a 'server.py' --list-tools --json

Project Structure

mcpp/
β”œβ”€β”€ include/mcpp/
β”‚   β”œβ”€β”€ protocol/      # MCP types and JSON serialization
β”‚   β”œβ”€β”€ transport/     # Transport layer (Process, HTTP/SSE)
β”‚   β”œβ”€β”€ client/        # Synchronous McpClient
β”‚   β”œβ”€β”€ async/         # Asynchronous AsyncMcpClient
β”‚   β”œβ”€β”€ resilience/    # Circuit breaker
β”‚   β”œβ”€β”€ security/      # URL validation
β”‚   └── log/           # Logging interfaces
β”œβ”€β”€ src/               # Implementation files
β”œβ”€β”€ tests/             # Test suite (495+ tests)
β”œβ”€β”€ tools/mcpp-cli/    # Command-line interface
└── examples/          # Usage examples

Dependencies

All fetched automatically via CMake FetchContent:

Running Tests

cd build
ctest --output-on-failure

# Or directly
./mcpp_tests                    # All tests
./mcpp_tests "[mcp_client]"     # Client tests
./mcpp_tests "[real-server]"    # Integration tests

License

MIT License - see LICENSE file.

About

No description, website, or topics provided.

Resources

License

Stars

Watchers

Forks

Releases

No releases published

Packages

No packages published