Entropic 2.11.1
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
41static std::pair<std::string, int> run_git(
42 const std::string& repo_dir,
43 const std::string& git_args) {
44
45 std::string full_cmd =
46 "git -C " + repo_dir + " " + git_args + " 2>&1";
47
48 FILE* pipe = popen(full_cmd.c_str(), "r"); // NOLINT
49 if (pipe == nullptr) {
50 return {"Failed to open git process", -1};
51 }
52
53 std::string output;
54 std::array<char, 4096> buf{};
55 while (fgets(buf.data(), buf.size(), pipe) != nullptr) {
56 output += buf.data();
57 }
58
59 int status = pclose(pipe); // NOLINT
60 int exit_code = WEXITSTATUS(status);
61 logger->info("Git: '{}' exit={}, {} chars",
62 git_args, exit_code, output.size());
63 return {output, exit_code};
64}
65
81 const std::string& output, int exit_code) {
82
83 nlohmann::json result;
84 result["exit_code"] = exit_code;
85 result["output"] = output;
86 return {result.dump(), {}};
87}
88
89// ── GitStatusTool ───────────────────────────────────────────────
90
96class GitStatusTool : public ToolBase {
97public:
106 : ToolBase(std::move(def)), server_(server) {}
107
120 }
121
129 ServerResponse execute(const std::string& args_json) override {
130 (void)args_json;
131 auto [out, rc] = run_git(
132 server_.repo_dir().string(), "status --short");
133 logger->info("[git.status] exit={}", rc);
134 return make_git_response(out, rc);
135 }
136
137private:
138 GitServer& server_;
139};
140
141// ── GitDiffTool ─────────────────────────────────────────────────
142
148class GitDiffTool : public ToolBase {
149public:
158 : ToolBase(std::move(def)), server_(server) {}
159
169 }
170
178 ServerResponse execute(const std::string& args_json) override {
179 auto args = nlohmann::json::parse(args_json);
180 std::string cmd = "diff";
181 if (args.value("staged", false)) {
182 cmd += " --staged";
183 }
184 if (args.contains("file")) {
185 cmd += " " + args["file"].get<std::string>();
186 }
187 auto [out, rc] = run_git(server_.repo_dir().string(), cmd);
188 logger->info("[git.diff] exit={}", rc);
189 return make_git_response(out, rc);
190 }
191
192private:
193 GitServer& server_;
194};
195
196// ── GitLogTool ──────────────────────────────────────────────────
197
203class GitLogTool : public ToolBase {
204public:
213 : ToolBase(std::move(def)), server_(server) {}
214
224 }
225
233 ServerResponse execute(const std::string& args_json) override {
234 auto args = nlohmann::json::parse(args_json);
235 int count = args.value("count", 10);
236 std::string cmd = "log -" + std::to_string(count);
237 if (args.value("oneline", false)) {
238 cmd += " --oneline";
239 }
240 auto [out, rc] = run_git(server_.repo_dir().string(), cmd);
241 logger->info("[git.log] exit={}", rc);
242 return make_git_response(out, rc);
243 }
244
245private:
246 GitServer& server_;
247};
248
249// ── GitCommitTool ───────────────────────────────────────────────
250
256class GitCommitTool : public ToolBase {
257public:
266 : ToolBase(std::move(def)), server_(server) {}
267
275 ServerResponse execute(const std::string& args_json) override {
276 auto args = nlohmann::json::parse(args_json);
277 auto repo = server_.repo_dir().string();
278
279 if (args.value("add_all", false)) {
280 auto [out, rc] = run_git(repo, "add -A");
281 if (rc != 0) {
282 logger->error("[git.commit] add -A failed: {}", out);
283 return make_git_response(out, rc);
284 }
285 }
286
287 std::string msg = args.at("message").get<std::string>();
288 std::string cmd = "commit -m \"" + msg + "\"";
289 auto [out, rc] = run_git(repo, cmd);
290 logger->info("[git.commit] exit={}", rc);
291 return make_git_response(out, rc);
292 }
293
294private:
295 GitServer& server_;
296};
297
298// ── GitBranchTool ───────────────────────────────────────────────
299
305class GitBranchTool : public ToolBase {
306public:
315 : ToolBase(std::move(def)), server_(server) {}
316
324 ServerResponse execute(const std::string& args_json) override {
325 auto args = nlohmann::json::parse(args_json);
326 std::string cmd = "branch -a";
327 if (args.contains("create")) {
328 cmd = "checkout -b "
329 + args["create"].get<std::string>();
330 }
331 auto [out, rc] = run_git(server_.repo_dir().string(), cmd);
332 logger->info("[git.branch] exit={}", rc);
333 return make_git_response(out, rc);
334 }
335
336private:
337 GitServer& server_;
338};
339
340// ── GitCheckoutTool ─────────────────────────────────────────────
341
347class GitCheckoutTool : public ToolBase {
348public:
357 : ToolBase(std::move(def)), server_(server) {}
358
366 ServerResponse execute(const std::string& args_json) override {
367 auto args = nlohmann::json::parse(args_json);
368 std::string target = args.at("target").get<std::string>();
369 std::string cmd = "checkout " + target;
370 auto [out, rc] = run_git(server_.repo_dir().string(), cmd);
371 logger->info("[git.checkout] target='{}' exit={}", target, rc);
372 return make_git_response(out, rc);
373 }
374
375private:
376 GitServer& server_;
377};
378
379// ── GitAddTool ──────────────────────────────────────────────────
380
386class GitAddTool : public ToolBase {
387public:
396 : ToolBase(std::move(def)), server_(server) {}
397
405 ServerResponse execute(const std::string& args_json) override {
406 auto args = nlohmann::json::parse(args_json);
407 std::string files = args.at("files").get<std::string>();
408 std::string cmd = "add " + files;
409 auto [out, rc] = run_git(server_.repo_dir().string(), cmd);
410 logger->info("[git.add] files='{}' exit={}", files, rc);
411 return make_git_response(out, rc);
412 }
413
414private:
415 GitServer& server_;
416};
417
418// ── GitResetTool ────────────────────────────────────────────────
419
425class GitResetTool : public ToolBase {
426public:
435 : ToolBase(std::move(def)), server_(server) {}
436
444 ServerResponse execute(const std::string& args_json) override {
445 auto args = nlohmann::json::parse(args_json);
446 std::string cmd = "reset HEAD";
447 if (args.contains("files")) {
448 cmd += " " + args["files"].get<std::string>();
449 }
450 auto [out, rc] = run_git(server_.repo_dir().string(), cmd);
451 logger->info("[git.reset] exit={}", rc);
452 return make_git_response(out, rc);
453 }
454
455private:
456 GitServer& server_;
457};
458
459// ── GitServer ───────────────────────────────────────────────────
460
474 const std::filesystem::path& repo_dir,
475 const std::string& data_dir)
476 : MCPServerBase("git")
477 , repo_dir_(repo_dir) {
478
479 create_git_tools(data_dir + "/tools");
480 register_git_tools();
481
482 logger->info("GitServer initialized: repo='{}'",
483 repo_dir_.string());
484}
485
496void GitServer::create_git_tools(const std::string& tools_dir) {
497 status_ = std::make_unique<GitStatusTool>(
498 load_tool_definition("status", "git", tools_dir), *this);
499 diff_ = std::make_unique<GitDiffTool>(
500 load_tool_definition("diff", "git", tools_dir), *this);
501 log_ = std::make_unique<GitLogTool>(
502 load_tool_definition("log", "git", tools_dir), *this);
503 commit_ = std::make_unique<GitCommitTool>(
504 load_tool_definition("commit", "git", tools_dir), *this);
505 branch_ = std::make_unique<GitBranchTool>(
506 load_tool_definition("branch", "git", tools_dir), *this);
507 checkout_ = std::make_unique<GitCheckoutTool>(
508 load_tool_definition("checkout", "git", tools_dir), *this);
509 add_ = std::make_unique<GitAddTool>(
510 load_tool_definition("add", "git", tools_dir), *this);
511 reset_ = std::make_unique<GitResetTool>(
512 load_tool_definition("reset", "git", tools_dir), *this);
513}
514
524void GitServer::register_git_tools() {
525 register_tool(status_.get());
526 register_tool(diff_.get());
527 register_tool(log_.get());
528 register_tool(commit_.get());
529 register_tool(branch_.get());
530 register_tool(checkout_.get());
531 register_tool(add_.get());
532 register_tool(reset_.get());
533}
534
540GitServer::~GitServer() = default;
541
553bool GitServer::set_working_dir(const std::string& path) {
554 repo_dir_ = path;
555 logger->info("Repo directory set to: {}", path);
556 return true;
557}
558
565const std::filesystem::path& GitServer::repo_dir() const {
566 return repo_dir_;
567}
568
569} // namespace entropic
Tool: git add files (space-separated).
Definition git.cpp:386
GitAddTool(ToolDefinition def, GitServer &server)
Construct with definition and server ref.
Definition git.cpp:395
ServerResponse execute(const std::string &args_json) override
Stage files for commit.
Definition git.cpp:405
Tool: git branch -a, or git checkout -b name.
Definition git.cpp:305
GitBranchTool(ToolDefinition def, GitServer &server)
Construct with definition and server ref.
Definition git.cpp:314
ServerResponse execute(const std::string &args_json) override
List branches or create a new one.
Definition git.cpp:324
Tool: git checkout target.
Definition git.cpp:347
ServerResponse execute(const std::string &args_json) override
Checkout a branch or commit.
Definition git.cpp:366
GitCheckoutTool(ToolDefinition def, GitServer &server)
Construct with definition and server ref.
Definition git.cpp:356
Tool: git commit -m "message", optionally git add -A first.
Definition git.cpp:256
GitCommitTool(ToolDefinition def, GitServer &server)
Construct with definition and server ref.
Definition git.cpp:265
ServerResponse execute(const std::string &args_json) override
Run git commit with optional add-all.
Definition git.cpp:275
Tool: git diff [–staged] [file].
Definition git.cpp:148
ServerResponse execute(const std::string &args_json) override
Run git diff with optional flags.
Definition git.cpp:178
GitDiffTool(ToolDefinition def, GitServer &server)
Construct with definition and server ref.
Definition git.cpp:157
MCPAccessLevel required_access_level() const override
Read-only tool — requires READ access.
Definition git.cpp:167
Tool: git log -N [–oneline].
Definition git.cpp:203
GitLogTool(ToolDefinition def, GitServer &server)
Construct with definition and server ref.
Definition git.cpp:212
MCPAccessLevel required_access_level() const override
Read-only tool — requires READ access.
Definition git.cpp:222
ServerResponse execute(const std::string &args_json) override
Run git log with count and format options.
Definition git.cpp:233
Tool: git reset HEAD [files].
Definition git.cpp:425
ServerResponse execute(const std::string &args_json) override
Unstage files.
Definition git.cpp:444
GitResetTool(ToolDefinition def, GitServer &server)
Construct with definition and server ref.
Definition git.cpp:434
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:473
~GitServer() override
Destructor.
bool set_working_dir(const std::string &path) override
Set working directory (repo root).
Definition git.cpp:553
const std::filesystem::path & repo_dir() const
Get repo directory.
Definition git.cpp:565
Tool: git status –short.
Definition git.cpp:96
MCPAccessLevel required_access_level() const override
Read-only tool — requires READ access.
Definition git.cpp:118
GitStatusTool(ToolDefinition def, GitServer &server)
Construct with definition and repo dir ref.
Definition git.cpp:105
ServerResponse execute(const std::string &args_json) override
Run git status –short.
Definition git.cpp:129
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:99
@ count
Sentinel — MUST remain last.
static ServerResponse make_git_response(const std::string &output, int exit_code)
Format a git result as JSON ServerResponse.
Definition git.cpp:80
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:41
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.