Skip to content

Commit 76f8ae1

Browse files
Add errors_returned counter to MCP server status
Track the number of error responses returned by the MCP server, providing better visibility into server health and debugging. Changes: - Add errors_returned atomic counter to MCPServer class - Increment counter when response.IsError() in ProcessOneMessage and HandleConnection - Add errors_returned to MCPStatus struct type - Include in GetStatus() output - Update CreateMCPStatus helper function - Update tests with new field in expected output 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
1 parent b4daa09 commit 76f8ae1

File tree

5 files changed

+26
-11
lines changed

5 files changed

+26
-11
lines changed

src/duckdb_mcp_extension.cpp

Lines changed: 10 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -462,14 +462,16 @@ static LogicalType GetMCPStatusType() {
462462
members.push_back({"background", LogicalType::BOOLEAN});
463463
members.push_back({"requests_received", LogicalType::UBIGINT});
464464
members.push_back({"responses_sent", LogicalType::UBIGINT});
465+
members.push_back({"errors_returned", LogicalType::UBIGINT});
465466
return LogicalType::STRUCT(members);
466467
}
467468

468469
// Helper to create MCPStatus struct value
469470
static Value CreateMCPStatus(bool success, bool running, const string &message,
470471
const string &transport = "", const string &listen = "",
471472
int port = 0, bool background = false,
472-
uint64_t requests_received = 0, uint64_t responses_sent = 0) {
473+
uint64_t requests_received = 0, uint64_t responses_sent = 0,
474+
uint64_t errors_returned = 0) {
473475
child_list_t<Value> values;
474476
values.push_back({"success", Value::BOOLEAN(success)});
475477
values.push_back({"running", Value::BOOLEAN(running)});
@@ -480,6 +482,7 @@ static Value CreateMCPStatus(bool success, bool running, const string &message,
480482
values.push_back({"background", Value::BOOLEAN(background)});
481483
values.push_back({"requests_received", Value::UBIGINT(requests_received)});
482484
values.push_back({"responses_sent", Value::UBIGINT(responses_sent)});
485+
values.push_back({"errors_returned", Value::UBIGINT(errors_returned)});
483486
return Value::STRUCT(values);
484487
}
485488

@@ -578,11 +581,13 @@ static Value MCPServerStartImpl(ExpressionState &state,
578581
server.RunMainLoop(); // Blocks until max_requests or shutdown
579582
return CreateMCPStatus(true, false, "MCP server completed",
580583
transport, bind_address, port, false,
581-
server.GetRequestsReceived(), server.GetResponsesSent());
584+
server.GetRequestsReceived(), server.GetResponsesSent(),
585+
server.GetErrorsReturned());
582586
} catch (const std::exception &e) {
583587
return CreateMCPStatus(false, false, string(e.what()),
584588
transport, bind_address, port, false,
585-
server.GetRequestsReceived(), server.GetResponsesSent());
589+
server.GetRequestsReceived(), server.GetResponsesSent(),
590+
server.GetErrorsReturned());
586591
}
587592
}
588593
} else if (transport == "memory") {
@@ -723,7 +728,8 @@ static void MCPServerStatusFunction(DataChunk &args, ExpressionState &state, Vec
723728
result.SetValue(i, CreateMCPStatus(true, true, server->GetStatus(),
724729
"", "", 0, true,
725730
server->GetRequestsReceived(),
726-
server->GetResponsesSent()));
731+
server->GetResponsesSent(),
732+
server->GetErrorsReturned()));
727733
} else {
728734
result.SetValue(i, CreateMCPStatus(false, false, "Server manager inconsistency"));
729735
}

