Skip to content

Commit ce5a1c2

Browse files
committed
feat: complete MCP parity slice and docker validation
1 parent 1eed8d9 commit ce5a1c2

23 files changed

Lines changed: 2873 additions & 286 deletions

Dockerfile.demo

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -34,7 +34,7 @@ RUN bash -lc 'set -euo pipefail; \
3434
-DCMAKE_VERBOSE_MAKEFILE=ON \
3535
-DCMAKE_CXX_FLAGS="-Wfatal-errors -fdiagnostics-color=always" \
3636
-DCMAKE_C_FLAGS="-Wfatal-errors -fdiagnostics-color=always"; \
37-
cmake --build build --parallel 1 --'
37+
cmake --build build --parallel "${CMAKE_BUILD_PARALLEL_LEVEL:-6}" --'
3838

3939
# 1b) Test stage: run unit tests inside the build environment
4040
FROM build AS test
@@ -58,7 +58,9 @@ ENV CTEST_PARALLEL_LEVEL=4
5858
# mcp-cpp-build \
5959
# bash -lc 'cd /src && ctest --test-dir build -R TransportDemo.Run -VV --output-on-failure'
6060
# Docker build stages cannot mount host devices; SHM demos may fail here without a host-IPC setup.
61-
RUN ctest --test-dir build -VV --progress --timeout 180
61+
# Architecture checks are the first gate before the full suite.
62+
RUN ctest --test-dir build -VV --progress --timeout 180 -R "^Architecture" \
63+
&& ctest --test-dir build -VV --progress --timeout 180
6264

6365
# 2) Demo runtime stage
6466
FROM ubuntu:24.04 AS demo

README.md

Lines changed: 22 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -27,22 +27,23 @@ docker run --rm --name mcp-cpp-demo --mount type=bind,src=$(pwd),dst=/work mcp-c
2727

2828
- Windows (PowerShell via WSL2 Ubuntu):
2929
```powershell
30-
wsl -d Ubuntu -- bash -lc "cd /mnt/c/Work/mcp-cpp && docker buildx build -f Dockerfile.demo --target test --progress=plain --pull --load -t mcp-cpp-test ."
31-
wsl -d Ubuntu -- bash -lc "cd /mnt/c/Work/mcp-cpp && docker buildx build -f Dockerfile.demo --target demo --progress=plain --pull --load -t mcp-cpp-demo ."
32-
wsl -d Ubuntu -- bash -lc "docker run --rm --name mcp-cpp-demo --mount type=bind,src=/mnt/c/Work/mcp-cpp,dst=/work mcp-cpp-demo"
30+
wsl -d Ubuntu -- bash -lc "cd /mnt/c/<path-to-repo>/mcp-cpp && docker buildx build -f Dockerfile.demo --target test --progress=plain --pull --load -t mcp-cpp-test ."
31+
wsl -d Ubuntu -- bash -lc "cd /mnt/c/<path-to-repo>/mcp-cpp && docker buildx build -f Dockerfile.demo --target demo --progress=plain --pull --load -t mcp-cpp-demo ."
32+
wsl -d Ubuntu -- bash -lc "docker run --rm --name mcp-cpp-demo --mount type=bind,src=/mnt/c/<path-to-repo>/mcp-cpp,dst=/work mcp-cpp-demo"
3333
```
3434

3535
## API Reference
3636

3737
This section summarizes the primary SDK interfaces and feature-specific APIs.
3838

39-
- Client API header: [include/mcp/Client.h](c:/Work/mcp-cpp/include/mcp/Client.h)
40-
- Server API header: [include/mcp/Server.h](c:/Work/mcp-cpp/include/mcp/Server.h)
41-
- Transport headers: [include/mcp/Transport.h](c:/Work/mcp-cpp/include/mcp/Transport.h),
42-
[include/mcp/InMemoryTransport.hpp](c:/Work/mcp-cpp/include/mcp/InMemoryTransport.hpp),
43-
[include/mcp/StdioTransport.hpp](c:/Work/mcp-cpp/include/mcp/StdioTransport.hpp),
44-
[include/mcp/SharedMemoryTransport.hpp](c:/Work/mcp-cpp/include/mcp/SharedMemoryTransport.hpp),
45-
[include/mcp/HTTPTransport.hpp](c:/Work/mcp-cpp/include/mcp/HTTPTransport.hpp)
39+
- Client API header: [include/mcp/Client.h](./include/mcp/Client.h)
40+
- Server API header: [include/mcp/Server.h](./include/mcp/Server.h)
41+
- Transport headers: [include/mcp/Transport.h](./include/mcp/Transport.h),
42+
[include/mcp/InMemoryTransport.hpp](./include/mcp/InMemoryTransport.hpp),
43+
[include/mcp/StdioTransport.hpp](./include/mcp/StdioTransport.hpp),
44+
[include/mcp/SharedMemoryTransport.hpp](./include/mcp/SharedMemoryTransport.hpp),
45+
[include/mcp/HTTPTransport.hpp](./include/mcp/HTTPTransport.hpp),
46+
[include/mcp/HTTPServer.hpp](./include/mcp/HTTPServer.hpp)
4647

