Skip to content

Commit 3a7d873

Browse files
committed
feat: complete tasks and icon metadata parity
1 parent ae2e7e1 commit 3a7d873

16 files changed

Lines changed: 3463 additions & 231 deletions

README.md

Lines changed: 7 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -49,7 +49,8 @@ This section summarizes the primary SDK interfaces and feature-specific APIs.
4949

5050
- Connection: `Connect(transport)`, `Disconnect()`, `IsConnected()`
5151
- Initialize: `Initialize(clientInfo, capabilities)``ServerCapabilities`
52-
- Tools: `ListTools()`, `ListToolsPaged(cursor, limit)`, `CallTool(name, args)`
52+
- Tools: `ListTools()`, `ListToolsPaged(cursor, limit)`, `CallTool(name, args)`, `CallToolTask(name, args, task)`
53+
- Tasks: `GetTask(taskId)`, `ListTasks()`, `ListTasksPaged(cursor, limit)`, `GetTaskResult(taskId)`, `CancelTask(taskId)`
5354
- Resources: `ListResources()`, `ListResourcesPaged(cursor, limit)`, `ReadResource(uri)`
5455
- Resource templates: `ListResourceTemplates()`, `ListResourceTemplatesPaged(cursor, limit)`
5556
- Subscriptions: `SubscribeResources()`, `SubscribeResources(optional<string> uri)`,
@@ -73,11 +74,12 @@ ClientCapabilities caps; auto serverCaps = client->Initialize(info, caps).get();
7374
7475
- Lifecycle: `Start(transport)`, `Stop()`, `IsRunning()`
7576
- Initialize: `HandleInitialize(clientInfo, capabilities)`
76-
- Tools: `RegisterTool(name, handler)` or `RegisterTool(tool, handler)`, `UnregisterTool(name)`, `ListTools()`, `CallTool(name, args)`
77-
- Resources: `RegisterResource(uri, handler)`, `UnregisterResource(uri)`, `ListResources()`, `ReadResource(uri)`
77+
- Tools: `RegisterTool(name, handler)` or `RegisterTool(tool, handler)`, `UnregisterTool(name)`, `ListTools()`, `CallTool(name, args)`, `CallToolTask(name, args, task)`
78+
- Tasks: `GetTask(taskId)`, `ListTasks()`, `ListTasksPaged(cursor, limit)`, `GetTaskResult(taskId)`, `CancelTask(taskId)`
79+
- Resources: `RegisterResource(uri, handler)` or `RegisterResource(resource, handler)`, `UnregisterResource(uri)`, `ListResources()`, `ReadResource(uri)`
7880
- Resource templates: `RegisterResourceTemplate(t)`, `UnregisterResourceTemplate(template)`, `ListResourceTemplates()`
79-
- Prompts: `RegisterPrompt(name, handler)`, `UnregisterPrompt(name)`, `ListPrompts()`, `GetPrompt(name, args)`
80-
- Utilities: `SetCompletionHandler(handler)`, `RequestCreateMessage(params)`, `RequestElicitation(request)`, `RequestRootsList()`, `Ping()`
81+
- Prompts: `RegisterPrompt(name, handler)` or `RegisterPrompt(prompt, handler)`, `UnregisterPrompt(name)`, `ListPrompts()`, `GetPrompt(name, args)`
82+
- Utilities: `SetCompletionHandler(handler)`, `RequestCreateMessage(params)`, `RequestCreateMessageTask(params, task)`, `RequestElicitation(request)`, `RequestElicitationTask(request, task)`, `RequestRootsList()`, `Ping()`
8183
- Sampling: `SetSamplingHandler(handler)`
8284
- Keepalive: `SetKeepaliveIntervalMs(intervalMs)`
8385
- Logging: `LogToClient(level, message, data)`

docs/api/server.md

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -272,10 +272,17 @@ Notes:
272272

273273
## Resources
274274
- void RegisterResource(const std::string& uri, ResourceHandler handler)
275+
- void RegisterResource(const Resource& resource, ResourceHandler handler)
275276
- void UnregisterResource(const std::string& uri)
276277
- std::vector<Resource> ListResources()
277278
- std::future<JSONValue> ReadResource(const std::string& uri)
278279

