@andre.buzeli/git-mcp 15.12.5
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +40 -0
- package/package.json +29 -0
- package/src/index.js +147 -0
- package/src/prompts/index.js +870 -0
- package/src/providers/providerManager.js +317 -0
- package/src/resources/index.js +276 -0
- package/src/tools/git-branches.js +126 -0
- package/src/tools/git-clone.js +137 -0
- package/src/tools/git-config.js +94 -0
- package/src/tools/git-diff.js +137 -0
- package/src/tools/git-files.js +82 -0
- package/src/tools/git-help.js +284 -0
- package/src/tools/git-history.js +90 -0
- package/src/tools/git-ignore.js +98 -0
- package/src/tools/git-issues.js +101 -0
- package/src/tools/git-merge.js +152 -0
- package/src/tools/git-pulls.js +115 -0
- package/src/tools/git-remote.js +492 -0
- package/src/tools/git-reset.js +105 -0
- package/src/tools/git-stash.js +120 -0
- package/src/tools/git-sync.js +129 -0
- package/src/tools/git-tags.js +113 -0
- package/src/tools/git-workflow.js +443 -0
- package/src/utils/env.js +104 -0
- package/src/utils/errors.js +431 -0
- package/src/utils/gitAdapter.js +996 -0
- package/src/utils/hooks.js +255 -0
- package/src/utils/metrics.js +198 -0
- package/src/utils/providerExec.js +61 -0
- package/src/utils/repoHelpers.js +216 -0
- package/src/utils/retry.js +123 -0
package/README.md
ADDED
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
# @andrebuzeli/git-mcp
|
|
2
|
+
|
|
3
|
+
Servidor MCP (Model Context Protocol) para operações Git locais sem git instalado, com sincronização paralela para GitHub e Gitea.
|
|
4
|
+
|
|
5
|
+
## Configuração MCP
|
|
6
|
+
|
|
7
|
+
```json
|
|
8
|
+
{
|
|
9
|
+
"mcpServers": {
|
|
10
|
+
"git-mcp": {
|
|
11
|
+
"command": "npx",
|
|
12
|
+
"args": ["@andrebuzeli/git-mcp@latest"],
|
|
13
|
+
"env": {
|
|
14
|
+
"GITEA_URL": "https://seu-gitea",
|
|
15
|
+
"GITEA_TOKEN": "...",
|
|
16
|
+
"GITHUB_TOKEN": "..."
|
|
17
|
+
}
|
|
18
|
+
}
|
|
19
|
+
}
|
|
20
|
+
}
|
|
21
|
+
```
|
|
22
|
+
|
|
23
|
+
## Tools
|
|
24
|
+
|
|
25
|
+
- git-workflow: init, status, add, remove, commit, ensure-remotes, push
|
|
26
|
+
- git-update: status -> add -> commit -> push (all-in-one)
|
|
27
|
+
- git-remote: list, ensure
|
|
28
|
+
- git-branches: list, create, delete, rename, checkout
|
|
29
|
+
- git-tags: list, create, delete, push
|
|
30
|
+
- git-stash: list, save, apply, pop, drop, clear
|
|
31
|
+
- git-reset: soft, mixed, hard
|
|
32
|
+
- git-config: get, set, unset, list
|
|
33
|
+
- git-ignore: list, create, add, remove
|
|
34
|
+
- git-files: list, read
|
|
35
|
+
- git-history: log
|
|
36
|
+
- git-sync: fetch, pull
|
|
37
|
+
- git-issues: create, list, comment
|
|
38
|
+
- git-pulls: create, list, files
|
|
39
|
+
|
|
40
|
+
Todas as tools exigem `projectPath` e operam com derivação automática do nome do repositório a partir do caminho.
|
package/package.json
ADDED
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@andre.buzeli/git-mcp",
|
|
3
|
+
"version": "15.12.5",
|
|
4
|
+
"private": false,
|
|
5
|
+
"description": "MCP server para Git com operações locais e sincronização paralela GitHub/Gitea",
|
|
6
|
+
"license": "MIT",
|
|
7
|
+
"author": "andrebuzeli",
|
|
8
|
+
"type": "module",
|
|
9
|
+
"publishConfig": {
|
|
10
|
+
"access": "public"
|
|
11
|
+
},
|
|
12
|
+
"files": [
|
|
13
|
+
"src",
|
|
14
|
+
"README.md"
|
|
15
|
+
],
|
|
16
|
+
"main": "src/index.js",
|
|
17
|
+
"bin": {
|
|
18
|
+
"git-mcp": "src/index.js",
|
|
19
|
+
"git-mcpv2": "src/index.js"
|
|
20
|
+
},
|
|
21
|
+
"scripts": {},
|
|
22
|
+
"dependencies": {
|
|
23
|
+
"@modelcontextprotocol/sdk": "^0.4.0",
|
|
24
|
+
"@octokit/rest": "^20.0.0",
|
|
25
|
+
"ajv": "^8.12.0",
|
|
26
|
+
"archiver": "^7.0.0",
|
|
27
|
+
"axios": "^1.7.7"
|
|
28
|
+
}
|
|
29
|
+
}
|
package/src/index.js
ADDED
|
@@ -0,0 +1,147 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
import { Server } from "@modelcontextprotocol/sdk/server/index.js";
|
|
3
|
+
import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio.js";
|
|
4
|
+
import Ajv from "ajv";
|
|
5
|
+
import { loadEnv } from "./utils/env.js";
|
|
6
|
+
import { asToolError } from "./utils/errors.js";
|
|
7
|
+
import { ProviderManager } from "./providers/providerManager.js";
|
|
8
|
+
import { GitAdapter } from "./utils/gitAdapter.js";
|
|
9
|
+
import { createGitWorkflowTool } from "./tools/git-workflow.js";
|
|
10
|
+
import { createGitRemoteTool } from "./tools/git-remote.js";
|
|
11
|
+
import { createGitBranchesTool } from "./tools/git-branches.js";
|
|
12
|
+
import { createGitTagsTool } from "./tools/git-tags.js";
|
|
13
|
+
import { createGitStashTool } from "./tools/git-stash.js";
|
|
14
|
+
import { createGitResetTool } from "./tools/git-reset.js";
|
|
15
|
+
import { createGitConfigTool } from "./tools/git-config.js";
|
|
16
|
+
import { createGitIgnoreTool } from "./tools/git-ignore.js";
|
|
17
|
+
import { createGitFilesTool } from "./tools/git-files.js";
|
|
18
|
+
import { createGitHistoryTool } from "./tools/git-history.js";
|
|
19
|
+
import { createGitSyncTool } from "./tools/git-sync.js";
|
|
20
|
+
import { createGitIssuesTool } from "./tools/git-issues.js";
|
|
21
|
+
import { createGitPullsTool } from "./tools/git-pulls.js";
|
|
22
|
+
import { createGitMergeTool } from "./tools/git-merge.js";
|
|
23
|
+
import { createGitDiffTool } from "./tools/git-diff.js";
|
|
24
|
+
import { createGitCloneTool } from "./tools/git-clone.js";
|
|
25
|
+
import { createGitHelpTool } from "./tools/git-help.js";
|
|
26
|
+
import { getResources, readResource } from "./resources/index.js";
|
|
27
|
+
import { createPromptsHandler, PROMPTS } from "./prompts/index.js";
|
|
28
|
+
|
|
29
|
+
// Carrega variáveis de ambiente do arquivo .env (se existir)
|
|
30
|
+
loadEnv();
|
|
31
|
+
|
|
32
|
+
const pm = new ProviderManager();
|
|
33
|
+
const git = new GitAdapter(pm);
|
|
34
|
+
|
|
35
|
+
// Log de inicialização para stderr (não interfere com stdio do MCP)
|
|
36
|
+
const hasGitHub = !!process.env.GITHUB_TOKEN;
|
|
37
|
+
const hasGitea = !!process.env.GITEA_URL && !!process.env.GITEA_TOKEN;
|
|
38
|
+
if (!hasGitHub && !hasGitea) {
|
|
39
|
+
console.error("[git-mcp] ⚠️ Nenhum provider configurado. Operações remotas não funcionarão.");
|
|
40
|
+
console.error("[git-mcp] Configure GITHUB_TOKEN e/ou GITEA_URL + GITEA_TOKEN");
|
|
41
|
+
} else {
|
|
42
|
+
const providers = [];
|
|
43
|
+
if (hasGitHub) providers.push("GitHub");
|
|
44
|
+
if (hasGitea) providers.push("Gitea");
|
|
45
|
+
console.error(`[git-mcp] ✓ Providers ativos: ${providers.join(", ")}`);
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
const transport = new StdioServerTransport();
|
|
49
|
+
const server = new Server(
|
|
50
|
+
{ name: "git-mcp", version: "15.12.4" },
|
|
51
|
+
{ capabilities: { tools: {}, resources: {}, prompts: {} } }
|
|
52
|
+
);
|
|
53
|
+
server.connect(transport);
|
|
54
|
+
|
|
55
|
+
// Prompts handler
|
|
56
|
+
const promptsHandler = createPromptsHandler(git, pm);
|
|
57
|
+
|
|
58
|
+
// Ajv singleton para validação
|
|
59
|
+
const ajv = new Ajv({ allErrors: true });
|
|
60
|
+
|
|
61
|
+
const tools = [
|
|
62
|
+
createGitHelpTool(), // Primeiro: AI pode pedir ajuda
|
|
63
|
+
createGitWorkflowTool(pm, git),
|
|
64
|
+
createGitRemoteTool(pm, git),
|
|
65
|
+
createGitBranchesTool(git),
|
|
66
|
+
createGitTagsTool(git),
|
|
67
|
+
createGitStashTool(git),
|
|
68
|
+
createGitResetTool(git),
|
|
69
|
+
createGitConfigTool(git),
|
|
70
|
+
createGitIgnoreTool(git),
|
|
71
|
+
createGitFilesTool(git),
|
|
72
|
+
createGitHistoryTool(git),
|
|
73
|
+
createGitSyncTool(git),
|
|
74
|
+
createGitIssuesTool(pm),
|
|
75
|
+
createGitPullsTool(pm),
|
|
76
|
+
createGitMergeTool(git),
|
|
77
|
+
createGitDiffTool(git),
|
|
78
|
+
createGitCloneTool(git),
|
|
79
|
+
];
|
|
80
|
+
|
|
81
|
+
// ============ TOOLS ============
|
|
82
|
+
server.setRequestHandler(
|
|
83
|
+
(await import("@modelcontextprotocol/sdk/types.js")).ListToolsRequestSchema,
|
|
84
|
+
async () => ({
|
|
85
|
+
tools: tools.map(t => ({ name: t.name, description: t.description, inputSchema: t.inputSchema })),
|
|
86
|
+
})
|
|
87
|
+
);
|
|
88
|
+
|
|
89
|
+
server.setRequestHandler(
|
|
90
|
+
(await import("@modelcontextprotocol/sdk/types.js")).CallToolRequestSchema,
|
|
91
|
+
async (req) => {
|
|
92
|
+
const name = req.params?.name || "";
|
|
93
|
+
const args = req.params?.arguments || {};
|
|
94
|
+
// Progress reporting removed to prevent timeouts/unknown token errors on slow networks
|
|
95
|
+
// const progressToken = req.params?._meta?.progressToken;
|
|
96
|
+
|
|
97
|
+
const tool = tools.find(t => t.name === name);
|
|
98
|
+
if (!tool) return { content: [{ type: "text", text: `Tool não encontrada: ${name}` }], isError: true };
|
|
99
|
+
try {
|
|
100
|
+
// if (progressToken) { await server.notification({ method: "notifications/progress", params: { progressToken, progress: 0 } }); }
|
|
101
|
+
|
|
102
|
+
const result = await tool.handle(args);
|
|
103
|
+
|
|
104
|
+
// if (progressToken) { await server.notification({ method: "notifications/progress", params: { progressToken, progress: 100 } }); }
|
|
105
|
+
|
|
106
|
+
return result;
|
|
107
|
+
} catch (e) {
|
|
108
|
+
return asToolError(e.code || "ERROR", e.message || String(e));
|
|
109
|
+
}
|
|
110
|
+
}
|
|
111
|
+
);
|
|
112
|
+
|
|
113
|
+
// ============ RESOURCES ============
|
|
114
|
+
server.setRequestHandler(
|
|
115
|
+
(await import("@modelcontextprotocol/sdk/types.js")).ListResourcesRequestSchema,
|
|
116
|
+
async () => ({ resources: getResources() })
|
|
117
|
+
);
|
|
118
|
+
|
|
119
|
+
server.setRequestHandler(
|
|
120
|
+
(await import("@modelcontextprotocol/sdk/types.js")).ReadResourceRequestSchema,
|
|
121
|
+
async (req) => {
|
|
122
|
+
const uri = req.params?.uri || "";
|
|
123
|
+
const content = readResource(uri);
|
|
124
|
+
if (!content) {
|
|
125
|
+
return { contents: [{ uri, mimeType: "text/plain", text: `Resource não encontrado: ${uri}` }] };
|
|
126
|
+
}
|
|
127
|
+
return { contents: [{ uri, mimeType: "text/markdown", text: content }] };
|
|
128
|
+
}
|
|
129
|
+
);
|
|
130
|
+
|
|
131
|
+
// ============ PROMPTS ============
|
|
132
|
+
server.setRequestHandler(
|
|
133
|
+
(await import("@modelcontextprotocol/sdk/types.js")).ListPromptsRequestSchema,
|
|
134
|
+
async () => ({ prompts: PROMPTS })
|
|
135
|
+
);
|
|
136
|
+
|
|
137
|
+
server.setRequestHandler(
|
|
138
|
+
(await import("@modelcontextprotocol/sdk/types.js")).GetPromptRequestSchema,
|
|
139
|
+
async (req) => {
|
|
140
|
+
const name = req.params?.name || "";
|
|
141
|
+
const args = req.params?.arguments || {};
|
|
142
|
+
return await promptsHandler.get(name, args);
|
|
143
|
+
}
|
|
144
|
+
);
|
|
145
|
+
|
|
146
|
+
// Keep process alive
|
|
147
|
+
process.stdin.resume();
|