@andre.buzeli/git-mcp 16.0.6 → 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 CHANGED
@@ -1,29 +1,32 @@
1
- {
2
- "name": "@andre.buzeli/git-mcp",
3
- "version": "16.0.6",
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
- "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
- }
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 { 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();
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();
@@ -93,7 +93,9 @@ export class ProviderManager {
93
93
  }
94
94
 
95
95
  async getRemoteUrls(repoName, organization) {
96
- const cacheKey = `urls_${organization || ""}_${repoName}`;
96
+ // When organization is specified, prefix repo name (no actual org needed)
97
+ const effectiveName = organization ? `${organization}---${repoName}` : repoName;
98
+ const cacheKey = `urls_${effectiveName}`;
97
99
  const now = Date.now();
98
100
 
99
101
  // Verificar cache
@@ -106,20 +108,20 @@ export class ProviderManager {
106
108
 
107
109
  const urls = {};
108
110
 
109
- // GitHub URL
111
+ // GitHub URL — always personal account
110
112
  if (this.github) {
111
- const owner = organization || await this.getGitHubOwner();
113
+ const owner = await this.getGitHubOwner();
112
114
  if (owner) {
113
- urls.github = `https://github.com/${owner}/${repoName}.git`;
115
+ urls.github = `https://github.com/${owner}/${effectiveName}.git`;
114
116
  }
115
117
  }
116
118
 
117
- // Gitea URL
119
+ // Gitea URL — always personal account
118
120
  if (this.giteaUrl && this.giteaToken) {
119
- const owner = organization || await this.getGiteaOwner();
121
+ const owner = await this.getGiteaOwner();
120
122
  if (owner) {
121
123
  const base = this.giteaUrl.replace(/\/$/, "");
122
- urls.gitea = `${base}/${owner}/${repoName}.git`;
124
+ urls.gitea = `${base}/${owner}/${effectiveName}.git`;
123
125
  }
124
126
  }
125
127
 
@@ -130,76 +132,27 @@ export class ProviderManager {
130
132
  }
131
133
 
132
134
  async ensureRepos({ repoName, createIfMissing = true, description = "Managed by git-mcpv2", isPublic = false, organization }) {
133
- // Por padrão, repositórios são PRIVADOS. Use isPublic=true para público.
135
+ // When organization is specified, prefix repo name (e.g., "MCP---GIT_MCP")
136
+ const effectiveName = organization ? `${organization}---${repoName}` : repoName;
134
137
  const isPrivate = !isPublic;
135
138
  const results = { github: null, gitea: null };
136
- // GitHub
139
+
140
+ // GitHub — always personal account
137
141
  if (this.github) {
138
- const owner = organization || await this.getGitHubOwner();
142
+ const owner = await this.getGitHubOwner();
139
143
  if (owner) {
140
144
  try {
141
- const full = `${owner}/${repoName}`;
142
145
  try {
143
- await this.github.rest.repos.get({ owner, repo: repoName });
144
- results.github = { ok: true, repo: full, created: false };
146
+ await this.github.rest.repos.get({ owner, repo: effectiveName });
147
+ results.github = { ok: true, repo: `${owner}/${effectiveName}`, created: false };
145
148
  } catch {
146
149
  if (createIfMissing) {
147
- let cr;
148
- if (organization) {
149
- // Tentar criar repo na organização
150
- try {
151
- cr = await this.github.rest.repos.createInOrg({
152
- org: organization,
153
- name: repoName,
154
- description,
155
- private: isPrivate,
156
- auto_init: false,
157
- });
158
- } catch (orgRepoErr) {
159
- const errMsg = String(orgRepoErr?.message || orgRepoErr).toLowerCase();
160
- // Se org não existe, criar a org primeiro e depois o repo
161
- if (errMsg.includes("not found") || errMsg.includes("404")) {
162
- console.error(`[ProviderManager] GitHub org '${organization}' not found, creating...`);
163
- try {
164
- await this.github.rest.orgs.createForAuthenticatedUser
165
- ? await this.github.request("POST /user/orgs", { login: organization, profile_name: organization })
166
- : null;
167
- } catch (orgCreateErr) {
168
- // GitHub free users can't create orgs via API, try alternative
169
- console.error(`[ProviderManager] GitHub org creation failed: ${orgCreateErr?.message}. Trying as user repo with org topic...`);
170
- }
171
- // Retry repo creation in org
172
- try {
173
- cr = await this.github.rest.repos.createInOrg({
174
- org: organization,
175
- name: repoName,
176
- description,
177
- private: isPrivate,
178
- auto_init: false,
179
- });
180
- } catch {
181
- // Fallback: create as personal repo if org creation not possible
182
- console.error(`[ProviderManager] Fallback: creating '${repoName}' as personal repo (GitHub org '${organization}' unavailable)`);
183
- cr = await this.github.rest.repos.createForAuthenticatedUser({
184
- name: repoName,
185
- description: `[org:${organization}] ${description}`,
186
- private: isPrivate,
187
- auto_init: false,
188
- });
189
- }
190
- } else {
191
- throw orgRepoErr;
192
- }
193
- }
194
- } else {
195
- // Criar repo no usuário pessoal
196
- cr = await this.github.rest.repos.createForAuthenticatedUser({
197
- name: repoName,
198
- description,
199
- private: isPrivate,
200
- auto_init: false,
201
- });
202
- }
150
+ const cr = await this.github.rest.repos.createForAuthenticatedUser({
151
+ name: effectiveName,
152
+ description,
153
+ private: isPrivate,
154
+ auto_init: false,
155
+ });
203
156
  results.github = { ok: true, repo: cr.data.full_name, created: true };
204
157
  } else {
205
158
  results.github = { ok: false, error: "missing" };
@@ -210,52 +163,26 @@ export class ProviderManager {
210
163
  }
211
164
  }
212
165
  }
213
- // Gitea
166
+
167
+ // Gitea — always personal account
214
168
  if (this.giteaUrl && this.giteaToken) {
215
- const owner = organization || await this.getGiteaOwner();
169
+ const owner = await this.getGiteaOwner();
216
170
  if (owner) {
217
171
  try {
218
172
  const base = this.giteaUrl.replace(/\/$/, "");
219
- const getRepo = await axios.get(`${base}/api/v1/repos/${owner}/${repoName}`,
173
+ const getRepo = await axios.get(`${base}/api/v1/repos/${owner}/${effectiveName}`,
220
174
  { headers: { Authorization: `token ${this.giteaToken}` }, timeout: 8000 });
221
175
  if (getRepo.status === 200) {
222
- results.gitea = { ok: true, repo: `${owner}/${repoName}`, created: false };
176
+ results.gitea = { ok: true, repo: `${owner}/${effectiveName}`, created: false };
223
177
  }
224
178
  } catch (e) {
225
179
  if (createIfMissing) {
226
180
  try {
227
- let createUrl;
228
- if (organization) {
229
- // Verificar se org existe, criar se não existir
230
- try {
231
- await axios.get(`${this.giteaUrl}/api/v1/orgs/${organization}`,
232
- { headers: { Authorization: `token ${this.giteaToken}` }, timeout: 8000 });
233
- } catch (orgCheckErr) {
234
- // Org não existe, criar
235
- console.error(`[ProviderManager] Gitea org '${organization}' not found, creating...`);
236
- try {
237
- await axios.post(`${this.giteaUrl}/api/v1/orgs`, {
238
- username: organization,
239
- full_name: organization,
240
- description: `Organization ${organization}`,
241
- visibility: isPublic ? "public" : "limited",
242
- }, { headers: { Authorization: `token ${this.giteaToken}` }, timeout: 8000 });
243
- console.error(`[ProviderManager] Gitea org '${organization}' created successfully`);
244
- } catch (orgCreateErr) {
245
- const msg = String(orgCreateErr?.message || orgCreateErr).toLowerCase();
246
- if (!msg.includes("already exists") && !msg.includes("409")) {
247
- console.error(`[ProviderManager] Gitea org creation failed: ${orgCreateErr?.message}`);
248
- }
249
- }
250
- }
251
- createUrl = `${this.giteaUrl}/api/v1/orgs/${organization}/repos`;
252
- } else {
253
- createUrl = `${this.giteaUrl}/api/v1/user/repos`;
254
- }
255
- const cr = await axios.post(createUrl,
256
- { name: repoName, description, private: isPrivate, auto_init: false },
181
+ const base = this.giteaUrl.replace(/\/$/, "");
182
+ const cr = await axios.post(`${base}/api/v1/user/repos`,
183
+ { name: effectiveName, description, private: isPrivate, auto_init: false },
257
184
  { headers: { Authorization: `token ${this.giteaToken}` }, timeout: 8000 });
258
- results.gitea = { ok: true, repo: `${cr.data?.owner?.login || owner}/${repoName}`, created: true };
185
+ results.gitea = { ok: true, repo: `${cr.data?.owner?.login || owner}/${effectiveName}`, created: true };
259
186
  } catch (err) {
260
187
  results.gitea = { ok: false, error: String(err?.message || err) };
261
188
  }
@@ -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 = `Gerenciamento de branches Git.
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 { name: "git-branches", description, inputSchema, handle };
129
+ return {
130
+ name: "git-branches",
131
+ description,
132
+ inputSchema,
133
+ handle,
134
+ annotations: { readOnlyHint: false, destructiveHint: false, idempotentHint: false }
135
+ };
126
136
  }