summaryrefslogtreecommitdiff
path: root/src/mcp/tools/common
diff options
context:
space:
mode:
authortanaka takashi <isazaka@gmail.com>2026-07-04 14:54:45 +0900
committertanaka takashi <isazaka@gmail.com>2026-07-04 14:54:45 +0900
commit1efecaef1f867cb218366e2b4ab4b901fdd2835f (patch)
tree3080a3d80a1a0671e8e82819d3f785465aace162 /src/mcp/tools/common
parent34e00404e9561dcaf8d2d99df7470757a4fee915 (diff)
途中経過コミット
Diffstat (limited to 'src/mcp/tools/common')
-rw-r--r--src/mcp/tools/common/common.c36
-rw-r--r--src/mcp/tools/common/common.h3
-rw-r--r--src/mcp/tools/common/context.c34
-rw-r--r--src/mcp/tools/common/context.h4
-rw-r--r--src/mcp/tools/common/history.c23
-rw-r--r--src/mcp/tools/common/history.h6
-rw-r--r--src/mcp/tools/common/memory_index.c219
-rw-r--r--src/mcp/tools/common/memory_index.h24
-rw-r--r--src/mcp/tools/common/registry.c5
-rw-r--r--src/mcp/tools/common/registry.h1
10 files changed, 352 insertions, 3 deletions
diff --git a/src/mcp/tools/common/common.c b/src/mcp/tools/common/common.c
index d6669f8..62f507f 100644
--- a/src/mcp/tools/common/common.c
+++ b/src/mcp/tools/common/common.c
@@ -68,6 +68,10 @@ tiny_mcp_tool_append_message(tiny_json_buffer_t *json, const tiny_message_t *mes
tiny_json_string(json, tiny_role_name(message->role));
tiny_json_raw(json, ",\"content\":");
tiny_json_string(json, message->content);
+ tiny_json_raw(json, ",\"revision\":");
+ tiny_json_u64(json, message->revision);
+ tiny_json_raw(json, ",\"updated_at\":");
+ tiny_json_i64(json, message->updated_at_ms);
tiny_json_raw(json, ",\"metadata\":{");
if (message->metadata.tool_call_id)
{
@@ -86,6 +90,38 @@ tiny_mcp_tool_append_message(tiny_json_buffer_t *json, const tiny_message_t *mes
}
tiny_json_raw(json, "],\"memory_tier\":");
tiny_json_string(json, tiny_tier_name(message->metadata.memory_tier));
+ tiny_json_raw(json, ",\"memory_kind\":");
+ tiny_json_string(json, tiny_kind_name(message->metadata.memory_kind));
+ tiny_json_raw(json, ",\"importance\":");
+ tiny_json_u64(json, message->metadata.importance);
+ if (message->metadata.summary)
+ {
+ tiny_json_raw(json, ",\"summary\":");
+ tiny_json_string(json, message->metadata.summary);
+ }
+ tiny_json_raw(json, ",\"relations\":[");
+ for (index = 0; index < message->metadata.relation_count; ++index)
+ {
+ if (index)
+ {
+ tiny_json_raw(json, ",");
+ }
+ tiny_json_raw(json, "{\"type\":");
+ tiny_json_string(json, tiny_relation_type_name(message->metadata.relations[index].type));
+ tiny_json_raw(json, ",\"message_id\":");
+ tiny_json_string(json, message->metadata.relations[index].message_id);
+ tiny_json_raw(json, "}");
+ }
+ tiny_json_raw(json, "],\"source_message_ids\":[");
+ for (index = 0; index < message->metadata.source_count; ++index)
+ {
+ if (index)
+ {
+ tiny_json_raw(json, ",");
+ }
+ tiny_json_string(json, message->metadata.source_message_ids[index]);
+ }
+ tiny_json_raw(json, "]");
tiny_json_raw(json, "}}");
}
diff --git a/src/mcp/tools/common/common.h b/src/mcp/tools/common/common.h
index 07caea1..741b2ce 100644
--- a/src/mcp/tools/common/common.h
+++ b/src/mcp/tools/common/common.h
@@ -3,12 +3,15 @@
#include "domain/message.h"
#include "mcp/json.h"
+#include "domain/message.h"
#include <mcpc/mcpc.h>
void tiny_mcp_tool_add_error(mcpc_ucbr_t *result, const char *code, const char *message);
void tiny_mcp_tool_add_json(mcpc_ucbr_t *result, tiny_json_buffer_t *json);
char *tiny_mcp_tool_get_string(const mcpc_tool_t *tool, const char *name, size_t maximum);
void tiny_mcp_tool_append_message(tiny_json_buffer_t *json, const tiny_message_t *message);
+bool
+tiny_mcp_parse_metadata(const char *json, tiny_message_t *message, tiny_metadata_mask_t *present);
mcpc_tool_t *tiny_mcp_tool_new(const char *name, const char *description, mcpc_tcallcb_t callback);
bool tiny_mcp_tool_add_property(mcpc_tool_t *tool,
diff --git a/src/mcp/tools/common/context.c b/src/mcp/tools/common/context.c
index d79b5de..e833f70 100644
--- a/src/mcp/tools/common/context.c
+++ b/src/mcp/tools/common/context.c
@@ -43,10 +43,12 @@ tiny_mcp_tools_context_new(tiny_store_t *store)
context->store = store;
context->search_index = tiny_mcp_tools_build_search_index(store);
context->history_index = tiny_history_index_build(store);
- if (!context->search_index || !context->history_index)
+ context->memory_index = tiny_memory_index_build(store);
+ if (!context->search_index || !context->history_index || !context->memory_index)
{
tiny_search_index_free(context->search_index);
tiny_history_index_free(context->history_index);
+ tiny_memory_index_free(context->memory_index);
free(context);
return NULL;
}
@@ -62,10 +64,40 @@ tiny_mcp_tools_context_free(tiny_mcp_tools_context_t *context)
}
tiny_search_index_free(context->search_index);
tiny_history_index_free(context->history_index);
+ tiny_memory_index_free(context->memory_index);
free(context);
}
bool
+tiny_mcp_tools_ensure_memory_index(tiny_mcp_tools_context_t *context)
+{
+ if (!context)
+ {
+ return false;
+ }
+ if (!context->memory_index)
+ {
+ context->memory_index = tiny_memory_index_build(context->store);
+ }
+ return context->memory_index != NULL;
+}
+
+void
+tiny_mcp_tools_invalidate_indexes(tiny_mcp_tools_context_t *context)
+{
+ if (!context)
+ {
+ return;
+ }
+ tiny_search_index_free(context->search_index);
+ tiny_history_index_free(context->history_index);
+ tiny_memory_index_free(context->memory_index);
+ context->search_index = NULL;
+ context->history_index = NULL;
+ context->memory_index = NULL;
+}
+
+bool
tiny_mcp_tools_context_activate(tiny_mcp_tools_context_t *context)
{
if (!context || active_context)
diff --git a/src/mcp/tools/common/context.h b/src/mcp/tools/common/context.h
index 2a6650a..bd167f2 100644
--- a/src/mcp/tools/common/context.h
+++ b/src/mcp/tools/common/context.h
@@ -3,6 +3,7 @@
#include "domain/search.h"
#include "mcp/tools/common/history.h"
+#include "mcp/tools/common/memory_index.h"
#include "storage/store.h"
typedef struct tiny_mcp_tools_context
@@ -10,6 +11,7 @@ typedef struct tiny_mcp_tools_context
tiny_store_t *store;
tiny_search_index_t *search_index;
tiny_history_index_t *history_index;
+ tiny_memory_index_t *memory_index;
} tiny_mcp_tools_context_t;
tiny_mcp_tools_context_t *tiny_mcp_tools_context_new(tiny_store_t *store);
@@ -19,5 +21,7 @@ void tiny_mcp_tools_context_deactivate(tiny_mcp_tools_context_t *context);
tiny_mcp_tools_context_t *tiny_mcp_tools_context_current(void);
tiny_search_index_t *tiny_mcp_tools_build_search_index(const tiny_store_t *store);
bool tiny_mcp_tools_ensure_history_index(tiny_mcp_tools_context_t *context);
+bool tiny_mcp_tools_ensure_memory_index(tiny_mcp_tools_context_t *context);
+void tiny_mcp_tools_invalidate_indexes(tiny_mcp_tools_context_t *context);
#endif
diff --git a/src/mcp/tools/common/history.c b/src/mcp/tools/common/history.c
index 6254d8c..9f08e84 100644
--- a/src/mcp/tools/common/history.c
+++ b/src/mcp/tools/common/history.c
@@ -284,3 +284,26 @@ tiny_history_index_session(const tiny_history_index_t *index,
}
return index && session_id;
}
+
+size_t
+tiny_history_index_session_count(const tiny_history_index_t *index)
+{
+ return index ? index->count : 0;
+}
+
+bool
+tiny_history_index_session_at(const tiny_history_index_t *index,
+ size_t position,
+ const char **session_id,
+ const size_t **entries,
+ size_t *count)
+{
+ if (!index || position >= index->count || !session_id || !entries || !count)
+ {
+ return false;
+ }
+ *session_id = index->buckets[position].session_id;
+ *entries = index->buckets[position].entries;
+ *count = index->buckets[position].count;
+ return true;
+}
diff --git a/src/mcp/tools/common/history.h b/src/mcp/tools/common/history.h
index ac08d99..d6f5708 100644
--- a/src/mcp/tools/common/history.h
+++ b/src/mcp/tools/common/history.h
@@ -13,5 +13,11 @@ bool tiny_history_index_session(const tiny_history_index_t *index,
const char *session_id,
const size_t **entries,
size_t *count);
+size_t tiny_history_index_session_count(const tiny_history_index_t *index);
+bool tiny_history_index_session_at(const tiny_history_index_t *index,
+ size_t position,
+ const char **session_id,
+ const size_t **entries,
+ size_t *count);
#endif
diff --git a/src/mcp/tools/common/memory_index.c b/src/mcp/tools/common/memory_index.c
new file mode 100644
index 0000000..36e430b
--- /dev/null
+++ b/src/mcp/tools/common/memory_index.c
@@ -0,0 +1,219 @@
+#include "mcp/tools/common/memory_index.h"
+
+#include <stdint.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include "base/allocator.h"
+
+#define EMPTY_SLOT SIZE_MAX
+
+typedef struct memory_bucket
+{
+ uint64_t hash;
+ char message_id[TINY_MESSAGE_ID_LENGTH + 1];
+ size_t entry_index;
+ tiny_relation_reference_t *incoming;
+ size_t incoming_count;
+ size_t incoming_capacity;
+} memory_bucket_t;
+
+struct tiny_memory_index
+{
+ memory_bucket_t *buckets;
+ size_t count;
+ size_t *slots;
+ size_t slot_capacity;
+};
+
+static uint64_t
+id_hash(const char *value)
+{
+ uint64_t hash = UINT64_C(1469598103934665603);
+ while (*value)
+ {
+ hash ^= (unsigned char)*value++;
+ hash *= UINT64_C(1099511628211);
+ }
+ return hash;
+}
+
+static size_t
+slot_start(uint64_t hash, size_t capacity)
+{
+ return (size_t)(hash ^ (hash >> 32)) & (capacity - 1);
+}
+
+static memory_bucket_t *
+find_bucket(const tiny_memory_index_t *index, const char *message_id)
+{
+ uint64_t hash;
+ size_t slot, bucket;
+ if (!index || !message_id || !index->slot_capacity)
+ {
+ return NULL;
+ }
+ hash = id_hash(message_id);
+ slot = slot_start(hash, index->slot_capacity);
+ while ((bucket = index->slots[slot]) != EMPTY_SLOT)
+ {
+ if (bucket >= index->count)
+ {
+ return NULL;
+ }
+ if (index->buckets[bucket].hash == hash
+ && strcmp(index->buckets[bucket].message_id, message_id) == 0)
+ {
+ return &index->buckets[bucket];
+ }
+ slot = (slot + 1) & (index->slot_capacity - 1);
+ }
+ return NULL;
+}
+
+static bool
+add_incoming(memory_bucket_t *bucket, size_t source, tiny_relation_type_t type)
+{
+ tiny_relation_reference_t *resized;
+ size_t capacity;
+ if (bucket->incoming_count == bucket->incoming_capacity)
+ {
+ capacity = bucket->incoming_capacity ? bucket->incoming_capacity * 2 : 4;
+ if (capacity < bucket->incoming_capacity
+ || !(resized = realloc(bucket->incoming, capacity * sizeof(*resized))))
+ {
+ return false;
+ }
+ bucket->incoming = resized;
+ bucket->incoming_capacity = capacity;
+ }
+ bucket->incoming[bucket->incoming_count].source_index = source;
+ bucket->incoming[bucket->incoming_count].type = type;
+ bucket->incoming_count++;
+ return true;
+}
+
+tiny_memory_index_t *
+tiny_memory_index_build(const tiny_store_t *store)
+{
+ tiny_memory_index_t *index;
+ size_t count = tiny_store_entry_count(store), capacity = 64, position;
+ if (!store || count > SIZE_MAX / sizeof(memory_bucket_t))
+ {
+ return NULL;
+ }
+ while (count > (capacity / 10) * 7)
+ {
+ if (capacity > SIZE_MAX / 2)
+ {
+ return NULL;
+ }
+ capacity *= 2;
+ }
+ index = calloc(1, sizeof(*index));
+ if (!index || (count && !(index->buckets = calloc(count, sizeof(*index->buckets))))
+ || !(index->slots = malloc(capacity * sizeof(*index->slots))))
+ {
+ tiny_memory_index_free(index);
+ return NULL;
+ }
+ index->count = count;
+ index->slot_capacity = capacity;
+ for (position = 0; position < capacity; ++position)
+ {
+ index->slots[position] = EMPTY_SLOT;
+ }
+ for (position = 0; position < count; ++position)
+ {
+ const tiny_store_entry_t *entry = tiny_store_entry(store, position);
+ memory_bucket_t *bucket = &index->buckets[position];
+ size_t slot;
+ memcpy(bucket->message_id, entry->message.message_id, sizeof(bucket->message_id));
+ bucket->hash = id_hash(bucket->message_id);
+ bucket->entry_index = position;
+ slot = slot_start(bucket->hash, capacity);
+ while (index->slots[slot] != EMPTY_SLOT)
+ {
+ slot = (slot + 1) & (capacity - 1);
+ }
+ index->slots[slot] = position;
+ }
+ for (position = 0; position < count; ++position)
+ {
+ const tiny_store_entry_t *entry = tiny_store_entry(store, position);
+ size_t relation;
+ if (entry->deleted)
+ {
+ continue;
+ }
+ for (relation = 0; relation < entry->message.metadata.relation_count; ++relation)
+ {
+ const tiny_relation_t *value = &entry->message.metadata.relations[relation];
+ memory_bucket_t *target = find_bucket(index, value->message_id);
+ if (!target || !add_incoming(target, position, value->type))
+ {
+ tiny_memory_index_free(index);
+ return NULL;
+ }
+ }
+ }
+ return index;
+}
+
+void
+tiny_memory_index_free(tiny_memory_index_t *index)
+{
+ size_t position;
+ if (!index)
+ {
+ return;
+ }
+ for (position = 0; position < index->count; ++position)
+ {
+ free(index->buckets[position].incoming);
+ }
+ free(index->buckets);
+ free(index->slots);
+ free(index);
+}
+
+bool
+tiny_memory_index_find(const tiny_memory_index_t *index,
+ const char *message_id,
+ size_t *entry_index)
+{
+ memory_bucket_t *bucket;
+ if (!entry_index)
+ {
+ return false;
+ }
+ *entry_index = 0;
+ bucket = find_bucket(index, message_id);
+ if (bucket)
+ {
+ *entry_index = bucket->entry_index;
+ }
+ return bucket != NULL;
+}
+
+bool
+tiny_memory_index_incoming(const tiny_memory_index_t *index,
+ const char *message_id,
+ const tiny_relation_reference_t **references,
+ size_t *count)
+{
+ memory_bucket_t *bucket;
+ if (!references || !count)
+ {
+ return false;
+ }
+ *references = NULL;
+ *count = 0;
+ bucket = find_bucket(index, message_id);
+ if (bucket)
+ {
+ *references = bucket->incoming;
+ *count = bucket->incoming_count;
+ }
+ return bucket != NULL;
+}
diff --git a/src/mcp/tools/common/memory_index.h b/src/mcp/tools/common/memory_index.h
new file mode 100644
index 0000000..fbe43a7
--- /dev/null
+++ b/src/mcp/tools/common/memory_index.h
@@ -0,0 +1,24 @@
+#ifndef TINY_CONVMEM_MCP_TOOLS_MEMORY_INDEX_H
+#define TINY_CONVMEM_MCP_TOOLS_MEMORY_INDEX_H
+
+#include "storage/store.h"
+
+typedef struct tiny_relation_reference
+{
+ size_t source_index;
+ tiny_relation_type_t type;
+} tiny_relation_reference_t;
+
+typedef struct tiny_memory_index tiny_memory_index_t;
+
+tiny_memory_index_t *tiny_memory_index_build(const tiny_store_t *store);
+void tiny_memory_index_free(tiny_memory_index_t *index);
+bool tiny_memory_index_find(const tiny_memory_index_t *index,
+ const char *message_id,
+ size_t *entry_index);
+bool tiny_memory_index_incoming(const tiny_memory_index_t *index,
+ const char *message_id,
+ const tiny_relation_reference_t **references,
+ size_t *count);
+
+#endif
diff --git a/src/mcp/tools/common/registry.c b/src/mcp/tools/common/registry.c
index 9aa1dff..1bdafc3 100644
--- a/src/mcp/tools/common/registry.c
+++ b/src/mcp/tools/common/registry.c
@@ -6,6 +6,7 @@ bool
tiny_mcp_tools_register(mcpc_server_t *server)
{
return tiny_mcp_register_write_message(server) && tiny_mcp_register_read_messages(server)
- && tiny_mcp_register_search_messages(server) && tiny_mcp_register_delete_message(server)
- && tiny_mcp_register_rebuild_index(server) && tiny_mcp_register_get_system_health(server);
+ && tiny_mcp_register_search_messages(server) && tiny_mcp_register_update_message(server)
+ && tiny_mcp_register_delete_message(server) && tiny_mcp_register_rebuild_index(server)
+ && tiny_mcp_register_get_system_health(server);
}
diff --git a/src/mcp/tools/common/registry.h b/src/mcp/tools/common/registry.h
index bbc68d0..451d300 100644
--- a/src/mcp/tools/common/registry.h
+++ b/src/mcp/tools/common/registry.h
@@ -4,6 +4,7 @@
#include <mcpc/mcpc.h>
bool tiny_mcp_register_write_message(mcpc_server_t *server);
+bool tiny_mcp_register_update_message(mcpc_server_t *server);
bool tiny_mcp_register_read_messages(mcpc_server_t *server);
bool tiny_mcp_register_search_messages(mcpc_server_t *server);
bool tiny_mcp_register_delete_message(mcpc_server_t *server);