#include "mcp/tools/common/registry.h" #include "mcp/tools/common/common.h" #include "mcp/tools/common/context.h" #include #include static void call_update_message(const mcpc_tool_t *tool, mcpc_ucbr_t *result) { tiny_mcp_tools_context_t *context = tiny_mcp_tools_context_current(); char *message_id = tiny_mcp_tool_get_string(tool, "message_id", TINY_MESSAGE_ID_LENGTH); char *content = tiny_mcp_tool_get_string(tool, "content", TINY_CONTENT_MAX); char *metadata_json = tiny_mcp_tool_get_string(tool, "metadata_json", TINY_CONTENT_MAX); int32_t expected = 0; mcpc_errcode_t expected_status = mcpc_tool_get_tpropval_i32(tool, (const char8_t *)"expected_revision", &expected); tiny_message_t parsed, updated; tiny_message_patch_t patch; tiny_store_status_t status; tiny_json_buffer_t json; bool changed = false; tiny_metadata_mask_t metadata_mask = 0; const char *metadata_error = NULL; tiny_metadata_parse_status_t metadata_status = TINY_METADATA_PARSE_OK; tiny_message_init(&parsed); tiny_message_init(&updated); patch.content = content; patch.metadata = metadata_json ? &parsed.metadata : NULL; patch.metadata_mask = 0; patch.expected_revision = (uint64_t)expected; patch.has_expected_revision = expected_status == MCPC_EC_0; if (metadata_json) { metadata_status = tiny_mcp_parse_metadata(metadata_json, &parsed, &metadata_mask, &metadata_error); } if (metadata_status == TINY_METADATA_PARSE_NO_MEMORY) { tiny_mcp_tool_add_error(result, "INTERNAL_ERROR", metadata_error); } else if (metadata_status == TINY_METADATA_PARSE_INVALID) { tiny_mcp_tool_add_error(result, "VALIDATION_ERROR", metadata_error); } else if (!context || !message_id || (!content && !metadata_json) || (expected_status != MCPC_EC_0 && expected_status != MCPC_EC_ANYDATA_NOTFOUND) || (patch.has_expected_revision && expected < 1)) { tiny_mcp_tool_add_error(result, "VALIDATION_ERROR", "invalid update_message arguments"); } else { patch.metadata_mask = metadata_mask; status = tiny_store_update(context->store, message_id, &patch, &updated, &changed); if (status != TINY_STORE_OK) { tiny_mcp_tool_add_error( result, tiny_store_status_name(status), "message was not updated"); } else { if (changed) { tiny_mcp_tools_invalidate_indexes(context); } tiny_json_init(&json); tiny_json_raw(&json, "{\"status\":\"OK\",\"changed\":"); tiny_json_raw(&json, changed ? "true" : "false"); tiny_json_raw(&json, ",\"message\":"); tiny_mcp_tool_append_message(&json, &updated); tiny_json_raw(&json, "}"); tiny_mcp_tool_add_json(result, &json); tiny_json_free(&json); } } free(message_id); free(content); free(metadata_json); tiny_message_free(&parsed); tiny_message_free(&updated); } bool tiny_mcp_register_update_message(mcpc_server_t *server) { mcpc_tool_t *tool = tiny_mcp_tool_new("update_message", "Update message content or metadata while preserving " "identity, session, role, and creation time.", call_update_message); return tool && tiny_mcp_tool_add_property( tool, "message_id", "ULID of the live message to update.", MCPC_U8STR, true) && tiny_mcp_tool_add_property(tool, "content", "Replacement UTF-8 content; omit to retain content.", MCPC_U8STR, false) && tiny_mcp_tool_add_property(tool, "metadata_json", "Replacement metadata JSON; omit to retain metadata.", MCPC_U8STR, false) && tiny_mcp_tool_add_property(tool, "expected_revision", "Optional positive revision for optimistic concurrency.", MCPC_I32, false) && mcpc_server_add_tool(server, tool) == MCPC_EC_0; }