diff options
| author | tanaka takashi <isazaka@gmail.com> | 2026-06-30 19:03:25 +0900 |
|---|---|---|
| committer | tanaka takashi <isazaka@gmail.com> | 2026-06-30 19:03:25 +0900 |
| commit | 05c8e0a31a0d4192c590e833b24393208e1c751f (patch) | |
| tree | f7c2c82c9327abde67bf3acf1d0258573b3bc6c2 /src/mcp | |
| parent | 4bc721c3bf7589b519c5730d093f704ce56e3f09 (diff) | |
fix: MCPCをvendored fork化しMCP準拠と接続安定性を改善
- Git submoduleを廃止してMCPCを直接管理
- Windowsで254リクエスト付近に発生する切断を修正
- JSON-RPC 2.0エラー応答を標準化
- tool schemaとruntimeの必須・任意引数を一致
- 1000回連続呼び出しの回帰テストを追加
Diffstat (limited to 'src/mcp')
| -rw-r--r-- | src/mcp/server.c | 4 | ||||
| -rw-r--r-- | src/mcp/tools/common/common.c | 7 | ||||
| -rw-r--r-- | src/mcp/tools/common/common.h | 3 | ||||
| -rw-r--r-- | src/mcp/tools/delete_message.c | 10 | ||||
| -rw-r--r-- | src/mcp/tools/read_messages.c | 2 | ||||
| -rw-r--r-- | src/mcp/tools/search_messages.c | 21 | ||||
| -rw-r--r-- | src/mcp/tools/write_message.c | 17 |
7 files changed, 40 insertions, 24 deletions
diff --git a/src/mcp/server.c b/src/mcp/server.c index a0ff436..498e9f4 100644 --- a/src/mcp/server.c +++ b/src/mcp/server.c @@ -30,6 +30,10 @@ tiny_convmem_server_run(FILE *input, FILE *output, tiny_store_t *store) return 1; } status = mcpc_server_start(server); + if (status != MCPC_EC_0) + { + fprintf(stderr, "mcpc server stopped with status %d\n", (int)status); + } tiny_mcp_tools_context_deactivate(context); mcpc_server_close(server); tiny_mcp_tools_context_free(context); diff --git a/src/mcp/tools/common/common.c b/src/mcp/tools/common/common.c index 71b6f68..d6669f8 100644 --- a/src/mcp/tools/common/common.c +++ b/src/mcp/tools/common/common.c @@ -104,7 +104,8 @@ bool tiny_mcp_tool_add_property(mcpc_tool_t *tool, const char *name, const char *description, - mcpc_anytype_t type) + mcpc_anytype_t type, + bool required) { mcpc_toolprop_t *property = mcpc_toolprop_new2((const char8_t *)name, (const char8_t *)description, type); @@ -112,6 +113,10 @@ tiny_mcp_tool_add_property(mcpc_tool_t *tool, { return false; } + if (mcpc_toolprop_set_required(property, required) != MCPC_EC_0) + { + return false; + } mcpc_tool_add_toolprop(tool, property); return true; } diff --git a/src/mcp/tools/common/common.h b/src/mcp/tools/common/common.h index 6b1cc96..07caea1 100644 --- a/src/mcp/tools/common/common.h +++ b/src/mcp/tools/common/common.h @@ -14,6 +14,7 @@ mcpc_tool_t *tiny_mcp_tool_new(const char *name, const char *description, mcpc_t bool tiny_mcp_tool_add_property(mcpc_tool_t *tool, const char *name, const char *description, - mcpc_anytype_t type); + mcpc_anytype_t type, + bool required); #endif diff --git a/src/mcp/tools/delete_message.c b/src/mcp/tools/delete_message.c index ae924d7..8b6e8f9 100644 --- a/src/mcp/tools/delete_message.c +++ b/src/mcp/tools/delete_message.c @@ -14,14 +14,15 @@ call_delete_message(const mcpc_tool_t *tool, mcpc_ucbr_t *result) char *message_id = tiny_mcp_tool_get_string(tool, "message_id", TINY_MESSAGE_ID_LENGTH); char *session = tiny_mcp_tool_get_string(tool, "session_id", TINY_SESSION_ID_MAX); tiny_store_status_t status; - if (!context || !message_id || !session || !tiny_message_id_valid(message_id)) + if (!context || !message_id || !tiny_message_id_valid(message_id)) { tiny_mcp_tool_add_error( result, "VALIDATION_ERROR", "message_id must be a canonical 26-character ULID"); } else { - status = tiny_store_delete(context->store, message_id, session[0] ? session : NULL); + status + = tiny_store_delete(context->store, message_id, session && session[0] ? session : NULL); if (status != TINY_STORE_OK && status != TINY_STORE_NOT_FOUND) { tiny_mcp_tool_add_error( @@ -43,8 +44,7 @@ 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) - && tiny_mcp_tool_add_property( - tool, "session_id", "Session ID; empty if omitted", MCPC_U8STR) + 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_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 55696d6..5a9e49f 100644 --- a/src/mcp/tools/read_messages.c +++ b/src/mcp/tools/read_messages.c @@ -75,6 +75,6 @@ bool tiny_mcp_register_read_messages(mcpc_server_t *server) { mcpc_tool_t *tool = tiny_mcp_tool_new("read_messages", "Read a session", call_read_messages); - return tool && tiny_mcp_tool_add_property(tool, "session_id", "Session ID", MCPC_U8STR) + return tool && tiny_mcp_tool_add_property(tool, "session_id", "Session ID", MCPC_U8STR, true) && 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 166c167..d20d7b2 100644 --- a/src/mcp/tools/search_messages.c +++ b/src/mcp/tools/search_messages.c @@ -45,14 +45,15 @@ 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; + int32_t requested_limit = 20; + mcpc_errcode_t limit_status + = mcpc_tool_get_tpropval_i32(tool, (const char8_t *)"limit", &requested_limit); 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; + bool valid = context && query && query[0] + && (limit_status == MCPC_EC_0 || limit_status == MCPC_EC_ANYDATA_NOTFOUND) + && requested_limit >= 1 && requested_limit <= 100; if (!valid) { tiny_mcp_tool_add_error(result, "VALIDATION_ERROR", "query or limit is invalid"); @@ -85,7 +86,7 @@ call_search_messages(const mcpc_tool_t *tool, mcpc_ucbr_t *result) = tiny_store_entry(context->store, candidates[index]); double score; if (!entry || entry->deleted - || (session[0] && strcmp(entry->message.session_id, session) != 0)) + || (session && session[0] && strcmp(entry->message.session_id, session) != 0)) { continue; } @@ -127,8 +128,10 @@ 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) + return tool && tiny_mcp_tool_add_property(tool, "query", "Search text", MCPC_U8STR, true) + && tiny_mcp_tool_add_property( + tool, "session_id", "Optional session ID; omitted searches all", MCPC_U8STR, false) + && tiny_mcp_tool_add_property( + tool, "limit", "Optional result limit 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 1d7ece2..f9c078a 100644 --- a/src/mcp/tools/write_message.c +++ b/src/mcp/tools/write_message.c @@ -162,8 +162,8 @@ call_write_message(const mcpc_tool_t *tool, mcpc_ucbr_t *result) input.content = tiny_mcp_tool_get_string(tool, "content", TINY_CONTENT_MAX); metadata = tiny_mcp_tool_get_string(tool, "metadata_json", TINY_CONTENT_MAX); bool valid = context && input.session_id && input.session_id[0] && role && input.content - && input.content[0] && metadata && tiny_role_parse(role, &input.role) - && parse_metadata(metadata, &input); + && input.content[0] && tiny_role_parse(role, &input.role) + && parse_metadata(metadata ? metadata : "{}", &input); if (!valid) { tiny_mcp_tool_add_error(result, "VALIDATION_ERROR", "invalid write_message arguments"); @@ -204,10 +204,13 @@ 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) - && tiny_mcp_tool_add_property(tool, "role", "user, assistant, or system", MCPC_U8STR) - && tiny_mcp_tool_add_property(tool, "content", "Message text", MCPC_U8STR) - && tiny_mcp_tool_add_property( - tool, "metadata_json", "Metadata object JSON; use {} when empty", MCPC_U8STR) + 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_add_property(tool, + "metadata_json", + "Optional metadata object JSON; defaults to {}", + MCPC_U8STR, + false) && mcpc_server_add_tool(server, tool) == MCPC_EC_0; } |
