summaryrefslogtreecommitdiff
path: root/src/mcp/tools/search_messages.c
diff options
context:
space:
mode:
authortanaka takashi <isazaka@gmail.com>2026-06-29 21:43:54 +0900
committertanaka takashi <isazaka@gmail.com>2026-06-30 01:23:51 +0900
commit4bc721c3bf7589b519c5730d093f704ce56e3f09 (patch)
tree38da055ab15fd70f5c92584560ea73486e5ddce0 /src/mcp/tools/search_messages.c
parent4c6a831aa2a57e2bcc20aa3fc2f1b7172f5be285 (diff)
refactor: MCP層をmcpc APIベースに刷新
- 独自JSON-RPC処理をmcpcへ置き換え - 各MCPツールを個別ソースへ分離 - 共通コンテキストと登録処理を整理 - mcpc互換修正と統合テストを更新
Diffstat (limited to 'src/mcp/tools/search_messages.c')
-rw-r--r--src/mcp/tools/search_messages.c134
1 files changed, 134 insertions, 0 deletions
diff --git a/src/mcp/tools/search_messages.c b/src/mcp/tools/search_messages.c
new file mode 100644
index 0000000..166c167
--- /dev/null
+++ b/src/mcp/tools/search_messages.c
@@ -0,0 +1,134 @@
+#include "mcp/tools/common/registry.h"
+
+#include "mcp/tools/common/common.h"
+#include "mcp/tools/common/context.h"
+
+#include <stdint.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include "base/allocator.h"
+
+typedef struct result_item
+{
+ const tiny_store_entry_t *entry;
+ double score;
+} result_item_t;
+
+static int
+compare_results(const void *left, const void *right)
+{
+ const result_item_t *a = left;
+ const result_item_t *b = right;
+ if (a->score > b->score)
+ {
+ return -1;
+ }
+ if (a->score < b->score)
+ {
+ return 1;
+ }
+ if (a->entry->message.timestamp_ms > b->entry->message.timestamp_ms)
+ {
+ return -1;
+ }
+ if (a->entry->message.timestamp_ms < b->entry->message.timestamp_ms)
+ {
+ return 1;
+ }
+ return strcmp(a->entry->message.message_id, b->entry->message.message_id);
+}
+
+static void
+call_search_messages(const mcpc_tool_t *tool, mcpc_ucbr_t *result)
+{
+ tiny_mcp_tools_context_t *context = tiny_mcp_tools_context_current();
+ char *query = tiny_mcp_tool_get_string(tool, "query", TINY_QUERY_MAX);
+ char *session = tiny_mcp_tool_get_string(tool, "session_id", TINY_SESSION_ID_MAX);
+ int32_t requested_limit = 0;
+ size_t limit, index, count = 0, candidate_count = 0, *candidates = NULL;
+ result_item_t *items = NULL;
+ tiny_json_buffer_t json;
+ bool valid
+ = context && query && query[0] && session
+ && mcpc_tool_get_tpropval_i32(tool, (const char8_t *)"limit", &requested_limit) == MCPC_EC_0
+ && requested_limit >= 1 && requested_limit <= 100;
+ if (!valid)
+ {
+ tiny_mcp_tool_add_error(result, "VALIDATION_ERROR", "query or limit is invalid");
+ }
+ else
+ {
+ limit = (size_t)requested_limit;
+ if (!context->search_index)
+ {
+ context->search_index = tiny_mcp_tools_build_search_index(context->store);
+ }
+ if (!context->search_index
+ || !tiny_search_index_candidates(
+ context->search_index, query, &candidates, &candidate_count))
+ {
+ tiny_mcp_tool_add_error(result, "INTERNAL_ERROR", "search index allocation failed");
+ }
+ else
+ {
+ items = malloc((candidate_count + 1) * sizeof(*items));
+ if (!items)
+ {
+ tiny_mcp_tool_add_error(result, "INTERNAL_ERROR", "out of memory");
+ }
+ else
+ {
+ for (index = 0; index < candidate_count; ++index)
+ {
+ const tiny_store_entry_t *entry
+ = tiny_store_entry(context->store, candidates[index]);
+ double score;
+ if (!entry || entry->deleted
+ || (session[0] && strcmp(entry->message.session_id, session) != 0))
+ {
+ continue;
+ }
+ score = tiny_search_score(query, &entry->message);
+ if (score > 0)
+ {
+ items[count].entry = entry;
+ items[count++].score = score;
+ }
+ }
+ qsort(items, count, sizeof(*items), compare_results);
+ if (count > limit)
+ {
+ count = limit;
+ }
+ tiny_json_init(&json);
+ tiny_json_raw(&json, "{\"results\":[");
+ for (index = 0; index < count; ++index)
+ {
+ if (index)
+ {
+ tiny_json_raw(&json, ",");
+ }
+ tiny_mcp_tool_append_message(&json, &items[index].entry->message);
+ }
+ tiny_json_raw(&json, "]}");
+ tiny_mcp_tool_add_json(result, &json);
+ tiny_json_free(&json);
+ }
+ }
+ }
+ free(items);
+ free(candidates);
+ free(query);
+ free(session);
+}
+
+bool
+tiny_mcp_register_search_messages(mcpc_server_t *server)
+{
+ mcpc_tool_t *tool = tiny_mcp_tool_new("search_messages", "Search messages", call_search_messages);
+ return tool && tiny_mcp_tool_add_property(tool, "query", "Search text", MCPC_U8STR)
+ && tiny_mcp_tool_add_property(tool, "session_id", "Session ID; empty for all", MCPC_U8STR)
+ && tiny_mcp_tool_add_property(tool, "limit", "Result limit from 1 to 100", MCPC_I32)
+ && mcpc_server_add_tool(server, tool) == MCPC_EC_0;
+}