#pragma once #include "MCPServer.h" #include #include #include #include class MCPAgentWorkflowLoop { public: struct Config { std::string projectName = "workflow-project"; std::string skeletonName = "skeleton"; std::string language = "cpp"; }; struct Blocker { std::string itemId; std::string kind; std::string prompt; }; struct AgentSubmission { std::string generatedCode; double confidence = 0.8; std::string reasoning; }; struct Report { bool success = false; int blockersProcessed = 0; std::vector toolCalls; json finalProgress = json::object(); }; using AgentHandler = std::function; explicit MCPAgentWorkflowLoop(MCPServer& server) : server_(server) {} Report run(const Config& config, AgentHandler handler) { Report r; ensureRequiredToolsPresent(); callTool("whetstone_infer_annotations", json::object(), r); callTool("whetstone_create_skeleton", {{"name", config.skeletonName}, {"language", config.language}}, r); callTool("whetstone_create_workflow", {{"projectName", config.projectName}}, r); callTool("whetstone_orchestrate_run_deterministic", json::object(), r); json blockersResp = callTool("whetstone_get_blockers", json::object(), r); auto blockers = parseBlockers(blockersResp); for (const auto& b : blockers) { AgentSubmission sub = handler ? handler(b) : AgentSubmission{}; json result = { {"generatedCode", sub.generatedCode}, {"confidence", sub.confidence}, {"reasoning", sub.reasoning} }; callTool("whetstone_submit_result", {{"itemId", b.itemId}, {"result", result}}, r); r.blockersProcessed++; } r.finalProgress = callTool("whetstone_get_progress", json::object(), r); r.success = !r.finalProgress.contains("error"); return r; } static std::vector parseBlockers(const json& response) { std::vector out; if (!response.is_object()) return out; if (!response.contains("blockers") || !response["blockers"].is_array()) return out; for (const auto& b : response["blockers"]) { Blocker item; item.itemId = b.value("itemId", b.value("id", "")); item.kind = b.value("kind", b.value("type", "")); item.prompt = b.value("prompt", b.value("reason", "")); if (!item.itemId.empty()) out.push_back(item); } return out; } private: MCPServer& server_; void ensureRequiredToolsPresent() const { const std::vector required = { "whetstone_infer_annotations", "whetstone_create_skeleton", "whetstone_create_workflow", "whetstone_orchestrate_run_deterministic", "whetstone_get_blockers", "whetstone_submit_result", "whetstone_get_progress" }; for (const auto& name : required) { if (!hasTool(name)) { throw std::runtime_error("Missing required MCP tool: " + name); } } } bool hasTool(const std::string& name) const { for (const auto& t : server_.getTools()) if (t.name == name) return true; return false; } json callTool(const std::string& name, const json& args, Report& r) { r.toolCalls.push_back(name); json req = { {"jsonrpc", "2.0"}, {"id", 1}, {"method", "tools/call"}, {"params", { {"name", name}, {"arguments", args} }} }; json resp = server_.handleRequest(req); if (!resp.contains("result")) return json{{"error", "missing result"}}; auto result = resp["result"]; if (result.value("isError", false)) return json{{"error", "tool call failed"}}; if (!result.contains("content") || !result["content"].is_array() || result["content"].empty()) { return json{{"error", "missing content"}}; } std::string text = result["content"][0].value("text", ""); try { return json::parse(text); } catch (...) { return json{{"raw", text}}; } } };