Skip to content

Commit 2f07e63

Browse files
committed
MCP: add basic tools as reference
1 parent cfb123f commit 2f07e63

5 files changed

Lines changed: 552 additions & 11 deletions

File tree

network/mcp/mcp_adapter.c

Lines changed: 102 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,7 @@
2323
#include "mcp_adapter.h"
2424
#include "mcp_defines.h"
2525
#include "mcp_adapter_tool_list.h"
26+
#include "mcp_adapter_utils.h"
2627
#include "mcp_json_templates.h"
2728
#include "../../version.h"
2829
#include "../../verbosity.h"
@@ -36,6 +37,8 @@ typedef struct
3637
char method[128];
3738
char tool_name[128];
3839
char protocol_version[32];
40+
char args_json[MCP_JSON_MAX_REQUEST];
41+
size_t args_len;
3942
bool is_notification;
4043
} mcp_request_t;
4144

@@ -46,6 +49,9 @@ static bool mcp_parse_request(const char *json, size_t len, mcp_request_t *req)
4649
int depth = 0;
4750
bool in_params = false;
4851
int params_depth = 0;
52+
bool in_arguments = false;
53+
int args_depth = 0;
54+
const char *args_key = NULL;
4955
const char *key = NULL;
5056
size_t key_len = 0;
5157

@@ -65,8 +71,24 @@ static bool mcp_parse_request(const char *json, size_t len, mcp_request_t *req)
6571
if (type == RJSON_OBJECT)
6672
{
6773
depth++;
68-
if (in_params)
74+
if (in_arguments)
75+
{
76+
args_depth++;
77+
}
78+
else if (in_params)
79+
{
6980
params_depth++;
81+
if (params_depth == 2 && key && string_is_equal(key, "arguments"))
82+
{
83+
in_arguments = true;
84+
args_depth = 1;
85+
args_key = NULL;
86+
req->args_json[0] = '{';
87+
req->args_json[1] = '\0';
88+
req->args_len = 1;
89+
key = NULL;
90+
}
91+
}
7092
else if (depth == 2 && key && string_is_equal(key, "params"))
7193
{
7294
in_params = true;
@@ -77,6 +99,19 @@ static bool mcp_parse_request(const char *json, size_t len, mcp_request_t *req)
7799
}
78100
if (type == RJSON_OBJECT_END)
79101
{
102+
if (in_arguments)
103+
{
104+
args_depth--;
105+
if (args_depth <= 0)
106+
{
107+
if (req->args_len + 2 < sizeof(req->args_json))
108+
{
109+
req->args_json[req->args_len++] = '}';
110+
req->args_json[req->args_len] = '\0';
111+
}
112+
in_arguments = false;
113+
}
114+
}
80115
if (in_params)
81116
{
82117
params_depth--;
@@ -88,17 +123,78 @@ static bool mcp_parse_request(const char *json, size_t len, mcp_request_t *req)
88123
}
89124
if (type == RJSON_ARRAY)
90125
{
91-
if (in_params)
126+
if (in_arguments)
127+
args_depth++;
128+
else if (in_params)
92129
params_depth++;
93130
continue;
94131
}
95132
if (type == RJSON_ARRAY_END)
96133
{
97-
if (in_params)
134+
if (in_arguments)
135+
args_depth--;
136+
else if (in_params)
98137
params_depth--;
99138
continue;
100139
}
101140

141+
/* inside arguments - capture flat key/value pairs */
142+
if (in_arguments && args_depth == 1)
143+
{
144+
if (type == RJSON_STRING)
145+
{
146+
size_t slen;
147+
const char *s = rjson_get_string(parser, &slen);
148+
if (!args_key)
149+
args_key = s;
150+
else
151+
{
152+
/* string value: append "key":"value" */
153+
char tmp[512];
154+
char escaped[256];
155+
mcp_json_escape(escaped, sizeof(escaped), s);
156+
if (req->args_len > 1)
157+
req->args_json[req->args_len++] = ',';
158+
snprintf(tmp, sizeof(tmp), "\"%s\":\"%s\"", args_key, escaped);
159+
req->args_len += strlcpy(
160+
req->args_json + req->args_len,
161+
tmp,
162+
sizeof(req->args_json) - req->args_len);
163+
args_key = NULL;
164+
}
165+
}
166+
else if (type == RJSON_NUMBER && args_key)
167+
{
168+
/* number value: append "key":123 */
169+
char tmp[256];
170+
if (req->args_len > 1)
171+
req->args_json[req->args_len++] = ',';
172+
snprintf(tmp, sizeof(tmp), "\"%s\":%d", args_key,
173+
rjson_get_int(parser));
174+
req->args_len += strlcpy(
175+
req->args_json + req->args_len,
176+
tmp,
177+
sizeof(req->args_json) - req->args_len);
178+
args_key = NULL;
179+
}
180+
else if ((type == RJSON_TRUE || type == RJSON_FALSE) && args_key)
181+
{
182+
char tmp[256];
183+
if (req->args_len > 1)
184+
req->args_json[req->args_len++] = ',';
185+
snprintf(tmp, sizeof(tmp), "\"%s\":%s", args_key,
186+
type == RJSON_TRUE ? "true" : "false");
187+
req->args_len += strlcpy(
188+
req->args_json + req->args_len,
189+
tmp,
190+
sizeof(req->args_json) - req->args_len);
191+
args_key = NULL;
192+
}
193+
else
194+
args_key = NULL;
195+
continue;
196+
}
197+
102198
/* inside params - look for "name" key for tools/call */
103199
if (in_params && params_depth == 1 && type == RJSON_STRING)
104200
{
@@ -233,7 +329,9 @@ void mcp_adapter_handle_request(const char *json_request, size_t len,
233329
"Invalid params: missing tool name");
234330
return;
235331
}
236-
mcp_tools_call(req.id, req.tool_name, response, response_size);
332+
mcp_tools_call(req.id, req.tool_name,
333+
req.args_json, req.args_len,
334+
response, response_size);
237335
return;
238336
}
239337

network/mcp/mcp_adapter_tool_list.c

Lines changed: 15 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,11 @@
2828
#include "../../content.h"
2929
#include "../../paths.h"
3030
#include "../../verbosity.h"
31+
#include "../../command.h"
32+
#include "../../configuration.h"
33+
#include "../../version.h"
34+
#include "../../gfx/video_driver.h"
35+
#include "../../audio/audio_driver.h"
3136

3237
#include "mcp_adapter_tools.h"
3338

@@ -39,7 +44,12 @@
3944
*/
4045

4146
static const mcp_tool_t mcp_tools[] = {
42-
{ "get_content_info", tool_get_content_info_json, mcp_tool_get_content_info },
47+
{ "get_content_info", tool_get_content_info_json, mcp_tool_get_content_info },
48+
{ "get_status", tool_get_status_json, mcp_tool_get_status },
49+
{ "pause_resume", tool_pause_resume_json, mcp_tool_pause_resume },
50+
{ "reset", tool_reset_json, mcp_tool_reset },
51+
{ "save_state", tool_save_state_json, mcp_tool_save_state },
52+
{ "load_state", tool_load_state_json, mcp_tool_load_state },
4353
};
4454

4555
static const size_t mcp_tools_count = sizeof(mcp_tools) / sizeof(mcp_tools[0]);
@@ -66,7 +76,9 @@ void mcp_tools_build_list(int64_t id, char *buf, size_t buf_size)
6676
strlcpy(buf + pos, "]}}", buf_size - pos);
6777
}
6878