4748
### Client API (IClient / Client)
4849

@@ -54,6 +55,8 @@ This section summarizes the primary SDK interfaces and feature-specific APIs.
5455
- Subscriptions: `SubscribeResources()`, `SubscribeResources(optional<string> uri)`,
5556
`UnsubscribeResources()`, `UnsubscribeResources(optional<string> uri)`
5657
- Prompts: `ListPrompts()`, `ListPromptsPaged(cursor, limit)`, `GetPrompt(name, args)`
58+
- Utilities: `Complete(params)`, `Ping()`
59+
- Roots and elicitation: `SetRootsListHandler(handler)`, `NotifyRootsListChanged()`, `SetElicitationHandler(handler)`
5760
- Sampling (server → client): `SetSamplingHandler(handler)`
5861
- Notifications & progress: `SetNotificationHandler(method, handler)`, `RemoveNotificationHandler(method)`,
5962
`SetProgressHandler(handler)`, `SetErrorHandler(handler)`
@@ -74,7 +77,8 @@ ClientCapabilities caps; auto serverCaps = client->Initialize(info, caps).get();
7477
- Resources: `RegisterResource(uri, handler)`, `UnregisterResource(uri)`, `ListResources()`, `ReadResource(uri)`
7578
- Resource templates: `RegisterResourceTemplate(t)`, `UnregisterResourceTemplate(template)`, `ListResourceTemplates()`
7679
- Prompts: `RegisterPrompt(name, handler)`, `UnregisterPrompt(name)`, `ListPrompts()`, `GetPrompt(name, args)`
77-
- Sampling: `SetSamplingHandler(handler)`, `RequestCreateMessage(params)`
80+
- Utilities: `SetCompletionHandler(handler)`, `RequestCreateMessage(params)`, `RequestElicitation(request)`, `RequestRootsList()`, `Ping()`
81+
- Sampling: `SetSamplingHandler(handler)`
7882
- Keepalive: `SetKeepaliveIntervalMs(intervalMs)`
7983
- Logging: `LogToClient(level, message, data)`
8084
- Notifications: `NotifyResourcesListChanged()`, `NotifyResourceUpdated(uri)`, `NotifyToolsListChanged()`, `NotifyPromptsListChanged()`
@@ -87,10 +91,11 @@ ClientCapabilities caps; auto serverCaps = client->Initialize(info, caps).get();
8791
- Messaging: `SendRequest(req)`, `SendNotification(note)`
8892
- Handlers: `SetNotificationHandler(h)`, `SetErrorHandler(h)`, `SetRequestHandler(h)`
8993
- Implementations:
90-
- In-memory: [include/mcp/InMemoryTransport.hpp](c:/Work/mcp-cpp/include/mcp/InMemoryTransport.hpp)
91-
- Stdio: [include/mcp/StdioTransport.hpp](c:/Work/mcp-cpp/include/mcp/StdioTransport.hpp)
92-
- Shared Memory: [include/mcp/SharedMemoryTransport.hpp](c:/Work/mcp-cpp/include/mcp/SharedMemoryTransport.hpp)
93-
- HTTP client: [include/mcp/HTTPTransport.hpp](c:/Work/mcp-cpp/include/mcp/HTTPTransport.hpp)
94+
- In-memory: [include/mcp/InMemoryTransport.hpp](./include/mcp/InMemoryTransport.hpp)
95+
- Stdio: [include/mcp/StdioTransport.hpp](./include/mcp/StdioTransport.hpp)
96+
- Shared Memory: [include/mcp/SharedMemoryTransport.hpp](./include/mcp/SharedMemoryTransport.hpp)
97+
- HTTP client: [include/mcp/HTTPTransport.hpp](./include/mcp/HTTPTransport.hpp)
98+
- HTTP server/acceptor: [include/mcp/HTTPServer.hpp](./include/mcp/HTTPServer.hpp)
9499
95100
#### HTTP Authentication (Bearer/OAuth2)
96101
@@ -207,8 +212,8 @@ Tests use GoogleTest via CMake FetchContent (build-time only). See [BUILD+TEST.M
207212

208213
Build and run the client/server demo using stdio transport (WSL2 PowerShell example below):
209214
```powershell
210-
wsl -d Ubuntu -- bash -lc "cd /mnt/c/Work/mcp-cpp && docker buildx build -f Dockerfile.demo --target demo --progress=plain --pull --load -t mcp-cpp-demo ."
211-
wsl -d Ubuntu -- bash -lc "docker run --rm --name mcp-cpp-demo --mount type=bind,src=/mnt/c/Work/mcp-cpp,dst=/work mcp-cpp-demo"
215+
wsl -d Ubuntu -- bash -lc "cd /mnt/c/<path-to-repo>/mcp-cpp && docker buildx build -f Dockerfile.demo --target demo --progress=plain --pull --load -t mcp-cpp-demo ."
216+
wsl -d Ubuntu -- bash -lc "docker run --rm --name mcp-cpp-demo --mount type=bind,src=/mnt/c/<path-to-repo>/mcp-cpp,dst=/work mcp-cpp-demo"
212217
```
213218

214219
## Examples

docs/parity-matrix.md

Lines changed: 24 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,12 @@ This matrix tracks the MCP C++ SDK feature coverage relative to the MCP spec.
2929
- Get prompt: Implemented (returns `PromptResult.messages`)
3030
- List-changed notifications: Implemented
3131

32+
- Utilities
33+
- `ping`: Implemented
34+
- `completion/complete`: Implemented
35+
- `roots/list` and `notifications/roots/list_changed`: Implemented
36+
- `elicitation/create`: Implemented
37+
3238
- Sampling
3339
- Client-registered sampling handler: Implemented (client API)
3440
- Server-initiated `sampling/createMessage`: Implemented (`tests/test_server_initiated_sampling.cpp`)
@@ -56,6 +62,7 @@ This matrix tracks the MCP C++ SDK feature coverage relative to the MCP spec.
5662
- Transports
5763
- InMemory: Implemented (unit-test transport)
5864
- Stdio: Implemented (demo integration test in CTest)
65+
- HTTP streamable transport/session lifecycle: Implemented (`tests/test_http_streamable.cpp`)
5966
- Stdio hardening negative tests: Implemented (idle read timeout, write queue overflow, write timeout, bad Content-Length)
6067

6168
- CI
@@ -69,10 +76,10 @@ Notes:
6976

7077
---
7178

72-
## Detailed Parity by Spec Area (MCP 2025-06-18)
79+
## Detailed Parity by Spec Area (MCP 2025-11-25)
7380

7481
- **[Protocol Version]**
75-
- Version constant: `PROTOCOL_VERSION = "2025-06-18"`.
82+
- Version constant: `PROTOCOL_VERSION = "2025-11-25"`.
7683
- Source: [include/mcp/Protocol.h](../include/mcp/Protocol.h)
7784

7885
- **[Initialize Handshake & Post-Init Notifications]**
@@ -81,9 +88,10 @@ Notes:
8188
- Tests: [tests/test_initialize_notifications.cpp](../tests/test_initialize_notifications.cpp)
8289

8390
- **[Capabilities Advertisement]**
84-
- `ServerCapabilities` includes `tools`, `resources`, `prompts`, `sampling`, `logging`, and `experimental` map.
91+
- `ServerCapabilities` includes `tools`, `resources`, `prompts`, `sampling`, `completions`, `logging`, and `experimental` map.
92+
- `ClientCapabilities` includes `roots`, `sampling`, `elicitation`, `experimental`, and `extensions`.
8593
- Source: [include/mcp/Protocol.h](../include/mcp/Protocol.h)
86-
- Logging capability explicitly advertised; parsed by client.
94+
- Logging and completion capabilities are explicitly advertised; roots and elicitation are negotiated from the client.
8795
- Tests: [tests/test_capabilities_logging.cpp](../tests/test_capabilities_logging.cpp)
8896

8997
- **[Tools]**
@@ -106,6 +114,14 @@ Notes:
106114
- Sources: [include/mcp/Protocol.h](../include/mcp/Protocol.h)
107115
- Tests: [tests/test_prompts_get.cpp](../tests/test_prompts_get.cpp), [tests/test_client_paging.cpp](../tests/test_client_paging.cpp)
108116

117+
- **[Utilities: Ping, Completion, Roots, Elicitation]**
118+
- `ping`: Implemented for client->server and server->client flows.
119+
- `completion/complete`: Implemented with strict validation and typed result parsing.
120+
- `roots/list` + `notifications/roots/list_changed`: Implemented.
121+
- `elicitation/create`: Implemented with strict validation and typed request/result parsing.
122+
- Sources: [include/mcp/Protocol.h](../include/mcp/Protocol.h), [src/mcp/Client.cpp](../src/mcp/Client.cpp), [src/mcp/Server.cpp](../src/mcp/Server.cpp)
123+
- Tests: [tests/test_completion_ping.cpp](../tests/test_completion_ping.cpp), [tests/test_roots.cpp](../tests/test_roots.cpp), [tests/test_elicitation.cpp](../tests/test_elicitation.cpp)
124+
109125
- **[Sampling (Server → Client)]**
110126
- Server-initiated `sampling/createMessage` with optional cancelable handler on client.
111127
- Cancellation via `notifications/cancelled` supported end-to-end.
@@ -146,14 +162,18 @@ Notes:
146162
- **[Validation (Opt‑In)]**
147163
- Toggle Off/Strict for runtime shape checks; docs describe API.
148164
- Sources: [docs/api/validation.md](./api/validation.md)
165+
- Strict validators accept richer non-text content blocks, structured tool outputs, and richer prompt/resource payloads.
166+
- Tests: [tests/test_content_parity.cpp](../tests/test_content_parity.cpp), [tests/test_validation_strict.cpp](../tests/test_validation_strict.cpp)
149167

150168
- **[Transports]**
151169
- InMemory: Implemented — [include/mcp/InMemoryTransport.hpp](../include/mcp/InMemoryTransport.hpp)
152170
- Stdio: Implemented — [include/mcp/StdioTransport.hpp](../include/mcp/StdioTransport.hpp), hardening tests driven by scripts.
153171
- Shared Memory: Implemented — [include/mcp/SharedMemoryTransport.hpp](../include/mcp/SharedMemoryTransport.hpp)
154172
- HTTP client: Implemented — [include/mcp/HTTPTransport.hpp](../include/mcp/HTTPTransport.hpp)
155173
- HTTP server acceptor: Implemented — [include/mcp/HTTPServer.hpp](../include/mcp/HTTPServer.hpp)
174+
- Streamable HTTP (`POST` endpoint + `GET` SSE stream + session lifecycle): Implemented.
156175
- Integration demo test: `TransportDemo.Run` — defined in [tests/CMakeLists.txt](../tests/CMakeLists.txt)
176+
- Streamable HTTP tests: [tests/test_http_streamable.cpp](../tests/test_http_streamable.cpp)
157177

158178
- **[OAuth]**
159179
- Status: Implemented

include/mcp/Client.h

Lines changed: 33 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
//==========================================================================================================
22
// SPDX-License-Identifier: MIT
33
// Copyright (c) 2025 Vinny Parla
4-
// File: Client.h
4+
// File: include/mcp/Client.h
55
// Purpose: MCP client interface - COM-style abstraction for MCP client operations
66
//==========================================================================================================
77

@@ -236,6 +236,24 @@ class IClient {
236236
virtual std::future<JSONValue> GetPrompt(const std::string& name,
237237
const JSONValue& arguments) = 0;
238238

239+
////////////////////////////////////////// Completion ///////////////////////////////////////////////
240+
//==========================================================================================================
241+
// Requests argument completions from the server.
242+
// Args:
243+
// params: Completion reference and argument context.
244+
// Returns:
245+
// Future with typed completion values/metadata.
246+
//==========================================================================================================
247+
virtual std::future<CompletionResult> Complete(const CompleteParams& params) = 0;
248+
249+
////////////////////////////////////////////// Ping //////////////////////////////////////////////////////
250+
//==========================================================================================================
251+
// Pings the connected server using the MCP ping utility method.
252+
// Returns:
253+
// Future that completes once a successful ping response is received.
254+
//==========================================================================================================
255+
virtual std::future<void> Ping() = 0;
256+
239257
/////////////////////////////////////////// Roots operations ////////////////////////////////////////////////
240258
//==========================================================================================================
241259
// Registers a handler for server-initiated roots/list requests.
@@ -282,6 +300,17 @@ class IClient {
282300
std::stop_token st)>;
283301
virtual void SetSamplingHandlerCancelable(SamplingHandlerCancelable handler) = 0;
284302

303+
///////////////////////////////////////////// Elicitation /////////////////////////////////////////////////
304+
//==========================================================================================================
305+
// Registers a handler to service server-initiated elicitation/create requests.
306+
// Args:
307+
// handler: Async callback returning accept/decline/cancel plus optional content.
308+
// Returns:
309+
// (none)
310+
//==========================================================================================================
311+
using ElicitationHandler = std::function<std::future<ElicitationResult>(const ElicitationRequest&)>;
312+
virtual void SetElicitationHandler(ElicitationHandler handler) = 0;
313+
285314
////////////////////////////////////////// Notification handlers ///////////////////////////////////////////
286315
//==========================================================================================================
287316
// Registers a notification handler for a specific method name.
@@ -399,12 +428,15 @@ class Client : public IClient {
399428
const std::optional<int>& limit) override;
400429
std::future<JSONValue> GetPrompt(const std::string& name,
401430
const JSONValue& arguments) override;
431+
std::future<CompletionResult> Complete(const CompleteParams& params) override;
432+
std::future<void> Ping() override;
402433

403434
void SetRootsListHandler(RootsListHandler handler) override;
404435
std::future<void> NotifyRootsListChanged() override;
405436

406437
void SetSamplingHandler(SamplingHandler handler) override;
407438
void SetSamplingHandlerCancelable(SamplingHandlerCancelable handler) override;
439+
void SetElicitationHandler(ElicitationHandler handler) override;
408440

409441
void SetNotificationHandler(const std::string& method, NotificationHandler handler) override;
410442
void RemoveNotificationHandler(const std::string& method) override;

include/mcp/HTTPServer.hpp

Lines changed: 17 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
//==========================================================================================================
22
// SPDX-License-Identifier: MIT
33
// Copyright (c) 2025 Vinny Parla
4-
// File: HTTPServer.hpp
4+
// File: include/mcp/HTTPServer.hpp
55
// Purpose: Coroutine-based HTTP/HTTPS JSON-RPC server using Boost.Beast (TLS 1.3 only for HTTPS)
66
//==========================================================================================================
77

@@ -17,23 +17,27 @@
1717

1818
namespace mcp {
1919

20-
// Note: HTTPServer implements the server-side acceptor role (ITransportAcceptor)
21-
class HTTPServer : public ITransportAcceptor {
20+
// Note: HTTPServer implements both the server-side acceptor role and the single-session ITransport role.
21+
class HTTPServer : public ITransportAcceptor, public ITransport {
2222
public:
2323
//==========================================================================================================
2424
// Options
2525
// Purpose: Configuration for bind address/port, JSON-RPC paths, and TLS files.
2626
// Fields:
2727
// address: Bind address (default: 0.0.0.0)
2828
// port: Listen port (default: 9443)
29-
// rpcPath: JSON-RPC request path
30-
// notifyPath: JSON-RPC notification path
29+
// endpointPath: Streamable HTTP endpoint path (single POST + GET SSE endpoint). Empty keeps legacy mode.
30+
// streamPath: Optional override for GET SSE. Defaults to endpointPath when empty.
31+
// rpcPath: Legacy JSON-RPC request path
32+
// notifyPath: Legacy JSON-RPC notification path
3133
// scheme: "http" or "https" (TLS 1.3 only for https)
3234
// certFile/keyFile: PEM files required when scheme == https
3335
//==========================================================================================================
3436
struct Options {
3537
std::string address{"0.0.0.0"};
3638
std::string port{"9443"};
39+
std::string endpointPath;
40+
std::string streamPath;
3741
std::string rpcPath{"/mcp/rpc"};
3842
std::string notifyPath{"/mcp/notify"};
3943
std::string scheme{"https"}; // "http" or "https"
@@ -58,6 +62,13 @@ namespace mcp {
5862
//==========================================================================================================
5963
std::future<void> Stop() override;
6064

65+
////////////////////////////////////////// ITransport //////////////////////////////////////////
66+
std::future<void> Close() override;
67+
bool IsConnected() const override;
68+
std::string GetSessionId() const override;
69+
std::future<std::unique_ptr<JSONRPCResponse>> SendRequest(std::unique_ptr<JSONRPCRequest> request) override;
70+
std::future<void> SendNotification(std::unique_ptr<JSONRPCNotification> notification) override;
71+
6172
//==========================================================================================================
6273
// Sets the request handler (JSON-RPC request -> response).
6374
// Args:
@@ -109,6 +120,7 @@ namespace mcp {
109120
// string. The configuration format is uri format, intentionally simple and stable:
110121
// - "http://<address>:<port>" (e.g., http://127.0.0.1:0)
111122
// - "https://<address>:<port>?cert=<pem>&key=<pem>"
123+
// - optional query params: endpointPath, streamPath, rpcPath, notifyPath
112124
// Unknown parameters are ignored. If scheme is omitted, defaults to http.
113125
//==========================================================================================================
114126
class HTTPServerFactory : public ITransportAcceptorFactory {

0 commit comments

Comments
 (0)