280+
Notes:
281+
282+
- Use the `Resource` overload when you want list metadata such as `title`, `annotations`, `_meta`, `size`, or `icons`
283+
to round-trip through `resources/list`.
284+
- The string-only overload remains available and synthesizes default metadata from the URI for compatibility.
285+
279286
## Resource read chunking (experimental)
280287

281288
- The server supports optional byte-range parameters for resource reads. When the client includes `offset` and/or `length` in the `resources/read` request, the server will slice returned text content accordingly before responding. The overall result shape remains identical to a normal read.
@@ -337,10 +344,16 @@ Tests:
337344

338345
## Prompts
339346
- void RegisterPrompt(const std::string& name, PromptHandler handler)
347+
- void RegisterPrompt(const Prompt& prompt, PromptHandler handler)
340348
- void UnregisterPrompt(const std::string& name)
341349
- std::vector<Prompt> ListPrompts()
342350
- std::future<JSONValue> GetPrompt(const std::string& name, const JSONValue& arguments)
343351

352+
Notes:
353+
354+
- Use the `Prompt` overload when you want `title`, `arguments`, `_meta`, or `icons` preserved in `prompts/list`.
355+
- The string-only overload remains available and synthesizes the historical `Prompt: <name>` description.
356+
344357
- void SetSamplingHandler(SamplingHandler handler)
345358
- Register a server-side handler for `sampling/createMessage`.
346359
- std::future<JSONValue> RequestCreateMessage(const CreateMessageParams& params)

docs/parity-matrix.md

Lines changed: 22 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -13,19 +13,23 @@ This matrix tracks the MCP C++ SDK feature coverage relative to the MCP spec.
1313
- List tools (paged): Implemented
1414
- Call tool (server → client): Implemented
1515
- Input schema (tool metadata): Implemented (tests: `ToolsInputSchema.*` in `tests/test_tools_inputschema.cpp`)
16+
- Icon and title metadata: Implemented (`tests/test_icon_parity.cpp`)
1617
- List-changed notifications: Implemented (one-time on initialize)
1718

1819
- Resources
1920
- List resources (paged): Implemented
21+
- Resource metadata (`title`, `size`, `annotations`, `_meta`, `icons`): Implemented (`tests/test_icon_parity.cpp`)
2022
- Read resource (server → client): Implemented (shape covered by tests)
2123
- Resource templates (list, register/unregister): Implemented (`tests/test_resource_templates.cpp`)
24+
- Resource template metadata (`title`, `annotations`, `_meta`, `icons`): Implemented (`tests/test_icon_parity.cpp`)
2225
- Subscriptions (global and per-URI): Implemented (`tests/test_resource_subscriptions.cpp`)
2326
- List/updated notifications: Implemented
2427
- Read chunking (experimental offset/length): Implemented (`tests/test_resource_read_chunking.cpp`, `tests/test_resource_read_chunking_capability_absence.cpp`)
2528
- Listings cache: Implemented with TTL and invalidation (`tests/test_client_cache_extended.cpp`)
2629

2730
- Prompts
2831
- List prompts (paged): Implemented
32+
- Prompt metadata (`title`, `arguments`, `_meta`, `icons`): Implemented (`tests/test_icon_parity.cpp`)
2933
- Get prompt: Implemented (returns `PromptResult.messages`)
3034
- List-changed notifications: Implemented
3135

@@ -34,13 +38,20 @@ This matrix tracks the MCP C++ SDK feature coverage relative to the MCP spec.
3438
- `completion/complete`: Implemented
3539
- `roots/list` and `notifications/roots/list_changed`: Implemented
3640
- `elicitation/create`: Implemented
41+
- `tasks/get`, `tasks/list`, `tasks/result`, and `tasks/cancel`: Implemented (`tests/test_tasks.cpp`)
3742

3843
- Sampling
3944
- Client-registered sampling handler: Implemented (client API)
4045
- Server-initiated `sampling/createMessage`: Implemented (`tests/test_server_initiated_sampling.cpp`)
4146
- Capability advertisement: Implemented (only when handler set)
4247
- Server-initiated cancellation (E2E) via `notifications/cancelled`: Implemented (`tests/test_sampling_cancellation_e2e.cpp`)
4348

