summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--.gitignore3
-rw-r--r--README.md12
-rw-r--r--src/mcp/tools/delete_message.c20
-rw-r--r--src/mcp/tools/get_system_health.c7
-rw-r--r--src/mcp/tools/read_messages.c26
-rw-r--r--src/mcp/tools/rebuild_index.c7
-rw-r--r--src/mcp/tools/search_messages.c26
-rw-r--r--src/mcp/tools/write_message.c18
-rw-r--r--tests/mcp_protocol_test.py34
9 files changed, 128 insertions, 25 deletions
diff --git a/.gitignore b/.gitignore
index 82b0bc7..d4dcdce 100644
--- a/.gitignore
+++ b/.gitignore
@@ -85,3 +85,6 @@ __pycache__/
.DS_Store
Thumbs.db
Desktop.ini
+
+# other
+data/
diff --git a/README.md b/README.md
index db9a5ff..e264c54 100644
--- a/README.md
+++ b/README.md
@@ -54,12 +54,12 @@ stdoutはMCP JSON-RPC専用、stderrは診断専用です。
## MCP tools
-- `write_message`: サーバ生成ULID・UTC timestamp付きメッセージを同期永続化
-- `read_messages`: sessionの有効メッセージを時系列順にpagination取得(既定100件、最大1000件)
-- `search_messages`: contentとtagsをUTF-8コードポイントの2/3-gramで検索
-- `delete_message`: DELレコードを同期永続化して即時不可視化
-- `rebuild_index`: 有効PUTだけにcompactionしsnapshotを再生成
-- `get_system_health`: ログ、snapshot、復旧状態、件数を報告
+- `write_message`: 再起動後も利用する会話メッセージを同期永続化
+- `read_messages`: 既知のsessionの会話履歴を時系列順にpagination取得
+- `search_messages`: 全sessionまたは特定sessionからcontent・tagsに一致する記憶を検索
+- `delete_message`: メッセージをread/searchから即時除外(物理除去はrebuild後)
+- `rebuild_index`: 保守時にStoreをcompactし、snapshotとメモリindexを再構築
+- `get_system_health`: 永続化・復旧問題の診断に必要なStore状態と件数を取得
ツール結果はMCP TextContent内のJSON文字列です。入力schema、サイズ制限、エラーコード
および物理フォーマットは[architecture](docs/architecture.md)を参照してください。
diff --git a/src/mcp/tools/delete_message.c b/src/mcp/tools/delete_message.c
index 8b6e8f9..f90bbe3 100644
--- a/src/mcp/tools/delete_message.c
+++ b/src/mcp/tools/delete_message.c
@@ -43,8 +43,22 @@ call_delete_message(const mcpc_tool_t *tool, mcpc_ucbr_t *result)
bool
tiny_mcp_register_delete_message(mcpc_server_t *server)
{
- mcpc_tool_t *tool = tiny_mcp_tool_new("delete_message", "Delete a message", call_delete_message);
- return tool && tiny_mcp_tool_add_property(tool, "message_id", "Message ULID", MCPC_U8STR, true)
- && tiny_mcp_tool_add_property(tool, "session_id", "Optional session ID", MCPC_U8STR, false)
+ mcpc_tool_t *tool = tiny_mcp_tool_new(
+ "delete_message",
+ "Delete a persisted message so it is immediately excluded from reads and "
+ "searches. Physical removal occurs after rebuild_index compacts the store.",
+ call_delete_message);
+ return tool
+ && tiny_mcp_tool_add_property(tool,
+ "message_id",
+ "Canonical 26-character ULID of the message to delete.",
+ MCPC_U8STR,
+ true)
+ && tiny_mcp_tool_add_property(tool,
+ "session_id",
+ "Optional session guard; when provided, delete only if the "
+ "message belongs to this session.",
+ MCPC_U8STR,
+ false)
&& mcpc_server_add_tool(server, tool) == MCPC_EC_0;
}
diff --git a/src/mcp/tools/get_system_health.c b/src/mcp/tools/get_system_health.c
index eb02090..5fd3fc8 100644
--- a/src/mcp/tools/get_system_health.c
+++ b/src/mcp/tools/get_system_health.c
@@ -43,7 +43,10 @@ call_get_system_health(const mcpc_tool_t *tool, mcpc_ucbr_t *result)
bool
tiny_mcp_register_get_system_health(mcpc_server_t *server)
{
- mcpc_tool_t *tool
- = tiny_mcp_tool_new("get_system_health", "Report storage health", call_get_system_health);
+ mcpc_tool_t *tool = tiny_mcp_tool_new(
+ "get_system_health",
+ "Inspect storage health, recovery state, message counts, and file sizes. Use "
+ "it to diagnose persistence or recovery problems.",
+ call_get_system_health);
return tool && mcpc_server_add_tool(server, tool) == MCPC_EC_0;
}
diff --git a/src/mcp/tools/read_messages.c b/src/mcp/tools/read_messages.c
index 1581534..44a026f 100644
--- a/src/mcp/tools/read_messages.c
+++ b/src/mcp/tools/read_messages.c
@@ -318,11 +318,29 @@ call_read_messages(const mcpc_tool_t *tool, mcpc_ucbr_t *result)
bool
tiny_mcp_register_read_messages(mcpc_server_t *server)
{
- mcpc_tool_t *tool = tiny_mcp_tool_new("read_messages", "Read a session page", call_read_messages);
- return tool && tiny_mcp_tool_add_property(tool, "session_id", "Session ID", MCPC_U8STR, true)
+ mcpc_tool_t *tool
+ = tiny_mcp_tool_new("read_messages",
+ "Read persisted messages from one known session in chronological order. "
+ "Returns a paginated history for reconstructing that conversation.",
+ call_read_messages);
+ return tool
+ && tiny_mcp_tool_add_property(tool,
+ "session_id",
+ "Conversation session whose chronological history to read.",
+ MCPC_U8STR,
+ true)
&& tiny_mcp_tool_add_property(
- tool, "limit", "Optional page limit from 1 to 1000; defaults to 100", MCPC_I32, false)
+ tool,
+ "limit",
+ "Maximum messages to return in this page, from 1 to 1000; defaults to 100.",
+ MCPC_I32,
+ false)
&& tiny_mcp_tool_add_property(
- tool, "cursor", "Optional opaque page cursor", MCPC_U8STR, false)
+ tool,
+ "cursor",
+ "Opaque nextCursor returned by a previous read_messages call; "
+ "omit for the first page.",
+ MCPC_U8STR,
+ false)
&& mcpc_server_add_tool(server, tool) == MCPC_EC_0;
}
diff --git a/src/mcp/tools/rebuild_index.c b/src/mcp/tools/rebuild_index.c
index 7208d77..e6dbf69 100644
--- a/src/mcp/tools/rebuild_index.c
+++ b/src/mcp/tools/rebuild_index.c
@@ -59,6 +59,11 @@ call_rebuild_index(const mcpc_tool_t *tool, mcpc_ucbr_t *result)
bool
tiny_mcp_register_rebuild_index(mcpc_server_t *server)
{
- mcpc_tool_t *tool = tiny_mcp_tool_new("rebuild_index", "Compact and rebuild", call_rebuild_index);
+ mcpc_tool_t *tool = tiny_mcp_tool_new(
+ "rebuild_index",
+ "Compact the store and rebuild its snapshot and in-memory indexes. Use it "
+ "for maintenance or to physically remove logically deleted records; it may "
+ "block other requests while running.",
+ call_rebuild_index);
return tool && mcpc_server_add_tool(server, tool) == MCPC_EC_0;
}
diff --git a/src/mcp/tools/search_messages.c b/src/mcp/tools/search_messages.c
index d20d7b2..44db1ef 100644
--- a/src/mcp/tools/search_messages.c
+++ b/src/mcp/tools/search_messages.c
@@ -127,11 +127,29 @@ call_search_messages(const mcpc_tool_t *tool, mcpc_ucbr_t *result)
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, true)
+ mcpc_tool_t *tool
+ = tiny_mcp_tool_new("search_messages",
+ "Search persisted message content and tags by text relevance. Use it to "
+ "recall matching information globally or within one session.",
+ call_search_messages);
+ return tool
&& tiny_mcp_tool_add_property(
- tool, "session_id", "Optional session ID; omitted searches all", MCPC_U8STR, false)
+ tool,
+ "query",
+ "UTF-8 text to match against persisted message content and tags.",
+ MCPC_U8STR,
+ true)
&& tiny_mcp_tool_add_property(
- tool, "limit", "Optional result limit from 1 to 100; defaults to 20", MCPC_I32, false)
+ tool,
+ "session_id",
+ "Conversation session to search; omit to search across all sessions.",
+ MCPC_U8STR,
+ false)
+ && tiny_mcp_tool_add_property(
+ tool,
+ "limit",
+ "Maximum ranked matches to return, from 1 to 100; defaults to 20.",
+ MCPC_I32,
+ false)
&& mcpc_server_add_tool(server, tool) == MCPC_EC_0;
}
diff --git a/src/mcp/tools/write_message.c b/src/mcp/tools/write_message.c
index c4b18cc..7df0058 100644
--- a/src/mcp/tools/write_message.c
+++ b/src/mcp/tools/write_message.c
@@ -211,13 +211,21 @@ bool
tiny_mcp_register_write_message(mcpc_server_t *server)
{
mcpc_tool_t *tool
- = tiny_mcp_tool_new("write_message", "Append a conversation message", call_write_message);
- return tool && tiny_mcp_tool_add_property(tool, "session_id", "Session ID", MCPC_U8STR, true)
- && tiny_mcp_tool_add_property(tool, "role", "user, assistant, or system", MCPC_U8STR, true)
- && tiny_mcp_tool_add_property(tool, "content", "Message text", MCPC_U8STR, true)
+ = tiny_mcp_tool_new("write_message",
+ "Append and durably persist a conversation message. Use it to store "
+ "information that should remain available after server restarts.",
+ call_write_message);
+ return tool
+ && tiny_mcp_tool_add_property(
+ tool, "session_id", "Conversation session that owns the message.", MCPC_U8STR, true)
+ && tiny_mcp_tool_add_property(
+ tool, "role", "Message author role: user, assistant, or system.", MCPC_U8STR, true)
+ && tiny_mcp_tool_add_property(
+ tool, "content", "UTF-8 message text to persist.", MCPC_U8STR, true)
&& tiny_mcp_tool_add_property(tool,
"metadata_json",
- "Optional metadata object JSON; defaults to {}",
+ "Optional JSON object string containing tool_call_id, tags, "
+ "and/or memory_tier; defaults to {}.",
MCPC_U8STR,
false)
&& mcpc_server_add_tool(server, tool) == MCPC_EC_0;
diff --git a/tests/mcp_protocol_test.py b/tests/mcp_protocol_test.py
index 4d1deb2..2dc70ff 100644
--- a/tests/mcp_protocol_test.py
+++ b/tests/mcp_protocol_test.py
@@ -128,6 +128,40 @@ def main() -> None:
"rebuild_index",
"get_system_health",
}
+ expected_descriptions = {
+ "write_message": "Append and durably persist a conversation message. Use it to store information that should remain available after server restarts.",
+ "read_messages": "Read persisted messages from one known session in chronological order. Returns a paginated history for reconstructing that conversation.",
+ "search_messages": "Search persisted message content and tags by text relevance. Use it to recall matching information globally or within one session.",
+ "delete_message": "Delete a persisted message so it is immediately excluded from reads and searches. Physical removal occurs after rebuild_index compacts the store.",
+ "rebuild_index": "Compact the store and rebuild its snapshot and in-memory indexes. Use it for maintenance or to physically remove logically deleted records; it may block other requests while running.",
+ "get_system_health": "Inspect storage health, recovery state, message counts, and file sizes. Use it to diagnose persistence or recovery problems.",
+ }
+ assert {name: tool["description"] for name, tool in tools.items()} == expected_descriptions
+ expected_property_descriptions = {
+ "write_message": {
+ "session_id": "Conversation session that owns the message.",
+ "role": "Message author role: user, assistant, or system.",
+ "content": "UTF-8 message text to persist.",
+ "metadata_json": "Optional JSON object string containing tool_call_id, tags, and/or memory_tier; defaults to {}.",
+ },
+ "read_messages": {
+ "session_id": "Conversation session whose chronological history to read.",
+ "limit": "Maximum messages to return in this page, from 1 to 1000; defaults to 100.",
+ "cursor": "Opaque nextCursor returned by a previous read_messages call; omit for the first page.",
+ },
+ "search_messages": {
+ "query": "UTF-8 text to match against persisted message content and tags.",
+ "session_id": "Conversation session to search; omit to search across all sessions.",
+ "limit": "Maximum ranked matches to return, from 1 to 100; defaults to 20.",
+ },
+ "delete_message": {
+ "message_id": "Canonical 26-character ULID of the message to delete.",
+ "session_id": "Optional session guard; when provided, delete only if the message belongs to this session.",
+ },
+ }
+ for tool_name, descriptions in expected_property_descriptions.items():
+ properties = tools[tool_name]["inputSchema"]["properties"]
+ assert {name: value["description"] for name, value in properties.items()} == descriptions
assert tools["write_message"]["inputSchema"]["required"] == [
"session_id",
"role",