69-
void mcp_tools_call(int64_t id, const char *tool_name, char *buf, size_t buf_size)
79+
void mcp_tools_call(int64_t id, const char *tool_name,
80+
const char *args_json, size_t args_len,
81+
char *buf, size_t buf_size)
7082
{
7183
char normalized[128];
7284
size_t i;
@@ -84,7 +96,7 @@ void mcp_tools_call(int64_t id, const char *tool_name, char *buf, size_t buf_siz
8496
if (string_is_equal(normalized, mcp_tools[i].name))
8597
{
8698
char escaped[MCP_JSON_MAX_RESPONSE];
87-
mcp_tools[i].handler(buf, buf_size);
99+
mcp_tools[i].handler(args_json, args_len, buf, buf_size);
88100
mcp_json_escape(escaped, sizeof(escaped), buf);
89101
snprintf(buf, buf_size, mcp_content_info_fmt, (long long)id, escaped);
90102
return;

network/mcp/mcp_adapter_tool_list.h

Lines changed: 8 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -22,8 +22,11 @@ RETRO_BEGIN_DECLS
2222

2323
/* Handler function for a single MCP tool.
2424
* Writes the raw JSON result object into the provided buffer.
25-
* The dispatcher wraps it in the JSON-RPC response envelope. */
26-
typedef void (*mcp_tool_handler_t)(char *buf, size_t buf_size);
25+
* The dispatcher wraps it in the JSON-RPC response envelope.
26+
* args_json / args_len contain the raw JSON of the
27+
* "arguments" object (may be empty or NULL). */
28+
typedef void (*mcp_tool_handler_t)(const char *args_json,
29+
size_t args_len, char *buf, size_t buf_size);
2730

2831
/* Definition of one MCP tool. */
2932
typedef struct
@@ -37,7 +40,9 @@ typedef struct
3740
void mcp_tools_build_list(int64_t id, char *buf, size_t buf_size);
3841

3942
/* Dispatch a "tools/call" request to the matching tool handler. */
40-
void mcp_tools_call(int64_t id, const char *tool_name, char *buf, size_t buf_size);
43+
void mcp_tools_call(int64_t id, const char *tool_name,
44+
const char *args_json, size_t args_len,
45+
char *buf, size_t buf_size);
4146

4247
RETRO_END_DECLS
4348

0 commit comments

Comments
 (0)