@andre.buzeli/git-mcp 16.0.8 → 16.1.2
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/package.json +32 -29
- package/src/index.js +159 -147
- package/src/tools/git-branches.js +13 -3
- package/src/tools/git-clone.js +48 -85
- package/src/tools/git-config.js +13 -3
- package/src/tools/git-diff.js +121 -137
- package/src/tools/git-files.js +13 -3
- package/src/tools/git-help.js +322 -284
- package/src/tools/git-history.js +13 -3
- package/src/tools/git-ignore.js +13 -3
- package/src/tools/git-issues.js +13 -3
- package/src/tools/git-merge.js +13 -3
- package/src/tools/git-pulls.js +14 -4
- package/src/tools/git-remote.js +503 -492
- package/src/tools/git-reset.js +23 -4
- package/src/tools/git-stash.js +13 -3
- package/src/tools/git-sync.js +13 -3
- package/src/tools/git-tags.js +13 -3
- package/src/tools/git-workflow.js +599 -456
- package/src/tools/git-worktree.js +180 -0
- package/src/utils/errors.js +434 -433
- package/src/utils/gitAdapter.js +118 -6
- package/src/utils/mcpNotify.js +45 -0
- package/src/utils/repoHelpers.js +5 -31
- package/src/utils/hooks.js +0 -255
- package/src/utils/metrics.js +0 -198
package/package.json
CHANGED
|
@@ -1,29 +1,32 @@
|
|
|
1
|
-
{
|
|
2
|
-
"name": "@andre.buzeli/git-mcp",
|
|
3
|
-
"version": "16.
|
|
4
|
-
"private": false,
|
|
5
|
-
"description": "MCP server para Git com operações locais e sincronização paralela GitHub/Gitea",
|
|
6
|
-
"license": "MIT",
|
|
7
|
-
"author": "andre.buzeli",
|
|
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
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
"
|
|
26
|
-
"
|
|
27
|
-
"
|
|
28
|
-
|
|
29
|
-
|
|
1
|
+
{
|
|
2
|
+
"name": "@andre.buzeli/git-mcp",
|
|
3
|
+
"version": "16.1.2",
|
|
4
|
+
"private": false,
|
|
5
|
+
"description": "MCP server para Git com operações locais e sincronização paralela GitHub/Gitea",
|
|
6
|
+
"license": "MIT",
|
|
7
|
+
"author": "andre.buzeli",
|
|
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
|
+
"start": "node src/index.js"
|
|
23
|
+
},
|
|
24
|
+
"dependencies": {
|
|
25
|
+
"@modelcontextprotocol/sdk": "^1.11.0",
|
|
26
|
+
"@octokit/rest": "^20.0.0",
|
|
27
|
+
"ajv": "^8.12.0",
|
|
28
|
+
"archiver": "^7.0.0",
|
|
29
|
+
"axios": "^1.7.7",
|
|
30
|
+
"zod": "^3.23.0"
|
|
31
|
+
}
|
|
32
|
+
}
|
package/src/index.js
CHANGED
|
@@ -1,147 +1,159 @@
|
|
|
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 {
|
|
26
|
-
import {
|
|
27
|
-
import {
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
(
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
}
|
|
129
|
-
);
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
);
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
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 { createGitWorktreeTool } from "./tools/git-worktree.js";
|
|
26
|
+
import { createGitHelpTool } from "./tools/git-help.js";
|
|
27
|
+
import { getResources, readResource } from "./resources/index.js";
|
|
28
|
+
import { createPromptsHandler, PROMPTS } from "./prompts/index.js";
|
|
29
|
+
import { sendProgress } from "./utils/mcpNotify.js";
|
|
30
|
+
|
|
31
|
+
// Carrega variáveis de ambiente do arquivo .env (se existir)
|
|
32
|
+
loadEnv();
|
|
33
|
+
|
|
34
|
+
const pm = new ProviderManager();
|
|
35
|
+
const git = new GitAdapter(pm);
|
|
36
|
+
|
|
37
|
+
// Log de inicialização para stderr (não interfere com stdio do MCP)
|
|
38
|
+
const hasGitHub = !!process.env.GITHUB_TOKEN;
|
|
39
|
+
const hasGitea = !!process.env.GITEA_URL && !!process.env.GITEA_TOKEN;
|
|
40
|
+
if (!hasGitHub && !hasGitea) {
|
|
41
|
+
console.error("[git-mcp] ⚠️ Nenhum provider configurado. Operações remotas não funcionarão.");
|
|
42
|
+
console.error("[git-mcp] Configure GITHUB_TOKEN e/ou GITEA_URL + GITEA_TOKEN");
|
|
43
|
+
} else {
|
|
44
|
+
const providers = [];
|
|
45
|
+
if (hasGitHub) providers.push("GitHub");
|
|
46
|
+
if (hasGitea) providers.push("Gitea");
|
|
47
|
+
console.error(`[git-mcp] ✓ Providers ativos: ${providers.join(", ")}`);
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
const transport = new StdioServerTransport();
|
|
51
|
+
const server = new Server(
|
|
52
|
+
{ name: "git-mcp", version: "16.0.8" },
|
|
53
|
+
{ capabilities: {
|
|
54
|
+
tools: { listChanged: true },
|
|
55
|
+
resources: { subscribe: true, listChanged: true },
|
|
56
|
+
prompts: {},
|
|
57
|
+
logging: {}
|
|
58
|
+
} }
|
|
59
|
+
);
|
|
60
|
+
server.connect(transport);
|
|
61
|
+
|
|
62
|
+
// Prompts handler
|
|
63
|
+
const promptsHandler = createPromptsHandler(git, pm);
|
|
64
|
+
|
|
65
|
+
// Ajv singleton para validação
|
|
66
|
+
const ajv = new Ajv({ allErrors: true });
|
|
67
|
+
|
|
68
|
+
const tools = [
|
|
69
|
+
createGitHelpTool(), // Primeiro: AI pode pedir ajuda
|
|
70
|
+
createGitWorkflowTool(pm, git, server),
|
|
71
|
+
createGitRemoteTool(pm, git, server),
|
|
72
|
+
createGitBranchesTool(git),
|
|
73
|
+
createGitTagsTool(git),
|
|
74
|
+
createGitStashTool(git),
|
|
75
|
+
createGitResetTool(git, server),
|
|
76
|
+
createGitConfigTool(git),
|
|
77
|
+
createGitIgnoreTool(git),
|
|
78
|
+
createGitFilesTool(git),
|
|
79
|
+
createGitHistoryTool(git),
|
|
80
|
+
createGitSyncTool(git),
|
|
81
|
+
createGitIssuesTool(pm),
|
|
82
|
+
createGitPullsTool(pm),
|
|
83
|
+
createGitMergeTool(git),
|
|
84
|
+
createGitDiffTool(git),
|
|
85
|
+
createGitCloneTool(git),
|
|
86
|
+
createGitWorktreeTool(git),
|
|
87
|
+
];
|
|
88
|
+
|
|
89
|
+
// ============ TOOLS ============
|
|
90
|
+
server.setRequestHandler(
|
|
91
|
+
(await import("@modelcontextprotocol/sdk/types.js")).ListToolsRequestSchema,
|
|
92
|
+
async () => ({
|
|
93
|
+
tools: tools.map(t => ({
|
|
94
|
+
name: t.name,
|
|
95
|
+
description: t.description,
|
|
96
|
+
inputSchema: t.inputSchema,
|
|
97
|
+
annotations: t.annotations
|
|
98
|
+
})),
|
|
99
|
+
})
|
|
100
|
+
);
|
|
101
|
+
|
|
102
|
+
server.setRequestHandler(
|
|
103
|
+
(await import("@modelcontextprotocol/sdk/types.js")).CallToolRequestSchema,
|
|
104
|
+
async (req) => {
|
|
105
|
+
const name = req.params?.name || "";
|
|
106
|
+
const args = req.params?.arguments || {};
|
|
107
|
+
const progressToken = req.params?._meta?.progressToken;
|
|
108
|
+
|
|
109
|
+
const tool = tools.find(t => t.name === name);
|
|
110
|
+
if (!tool) return { content: [{ type: "text", text: `Tool não encontrada: ${name}` }], isError: true };
|
|
111
|
+
try {
|
|
112
|
+
await sendProgress(server, progressToken, 0, 100, `Executando ${name}...`);
|
|
113
|
+
|
|
114
|
+
const result = await tool.handle(args);
|
|
115
|
+
|
|
116
|
+
await sendProgress(server, progressToken, 100, 100, `${name} concluído`);
|
|
117
|
+
|
|
118
|
+
return result;
|
|
119
|
+
} catch (e) {
|
|
120
|
+
return asToolError(e.code || "ERROR", e.message || String(e));
|
|
121
|
+
}
|
|
122
|
+
}
|
|
123
|
+
);
|
|
124
|
+
|
|
125
|
+
// ============ RESOURCES ============
|
|
126
|
+
server.setRequestHandler(
|
|
127
|
+
(await import("@modelcontextprotocol/sdk/types.js")).ListResourcesRequestSchema,
|
|
128
|
+
async () => ({ resources: getResources() })
|
|
129
|
+
);
|
|
130
|
+
|
|
131
|
+
server.setRequestHandler(
|
|
132
|
+
(await import("@modelcontextprotocol/sdk/types.js")).ReadResourceRequestSchema,
|
|
133
|
+
async (req) => {
|
|
134
|
+
const uri = req.params?.uri || "";
|
|
135
|
+
const content = readResource(uri);
|
|
136
|
+
if (!content) {
|
|
137
|
+
return { contents: [{ uri, mimeType: "text/plain", text: `Resource não encontrado: ${uri}` }] };
|
|
138
|
+
}
|
|
139
|
+
return { contents: [{ uri, mimeType: "text/markdown", text: content }] };
|
|
140
|
+
}
|
|
141
|
+
);
|
|
142
|
+
|
|
143
|
+
// ============ PROMPTS ============
|
|
144
|
+
server.setRequestHandler(
|
|
145
|
+
(await import("@modelcontextprotocol/sdk/types.js")).ListPromptsRequestSchema,
|
|
146
|
+
async () => ({ prompts: PROMPTS })
|
|
147
|
+
);
|
|
148
|
+
|
|
149
|
+
server.setRequestHandler(
|
|
150
|
+
(await import("@modelcontextprotocol/sdk/types.js")).GetPromptRequestSchema,
|
|
151
|
+
async (req) => {
|
|
152
|
+
const name = req.params?.name || "";
|
|
153
|
+
const args = req.params?.arguments || {};
|
|
154
|
+
return await promptsHandler.get(name, args);
|
|
155
|
+
}
|
|
156
|
+
);
|
|
157
|
+
|
|
158
|
+
// Keep process alive
|
|
159
|
+
process.stdin.resume();
|
|
@@ -10,7 +10,7 @@ export function createGitBranchesTool(git) {
|
|
|
10
10
|
properties: {
|
|
11
11
|
projectPath: {
|
|
12
12
|
type: "string",
|
|
13
|
-
description: "Caminho absoluto do diretório do projeto"
|
|
13
|
+
description: "Caminho absoluto do diretório do projeto no IDE (ex: '/home/user/meu-projeto' ou 'C:/Users/user/meu-projeto'). IMPORTANTE: este valor não pode ser inferido automaticamente pelo servidor — o agente deve fornecer o path real do projeto sendo trabalhado, não o diretório home do usuário."
|
|
14
14
|
},
|
|
15
15
|
action: {
|
|
16
16
|
type: "string",
|
|
@@ -39,7 +39,11 @@ export function createGitBranchesTool(git) {
|
|
|
39
39
|
additionalProperties: false
|
|
40
40
|
};
|
|
41
41
|
|
|
42
|
-
const description = `
|
|
42
|
+
const description = `IMPORTANTE — projectPath:
|
|
43
|
+
Informe o caminho absoluto do projeto aberto no IDE. O servidor MCP não tem acesso ao
|
|
44
|
+
contexto do IDE e não consegue detectar automaticamente qual projeto está sendo trabalhado.
|
|
45
|
+
|
|
46
|
+
Gerenciamento de branches Git.
|
|
43
47
|
|
|
44
48
|
AÇÕES DISPONÍVEIS:
|
|
45
49
|
- list: Ver branches existentes (locais e remotas)
|
|
@@ -122,5 +126,11 @@ CONVENÇÕES DE NOMES:
|
|
|
122
126
|
}
|
|
123
127
|
}
|
|
124
128
|
|
|
125
|
-
return {
|
|
129
|
+
return {
|
|
130
|
+
name: "git-branches",
|
|
131
|
+
description,
|
|
132
|
+
inputSchema,
|
|
133
|
+
handle,
|
|
134
|
+
annotations: { readOnlyHint: false, destructiveHint: false, idempotentHint: false }
|
|
135
|
+
};
|
|
126
136
|
}
|
package/src/tools/git-clone.js
CHANGED
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import Ajv from "ajv";
|
|
2
|
-
import { asToolError, asToolResult, errorToResponse
|
|
3
|
-
import { validateProjectPath
|
|
2
|
+
import { asToolError, asToolResult, errorToResponse } from "../utils/errors.js";
|
|
3
|
+
import { validateProjectPath } from "../utils/repoHelpers.js";
|
|
4
|
+
import { withRetry } from "../utils/retry.js";
|
|
4
5
|
|
|
5
6
|
const ajv = new Ajv({ allErrors: true });
|
|
6
7
|
|
|
@@ -10,128 +11,90 @@ export function createGitCloneTool(git) {
|
|
|
10
11
|
properties: {
|
|
11
12
|
projectPath: {
|
|
12
13
|
type: "string",
|
|
13
|
-
description: "Caminho absoluto onde o repositório será clonado"
|
|
14
|
+
description: "Caminho absoluto do DIRETÓRIO PAI onde o repositório será clonado. O nome da pasta será o nome do repo, a menos que especificado."
|
|
14
15
|
},
|
|
15
16
|
action: {
|
|
16
17
|
type: "string",
|
|
17
18
|
enum: ["clone"],
|
|
18
|
-
description: "Ação a executar: clone
|
|
19
|
+
description: "Ação a executar: clone"
|
|
19
20
|
},
|
|
20
21
|
url: {
|
|
21
22
|
type: "string",
|
|
22
|
-
description: "URL do repositório
|
|
23
|
+
description: "URL do repositório Git (HTTPS ou SSH)"
|
|
24
|
+
},
|
|
25
|
+
name: {
|
|
26
|
+
type: "string",
|
|
27
|
+
description: "Nome da pasta de destino (opcional). Se não informado, usa o nome do repo da URL"
|
|
23
28
|
},
|
|
24
29
|
branch: {
|
|
25
30
|
type: "string",
|
|
26
|
-
description: "Branch específica para clonar
|
|
31
|
+
description: "Branch específica para clonar (opcional)"
|
|
27
32
|
},
|
|
28
|
-
depth: {
|
|
33
|
+
depth: {
|
|
29
34
|
type: "number",
|
|
30
|
-
description: "Profundidade do clone (shallow clone). Ex: 1 para último commit
|
|
31
|
-
},
|
|
32
|
-
singleBranch: {
|
|
33
|
-
type: "boolean",
|
|
34
|
-
description: "Se true, clona apenas a branch especificada. Default: false"
|
|
35
|
+
description: "Profundidade do clone (shallow clone). Ex: 1 para apenas o último commit"
|
|
35
36
|
}
|
|
36
37
|
},
|
|
37
38
|
required: ["projectPath", "action", "url"],
|
|
38
39
|
additionalProperties: false
|
|
39
40
|
};
|
|
40
41
|
|
|
41
|
-
const description = `
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
- Baixar um repositório existente do GitHub/Gitea
|
|
45
|
-
- Iniciar trabalho em um projeto existente
|
|
46
|
-
- Criar cópia local de um repositório
|
|
42
|
+
const description = `IMPORTANTE — projectPath:
|
|
43
|
+
Informe o caminho absoluto do projeto aberto no IDE. O servidor MCP não tem acesso ao
|
|
44
|
+
contexto do IDE e não consegue detectar automaticamente qual projeto está sendo trabalhado.
|
|
47
45
|
|
|
48
|
-
|
|
49
|
-
- Clone básico: action='clone' url='https://github.com/user/repo.git'
|
|
50
|
-
- Clone shallow: action='clone' url='...' depth=1
|
|
51
|
-
- Clone de branch: action='clone' url='...' branch='develop'
|
|
46
|
+
Clonagem de repositórios Git.
|
|
52
47
|
|
|
53
|
-
|
|
54
|
-
-
|
|
55
|
-
-
|
|
48
|
+
QUANDO USAR:
|
|
49
|
+
- Baixar um projeto existente do GitHub/Gitea
|
|
50
|
+
- Iniciar trabalho em um novo repo
|
|
56
51
|
|
|
57
|
-
|
|
58
|
-
-
|
|
59
|
-
-
|
|
52
|
+
EXEMPLO:
|
|
53
|
+
- Clonar repo: action='clone' url='https://github.com/user/repo.git'
|
|
54
|
+
- Clonar em pasta específica: action='clone' url='...' name='minha-pasta'
|
|
55
|
+
- Shallow clone (rápido): action='clone' url='...' depth=1`;
|
|
60
56
|
|
|
61
57
|
async function handle(args) {
|
|
62
58
|
const validate = ajv.compile(inputSchema);
|
|
63
59
|
if (!validate(args || {})) return asToolError("VALIDATION_ERROR", "Parâmetros inválidos", validate.errors);
|
|
60
|
+
|
|
61
|
+
// projectPath aqui é o diretório PAI
|
|
64
62
|
const { projectPath, action, url } = args;
|
|
65
63
|
|
|
66
64
|
try {
|
|
67
|
-
//
|
|
65
|
+
// Validar se diretório pai existe
|
|
66
|
+
// validateProjectPath verifica se existe.
|
|
68
67
|
validateProjectPath(projectPath);
|
|
69
68
|
|
|
70
69
|
if (action === "clone") {
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
}
|
|
70
|
+
await withRetry(() => git.clone(projectPath, url, {
|
|
71
|
+
name: args.name,
|
|
72
|
+
branch: args.branch,
|
|
73
|
+
depth: args.depth
|
|
74
|
+
}), 3, "git-clone");
|
|
77
75
|
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
try {
|
|
81
|
-
// Check if it's the same repo
|
|
82
|
-
// git.getRemoteUrl is not standard in adapter, use exec or listRemotes logic
|
|
83
|
-
// Assuming git.listRemotes or similar exists, or we catch the error
|
|
84
|
-
// Let's try to infer from config or just warn
|
|
85
|
-
|
|
86
|
-
// We'll rely on git status to check if it's healthy
|
|
87
|
-
await git.status(projectPath);
|
|
88
|
-
|
|
89
|
-
return asToolResult({
|
|
90
|
-
success: true,
|
|
91
|
-
url,
|
|
92
|
-
path: projectPath,
|
|
93
|
-
branch: args.branch || "current",
|
|
94
|
-
message: `Repositório já existe em '${projectPath}'. Clone ignorado (idempotente).`,
|
|
95
|
-
nextStep: "Use git-workflow status para ver o estado atual"
|
|
96
|
-
});
|
|
97
|
-
} catch (e) {
|
|
98
|
-
// If status fails, maybe it's broken
|
|
99
|
-
console.warn("Existing repo check failed:", e);
|
|
100
|
-
}
|
|
101
|
-
} else if (fs.existsSync(projectPath) && fs.readdirSync(projectPath).length > 0) {
|
|
102
|
-
return asToolError("DIR_NOT_EMPTY", `Diretório '${projectPath}' existe e não está vazio`, {
|
|
103
|
-
suggestion: "Use um diretório novo ou limpe o atual"
|
|
104
|
-
});
|
|
105
|
-
}
|
|
106
|
-
|
|
107
|
-
const result = await withRetry(
|
|
108
|
-
() => git.clone(url, projectPath, {
|
|
109
|
-
branch: args.branch,
|
|
110
|
-
depth: args.depth,
|
|
111
|
-
singleBranch: args.singleBranch
|
|
112
|
-
}),
|
|
113
|
-
3,
|
|
114
|
-
"clone"
|
|
115
|
-
);
|
|
76
|
+
const repoName = args.name || url.split("/").pop().replace(".git", "");
|
|
77
|
+
const finalPath = `${projectPath}/${repoName}`.replace("//", "/");
|
|
116
78
|
|
|
117
|
-
return asToolResult({
|
|
118
|
-
success: true,
|
|
119
|
-
|
|
120
|
-
path:
|
|
121
|
-
|
|
122
|
-
...result,
|
|
123
|
-
message: `Repositório clonado com sucesso em '${projectPath}'`,
|
|
124
|
-
nextStep: "Use git-workflow status para ver o estado do repositório"
|
|
79
|
+
return asToolResult({
|
|
80
|
+
success: true,
|
|
81
|
+
message: `Repositório clonado com sucesso em '${finalPath}'`,
|
|
82
|
+
path: finalPath,
|
|
83
|
+
url
|
|
125
84
|
});
|
|
126
85
|
}
|
|
127
86
|
|
|
128
|
-
return asToolError("VALIDATION_ERROR", `Ação '${action}' não suportada`, {
|
|
129
|
-
availableActions: ["clone"]
|
|
130
|
-
});
|
|
87
|
+
return asToolError("VALIDATION_ERROR", `Ação '${action}' não suportada`, { availableActions: ["clone"] });
|
|
131
88
|
} catch (e) {
|
|
132
89
|
return errorToResponse(e);
|
|
133
90
|
}
|
|
134
91
|
}
|
|
135
92
|
|
|
136
|
-
return {
|
|
93
|
+
return {
|
|
94
|
+
name: "git-clone",
|
|
95
|
+
description,
|
|
96
|
+
inputSchema,
|
|
97
|
+
handle,
|
|
98
|
+
annotations: { readOnlyHint: false, destructiveHint: false, idempotentHint: false }
|
|
99
|
+
};
|
|
137
100
|
}
|
package/src/tools/git-config.js
CHANGED
|
@@ -11,7 +11,7 @@ export function createGitConfigTool(git) {
|
|
|
11
11
|
properties: {
|
|
12
12
|
projectPath: {
|
|
13
13
|
type: "string",
|
|
14
|
-
description: "Caminho absoluto do diretório do projeto"
|
|
14
|
+
description: "Caminho absoluto do diretório do projeto no IDE (ex: '/home/user/meu-projeto' ou 'C:/Users/user/meu-projeto'). IMPORTANTE: este valor não pode ser inferido automaticamente pelo servidor — o agente deve fornecer o path real do projeto sendo trabalhado, não o diretório home do usuário."
|
|
15
15
|
},
|
|
16
16
|
action: {
|
|
17
17
|
type: "string",
|
|
@@ -40,7 +40,11 @@ export function createGitConfigTool(git) {
|
|
|
40
40
|
additionalProperties: false
|
|
41
41
|
};
|
|
42
42
|
|
|
43
|
-
const description = `
|
|
43
|
+
const description = `IMPORTANTE — projectPath:
|
|
44
|
+
Informe o caminho absoluto do projeto aberto no IDE. O servidor MCP não tem acesso ao
|
|
45
|
+
contexto do IDE e não consegue detectar automaticamente qual projeto está sendo trabalhado.
|
|
46
|
+
|
|
47
|
+
Gerenciamento de configurações Git.
|
|
44
48
|
|
|
45
49
|
CONFIGURAÇÕES COMUNS:
|
|
46
50
|
- user.name: Nome do autor dos commits
|
|
@@ -90,5 +94,11 @@ EXEMPLOS:
|
|
|
90
94
|
}
|
|
91
95
|
}
|
|
92
96
|
|
|
93
|
-
return {
|
|
97
|
+
return {
|
|
98
|
+
name: "git-config",
|
|
99
|
+
description,
|
|
100
|
+
inputSchema,
|
|
101
|
+
handle,
|
|
102
|
+
annotations: { readOnlyHint: false, destructiveHint: false, idempotentHint: true }
|
|
103
|
+
};
|
|
94
104
|
}
|