src/include/server/mcp_server.hpp

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -91,6 +91,7 @@ class MCPServer {
9191
time_t GetUptime() const;
9292
uint64_t GetRequestsReceived() const { return requests_received.load(); }
9393
uint64_t GetResponsesSent() const { return responses_sent.load(); }
94+
uint64_t GetErrorsReturned() const { return errors_returned.load(); }
9495

9596
// Resource management
9697
bool PublishResource(const string &uri, unique_ptr<ResourceProvider> provider);
@@ -121,6 +122,7 @@ class MCPServer {
121122
atomic<uint32_t> active_connections;
122123
atomic<uint64_t> requests_received;
123124
atomic<uint64_t> responses_sent;
125+
atomic<uint64_t> errors_returned;
124126
time_t start_time;
125127

126128
ResourceRegistry resource_registry;

src/server/mcp_server.cpp

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -85,7 +85,7 @@ bool ToolRegistry::ToolExists(const string &name) const {
8585
//===--------------------------------------------------------------------===//
8686

8787
MCPServer::MCPServer(const MCPServerConfig &config)
88-
: config(config), running(false), active_connections(0), requests_received(0), responses_sent(0) {
88+
: config(config), running(false), active_connections(0), requests_received(0), responses_sent(0), errors_returned(0) {
8989
start_time = time(nullptr);
9090
}
9191

@@ -179,6 +179,7 @@ string MCPServer::GetStatus() const {
179179
status += "Connections: " + std::to_string(active_connections.load()) + "\n";
180180
status += "Requests Received: " + std::to_string(requests_received.load()) + "\n";
181181
status += "Responses Sent: " + std::to_string(responses_sent.load()) + "\n";
182+
status += "Errors Returned: " + std::to_string(errors_returned.load()) + "\n";
182183
status += "Uptime: " + std::to_string(GetUptime()) + " seconds\n";
183184
status += "Resources: " + std::to_string(resource_registry.ListResources().size()) + "\n";
184185
status += "Tools: " + std::to_string(tool_registry.ListTools().size());
@@ -271,6 +272,9 @@ bool MCPServer::ProcessOneMessage() {
271272
auto response = HandleRequest(request);
272273
test_transport->Send(response);
273274
responses_sent.fetch_add(1);
275+
if (response.IsError()) {
276+
errors_returned.fetch_add(1);
277+
}
274278
return true;
275279
} catch (const std::exception &) {
276280
return false;
@@ -288,6 +292,9 @@ void MCPServer::HandleConnection(unique_ptr<MCPTransport> transport) {
288292
auto response = HandleRequest(request);
289293
transport->Send(response);
290294
responses_sent.fetch_add(1);
295+
if (response.IsError()) {
296+
errors_returned.fetch_add(1);
297+
}
291298

292299
// If this was a shutdown request, break out of the loop
293300
if (request.method == MCPMethods::SHUTDOWN) {

test/sql/mcp_memory_transport.test

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,7 @@ SELECT mcp_server_stop(true);
2323
query I
2424
SELECT mcp_server_start('memory');
2525
----
26-
{'success': true, 'running': true, 'message': 'MCP server started on memory transport (background mode)', 'transport': memory, 'listen': localhost, 'port': 0, 'background': true, 'requests_received': 0, 'responses_sent': 0}
26+
{'success': true, 'running': true, 'message': 'MCP server started on memory transport (background mode)', 'transport': memory, 'listen': localhost, 'port': 0, 'background': true, 'requests_received': 0, 'responses_sent': 0, 'errors_returned': 0}
2727

2828
# Test initialize handshake - verify MCP spec compliance
2929
# See: https://modelcontextprotocol.io/specification/2024-11-05/basic/lifecycle

test/sql/mcp_server_lifecycle.test

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -10,36 +10,36 @@ require duckdb_mcp
1010
query I
1111
SELECT mcp_server_stop(true);
1212
----
13-
{'success': true, 'running': false, 'message': 'MCP server state cleared (forced)', 'transport': '', 'listen': '', 'port': 0, 'background': false, 'requests_received': 0, 'responses_sent': 0}
13+
{'success': true, 'running': false, 'message': 'MCP server state cleared (forced)', 'transport': '', 'listen': '', 'port': 0, 'background': false, 'requests_received': 0, 'responses_sent': 0, 'errors_returned': 0}
1414

1515
# ===================================
1616
# Test 2: Check status shows stopped
1717
# ===================================
1818
query I
1919
SELECT mcp_server_status();
2020
----
21-
{'success': true, 'running': false, 'message': Server is stopped, 'transport': '', 'listen': '', 'port': 0, 'background': false, 'requests_received': 0, 'responses_sent': 0}
21+
{'success': true, 'running': false, 'message': Server is stopped, 'transport': '', 'listen': '', 'port': 0, 'background': false, 'requests_received': 0, 'responses_sent': 0, 'errors_returned': 0}
2222

2323
# ===================================
2424
# Test 3: Start server with memory transport
2525
# ===================================
2626
query I
2727
SELECT mcp_server_start('memory');
2828
----
29-
{'success': true, 'running': true, 'message': 'MCP server started on memory transport (background mode)', 'transport': memory, 'listen': localhost, 'port': 0, 'background': true, 'requests_received': 0, 'responses_sent': 0}
29+
{'success': true, 'running': true, 'message': 'MCP server started on memory transport (background mode)', 'transport': memory, 'listen': localhost, 'port': 0, 'background': true, 'requests_received': 0, 'responses_sent': 0, 'errors_returned': 0}
3030

3131
# ===================================
3232
# Test 4: Stop server
3333
# ===================================
3434
query I
3535
SELECT mcp_server_stop();
3636
----
37-
{'success': true, 'running': false, 'message': MCP server stopped, 'transport': '', 'listen': '', 'port': 0, 'background': false, 'requests_received': 0, 'responses_sent': 0}
37+
{'success': true, 'running': false, 'message': MCP server stopped, 'transport': '', 'listen': '', 'port': 0, 'background': false, 'requests_received': 0, 'responses_sent': 0, 'errors_returned': 0}
3838

3939
# ===================================
4040
# Test 5: Final cleanup
4141
# ===================================
4242
query I
4343
SELECT mcp_server_stop(true);
4444
----
45-
{'success': true, 'running': false, 'message': 'MCP server state cleared (forced)', 'transport': '', 'listen': '', 'port': 0, 'background': false, 'requests_received': 0, 'responses_sent': 0}
45+
{'success': true, 'running': false, 'message': 'MCP server state cleared (forced)', 'transport': '', 'listen': '', 'port': 0, 'background': false, 'requests_received': 0, 'responses_sent': 0, 'errors_returned': 0}

0 commit comments

Comments
 (0)