49+
- Tasks
50+
- Task capability negotiation: Implemented for server tool tasks and client sampling/elicitation tasks
51+
- Task-augmented `tools/call`: Implemented
52+
- Task-augmented `sampling/createMessage` and `elicitation/create`: Implemented
53+
- `notifications/tasks/status`: Implemented
54+
4455
- Cancellation
4556
- Cancellation propagation to long-running handlers: Implemented (`tests/test_cancellation.cpp`)
4657
- `notifications/cancelled` handling: Implemented
@@ -98,21 +109,24 @@ Notes:
98109
- List (paged): Implemented.
99110
- Call: Implemented.
100111
- Input schema metadata: Implemented.
112+
- Title/icon metadata: Implemented.
101113
- List-changed notifications: Implemented, single-shot post-init.
102114
- Sources: [include/mcp/Protocol.h](../include/mcp/Protocol.h), [src/mcp/Server.cpp](../src/mcp/Server.cpp), [src/mcp/Client.cpp](../src/mcp/Client.cpp)
103115
- Tests: [tests/test_client_paging.cpp](../tests/test_client_paging.cpp), [tests/test_tools_inputschema.cpp](../tests/test_tools_inputschema.cpp)
104116

105117
- **[Resources]**
106118
- List (paged), Read, Templates (list/register/unregister): Implemented.
119+
- Resource/resource-template metadata parity for icons and related list metadata: Implemented.
107120
- Subscriptions: global and per-URI; filtered `notifications/resources/updated`.
108121
- List/updated notifications: Implemented.
109122
- Sources: [include/mcp/Protocol.h](../include/mcp/Protocol.h), [src/mcp/Server.cpp](../src/mcp/Server.cpp)
110123
- Tests: [tests/test_resource_templates.cpp](../tests/test_resource_templates.cpp), [tests/test_resource_subscriptions.cpp](../tests/test_resource_subscriptions.cpp), [tests/test_client_subscribe_uri.cpp](../tests/test_client_subscribe_uri.cpp), [tests/test_read_resource.cpp](../tests/test_read_resource.cpp)
111124

112125
- **[Prompts]**
113126
- List (paged), Get prompt returns `messages` with correct shape.
127+
- Title/icon metadata and richer list metadata: Implemented.
114128
- Sources: [include/mcp/Protocol.h](../include/mcp/Protocol.h)
115-
- Tests: [tests/test_prompts_get.cpp](../tests/test_prompts_get.cpp), [tests/test_client_paging.cpp](../tests/test_client_paging.cpp)
129+
- Tests: [tests/test_prompts_get.cpp](../tests/test_prompts_get.cpp), [tests/test_client_paging.cpp](../tests/test_client_paging.cpp), [tests/test_icon_parity.cpp](../tests/test_icon_parity.cpp)
116130

117131
- **[Utilities: Ping, Completion, Roots, Elicitation]**
118132
- `ping`: Implemented for client->server and server->client flows.
@@ -122,6 +136,13 @@ Notes:
122136
- 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)
123137
- 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)
124138

139+
- **[Tasks]**
140+
- Task capability negotiation for server-side `tools/call` and client-side `sampling/createMessage` / `elicitation/create`.
141+
- `tasks/get`, `tasks/list`, `tasks/result`, and `tasks/cancel`: Implemented.
142+
- `notifications/tasks/status`: Implemented on both requestor sides.
143+
- 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)
144+
- Tests: [tests/test_tasks.cpp](../tests/test_tasks.cpp)
145+
125146
- **[Sampling (Server → Client)]**
126147
- Server-initiated `sampling/createMessage` with optional cancelable handler on client.
127148
- Cancellation via `notifications/cancelled` supported end-to-end.

include/mcp/Client.h

