summaryrefslogtreecommitdiff
path: root/src/mcp
diff options
context:
space:
mode:
authortanaka takashi <isazaka@gmail.com>2026-06-30 19:03:25 +0900
committertanaka takashi <isazaka@gmail.com>2026-06-30 19:03:25 +0900
commit05c8e0a31a0d4192c590e833b24393208e1c751f (patch)
treef7c2c82c9327abde67bf3acf1d0258573b3bc6c2 /src/mcp
parent4bc721c3bf7589b519c5730d093f704ce56e3f09 (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.c4
-rw-r--r--src/mcp/tools/common/common.c7
-rw-r--r--src/mcp/tools/common/common.h3
-rw-r--r--src/mcp/tools/delete_message.c10
-rw-r--r--src/mcp/tools/read_messages.c2
-rw-r--r--src/mcp/tools/search_messages.c21
-rw-r--r--src/mcp/tools/write_message.c17
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;
}