Entropic 2.3.8
Local-first agentic inference engine
Loading...
Searching...
No Matches
git.cpp
Go to the documentation of this file.
1// SPDX-License-Identifier: Apache-2.0
12
13#include <nlohmann/json.hpp>
14
15#include <array>
16#include <cstdio>
17#include <string>
18
19static auto logger = entropic::log::get("mcp.git");
20
21namespace entropic {
22
23// ── shell helper ────────────────────────────────────────────────
24
33static std::pair<std::string, int> run_git(
34 const std::string& repo_dir,
35 const std::string& git_args) {
36
37 std::string full_cmd =
38 "git -C " + repo_dir + " " + git_args + " 2>&1";
39
40 FILE* pipe = popen(full_cmd.c_str(), "r"); // NOLINT
41 if (pipe == nullptr) {
42 return {"Failed to open git process", -1};
43 }
44
45 std::string output;
46 std::array<char, 4096> buf{};
47 while (fgets(buf.data(), buf.size(), pipe) != nullptr) {
48 output += buf.data();
49 }
50
51 int status = pclose(pipe); // NOLINT
52 int exit_code = WEXITSTATUS(status);
53 logger->info("Git: '{}' exit={}, {} chars",
54 git_args, exit_code, output.size());
55 return {output, exit_code};
56}
57
67 const std::string& output, int exit_code) {
68
69 nlohmann::json result;
70 result["exit_code"] = exit_code;
71 result["output"] = output;
72 return {result.dump(), {}};
73}
74
75// ── GitStatusTool ───────────────────────────────────────────────
76
82class GitStatusTool : public ToolBase {
83public:
92 : ToolBase(std::move(def)), server_(server) {}
93
102 }
103
111 ServerResponse execute(const std::string& args_json) override {
112 (void)args_json;
113 auto [out, rc] = run_git(
114 server_.repo_dir().string(), "status --short");
115 logger->info("[git.status] exit={}", rc);
116 return make_git_response(out, rc);
117 }
118
119private:
120 GitServer& server_;
121};
122
123// ── GitDiffTool ─────────────────────────────────────────────────
124
130class GitDiffTool : public ToolBase {
131public:
140 : ToolBase(std::move(def)), server_(server) {}
141
150 }
151
159 ServerResponse execute(const std::string& args_json) override {
160 auto args = nlohmann::json::parse(args_json);
161 std::string cmd = "diff";
162 if (args.value("staged", false)) {
163 cmd += " --staged";
164 }
165 if (args.contains("file")) {
166 cmd += " " + args["file"].get<std::string>();
167 }
168 auto [out, rc] = run_git(server_.repo_dir().string(), cmd);
169 logger->info("[git.diff] exit={}", rc);
170 return make_git_response(out, rc);
171 }
172
173private:
174 GitServer& server_;
175};
176
177// ── GitLogTool ──────────────────────────────────────────────────
178
184class GitLogTool : public ToolBase {
185public:
194 : ToolBase(std::move(def)), server_(server) {}
195
204 }
205
213 ServerResponse execute(const std::string& args_json) override {
214 auto args = nlohmann::json::parse(args_json);
215 int count = args.value("count", 10);
216 std::string cmd = "log -" + std::to_string(count);
217 if (args.value("oneline", false)) {
218 cmd += " --oneline";
219 }
220 auto [out, rc] = run_git(server_.repo_dir().string(), cmd);
221 logger->info("[git.log] exit={}", rc);
222 return make_git_response(out, rc);
223 }
224
225private:
226 GitServer& server_;
227};
228
229// ── GitCommitTool ───────────────────────────────────────────────
230
236class GitCommitTool : public ToolBase {
237public:
246 : ToolBase(std::move(def)), server_(server) {}
247
255 ServerResponse execute(const std::string& args_json) override {
256 auto args = nlohmann::json::parse(args_json);
257 auto repo = server_.repo_dir().string();
258
259 if (args.value("add_all", false)) {
260 auto [out, rc] = run_git(repo, "add -A");
261 if (rc != 0) {
262 logger->error("[git.commit] add -A failed: {}", out);
263 return make_git_response(out, rc);
264 }
265 }
266
267 std::string msg = args.at("message").get<std::string>();
268 std::string cmd = "commit -m \"" + msg + "\"";
269 auto [out, rc] = run_git(repo, cmd);
270 logger->info("[git.commit] exit={}", rc);
271 return make_git_response(out, rc);
272 }
273
274private:
275 GitServer& server_;
276};
277
278// ── GitBranchTool ───────────────────────────────────────────────
279
285class GitBranchTool : public ToolBase {
286public:
295 : ToolBase(std::move(def)), server_(server) {}
296
304 ServerResponse execute(const std::string& args_json) override {
305 auto args = nlohmann::json::parse(args_json);
306 std::string cmd = "branch -a";
307 if (args.contains("create")) {
308 cmd = "checkout -b "
309 + args["create"].get<std::string>();
310 }
311 auto [out, rc] = run_git(server_.repo_dir().string(), cmd);
312 logger->info("[git.branch] exit={}", rc);
313 return make_git_response(out, rc);
314 }
315
316private:
317 GitServer& server_;
318};
319
320// ── GitCheckoutTool ─────────────────────────────────────────────
321
327class GitCheckoutTool : public ToolBase {
328public:
337 : ToolBase(std::move(def)), server_(server) {}
338
346 ServerResponse execute(const std::string& args_json) override {
347 auto args = nlohmann::json::parse(args_json);
348 std::string target = args.at("target").get<std::string>();
349 std::string cmd = "checkout " + target;
350 auto [out, rc] = run_git(server_.repo_dir().string(), cmd);
351 logger->info("[git.checkout] target='{}' exit={}", target, rc);
352 return make_git_response(out, rc);
353 }
354
355private:
356 GitServer& server_;
357};
358
359// ── GitAddTool ──────────────────────────────────────────────────
360
366class GitAddTool : public ToolBase {
367public:
376 : ToolBase(std::move(def)), server_(server) {}
377
385 ServerResponse execute(const std::string& args_json) override {
386 auto args = nlohmann::json::parse(args_json);
387 std::string files = args.at("files").get<std::string>();
388 std::string cmd = "add " + files;
389 auto [out, rc] = run_git(server_.repo_dir().string(), cmd);
390 logger->info("[git.add] files='{}' exit={}", files, rc);
391 return make_git_response(out, rc);
392 }
393
394private:
395 GitServer& server_;
396};
397
398// ── GitResetTool ────────────────────────────────────────────────
399
405class GitResetTool : public ToolBase {
406public:
415 : ToolBase(std::move(def)), server_(server) {}
416
424 ServerResponse execute(const std::string& args_json) override {
425 auto args = nlohmann::json::parse(args_json);
426 std::string cmd = "reset HEAD";
427 if (args.contains("files")) {
428 cmd += " " + args["files"].get<std::string>();
429 }
430 auto [out, rc] = run_git(server_.repo_dir().string(), cmd);
431 logger->info("[git.reset] exit={}", rc);
432 return make_git_response(out, rc);
433 }
434
435private:
436 GitServer& server_;
437};
438
439// ── GitServer ───────────────────────────────────────────────────
440
449 const std::filesystem::path& repo_dir,
450 const std::string& data_dir)
451 : MCPServerBase("git")
452 , repo_dir_(repo_dir) {
453
454 create_git_tools(data_dir + "/tools");
455 register_git_tools();
456
457 logger->info("GitServer initialized: repo='{}'",
458 repo_dir_.string());
459}
460
467void GitServer::create_git_tools(const std::string& tools_dir) {
468 status_ = std::make_unique<GitStatusTool>(
469 load_tool_definition("status", "git", tools_dir), *this);
470 diff_ = std::make_unique<GitDiffTool>(
471 load_tool_definition("diff", "git", tools_dir), *this);
472 log_ = std::make_unique<GitLogTool>(
473 load_tool_definition("log", "git", tools_dir), *this);
474 commit_ = std::make_unique<GitCommitTool>(
475 load_tool_definition("commit", "git", tools_dir), *this);
476 branch_ = std::make_unique<GitBranchTool>(
477 load_tool_definition("branch", "git", tools_dir), *this);
478 checkout_ = std::make_unique<GitCheckoutTool>(
479 load_tool_definition("checkout", "git", tools_dir), *this);
480 add_ = std::make_unique<GitAddTool>(
481 load_tool_definition("add", "git", tools_dir), *this);
482 reset_ = std::make_unique<GitResetTool>(
483 load_tool_definition("reset", "git", tools_dir), *this);
484}
485
491void GitServer::register_git_tools() {
492 register_tool(status_.get());
493 register_tool(diff_.get());
494 register_tool(log_.get());
495 register_tool(commit_.get());
496 register_tool(branch_.get());
497 register_tool(checkout_.get());
498 register_tool(add_.get());
499 register_tool(reset_.get());
500}
501
507GitServer::~GitServer() = default;
508
516bool GitServer::set_working_dir(const std::string& path) {
517 repo_dir_ = path;
518 logger->info("Repo directory set to: {}", path);
519 return true;
520}
521
528const std::filesystem::path& GitServer::repo_dir() const {
529 return repo_dir_;
530}
531
532} // namespace entropic
Tool: git add files (space-separated).
Definition git.cpp:366
GitAddTool(ToolDefinition def, GitServer &server)
Construct with definition and server ref.
Definition git.cpp:375
ServerResponse execute(const std::string &args_json) override
Stage files for commit.
Definition git.cpp:385
Tool: git branch -a, or git checkout -b name.
Definition git.cpp:285
GitBranchTool(ToolDefinition def, GitServer &server)
Construct with definition and server ref.
Definition git.cpp:294
ServerResponse execute(const std::string &args_json) override
List branches or create a new one.
Definition git.cpp:304
Tool: git checkout target.
Definition git.cpp:327
ServerResponse execute(const std::string &args_json) override
Checkout a branch or commit.
Definition git.cpp:346
GitCheckoutTool(ToolDefinition def, GitServer &server)
Construct with definition and server ref.
Definition git.cpp:336
Tool: git commit -m "message", optionally git add -A first.
Definition git.cpp:236
GitCommitTool(ToolDefinition def, GitServer &server)
Construct with definition and server ref.
Definition git.cpp:245
ServerResponse execute(const std::string &args_json) override
Run git commit with optional add-all.
Definition git.cpp:255
Tool: git diff [–staged] [file].
Definition git.cpp:130
ServerResponse execute(const std::string &args_json) override
Run git diff with optional flags.
Definition git.cpp:159
GitDiffTool(ToolDefinition def, GitServer &server)
Construct with definition and server ref.
Definition git.cpp:139
MCPAccessLevel required_access_level() const override
Read-only tool — requires READ access.
Definition git.cpp:148
Tool: git log -N [–oneline].
Definition git.cpp:184
GitLogTool(ToolDefinition def, GitServer &server)
Construct with definition and server ref.
Definition git.cpp:193
MCPAccessLevel required_access_level() const override
Read-only tool — requires READ access.
Definition git.cpp:202
ServerResponse execute(const std::string &args_json) override
Run git log with count and format options.
Definition git.cpp:213
Tool: git reset HEAD [files].
Definition git.cpp:405
ServerResponse execute(const std::string &args_json) override
Unstage files.
Definition git.cpp:424
GitResetTool(ToolDefinition def, GitServer &server)
Construct with definition and server ref.
Definition git.cpp:414
Git MCP server for version control operations.
Definition git.h:32
GitServer(const std::filesystem::path &repo_dir, const std::string &data_dir)
Construct with repo directory and data dir.
Definition git.cpp:448
~GitServer() override
Destructor.
bool set_working_dir(const std::string &path) override
Set working directory (repo root).
Definition git.cpp:516
const std::filesystem::path & repo_dir() const
Get repo directory.
Definition git.cpp:528
Tool: git status –short.
Definition git.cpp:82
MCPAccessLevel required_access_level() const override
Read-only tool — requires READ access.
Definition git.cpp:100
GitStatusTool(ToolDefinition def, GitServer &server)
Construct with definition and repo dir ref.
Definition git.cpp:91
ServerResponse execute(const std::string &args_json) override
Run git status –short.
Definition git.cpp:111
Concrete base class for MCP servers (80% logic).
Definition server_base.h:66
void register_tool(ToolBase *tool)
Register a tool with this server.
Abstract base class for individual MCP tools.
Definition tool_base.h:45
Git MCP server — version control operations.
spdlog initialization and logger access.
ENTROPIC_EXPORT std::shared_ptr< spdlog::logger > get(const std::string &name)
Get or create a named logger.
Definition logging.cpp:211
Activate model on GPU (WARM → ACTIVE).
ToolDefinition load_tool_definition(const std::string &tool_name, const std::string &server_prefix, const std::string &data_dir)
Load a tool definition from a JSON file.
Definition tool_base.cpp:81
static ServerResponse make_git_response(const std::string &output, int exit_code)
Format a git result as JSON ServerResponse.
Definition git.cpp:66
MCPAccessLevel
MCP tool access level for per-identity authorization.
Definition config.h:38
@ READ
Read-only operations (e.g., read_file, list_directory)
static std::pair< std::string, int > run_git(const std::string &repo_dir, const std::string &git_args)
Run a git command in a given directory via popen.
Definition git.cpp:33
MCPServerBase concrete base class + ServerResponse.
Structured result from tool execution.
Definition server_base.h:33
Parsed tool definition from JSON schema file.
Definition tool_base.h:27
Abstract base class for individual MCP tools.