13#include <nlohmann/json.hpp>
41static std::pair<std::string, int>
run_git(
42 const std::string& repo_dir,
43 const std::string& git_args) {
45 std::string full_cmd =
46 "git -C " + repo_dir +
" " + git_args +
" 2>&1";
48 FILE* pipe = popen(full_cmd.c_str(),
"r");
49 if (pipe ==
nullptr) {
50 return {
"Failed to open git process", -1};
54 std::array<char, 4096> buf{};
55 while (fgets(buf.data(), buf.size(), pipe) !=
nullptr) {
59 int status = pclose(pipe);
60 int exit_code = WEXITSTATUS(status);
61 logger->info(
"Git: '{}' exit={}, {} chars",
62 git_args, exit_code, output.size());
63 return {output, exit_code};
81 const std::string& output,
int exit_code) {
83 nlohmann::json result;
84 result[
"exit_code"] = exit_code;
85 result[
"output"] = output;
86 return {result.dump(), {}};
106 :
ToolBase(std::move(def)), server_(server) {}
132 server_.
repo_dir().string(),
"status --short");
133 logger->info(
"[git.status] exit={}", rc);
158 :
ToolBase(std::move(def)), server_(server) {}
179 auto args = nlohmann::json::parse(args_json);
180 std::string cmd =
"diff";
181 if (args.value(
"staged",
false)) {
184 if (args.contains(
"file")) {
185 cmd +=
" " + args[
"file"].get<std::string>();
188 logger->info(
"[git.diff] exit={}", rc);
213 :
ToolBase(std::move(def)), server_(server) {}
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)) {
241 logger->info(
"[git.log] exit={}", rc);
266 :
ToolBase(std::move(def)), server_(server) {}
276 auto args = nlohmann::json::parse(args_json);
277 auto repo = server_.
repo_dir().string();
279 if (args.value(
"add_all",
false)) {
280 auto [out, rc] =
run_git(repo,
"add -A");
282 logger->error(
"[git.commit] add -A failed: {}", out);
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);
315 :
ToolBase(std::move(def)), server_(server) {}
325 auto args = nlohmann::json::parse(args_json);
326 std::string cmd =
"branch -a";
327 if (args.contains(
"create")) {
329 + args[
"create"].get<std::string>();
332 logger->info(
"[git.branch] exit={}", rc);
357 :
ToolBase(std::move(def)), server_(server) {}
367 auto args = nlohmann::json::parse(args_json);
368 std::string target = args.at(
"target").get<std::string>();
369 std::string cmd =
"checkout " + target;
371 logger->info(
"[git.checkout] target='{}' exit={}", target, rc);
396 :
ToolBase(std::move(def)), server_(server) {}
406 auto args = nlohmann::json::parse(args_json);
407 std::string files = args.at(
"files").get<std::string>();
408 std::string cmd =
"add " + files;
410 logger->info(
"[git.add] files='{}' exit={}", files, rc);
435 :
ToolBase(std::move(def)), server_(server) {}
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>();
451 logger->info(
"[git.reset] exit={}", rc);
474 const std::filesystem::path& repo_dir,
475 const std::string& data_dir)
477 , repo_dir_(repo_dir) {
479 create_git_tools(data_dir +
"/tools");
480 register_git_tools();
482 logger->info(
"GitServer initialized: repo='{}'",
496void GitServer::create_git_tools(
const std::string& tools_dir) {
497 status_ = std::make_unique<GitStatusTool>(
499 diff_ = std::make_unique<GitDiffTool>(
501 log_ = std::make_unique<GitLogTool>(
503 commit_ = std::make_unique<GitCommitTool>(
505 branch_ = std::make_unique<GitBranchTool>(
507 checkout_ = std::make_unique<GitCheckoutTool>(
509 add_ = std::make_unique<GitAddTool>(
511 reset_ = std::make_unique<GitResetTool>(
524void GitServer::register_git_tools() {
555 logger->info(
"Repo directory set to: {}", path);
Git MCP server for version control operations.
GitServer(const std::filesystem::path &repo_dir, const std::string &data_dir)
Construct with repo directory and data dir.
~GitServer() override
Destructor.
bool set_working_dir(const std::string &path) override
Set working directory (repo root).
const std::filesystem::path & repo_dir() const
Get repo directory.
Concrete base class for MCP servers (80% logic).
void register_tool(ToolBase *tool)
Register a tool with this server.
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.
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.
@ count
Sentinel — MUST remain last.
static ServerResponse make_git_response(const std::string &output, int exit_code)
Format a git result as JSON ServerResponse.
MCPAccessLevel
MCP tool access level for per-identity authorization.
@ 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.
MCPServerBase concrete base class + ServerResponse.
Structured result from tool execution.