Skip to content

Commit 83619f8

Browse files
committed
Bump MCP protocol version with proper negotiation
Support protocol versions 2025-11-25, 2025-06-18, 2025-03-26, and 2024-11-05. The server now reads the client's requested version and echoes it if supported, falling back to its latest otherwise. This fixes the "unsupported protocol" warning in VS Code 1.112+ while remaining backward-compatible with older clients.
1 parent 02575fb commit 83619f8

File tree

3 files changed

+58
-6
lines changed

3 files changed

+58
-6
lines changed

src/mcp/mcp.c

Lines changed: 35 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -342,12 +342,44 @@ char *cbm_mcp_tools_list(void) {
342342
return out;
343343
}
344344

345-
char *cbm_mcp_initialize_response(void) {
345+
/* Supported protocol versions, newest first. The server picks the newest
346+
* version that it shares with the client (per MCP spec version negotiation). */
347+
static const char *SUPPORTED_PROTOCOL_VERSIONS[] = {
348+
"2025-11-25",
349+
"2025-06-18",
350+
"2025-03-26",
351+
"2024-11-05",
352+
};
353+
static const int SUPPORTED_VERSION_COUNT =
354+
(int)(sizeof(SUPPORTED_PROTOCOL_VERSIONS) / sizeof(SUPPORTED_PROTOCOL_VERSIONS[0]));
355+
356+
char *cbm_mcp_initialize_response(const char *params_json) {
357+
/* Determine protocol version: if client requests a version we support,
358+
* echo it back; otherwise respond with our latest. */
359+
const char *version = SUPPORTED_PROTOCOL_VERSIONS[0]; /* default: latest */
360+
if (params_json) {
361+
yyjson_doc *pdoc = yyjson_read(params_json, strlen(params_json), 0);
362+
if (pdoc) {
363+
yyjson_val *pv =
364+
yyjson_obj_get(yyjson_doc_get_root(pdoc), "protocolVersion");
365+
if (pv && yyjson_is_str(pv)) {
366+
const char *requested = yyjson_get_str(pv);
367+
for (int i = 0; i < SUPPORTED_VERSION_COUNT; i++) {
368+
if (strcmp(requested, SUPPORTED_PROTOCOL_VERSIONS[i]) == 0) {
369+
version = SUPPORTED_PROTOCOL_VERSIONS[i];
370+
break;
371+
}
372+
}
373+
}
374+
yyjson_doc_free(pdoc);
375+
}
376+
}
377+
346378
yyjson_mut_doc *doc = yyjson_mut_doc_new(NULL);
347379
yyjson_mut_val *root = yyjson_mut_obj(doc);
348380
yyjson_mut_doc_set_root(doc, root);
349381

350-
yyjson_mut_obj_add_str(doc, root, "protocolVersion", "2024-11-05");
382+
yyjson_mut_obj_add_str(doc, root, "protocolVersion", version);
351383

352384
yyjson_mut_val *impl = yyjson_mut_obj(doc);
353385
yyjson_mut_obj_add_str(doc, impl, "name", "codebase-memory-mcp");
@@ -2253,7 +2285,7 @@ char *cbm_mcp_server_handle(cbm_mcp_server_t *srv, const char *line) {
22532285
char *result_json = NULL;
22542286

22552287
if (strcmp(req.method, "initialize") == 0) {
2256-
result_json = cbm_mcp_initialize_response();
2288+
result_json = cbm_mcp_initialize_response(req.params_raw);
22572289
start_update_check(srv);
22582290
detect_session(srv);
22592291
maybe_auto_index(srv);

src/mcp/mcp.h

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -55,8 +55,9 @@ char *cbm_mcp_text_result(const char *text, bool is_error);
5555
/* Format the tools/list response. Returns heap-allocated JSON. */
5656
char *cbm_mcp_tools_list(void);
5757

58-
/* Format the initialize response. Returns heap-allocated JSON. */
59-
char *cbm_mcp_initialize_response(void);
58+
/* Format the initialize response. params_json is the raw initialize params
59+
* (used for protocol version negotiation). Returns heap-allocated JSON. */
60+
char *cbm_mcp_initialize_response(const char *params_json);
6061

6162
/* ── Tool argument helpers ────────────────────────────────────── */
6263

tests/test_mcp.c

Lines changed: 20 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -98,11 +98,30 @@ TEST(jsonrpc_format_error) {
9898
* ══════════════════════════════════════════════════════════════════ */
9999

100100
TEST(mcp_initialize_response) {
101-
char *json = cbm_mcp_initialize_response();
101+
/* Default (no params): returns latest supported version */
102+
char *json = cbm_mcp_initialize_response(NULL);
102103
ASSERT_NOT_NULL(json);
103104
ASSERT_NOT_NULL(strstr(json, "codebase-memory-mcp"));
104105
ASSERT_NOT_NULL(strstr(json, "capabilities"));
105106
ASSERT_NOT_NULL(strstr(json, "tools"));
107+
ASSERT_NOT_NULL(strstr(json, "2025-11-25"));
108+
free(json);
109+
110+
/* Client requests a supported version: server echoes it */
111+
json = cbm_mcp_initialize_response("{\"protocolVersion\":\"2024-11-05\"}");
112+
ASSERT_NOT_NULL(json);
113+
ASSERT_NOT_NULL(strstr(json, "2024-11-05"));
114+
free(json);
115+
116+
json = cbm_mcp_initialize_response("{\"protocolVersion\":\"2025-06-18\"}");
117+
ASSERT_NOT_NULL(json);
118+
ASSERT_NOT_NULL(strstr(json, "2025-06-18"));
119+
free(json);
120+
121+
/* Client requests unknown version: server returns its latest */
122+
json = cbm_mcp_initialize_response("{\"protocolVersion\":\"9999-01-01\"}");
123+
ASSERT_NOT_NULL(json);
124+
ASSERT_NOT_NULL(strstr(json, "2025-11-25"));
106125
free(json);
107126
PASS();
108127
}

0 commit comments

Comments
 (0)