Lines changed: 77 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -109,6 +109,62 @@ class IClient {
109109
//==========================================================================================================
110110
virtual std::future<JSONValue> CallTool(const std::string& name,
111111
const JSONValue& arguments) = 0;
112+
//==========================================================================================================
113+
// Invokes a server tool using task augmentation and returns the created task metadata.
114+
// Args:
115+
// name: The tool name.
116+
// arguments: JSON object containing the tool parameters.
117+
// task: Optional task retention metadata.
118+
// Returns:
119+
// A future with the created task information.
120+
//==========================================================================================================
121+
virtual std::future<CreateTaskResult> CallToolTask(const std::string& name,
122+
const JSONValue& arguments,
123+
const TaskMetadata& task) = 0;
124+
125+
////////////////////////////////////////// Task operations /////////////////////////////////////////////////
126+
//==========================================================================================================
127+
// Retrieves the latest task state for the given task id.
128+
// Args:
129+
// taskId: Receiver-generated task identifier.
130+
// Returns:
131+
// A future with the current task metadata.
132+
//==========================================================================================================
133+
virtual std::future<Task> GetTask(const std::string& taskId) = 0;
134+
//==========================================================================================================
135+
// Lists receiver-side tasks (non-paged helper).
136+
// Args:
137+
// (none)
138+
// Returns:
139+
// A future with all currently known tasks.
140+
//==========================================================================================================
141+
virtual std::future<std::vector<Task>> ListTasks() = 0;
142+
//==========================================================================================================
143+
// Lists receiver-side tasks with optional paging.
144+
// Args:
145+
// cursor: Optional opaque cursor indicating the starting position.
146+
// limit: Optional maximum number of tasks to return; must be positive when provided.
147+
// Returns:
148+
// A future with a task page and optional nextCursor.
149+
//==========================================================================================================
150+
virtual std::future<TasksListResult> ListTasksPaged(const std::optional<std::string>& cursor,
151+
const std::optional<int>& limit) = 0;
152+
//==========================================================================================================
153+
// Retrieves the original result payload for a terminal task.
154+
// Args:
155+
// taskId: Receiver-generated task identifier.
156+
// Returns:
157+
// A future with either the original result payload or the original error payload.
158+
//==========================================================================================================
159+
virtual std::future<JSONValue> GetTaskResult(const std::string& taskId) = 0;
160+
//==========================================================================================================
161+
// Requests cancellation for a receiver-side task.
162+
// Args:
163+
// taskId: Receiver-generated task identifier.
164+
// Returns:
165+
// A future with the updated task metadata.
166+
//==========================================================================================================
167+
virtual std::future<Task> CancelTask(const std::string& taskId) = 0;
112168

113169
////////////////////////////////////////// Resource operations /////////////////////////////////////////////
114170
//==========================================================================================================
@@ -343,6 +399,17 @@ class IClient {
343399
using ProgressHandler = std::function<void(const std::string& token, double progress, const std::string& message)>;
344400
virtual void SetProgressHandler(ProgressHandler handler) = 0;
345401

402+
////////////////////////////////////////// Task status tracking ////////////////////////////////////////////
403+
//==========================================================================================================
404+
// Registers a task status notification handler.
405+
// Args:
406+
// handler: Callback receiving the latest task snapshot from notifications/tasks/status.
407+
// Returns:
408+
// (none)
409+
//==========================================================================================================
410+
using TaskStatusHandler = std::function<void(const Task&)>;
411+
virtual void SetTaskStatusHandler(TaskStatusHandler handler) = 0;
412+
346413
//////////////////////////////////////////// Error handling ////////////////////////////////////////////////
347414
//==========================================================================================================
348415
// Registers an error handler to receive transport/client errors.
@@ -407,6 +474,15 @@ class Client : public IClient {
407474
const std::optional<int>& limit) override;
408475
std::future<JSONValue> CallTool(const std::string& name,
409476
const JSONValue& arguments) override;
477+
std::future<CreateTaskResult> CallToolTask(const std::string& name,
478+
const JSONValue& arguments,
479+
const TaskMetadata& task) override;
480+
std::future<Task> GetTask(const std::string& taskId) override;
481+
std::future<std::vector<Task>> ListTasks() override;
482+
std::future<TasksListResult> ListTasksPaged(const std::optional<std::string>& cursor,
483+
const std::optional<int>& limit) override;
484+
std::future<JSONValue> GetTaskResult(const std::string& taskId) override;
485+
std::future<Task> CancelTask(const std::string& taskId) override;
410486

411487
std::future<std::vector<Resource>> ListResources() override;
412488
std::future<ResourcesListResult> ListResourcesPaged(const std::optional<std::string>& cursor,
@@ -441,6 +517,7 @@ class Client : public IClient {
441517
void SetNotificationHandler(const std::string& method, NotificationHandler handler) override;
442518
void RemoveNotificationHandler(const std::string& method) override;
443519
void SetProgressHandler(ProgressHandler handler) override;
520+
void SetTaskStatusHandler(TaskStatusHandler handler) override;
444521
void SetErrorHandler(ErrorHandler handler) override;
445522

446523
// Validation (opt-in)

0 commit comments

Comments
 (0)