Skip to content

Commit 4a363dc

Browse files
committed
Add title/description/icons fields to server-side Tool class
- Add optional title, description, icons fields to tools::Tool - Add builder pattern setters (set_title, set_description, set_icons) - Update MCP handler to serialize icons in tools/list response - Enables servers to expose icon metadata matching Python fastmcp
1 parent 926daf7 commit 4a363dc

2 files changed

Lines changed: 80 additions & 4 deletions

File tree

include/fastmcpp/tools/tool.hpp

Lines changed: 46 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22
#include "fastmcpp/types.hpp"
33

44
#include <functional>
5+
#include <optional>
56
#include <string>
67
#include <vector>
78

@@ -14,6 +15,8 @@ class Tool
1415
using Fn = std::function<fastmcpp::Json(const fastmcpp::Json&)>;
1516

1617
Tool() = default;
18+
19+
// Original constructor (backward compatible)
1720
Tool(std::string name, fastmcpp::Json input_schema, fastmcpp::Json output_schema, Fn fn,
1821
std::vector<std::string> exclude_args = {})
1922
: name_(std::move(name)), input_schema_(std::move(input_schema)),
@@ -22,10 +25,33 @@ class Tool
2225
{
2326
}
2427

28+
// Extended constructor with title, description, icons
29+
Tool(std::string name, fastmcpp::Json input_schema, fastmcpp::Json output_schema, Fn fn,
30+
std::optional<std::string> title, std::optional<std::string> description,
31+
std::optional<std::vector<fastmcpp::Icon>> icons,
32+
std::vector<std::string> exclude_args = {})
33+
: name_(std::move(name)), title_(std::move(title)), description_(std::move(description)),
34+
input_schema_(std::move(input_schema)), output_schema_(std::move(output_schema)),
35+
icons_(std::move(icons)), fn_(std::move(fn)), exclude_args_(std::move(exclude_args))
36+
{
37+
}
38+
2539
const std::string& name() const
2640
{
2741
return name_;
2842
}
43+
const std::optional<std::string>& title() const
44+
{
45+
return title_;
46+
}
47+
const std::optional<std::string>& description() const
48+
{
49+
return description_;
50+
}
51+
const std::optional<std::vector<fastmcpp::Icon>>& icons() const
52+
{
53+
return icons_;
54+
}
2955
fastmcpp::Json input_schema() const
3056
{
3157
if (exclude_args_.empty())
@@ -41,6 +67,23 @@ class Tool
4167
return fn_(input);
4268
}
4369

70+
// Setters for optional fields (builder pattern)
71+
Tool& set_title(std::string title)
72+
{
73+
title_ = std::move(title);
74+
return *this;
75+
}
76+
Tool& set_description(std::string desc)
77+
{
78+
description_ = std::move(desc);
79+
return *this;
80+
}
81+
Tool& set_icons(std::vector<fastmcpp::Icon> icons)
82+
{
83+
icons_ = std::move(icons);
84+
return *this;
85+
}
86+
4487
private:
4588
fastmcpp::Json prune_schema(const fastmcpp::Json& schema) const
4689
{
@@ -76,8 +119,11 @@ class Tool
76119
}
77120

78121
std::string name_;
122+
std::optional<std::string> title_;
123+
std::optional<std::string> description_;
79124
fastmcpp::Json input_schema_;
80125
fastmcpp::Json output_schema_;
126+
std::optional<std::vector<fastmcpp::Icon>> icons_;
81127
Fn fn_;
82128
std::vector<std::string> exclude_args_;
83129
};

src/mcp/handler.cpp

Lines changed: 34 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,7 @@
11
#include "fastmcpp/mcp/handler.hpp"
22

3+
#include <optional>
4+
35
namespace fastmcpp::mcp
46
{
57

@@ -11,17 +13,37 @@ static fastmcpp::Json jsonrpc_error(const fastmcpp::Json& id, int code, const st
1113
}
1214

1315
static fastmcpp::Json make_tool_entry(const std::string& name, const std::string& description,
14-
const fastmcpp::Json& schema)
16+
const fastmcpp::Json& schema,
17+
const std::optional<std::string>& title = std::nullopt,
18+
const std::optional<std::vector<fastmcpp::Icon>>& icons = std::nullopt)
1519
{
1620
fastmcpp::Json entry = {
1721
{"name", name},
18-
{"description", description},
1922
};
23+
if (title)
24+
entry["title"] = *title;
25+
if (!description.empty())
26+
entry["description"] = description;
2027
// Schema may be empty
2128
if (!schema.is_null() && !schema.empty())
2229
entry["inputSchema"] = schema;
2330
else
2431
entry["inputSchema"] = fastmcpp::Json::object();
32+
// Add icons if present
33+
if (icons && !icons->empty())
34+
{
35+
fastmcpp::Json icons_json = fastmcpp::Json::array();
36+
for (const auto& icon : *icons)
37+
{
38+
fastmcpp::Json icon_obj = {{"src", icon.src}};
39+
if (icon.mime_type)
40+
icon_obj["mimeType"] = *icon.mime_type;
41+
if (icon.sizes)
42+
icon_obj["sizes"] = *icon.sizes;
43+
icons_json.push_back(icon_obj);
44+
}
45+
entry["icons"] = icons_json;
46+
}
2547
return entry;
2648
}
2749

@@ -59,6 +81,9 @@ make_mcp_handler(const std::string& server_name, const std::string& version,
5981
fastmcpp::Json tools_array = fastmcpp::Json::array();
6082
for (auto& name : tools.list_names())
6183
{
84+
// Get full tool object to access all fields
85+
const auto& tool = tools.get(name);
86+
6287
fastmcpp::Json schema = fastmcpp::Json::object();
6388
auto it = input_schemas_override.find(name);
6489
if (it != input_schemas_override.end())
@@ -69,19 +94,24 @@ make_mcp_handler(const std::string& server_name, const std::string& version,
6994
{
7095
try
7196
{
72-
schema = tools.input_schema_for(name);
97+
schema = tool.input_schema();
7398
}
7499
catch (...)
75100
{
76101
schema = fastmcpp::Json::object();
77102
}
78103
}
79104

105+
// Get description from override map or from tool
80106
std::string desc = "";
81107
auto dit = descriptions.find(name);
82108
if (dit != descriptions.end())
83109
desc = dit->second;
84-
tools_array.push_back(make_tool_entry(name, desc, schema));
110+
else if (tool.description())
111+
desc = *tool.description();
112+
113+
tools_array.push_back(make_tool_entry(name, desc, schema,
114+
tool.title(), tool.icons()));
85115
}
86116

87117
return fastmcpp::Json{{"jsonrpc", "2.0"},

0 commit comments

Comments
 (0)