Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 0 additions & 2 deletions CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -63,7 +63,6 @@ if(ONE_INDEX OR ONE_SERVER)
add_subdirectory(src/metapack)
add_subdirectory(src/search)
add_subdirectory(src/http)
add_subdirectory(src/mcp)
add_subdirectory(src/router)

if(ONE_ENTERPRISE)
Expand Down Expand Up @@ -107,7 +106,6 @@ if(ONE_TESTS)
add_subdirectory(test/js)

if(ONE_INDEX OR ONE_SERVER)
add_subdirectory(test/unit/mcp)
add_subdirectory(test/unit/metapack)
add_subdirectory(test/unit/search)
Comment thread
jviotti marked this conversation as resolved.
endif()
Expand Down
2 changes: 1 addition & 1 deletion DEPENDENCIES
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
vendorpull https://github.com/sourcemeta/vendorpull 1dcbac42809cf87cb5b045106b863e17ad84ba02
uwebsockets https://github.com/uNetworking/uWebSockets v20.77.0
core https://github.com/sourcemeta/core 8018e9d85ef6fc0fd9ccd11c2ae438789214b00a
core https://github.com/sourcemeta/core 178137768156f9c8672dce6ec9d1a95a46ee3eae
blaze https://github.com/sourcemeta/blaze bc1f434acafd38803f58a941a756a6f788e556e2
bootstrap https://github.com/twbs/bootstrap v5.3.3
bootstrap-icons https://github.com/twbs/icons v1.11.3
Expand Down
2 changes: 1 addition & 1 deletion enterprise/index/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,6 @@ target_link_libraries(sourcemeta_one_enterprise_index PUBLIC sourcemeta::core::j
target_link_libraries(sourcemeta_one_enterprise_index PRIVATE sourcemeta::core::text)
target_link_libraries(sourcemeta_one_enterprise_index PRIVATE sourcemeta::one::search)
target_link_libraries(sourcemeta_one_enterprise_index PRIVATE sourcemeta::one::actions)
target_link_libraries(sourcemeta_one_enterprise_index PRIVATE sourcemeta::one::mcp)
target_link_libraries(sourcemeta_one_enterprise_index PRIVATE sourcemeta::core::mcp)
target_link_libraries(sourcemeta_one_enterprise_index PUBLIC sourcemeta::blaze::foundation)
target_link_libraries(sourcemeta_one_enterprise_index PUBLIC sourcemeta::core::uritemplate)
4 changes: 2 additions & 2 deletions enterprise/index/enterprise_index.cc
Original file line number Diff line number Diff line change
Expand Up @@ -5,12 +5,12 @@
#include <sourcemeta/blaze/foundation.h>

#include <sourcemeta/core/error.h>
#include <sourcemeta/core/mcp.h>
#include <sourcemeta/core/text.h>
#include <sourcemeta/core/uri.h>
#include <sourcemeta/core/yaml.h>

#include <sourcemeta/one/actions.h>
#include <sourcemeta/one/mcp.h>
#include <sourcemeta/one/search.h>

#include <cassert> // assert
Expand Down Expand Up @@ -87,7 +87,7 @@ auto generate_mcp_resources(const std::filesystem::path &search_metapack_path,
std::string uri{configuration.origin};
uri.append(entry.path);

entries.push_back(sourcemeta::one::mcp_make_resource(
entries.push_back(sourcemeta::core::mcp_make_resource(
uri, name, "application/schema+json", entry.description,
static_cast<std::size_t>(entry.bytes_raw)));
});
Expand Down
2 changes: 1 addition & 1 deletion enterprise/server/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,6 @@ target_link_libraries(sourcemeta_one_enterprise_server PRIVATE sourcemeta::core:
target_link_libraries(sourcemeta_one_enterprise_server PRIVATE sourcemeta::core::jsonrpc)
target_link_libraries(sourcemeta_one_enterprise_server PRIVATE sourcemeta::core::uri)
target_link_libraries(sourcemeta_one_enterprise_server PRIVATE sourcemeta::one::shared)
target_link_libraries(sourcemeta_one_enterprise_server PRIVATE sourcemeta::one::mcp)
target_link_libraries(sourcemeta_one_enterprise_server PRIVATE sourcemeta::core::mcp)
target_link_libraries(sourcemeta_one_enterprise_server PRIVATE sourcemeta::one::metapack)
target_link_libraries(sourcemeta_one_enterprise_server PRIVATE sourcemeta::blaze::output)
62 changes: 32 additions & 30 deletions enterprise/server/action_mcp_v1.cc
Original file line number Diff line number Diff line change
Expand Up @@ -3,10 +3,10 @@
#include <sourcemeta/core/io.h>
#include <sourcemeta/core/json.h>
#include <sourcemeta/core/jsonrpc.h>
#include <sourcemeta/core/mcp.h>
#include <sourcemeta/core/uri.h>

#include <sourcemeta/one/http.h>
#include <sourcemeta/one/mcp.h>
#include <sourcemeta/one/metapack.h>

#include <cassert> // assert
Expand Down Expand Up @@ -78,17 +78,17 @@ auto ActionMCP_v1::on_resources_list(const sourcemeta::core::JSON &request_json)
auto ActionMCP_v1::on_initialize(const sourcemeta::core::JSON &request_json)
const -> sourcemeta::core::JSON {
const auto &parts{
this->mcp_metadata_.at(sourcemeta::one::MCP_METHOD_INITIALIZE)};
return sourcemeta::one::mcp_make_initialize_result(
this->mcp_metadata_.at(sourcemeta::core::MCP_METHOD_INITIALIZE)};
return sourcemeta::core::mcp_make_initialize_result(
request_json,
sourcemeta::one::MCPServerCapabilities{
sourcemeta::core::MCPServerCapabilities{
.prompts = parts.at(0).to_boolean(),
.resources = parts.at(1).to_boolean(),
.tools = parts.at(2).to_boolean(),
.logging = parts.at(3).to_boolean(),
.completions = parts.at(4).to_boolean(),
},
sourcemeta::one::MCPImplementation{
sourcemeta::core::MCPImplementation{
.name = parts.at(5).to_string(),
.version = parts.at(6).to_string(),
.title = parts.at(7).to_string(),
Expand All @@ -99,22 +99,22 @@ auto ActionMCP_v1::on_initialize(const sourcemeta::core::JSON &request_json)
}

auto ActionMCP_v1::on_tools_list(
const sourcemeta::one::MCPProtocolVersion version,
const sourcemeta::core::MCPProtocolVersion version,
const sourcemeta::core::JSON &request_json) const
-> sourcemeta::core::JSON {
const auto &precomputed{
this->mcp_metadata_.at(sourcemeta::one::MCP_METHOD_TOOLS_LIST)};
this->mcp_metadata_.at(sourcemeta::core::MCP_METHOD_TOOLS_LIST)};

auto tools{sourcemeta::core::JSON::make_array()};
for (const auto &tool : precomputed.as_array()) {
std::optional<sourcemeta::core::JSON> output_schema;
if (!tool.at(3).is_null()) {
output_schema = tool.at(3);
}
tools.push_back(sourcemeta::one::mcp_make_tool_descriptor(
tools.push_back(sourcemeta::core::mcp_make_tool_descriptor(
version, tool.at(0).to_string(), tool.at(1).to_string(), tool.at(2),
std::move(output_schema),
sourcemeta::one::MCPToolAnnotations{
sourcemeta::core::MCPToolAnnotations{
.title = tool.at(4).to_string(),
.read_only = tool.at(5).to_boolean(),
.destructive = tool.at(6).to_boolean(),
Expand All @@ -138,46 +138,47 @@ auto ActionMCP_v1::on_resources_read(const sourcemeta::core::JSON &request_json)
sourcemeta::core::URI request{uri};
request.relative_to(sourcemeta::core::URI{this->server_uri()});
if (request.is_absolute()) {
return sourcemeta::one::mcp_make_error_resource_not_found(id, uri);
return sourcemeta::core::mcp_make_error_resource_not_found(id, uri);
}
const auto path{request.path().value_or("")};
std::string_view schema_path{path};
if (schema_path.ends_with(".json")) {
schema_path.remove_suffix(5);
}
if (schema_path.empty()) {
return sourcemeta::one::mcp_make_error_resource_not_found(id, uri);
return sourcemeta::core::mcp_make_error_resource_not_found(id, uri);
}
const auto query{request.query()};
const auto bundle{query.has_value() &&
!query->at("bundle").value_or("").empty()};
resolved = sourcemeta::core::weakly_canonical(
this->resolve_schema_path(schema_path, bundle));
} catch (const std::exception &) {
return sourcemeta::one::mcp_make_error_resource_not_found(id, uri);
return sourcemeta::core::mcp_make_error_resource_not_found(id, uri);
}

if (!sourcemeta::core::is_under_path(resolved, this->base() / "schemas")) {
return sourcemeta::one::mcp_make_error_resource_not_found(id, uri);
return sourcemeta::core::mcp_make_error_resource_not_found(id, uri);
}

const auto schema{sourcemeta::one::metapack_read_json(resolved)};
if (!schema.has_value()) {
return sourcemeta::one::mcp_make_error_resource_not_found(id, uri);
return sourcemeta::core::mcp_make_error_resource_not_found(id, uri);
}

std::ostringstream payload;
sourcemeta::core::prettify(schema.value(), payload);

auto contents{sourcemeta::core::JSON::make_array()};
contents.push_back(sourcemeta::one::mcp_make_resource_text_content(
contents.push_back(sourcemeta::core::mcp_make_resource_text_content(
uri, MCP_TEMPLATE_MIME_TYPE, payload.str()));
return sourcemeta::core::jsonrpc_make_success(
id, sourcemeta::one::mcp_make_resources_read_result(std::move(contents)));
id,
sourcemeta::core::mcp_make_resources_read_result(std::move(contents)));
}

auto ActionMCP_v1::on_tools_call(
const sourcemeta::one::MCPProtocolVersion version,
const sourcemeta::core::MCPProtocolVersion version,
const sourcemeta::core::JSON &request_json, const std::string_view envelope)
-> sourcemeta::core::JSON {
const auto &id{request_json.at("id")};
Expand All @@ -194,21 +195,22 @@ auto ActionMCP_v1::on_tools_call(
if (instance == nullptr) [[unlikely]] {
return sourcemeta::core::jsonrpc_make_error_internal(&id);
}
const auto *arguments{sourcemeta::one::mcp_tool_call_arguments(request_json)};
const auto *arguments{
sourcemeta::core::mcp_tool_call_arguments(request_json)};
if (arguments == nullptr) {
return sourcemeta::core::jsonrpc_make_error_invalid_params(id);
}
try {
return instance->mcp(version, id, *arguments, envelope);
} catch (const std::exception &error) {
return sourcemeta::one::mcp_make_tool_error(id, error.what());
return sourcemeta::core::mcp_make_tool_error(id, error.what());
}
}

auto ActionMCP_v1::on_message(const sourcemeta::one::MCPProtocolVersion version,
sourcemeta::one::HTTPRequest &request,
sourcemeta::one::HTTPResponse &response,
std::string &&body) -> void {
auto ActionMCP_v1::on_message(
const sourcemeta::core::MCPProtocolVersion version,
sourcemeta::one::HTTPRequest &request,
sourcemeta::one::HTTPResponse &response, std::string &&body) -> void {
sourcemeta::core::JSON request_json{nullptr};
try {
request_json = sourcemeta::core::parse_json(body);
Expand All @@ -219,7 +221,7 @@ auto ActionMCP_v1::on_message(const sourcemeta::one::MCPProtocolVersion version,
}

if (request_json.is_array()) {
if (version == sourcemeta::one::MCPProtocolVersion::V_2025_03_26) {
if (version == sourcemeta::core::MCPProtocolVersion::V_2025_03_26) {
// TODO: Support batches for strict compliance to MCP 2025-03-26
this->write_envelope(
request, response, sourcemeta::one::STATUS_OK,
Expand Down Expand Up @@ -256,19 +258,19 @@ auto ActionMCP_v1::on_message(const sourcemeta::one::MCPProtocolVersion version,
assert(id != nullptr);
const auto method{sourcemeta::core::jsonrpc_method(request_json)};
sourcemeta::core::JSON envelope{nullptr};
if (!sourcemeta::one::mcp_is_request_method(method)) {
if (!sourcemeta::core::mcp_is_request_method(method)) {
envelope = sourcemeta::core::jsonrpc_make_error_method_not_found(*id);
} else if (!this->validate(this->request_schema_, request_json)) {
envelope = sourcemeta::core::jsonrpc_make_error_invalid_request(id);
} else if (method == sourcemeta::one::MCP_METHOD_INITIALIZE) {
} else if (method == sourcemeta::core::MCP_METHOD_INITIALIZE) {
envelope = this->on_initialize(request_json);
} else if (method == sourcemeta::one::MCP_METHOD_TOOLS_LIST) {
} else if (method == sourcemeta::core::MCP_METHOD_TOOLS_LIST) {
envelope = this->on_tools_list(version, request_json);
} else if (method == sourcemeta::one::MCP_METHOD_RESOURCES_LIST) {
} else if (method == sourcemeta::core::MCP_METHOD_RESOURCES_LIST) {
envelope = this->on_resources_list(request_json);
} else if (method == sourcemeta::one::MCP_METHOD_RESOURCES_READ) {
} else if (method == sourcemeta::core::MCP_METHOD_RESOURCES_READ) {
envelope = this->on_resources_read(request_json);
} else if (method == sourcemeta::one::MCP_METHOD_TOOLS_CALL) {
} else if (method == sourcemeta::core::MCP_METHOD_TOOLS_CALL) {
envelope = this->on_tools_call(version, request_json, body);
} else if (this->mcp_metadata_.defines(method)) {
envelope = sourcemeta::core::jsonrpc_make_success(
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,10 +3,10 @@

#include <sourcemeta/core/json.h>
#include <sourcemeta/core/jsonrpc.h>
#include <sourcemeta/core/mcp.h>
#include <sourcemeta/core/uritemplate.h>

#include <sourcemeta/one/http.h>
#include <sourcemeta/one/mcp.h>
#include <sourcemeta/one/metapack.h>
#include <sourcemeta/one/router.h>

Expand Down Expand Up @@ -86,8 +86,9 @@ class ActionMCP_v1 : public sourcemeta::one::RouterAction {
return;
}

const auto negotiated_version{sourcemeta::one::mcp_resolve_protocol_version(
request.header("mcp-protocol-version"))};
const auto negotiated_version{
sourcemeta::core::mcp_resolve_protocol_version(
request.header("mcp-protocol-version"))};
if (!negotiated_version.has_value()) {
this->write_envelope(request, response,
sourcemeta::one::STATUS_BAD_REQUEST,
Expand Down Expand Up @@ -125,7 +126,7 @@ class ActionMCP_v1 : public sourcemeta::one::RouterAction {
});
}

auto mcp(const sourcemeta::one::MCPProtocolVersion,
auto mcp(const sourcemeta::core::MCPProtocolVersion,
const sourcemeta::core::JSON &id, const sourcemeta::core::JSON &,
const std::string_view) -> sourcemeta::core::JSON override {
return sourcemeta::core::jsonrpc_make_error_method_not_found(id);
Expand Down Expand Up @@ -154,18 +155,18 @@ class ActionMCP_v1 : public sourcemeta::one::RouterAction {
auto on_initialize(const sourcemeta::core::JSON &request_json) const
-> sourcemeta::core::JSON;

auto on_tools_list(sourcemeta::one::MCPProtocolVersion version,
auto on_tools_list(sourcemeta::core::MCPProtocolVersion version,
const sourcemeta::core::JSON &request_json) const
-> sourcemeta::core::JSON;

auto on_resources_read(const sourcemeta::core::JSON &request_json) const
-> sourcemeta::core::JSON;

auto on_tools_call(sourcemeta::one::MCPProtocolVersion version,
auto on_tools_call(sourcemeta::core::MCPProtocolVersion version,
const sourcemeta::core::JSON &request_json,
std::string_view envelope) -> sourcemeta::core::JSON;

auto on_message(sourcemeta::one::MCPProtocolVersion version,
auto on_message(sourcemeta::core::MCPProtocolVersion version,
sourcemeta::one::HTTPRequest &request,
sourcemeta::one::HTTPResponse &response, std::string &&body)
-> void;
Expand Down
2 changes: 1 addition & 1 deletion src/actions/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@ target_link_libraries(sourcemeta_one_actions PUBLIC sourcemeta::core::uritemplat
target_link_libraries(sourcemeta_one_actions PRIVATE sourcemeta::core::json)
target_link_libraries(sourcemeta_one_actions PRIVATE sourcemeta::core::uri)
target_link_libraries(sourcemeta_one_actions PUBLIC sourcemeta::core::jsonrpc)
target_link_libraries(sourcemeta_one_actions PRIVATE sourcemeta::one::mcp)
target_link_libraries(sourcemeta_one_actions PRIVATE sourcemeta::core::mcp)
target_link_libraries(sourcemeta_one_actions PRIVATE sourcemeta::core::jsonpointer)
target_link_libraries(sourcemeta_one_actions PRIVATE sourcemeta::core::io)
target_link_libraries(sourcemeta_one_actions PRIVATE sourcemeta::core::time)
Expand Down
3 changes: 2 additions & 1 deletion src/actions/action_default_v1.h
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@

#include <sourcemeta/core/json.h>
#include <sourcemeta/core/jsonrpc.h>
#include <sourcemeta/core/mcp.h>
#include <sourcemeta/core/uri.h>
#include <sourcemeta/core/uritemplate.h>

Expand Down Expand Up @@ -114,7 +115,7 @@ class ActionDefault_v1 : public sourcemeta::one::RouterAction {
}
}

auto mcp(const sourcemeta::one::MCPProtocolVersion,
auto mcp(const sourcemeta::core::MCPProtocolVersion,
const sourcemeta::core::JSON &id, const sourcemeta::core::JSON &,
const std::string_view) -> sourcemeta::core::JSON override {
return sourcemeta::core::jsonrpc_make_error_method_not_found(id);
Expand Down
18 changes: 9 additions & 9 deletions src/actions/action_dependency_tree_v1.h
Original file line number Diff line number Diff line change
Expand Up @@ -4,11 +4,11 @@
#include <sourcemeta/core/io.h>
#include <sourcemeta/core/json.h>
#include <sourcemeta/core/jsonrpc.h>
#include <sourcemeta/core/mcp.h>
#include <sourcemeta/core/uri.h>
#include <sourcemeta/core/uritemplate.h>

#include <sourcemeta/one/http.h>
#include <sourcemeta/one/mcp.h>
#include <sourcemeta/one/metapack.h>
#include <sourcemeta/one/router.h>

Expand Down Expand Up @@ -81,7 +81,7 @@ class ActionDependencyTree_v1 : public sourcemeta::one::RouterAction {
response, this->error_schema_);
}

auto mcp(const sourcemeta::one::MCPProtocolVersion version,
auto mcp(const sourcemeta::core::MCPProtocolVersion version,
const sourcemeta::core::JSON &request_id,
const sourcemeta::core::JSON &arguments, const std::string_view)
-> sourcemeta::core::JSON override {
Expand All @@ -96,15 +96,15 @@ class ActionDependencyTree_v1 : public sourcemeta::one::RouterAction {
const auto directory{
this->schema_directory(arguments.at("schema").to_string())};
if (!directory.has_value()) {
return sourcemeta::one::mcp_make_tool_error(request_id,
"Schema not found");
return sourcemeta::core::mcp_make_tool_error(request_id,
"Schema not found");
}

auto contents{sourcemeta::one::metapack_read_json(directory.value() /
this->metapack_)};
if (!contents.has_value()) {
return sourcemeta::one::mcp_make_tool_error(request_id,
"Schema not found");
return sourcemeta::core::mcp_make_tool_error(request_id,
"Schema not found");
}

auto &result{contents.value()};
Expand All @@ -124,13 +124,13 @@ class ActionDependencyTree_v1 : public sourcemeta::one::RouterAction {
auto content{sourcemeta::core::JSON::make_array()};
std::ostringstream payload;
sourcemeta::core::prettify(result, payload);
content.push_back(sourcemeta::one::mcp_make_text_block(payload.str()));
content.push_back(sourcemeta::core::mcp_make_text_block(payload.str()));
for (const auto uri : unique_uris) {
content.push_back(sourcemeta::one::mcp_make_resource_link(
content.push_back(sourcemeta::core::mcp_make_resource_link(
version, uri, "application/schema+json"));
}

return sourcemeta::one::mcp_make_tool_success(
return sourcemeta::core::mcp_make_tool_success(
version, request_id, std::move(result), std::move(content));
}

Expand Down
Loading
Loading