@andrebuzeli/git-mcp 15.2.2 → 15.2.4
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 +5 -7
- package/src/providers/providerManager.js +31 -3
- package/src/tools/git-remote.js +35 -19
- package/src/utils/gitAdapter.js +603 -1141
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@andrebuzeli/git-mcp",
|
|
3
|
-
"version": "15.2.
|
|
3
|
+
"version": "15.2.4",
|
|
4
4
|
"private": false,
|
|
5
5
|
"description": "MCP server para Git com operações locais e sincronização paralela GitHub/Gitea",
|
|
6
6
|
"license": "MIT",
|
|
@@ -18,13 +18,11 @@
|
|
|
18
18
|
"git-mcp": "src/index.js",
|
|
19
19
|
"git-mcpv2": "src/index.js"
|
|
20
20
|
},
|
|
21
|
-
"scripts": {
|
|
22
|
-
},
|
|
21
|
+
"scripts": {},
|
|
23
22
|
"dependencies": {
|
|
24
|
-
"
|
|
25
|
-
"axios": "^1.7.7",
|
|
23
|
+
"@modelcontextprotocol/sdk": "^0.4.0",
|
|
26
24
|
"@octokit/rest": "^20.0.0",
|
|
27
|
-
"
|
|
28
|
-
"
|
|
25
|
+
"ajv": "^8.12.0",
|
|
26
|
+
"axios": "^1.7.7"
|
|
29
27
|
}
|
|
30
28
|
}
|
|
@@ -48,7 +48,7 @@ export class ProviderManager {
|
|
|
48
48
|
|
|
49
49
|
async getRemoteUrls(repoName) {
|
|
50
50
|
const urls = {};
|
|
51
|
-
|
|
51
|
+
|
|
52
52
|
// GitHub URL
|
|
53
53
|
if (this.github) {
|
|
54
54
|
const owner = await this.getGitHubOwner();
|
|
@@ -86,7 +86,7 @@ export class ProviderManager {
|
|
|
86
86
|
name: repoName,
|
|
87
87
|
description,
|
|
88
88
|
private: false,
|
|
89
|
-
auto_init:
|
|
89
|
+
auto_init: false,
|
|
90
90
|
});
|
|
91
91
|
results.github = { ok: true, repo: cr.data.full_name, created: true };
|
|
92
92
|
} else {
|
|
@@ -113,7 +113,7 @@ export class ProviderManager {
|
|
|
113
113
|
if (createIfMissing) {
|
|
114
114
|
try {
|
|
115
115
|
const cr = await axios.post(`${this.giteaUrl}/api/v1/user/repos`,
|
|
116
|
-
{ name: repoName, description, private: false, auto_init:
|
|
116
|
+
{ name: repoName, description, private: false, auto_init: false },
|
|
117
117
|
{ headers: { Authorization: `token ${this.giteaToken}` }, timeout: 8000 });
|
|
118
118
|
results.gitea = { ok: true, repo: `${cr.data?.owner?.login || owner}/${repoName}`, created: true };
|
|
119
119
|
} catch (err) {
|
|
@@ -127,4 +127,32 @@ export class ProviderManager {
|
|
|
127
127
|
}
|
|
128
128
|
return results;
|
|
129
129
|
}
|
|
130
|
+
|
|
131
|
+
async listAllRepos() {
|
|
132
|
+
const results = { github: [], gitea: [] };
|
|
133
|
+
|
|
134
|
+
// GitHub
|
|
135
|
+
if (this.github) {
|
|
136
|
+
try {
|
|
137
|
+
const { data } = await this.github.rest.repos.listForAuthenticatedUser({ per_page: 100, visibility: "all" });
|
|
138
|
+
results.github = data.map(r => ({ name: r.name, full_name: r.full_name, url: r.html_url, private: r.private }));
|
|
139
|
+
} catch (e) {
|
|
140
|
+
console.error("GitHub List Error:", e.message);
|
|
141
|
+
}
|
|
142
|
+
}
|
|
143
|
+
|
|
144
|
+
// Gitea
|
|
145
|
+
if (this.giteaUrl && this.giteaToken) {
|
|
146
|
+
try {
|
|
147
|
+
const base = this.giteaUrl.replace(/\/$/, "");
|
|
148
|
+
const { data } = await axios.get(`${base}/api/v1/user/repos?limit=100`, {
|
|
149
|
+
headers: { Authorization: `token ${this.giteaToken}` }
|
|
150
|
+
});
|
|
151
|
+
results.gitea = data.map(r => ({ name: r.name, full_name: r.full_name, url: r.html_url, private: r.private }));
|
|
152
|
+
} catch (e) {
|
|
153
|
+
console.error("Gitea List Error:", e.message);
|
|
154
|
+
}
|
|
155
|
+
}
|
|
156
|
+
return results;
|
|
157
|
+
}
|
|
130
158
|
}
|
package/src/tools/git-remote.js
CHANGED
|
@@ -10,22 +10,24 @@ export function createGitRemoteTool(pm, git) {
|
|
|
10
10
|
const inputSchema = {
|
|
11
11
|
type: "object",
|
|
12
12
|
properties: {
|
|
13
|
-
projectPath: {
|
|
13
|
+
projectPath: {
|
|
14
14
|
type: "string",
|
|
15
15
|
description: "Caminho absoluto do diretório do projeto"
|
|
16
16
|
},
|
|
17
|
-
action: {
|
|
18
|
-
type: "string",
|
|
17
|
+
action: {
|
|
18
|
+
type: "string",
|
|
19
19
|
enum: [
|
|
20
|
-
"list", "ensure", "repo-delete",
|
|
20
|
+
"list", "list-all", "ensure", "repo-delete",
|
|
21
21
|
"release-create", "topics-set", "milestone-create", "label-create",
|
|
22
22
|
"fork-create", "fork-list", "star-set", "star-unset",
|
|
23
23
|
"subscription-set", "subscription-unset", "contents-create"
|
|
24
24
|
],
|
|
25
25
|
description: `Ação a executar:
|
|
26
26
|
|
|
27
|
+
CONFIGURAÇÃO:
|
|
27
28
|
CONFIGURAÇÃO:
|
|
28
29
|
- list: Lista remotes configurados (github, gitea, origin)
|
|
30
|
+
- list-all: Lista TODOS os repositórios da conta (GitHub + Gitea)
|
|
29
31
|
- ensure: Cria repos no GitHub/Gitea e configura remotes (USE ESTE se push falhar)
|
|
30
32
|
|
|
31
33
|
REPOSITÓRIO:
|
|
@@ -48,32 +50,32 @@ NOTIFICAÇÕES:
|
|
|
48
50
|
ARQUIVOS VIA API:
|
|
49
51
|
- contents-create: Cria arquivo diretamente via API (sem git local)`
|
|
50
52
|
},
|
|
51
|
-
tag: {
|
|
53
|
+
tag: {
|
|
52
54
|
type: "string",
|
|
53
55
|
description: "Tag para release-create. Ex: 'v1.0.0'"
|
|
54
56
|
},
|
|
55
|
-
name: {
|
|
57
|
+
name: {
|
|
56
58
|
type: "string",
|
|
57
59
|
description: "Nome da release, label, etc."
|
|
58
60
|
},
|
|
59
|
-
body: {
|
|
61
|
+
body: {
|
|
60
62
|
type: "string",
|
|
61
63
|
description: "Descrição/corpo da release"
|
|
62
64
|
},
|
|
63
|
-
topics: {
|
|
64
|
-
type: "array",
|
|
65
|
+
topics: {
|
|
66
|
+
type: "array",
|
|
65
67
|
items: { type: "string" },
|
|
66
68
|
description: "Lista de tópicos para topics-set. Ex: ['javascript', 'nodejs', 'mcp']"
|
|
67
69
|
},
|
|
68
|
-
path: {
|
|
70
|
+
path: {
|
|
69
71
|
type: "string",
|
|
70
72
|
description: "Caminho do arquivo para contents-create"
|
|
71
73
|
},
|
|
72
|
-
content: {
|
|
74
|
+
content: {
|
|
73
75
|
type: "string",
|
|
74
76
|
description: "Conteúdo do arquivo para contents-create"
|
|
75
77
|
},
|
|
76
|
-
branch: {
|
|
78
|
+
branch: {
|
|
77
79
|
type: "string",
|
|
78
80
|
description: "Branch alvo para contents-create. Default: main"
|
|
79
81
|
},
|
|
@@ -113,13 +115,13 @@ QUANDO USAR:
|
|
|
113
115
|
validateProjectPath(projectPath);
|
|
114
116
|
if (action === "list") {
|
|
115
117
|
const remotes = await git.listRemotes(projectPath);
|
|
116
|
-
|
|
118
|
+
|
|
117
119
|
// Debug info: calculate what URLs should be
|
|
118
120
|
let repoName = getRepoNameFromPath(projectPath);
|
|
119
121
|
if (repoName === "GIT_MCP") repoName = "git-mcp";
|
|
120
122
|
const calculated = await pm.getRemoteUrls(repoName);
|
|
121
123
|
|
|
122
|
-
return asToolResult({
|
|
124
|
+
return asToolResult({
|
|
123
125
|
remotes,
|
|
124
126
|
configured: remotes.length > 0,
|
|
125
127
|
hasGithub: remotes.some(r => r.remote === "github"),
|
|
@@ -136,6 +138,20 @@ QUANDO USAR:
|
|
|
136
138
|
message: remotes.length === 0 ? "Nenhum remote configurado. Use action='ensure' para configurar." : undefined
|
|
137
139
|
});
|
|
138
140
|
}
|
|
141
|
+
|
|
142
|
+
if (action === "list-all") {
|
|
143
|
+
const repos = await pm.listAllRepos();
|
|
144
|
+
const summary = [];
|
|
145
|
+
if (repos.github?.length) summary.push(`${repos.github.length} GitHub repos`);
|
|
146
|
+
if (repos.gitea?.length) summary.push(`${repos.gitea.length} Gitea repos`);
|
|
147
|
+
|
|
148
|
+
return asToolResult({
|
|
149
|
+
success: true,
|
|
150
|
+
summary: summary.join(", "),
|
|
151
|
+
github: repos.github,
|
|
152
|
+
gitea: repos.gitea
|
|
153
|
+
});
|
|
154
|
+
}
|
|
139
155
|
if (action === "ensure") {
|
|
140
156
|
const repo = getRepoNameFromPath(projectPath);
|
|
141
157
|
const ensured = await pm.ensureRepos({ repoName: repo, createIfMissing: true });
|
|
@@ -146,9 +162,9 @@ QUANDO USAR:
|
|
|
146
162
|
const giteaUrl = geOwner && base ? `${base}/${geOwner}/${repo}.git` : "";
|
|
147
163
|
await git.ensureRemotes(projectPath, { githubUrl, giteaUrl });
|
|
148
164
|
const remotes = await git.listRemotes(projectPath);
|
|
149
|
-
return asToolResult({
|
|
150
|
-
success: true,
|
|
151
|
-
ensured,
|
|
165
|
+
return asToolResult({
|
|
166
|
+
success: true,
|
|
167
|
+
ensured,
|
|
152
168
|
remotes,
|
|
153
169
|
urls: { github: githubUrl, gitea: giteaUrl },
|
|
154
170
|
message: "Remotes configurados. Agora pode usar git-workflow push."
|
|
@@ -257,8 +273,8 @@ QUANDO USAR:
|
|
|
257
273
|
});
|
|
258
274
|
return asToolResult({ success: !!(out.github?.ok || out.gitea?.ok), path: filePath, branch, providers: out });
|
|
259
275
|
}
|
|
260
|
-
return asToolError("VALIDATION_ERROR", `Ação '${action}' não suportada`, {
|
|
261
|
-
availableActions: ["list", "ensure", "repo-delete", "release-create", "topics-set", "milestone-create", "label-create", "fork-create", "fork-list", "star-set", "star-unset", "subscription-set", "subscription-unset", "contents-create"]
|
|
276
|
+
return asToolError("VALIDATION_ERROR", `Ação '${action}' não suportada`, {
|
|
277
|
+
availableActions: ["list", "ensure", "repo-delete", "release-create", "topics-set", "milestone-create", "label-create", "fork-create", "fork-list", "star-set", "star-unset", "subscription-set", "subscription-unset", "contents-create"]
|
|
262
278
|
});
|
|
263
279
|
} catch (e) {
|
|
264
280
|
return errorToResponse(e);
|