@andre.buzeli/git-mcp 16.1.4 → 16.1.6

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 CHANGED
@@ -17,10 +17,11 @@ Servidor MCP (Model Context Protocol) para operações Git locais sem git instal
17
17
  }
18
18
  }
19
19
  }
20
- }
20
+ }
21
21
  ```
22
22
 
23
- ## Tools
23
+ ## Tools
24
+
24
25
 
25
26
  - git-workflow: init, status, add, remove, commit, ensure-remotes, push
26
27
  - git-update: status -> add -> commit -> push (all-in-one)
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@andre.buzeli/git-mcp",
3
- "version": "16.1.4",
3
+ "version": "16.1.6",
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",
package/src/index.js CHANGED
@@ -59,53 +59,44 @@ const server = new Server(
59
59
  },
60
60
  instructions: `# git-mcp — Instruções para AI Agents
61
61
 
62
- ## REGRA #1: projectPath é OBRIGATÓRIO
63
- Toda tool (exceto git-help) exige "projectPath" com o caminho absoluto do projeto aberto no IDE.
64
- O servidor NÃO consegue detectar o projeto automaticamente.
65
- Exemplo: "projectPath": "C:/Users/user/meu-projeto" ou "/home/user/meu-projeto"
66
-
67
- ## REGRA #2: action é OBRIGATÓRIO
68
- Toda tool usa o padrão { "projectPath": "...", "action": "nome-da-action", ...params }.
69
- Consulte o enum de cada tool para saber as actions disponíveis.
70
-
71
- ## Guia Rápido de Tools
72
-
73
- | Necessidade | Tool | Action | Params obrigatórios |
74
- |-------------|------|--------|---------------------|
75
- | Atualizar projeto completo | git-workflow | update | message |
76
- | Ver status do repo | git-workflow | status | - |
77
- | Inicializar repo novo | git-workflow | init | - |
78
- | Ver diferenças locais | git-diff | show | - |
79
- | Comparar branches/commits | git-diff | compare | target |
80
- | Estatísticas de diff | git-diff | stat | - |
81
- | Criar branch | git-branches | create | branch |
82
- | Trocar branch | git-branches | checkout | branch |
83
- | Listar branches | git-branches | list | - |
84
- | Merge de branch | git-merge | merge | branch |
85
- | Criar tag | git-tags | create | tag |
86
- | Clonar repo | git-clone | clone | url |
87
- | Criar issue | git-issues | create | title |
88
- | Criar PR | git-pulls | create | head, base |
89
- | Salvar stash | git-stash | save | - |
90
- | Restaurar stash | git-stash | pop | - |
91
- | Reset commits | git-reset | soft/mixed/hard | ref |
92
- | Configurar git | git-config | get/set | key |
93
- | Gerenciar .gitignore | git-ignore | add/list | patterns |
94
- | Ler arquivo do git | git-files | read | filepath |
95
- | Ver histórico | git-history | log | - |
96
- | Fetch/Pull remoto | git-sync | fetch/pull | - |
97
- | Gerenciar remotes | git-remote | list/ensure | - |
98
- | Criar release | git-remote | release-create | tag |
99
- | Gerenciar worktrees | git-worktree | add/list/remove | branch (add) |
100
- | Ajuda sobre tools | git-help | - | query/listTools/showFlows |
101
-
102
- ## Exemplo Completo (ação mais comum)
103
- \`\`\`json
104
- { "projectPath": "/caminho/do/projeto", "action": "update", "message": "feat: descrição das mudanças" }
105
- \`\`\`
106
-
107
- ## Dica
108
- Use git-help action="listTools" para ver todas as tools e actions disponíveis em tempo real.`
62
+ ATENÇÃO: NUNCA chame uma tool sem os parâmetros obrigatórios. Toda call incompleta retorna erro.
63
+
64
+ ## Parâmetros obrigatórios em TODAS as tools (exceto git-help)
65
+ - "projectPath": caminho absoluto do projeto no sistema de arquivos do usuário. O servidor NÃO detecta automaticamente.
66
+ - "action": string com o nome da action a executar (ver enum no schema de cada tool)
67
+
68
+ ## Exemplos prontos para uso copie e substitua os valores
69
+
70
+ git-workflow (update): {"projectPath":"<PATH>","action":"update","message":"feat: descrição"}
71
+ git-workflow (status): {"projectPath":"<PATH>","action":"status"}
72
+ git-workflow (init): {"projectPath":"<PATH>","action":"init"}
73
+ git-workflow (push): {"projectPath":"<PATH>","action":"push"}
74
+ git-diff (show): {"projectPath":"<PATH>","action":"show"}
75
+ git-diff (compare): {"projectPath":"<PATH>","action":"compare","target":"main"}
76
+ git-branches (list): {"projectPath":"<PATH>","action":"list"}
77
+ git-branches (create): {"projectPath":"<PATH>","action":"create","branch":"feature/x"}
78
+ git-branches (checkout):{"projectPath":"<PATH>","action":"checkout","branch":"main"}
79
+ git-merge (merge): {"projectPath":"<PATH>","action":"merge","branch":"feature/x"}
80
+ git-tags (create): {"projectPath":"<PATH>","action":"create","tag":"v1.0.0"}
81
+ git-tags (push): {"projectPath":"<PATH>","action":"push","tag":"v1.0.0"}
82
+ git-stash (save): {"projectPath":"<PATH>","action":"save"}
83
+ git-stash (pop): {"projectPath":"<PATH>","action":"pop"}
84
+ git-reset (soft): {"projectPath":"<PATH>","action":"soft","ref":"HEAD~1"}
85
+ git-reset (hard): {"projectPath":"<PATH>","action":"hard","ref":"HEAD~1"}
86
+ git-history (log): {"projectPath":"<PATH>","action":"log"}
87
+ git-remote (ensure): {"projectPath":"<PATH>","action":"ensure"}
88
+ git-remote (list): {"projectPath":"<PATH>","action":"list"}
89
+ git-remote (release-create): {"projectPath":"<PATH>","action":"release-create","tag":"v1.0.0","name":"Release v1.0.0"}
90
+ git-worktree (list): {"projectPath":"<PATH>","action":"list"}
91
+ git-worktree (add): {"projectPath":"<PATH>","action":"add","branch":"feature/x"}
92
+ git-sync (pull): {"projectPath":"<PATH>","action":"pull"}
93
+ git-config (get): {"projectPath":"<PATH>","action":"get","key":"user.name"}
94
+ git-ignore (add): {"projectPath":"<PATH>","action":"add","patterns":["node_modules/"]}
95
+ git-files (read): {"projectPath":"<PATH>","action":"read","filepath":"package.json"}
96
+ git-issues (create): {"projectPath":"<PATH>","action":"create","title":"Bug: descrição"}
97
+ git-pulls (create): {"projectPath":"<PATH>","action":"create","head":"feature/x","base":"main","title":"feat: x"}
98
+ git-clone (clone): {"projectPath":"<PARENT_DIR>","action":"clone","url":"https://github.com/user/repo.git"}
99
+ git-help: {"listTools":true} ← única tool sem projectPath/action obrigatórios`
109
100
  }
110
101
  );
111
102
  server.connect(transport);
@@ -1,5 +1,5 @@
1
1
  import Ajv from "ajv";
2
- import { asToolError, asToolResult, errorToResponse } from "../utils/errors.js";
2
+ import { asToolError, asToolResult, errorToResponse, handleEmptyCall } from "../utils/errors.js";
3
3
  import { validateProjectPath } from "../utils/repoHelpers.js";
4
4
 
5
5
  const ajv = new Ajv({ allErrors: true });
@@ -59,8 +59,11 @@ CONVENÇÕES DE NOMES:
59
59
  - release/versao: Para releases`;
60
60
 
61
61
  async function handle(args) {
62
+ const emptyHelp = handleEmptyCall(args, inputSchema, "git-branches", { projectPath: "/path/to/project", action: "list" });
63
+ if (emptyHelp) return emptyHelp;
64
+
62
65
  const validate = ajv.compile(inputSchema);
63
- if (!validate(args || {})) return asToolError("VALIDATION_ERROR", "Parâmetros inválidos", validate.errors);
66
+ if (!validate(args)) return asToolError("VALIDATION_ERROR", "Parâmetros inválidos", validate.errors);
64
67
  const { projectPath, action } = args;
65
68
  try {
66
69
  validateProjectPath(projectPath);
@@ -1,5 +1,5 @@
1
1
  import Ajv from "ajv";
2
- import { asToolError, asToolResult, errorToResponse } from "../utils/errors.js";
2
+ import { asToolError, asToolResult, errorToResponse, handleEmptyCall } from "../utils/errors.js";
3
3
  import { validateProjectPath } from "../utils/repoHelpers.js";
4
4
  import { withRetry } from "../utils/retry.js";
5
5
 
@@ -55,8 +55,11 @@ EXEMPLO:
55
55
  - Shallow clone (rápido): action='clone' url='...' depth=1`;
56
56
 
57
57
  async function handle(args) {
58
+ const emptyHelp = handleEmptyCall(args, inputSchema, "git-clone", { projectPath: "/path/to/parent", action: "clone", url: "https://github.com/user/repo.git" });
59
+ if (emptyHelp) return emptyHelp;
60
+
58
61
  const validate = ajv.compile(inputSchema);
59
- if (!validate(args || {})) return asToolError("VALIDATION_ERROR", "Parâmetros inválidos", validate.errors);
62
+ if (!validate(args)) return asToolError("VALIDATION_ERROR", "Parâmetros inválidos", validate.errors);
60
63
 
61
64
  // projectPath aqui é o diretório PAI
62
65
  const { projectPath, action, url } = args;
@@ -1,5 +1,5 @@
1
1
  import Ajv from "ajv";
2
- import { asToolError, asToolResult, errorToResponse } from "../utils/errors.js";
2
+ import { asToolError, asToolResult, errorToResponse, handleEmptyCall } from "../utils/errors.js";
3
3
  import { validateProjectPath } from "../utils/repoHelpers.js";
4
4
  import { withRetry } from "../utils/retry.js";
5
5
 
@@ -63,8 +63,11 @@ EXEMPLOS:
63
63
  - Ver nome: action='get' key='user.name'`;
64
64
 
65
65
  async function handle(args) {
66
+ const emptyHelp = handleEmptyCall(args, inputSchema, "git-config", { projectPath: "/path/to/project", action: "get", key: "user.name" });
67
+ if (emptyHelp) return emptyHelp;
68
+
66
69
  const validate = ajv.compile(inputSchema);
67
- if (!validate(args || {})) return asToolError("VALIDATION_ERROR", "Parâmetros inválidos", validate.errors);
70
+ if (!validate(args)) return asToolError("VALIDATION_ERROR", "Parâmetros inválidos", validate.errors);
68
71
  const { projectPath, action } = args;
69
72
  const scope = args.scope || "local";
70
73
  try {
@@ -1,5 +1,5 @@
1
1
  import Ajv from "ajv";
2
- import { asToolError, asToolResult, errorToResponse } from "../utils/errors.js";
2
+ import { asToolError, asToolResult, errorToResponse, handleEmptyCall } from "../utils/errors.js";
3
3
  import { validateProjectPath } from "../utils/repoHelpers.js";
4
4
 
5
5
  const ajv = new Ajv({ allErrors: true });
@@ -70,8 +70,11 @@ EXEMPLOS:
70
70
  - Estatísticas de mudança: action='stat' target='HEAD~1'`;
71
71
 
72
72
  async function handle(args) {
73
+ const emptyHelp = handleEmptyCall(args, inputSchema, "git-diff", { projectPath: "/path/to/project", action: "show" });
74
+ if (emptyHelp) return emptyHelp;
75
+
73
76
  const validate = ajv.compile(inputSchema);
74
- if (!validate(args || {})) return asToolError("VALIDATION_ERROR", "Parâmetros inválidos", validate.errors);
77
+ if (!validate(args)) return asToolError("VALIDATION_ERROR", "Parâmetros inválidos", validate.errors);
75
78
  const { projectPath, action } = args;
76
79
 
77
80
  try {
@@ -1,5 +1,5 @@
1
1
  import Ajv from "ajv";
2
- import { asToolError, asToolResult, errorToResponse } from "../utils/errors.js";
2
+ import { asToolError, asToolResult, errorToResponse, handleEmptyCall } from "../utils/errors.js";
3
3
  import { validateProjectPath, withRetry } from "../utils/repoHelpers.js";
4
4
 
5
5
  const ajv = new Ajv({ allErrors: true });
@@ -52,8 +52,11 @@ EXEMPLOS:
52
52
  NOTA: Esta tool lê arquivos do histórico Git, não do sistema de arquivos.`;
53
53
 
54
54
  async function handle(args) {
55
+ const emptyHelp = handleEmptyCall(args, inputSchema, "git-files", { projectPath: "/path/to/project", action: "list" });
56
+ if (emptyHelp) return emptyHelp;
57
+
55
58
  const validate = ajv.compile(inputSchema);
56
- if (!validate(args || {})) return asToolError("VALIDATION_ERROR", "Parâmetros inválidos", validate.errors);
59
+ if (!validate(args)) return asToolError("VALIDATION_ERROR", "Parâmetros inválidos", validate.errors);
57
60
  const { projectPath, action } = args;
58
61
  try {
59
62
  validateProjectPath(projectPath);
@@ -1,5 +1,5 @@
1
1
  import Ajv from "ajv";
2
- import { asToolError, asToolResult, errorToResponse } from "../utils/errors.js";
2
+ import { asToolError, asToolResult, errorToResponse, handleEmptyCall } from "../utils/errors.js";
3
3
  import { validateProjectPath, withRetry } from "../utils/repoHelpers.js";
4
4
 
5
5
  const ajv = new Ajv({ allErrors: true });
@@ -58,8 +58,11 @@ EXEMPLOS:
58
58
  - Ver histórico de tag: action='log' ref='v1.0.0'`;
59
59
 
60
60
  async function handle(args) {
61
+ const emptyHelp = handleEmptyCall(args, inputSchema, "git-history", { projectPath: "/path/to/project", action: "log" });
62
+ if (emptyHelp) return emptyHelp;
63
+
61
64
  const validate = ajv.compile(inputSchema);
62
- if (!validate(args || {})) return asToolError("VALIDATION_ERROR", "Parâmetros inválidos", validate.errors);
65
+ if (!validate(args)) return asToolError("VALIDATION_ERROR", "Parâmetros inválidos", validate.errors);
63
66
  const { projectPath, action } = args;
64
67
  try {
65
68
  validateProjectPath(projectPath);
@@ -1,5 +1,5 @@
1
1
  import Ajv from "ajv";
2
- import { asToolError, asToolResult, errorToResponse } from "../utils/errors.js";
2
+ import { asToolError, asToolResult, errorToResponse, handleEmptyCall } from "../utils/errors.js";
3
3
  import { validateProjectPath } from "../utils/repoHelpers.js";
4
4
  import { withRetry } from "../utils/retry.js";
5
5
 
@@ -59,8 +59,11 @@ EXEMPLOS:
59
59
  - Adicionar padrão: action='add' patterns=['*.tmp']`;
60
60
 
61
61
  async function handle(args) {
62
+ const emptyHelp = handleEmptyCall(args, inputSchema, "git-ignore", { projectPath: "/path/to/project", action: "list" });
63
+ if (emptyHelp) return emptyHelp;
64
+
62
65
  const validate = ajv.compile(inputSchema);
63
- if (!validate(args || {})) return asToolError("VALIDATION_ERROR", "Parâmetros inválidos", validate.errors);
66
+ if (!validate(args)) return asToolError("VALIDATION_ERROR", "Parâmetros inválidos", validate.errors);
64
67
  const { projectPath, action } = args;
65
68
  const patterns = Array.isArray(args.patterns) ? args.patterns : [];
66
69
  try {
@@ -1,6 +1,6 @@
1
1
  import Ajv from "ajv";
2
2
  import axios from "axios";
3
- import { asToolError, asToolResult, errorToResponse } from "../utils/errors.js";
3
+ import { asToolError, asToolResult, errorToResponse, handleEmptyCall } from "../utils/errors.js";
4
4
  import { getRepoNameFromPath, validateProjectPath, withRetry } from "../utils/repoHelpers.js";
5
5
  import { runBoth } from "../utils/providerExec.js";
6
6
 
@@ -66,8 +66,11 @@ BOAS PRÁTICAS:
66
66
  - Use labels para categorizar (via git-remote label-create)`;
67
67
 
68
68
  async function handle(args) {
69
+ const emptyHelp = handleEmptyCall(args, inputSchema, "git-issues", { projectPath: "/path/to/project", action: "list" });
70
+ if (emptyHelp) return emptyHelp;
71
+
69
72
  const validate = ajv.compile(inputSchema);
70
- if (!validate(args || {})) return asToolError("VALIDATION_ERROR", "Parâmetros inválidos", validate.errors);
73
+ if (!validate(args)) return asToolError("VALIDATION_ERROR", "Parâmetros inválidos", validate.errors);
71
74
  validateProjectPath(args.projectPath);
72
75
  const repo = getRepoNameFromPath(args.projectPath);
73
76
  try {
@@ -1,5 +1,5 @@
1
1
  import Ajv from "ajv";
2
- import { asToolError, asToolResult, errorToResponse, createError } from "../utils/errors.js";
2
+ import { asToolError, asToolResult, errorToResponse, createError, handleEmptyCall } from "../utils/errors.js";
3
3
  import { validateProjectPath } from "../utils/repoHelpers.js";
4
4
 
5
5
  const ajv = new Ajv({ allErrors: true });
@@ -68,8 +68,11 @@ SQUASH:
68
68
  - Útil para manter histórico limpo`;
69
69
 
70
70
  async function handle(args) {
71
+ const emptyHelp = handleEmptyCall(args, inputSchema, "git-merge", { projectPath: "/path/to/project", action: "status" });
72
+ if (emptyHelp) return emptyHelp;
73
+
71
74
  const validate = ajv.compile(inputSchema);
72
- if (!validate(args || {})) return asToolError("VALIDATION_ERROR", "Parâmetros inválidos", validate.errors);
75
+ if (!validate(args)) return asToolError("VALIDATION_ERROR", "Parâmetros inválidos", validate.errors);
73
76
  const { projectPath, action } = args;
74
77
 
75
78
  try {
@@ -1,6 +1,6 @@
1
1
  import Ajv from "ajv";
2
2
  import axios from "axios";
3
- import { asToolError, asToolResult, errorToResponse } from "../utils/errors.js";
3
+ import { asToolError, asToolResult, errorToResponse, handleEmptyCall } from "../utils/errors.js";
4
4
  import { getRepoNameFromPath, validateProjectPath, withRetry } from "../utils/repoHelpers.js";
5
5
  import { runBoth } from "../utils/providerExec.js";
6
6
 
@@ -76,8 +76,11 @@ AÇÕES:
76
76
  NOTA: O PR é criado em AMBOS os providers simultaneamente.`;
77
77
 
78
78
  async function handle(args) {
79
+ const emptyHelp = handleEmptyCall(args, inputSchema, "git-pulls", { projectPath: "/path/to/project", action: "list" });
80
+ if (emptyHelp) return emptyHelp;
81
+
79
82
  const validate = ajv.compile(inputSchema);
80
- if (!validate(args || {})) return asToolError("VALIDATION_ERROR", "Parâmetros inválidos", validate.errors);
83
+ if (!validate(args)) return asToolError("VALIDATION_ERROR", "Parâmetros inválidos", validate.errors);
81
84
  validateProjectPath(args.projectPath);
82
85
  const repo = getRepoNameFromPath(args.projectPath);
83
86
  try {
@@ -3,7 +3,7 @@ import axios from "axios";
3
3
  import fs from "node:fs";
4
4
  import path from "node:path";
5
5
  import archiver from "archiver";
6
- import { asToolError, asToolResult, errorToResponse, mapExternalError } from "../utils/errors.js";
6
+ import { asToolError, asToolResult, errorToResponse, mapExternalError, handleEmptyCall } from "../utils/errors.js";
7
7
  import { getRepoNameFromPath, validateProjectPath, withRetry } from "../utils/repoHelpers.js";
8
8
  import { runBoth } from "../utils/providerExec.js";
9
9
  import { sendLog, requestConfirmation } from "../utils/mcpNotify.js";
@@ -218,8 +218,11 @@ QUANDO USAR:
218
218
  - Para configurar tópicos: use action='topics-set'`;
219
219
 
220
220
  async function handle(args) {
221
+ const emptyHelp = handleEmptyCall(args, inputSchema, "git-remote", { projectPath: "/path/to/project", action: "list" });
222
+ if (emptyHelp) return emptyHelp;
223
+
221
224
  const validate = ajv.compile(inputSchema);
222
- if (!validate(args || {})) return asToolError("VALIDATION_ERROR", "Parâmetros inválidos", validate.errors);
225
+ if (!validate(args)) return asToolError("VALIDATION_ERROR", "Parâmetros inválidos", validate.errors);
223
226
  const { projectPath, action } = args;
224
227
  try {
225
228
  validateProjectPath(projectPath);
@@ -1,5 +1,5 @@
1
1
  import Ajv from "ajv";
2
- import { asToolError, asToolResult, errorToResponse } from "../utils/errors.js";
2
+ import { asToolError, asToolResult, errorToResponse, handleEmptyCall } from "../utils/errors.js";
3
3
  import { validateProjectPath, withRetry } from "../utils/repoHelpers.js";
4
4
  import { sendLog, requestConfirmation } from "../utils/mcpNotify.js";
5
5
 
@@ -57,8 +57,11 @@ REFERÊNCIAS:
57
57
  - abc1234: SHA específico do commit`;
58
58
 
59
59
  async function handle(args) {
60
+ const emptyHelp = handleEmptyCall(args, inputSchema, "git-reset", { projectPath: "/path/to/project", action: "soft", ref: "HEAD~1" });
61
+ if (emptyHelp) return emptyHelp;
62
+
60
63
  const validate = ajv.compile(inputSchema);
61
- if (!validate(args || {})) return asToolError("VALIDATION_ERROR", "Parâmetros inválidos", validate.errors);
64
+ if (!validate(args)) return asToolError("VALIDATION_ERROR", "Parâmetros inválidos", validate.errors);
62
65
  const { projectPath, action, ref } = args;
63
66
  try {
64
67
  validateProjectPath(projectPath);
@@ -1,5 +1,5 @@
1
1
  import Ajv from "ajv";
2
- import { asToolError, asToolResult, errorToResponse } from "../utils/errors.js";
2
+ import { asToolError, asToolResult, errorToResponse, handleEmptyCall } from "../utils/errors.js";
3
3
  import { validateProjectPath } from "../utils/repoHelpers.js";
4
4
  import { withRetry } from "../utils/retry.js";
5
5
 
@@ -67,8 +67,11 @@ AÇÕES:
67
67
  - clear: Remover todos os stashes`;
68
68
 
69
69
  async function handle(args) {
70
+ const emptyHelp = handleEmptyCall(args, inputSchema, "git-stash", { projectPath: "/path/to/project", action: "list" });
71
+ if (emptyHelp) return emptyHelp;
72
+
70
73
  const validate = ajv.compile(inputSchema);
71
- if (!validate(args || {})) return asToolError("VALIDATION_ERROR", "Parâmetros inválidos", validate.errors);
74
+ if (!validate(args)) return asToolError("VALIDATION_ERROR", "Parâmetros inválidos", validate.errors);
72
75
  const { projectPath, action } = args;
73
76
  try {
74
77
  validateProjectPath(projectPath);
@@ -1,5 +1,5 @@
1
1
  import Ajv from "ajv";
2
- import { asToolError, asToolResult, errorToResponse } from "../utils/errors.js";
2
+ import { asToolError, asToolResult, errorToResponse, handleEmptyCall } from "../utils/errors.js";
3
3
  import { validateProjectPath, withRetry } from "../utils/repoHelpers.js";
4
4
 
5
5
  const ajv = new Ajv({ allErrors: true });
@@ -54,8 +54,11 @@ FLUXO RECOMENDADO:
54
54
  NOTA: Se pull falhar com conflito, resolva manualmente e faça commit.`;
55
55
 
56
56
  async function handle(args) {
57
+ const emptyHelp = handleEmptyCall(args, inputSchema, "git-sync", { projectPath: "/path/to/project", action: "fetch" });
58
+ if (emptyHelp) return emptyHelp;
59
+
57
60
  const validate = ajv.compile(inputSchema);
58
- if (!validate(args || {})) return asToolError("VALIDATION_ERROR", "Parâmetros inválidos", validate.errors);
61
+ if (!validate(args)) return asToolError("VALIDATION_ERROR", "Parâmetros inválidos", validate.errors);
59
62
  const { projectPath, action } = args;
60
63
  try {
61
64
  validateProjectPath(projectPath);
@@ -1,5 +1,5 @@
1
1
  import Ajv from "ajv";
2
- import { asToolError, asToolResult, errorToResponse } from "../utils/errors.js";
2
+ import { asToolError, asToolResult, errorToResponse, handleEmptyCall } from "../utils/errors.js";
3
3
  import { validateProjectPath, withRetry } from "../utils/repoHelpers.js";
4
4
 
5
5
  const ajv = new Ajv({ allErrors: true });
@@ -61,8 +61,11 @@ FLUXO TÍPICO:
61
61
  2. git-tags push tag='v1.0.0'`;
62
62
 
63
63
  async function handle(args) {
64
+ const emptyHelp = handleEmptyCall(args, inputSchema, "git-tags", { projectPath: "/path/to/project", action: "list" });
65
+ if (emptyHelp) return emptyHelp;
66
+
64
67
  const validate = ajv.compile(inputSchema);
65
- if (!validate(args || {})) return asToolError("VALIDATION_ERROR", "Parâmetros inválidos", validate.errors);
68
+ if (!validate(args)) return asToolError("VALIDATION_ERROR", "Parâmetros inválidos", validate.errors);
66
69
  const { projectPath, action } = args;
67
70
  try {
68
71
  validateProjectPath(projectPath);
@@ -1,7 +1,7 @@
1
1
  import Ajv from "ajv";
2
2
  import fs from "fs";
3
3
  import path from "path";
4
- import { asToolError, asToolResult, errorToResponse, createError } from "../utils/errors.js";
4
+ import { asToolError, asToolResult, errorToResponse, createError, handleEmptyCall } from "../utils/errors.js";
5
5
  import { getRepoNameFromPath, detectProjectType, GITIGNORE_TEMPLATES, validateProjectPath, withRetry } from "../utils/repoHelpers.js";
6
6
  import { resolveWorktreeContext, isProtectedPath } from "../utils/worktreeResolver.js";
7
7
  import { sendLog } from "../utils/mcpNotify.js";
@@ -134,8 +134,12 @@ EXEMPLOS DE USO:
134
134
  • Ver mudanças: { "projectPath": "/path/to/project", "action": "status" }`;
135
135
 
136
136
  async function handle(args) {
137
+ // Call vazia = modelo tentando descobrir o schema. Retorna help em vez de erro.
138
+ const emptyHelp = handleEmptyCall(args, inputSchema, "git-workflow", { projectPath: "/path/to/project", action: "update", message: "feat: descrição" });
139
+ if (emptyHelp) return emptyHelp;
140
+
137
141
  const validate = ajv.compile(inputSchema);
138
- if (!validate(args || {})) {
142
+ if (!validate(args)) {
139
143
  return asToolError("VALIDATION_ERROR", "Parâmetros inválidos", validate.errors);
140
144
  }
141
145
  const { projectPath, action } = args;
@@ -1,7 +1,7 @@
1
1
  import Ajv from "ajv";
2
2
  import fs from "fs";
3
3
  import path from "path";
4
- import { asToolError, asToolResult, errorToResponse } from "../utils/errors.js";
4
+ import { asToolError, asToolResult, errorToResponse, handleEmptyCall } from "../utils/errors.js";
5
5
  import { validateProjectPath, withRetry } from "../utils/repoHelpers.js";
6
6
  import { resolveWorktreeContext, isProtectedPath } from "../utils/worktreeResolver.js";
7
7
 
@@ -73,8 +73,11 @@ AÇÕES:
73
73
  - set-channel: Configurar canal de deploy (prod/beta/alpha)`;
74
74
 
75
75
  async function handle(args) {
76
+ const emptyHelp = handleEmptyCall(args, inputSchema, "git-worktree", { projectPath: "/path/to/project", action: "list" });
77
+ if (emptyHelp) return emptyHelp;
78
+
76
79
  const validate = ajv.compile(inputSchema);
77
- if (!validate(args || {})) return asToolError("VALIDATION_ERROR", "Parâmetros inválidos", validate.errors);
80
+ if (!validate(args)) return asToolError("VALIDATION_ERROR", "Parâmetros inválidos", validate.errors);
78
81
  const { projectPath, action } = args;
79
82
  let effectivePath = projectPath;
80
83
  let worktreeCtx = null;
@@ -432,3 +432,24 @@ export function errorToResponse(error) {
432
432
  const mapped = mapExternalError(error);
433
433
  return asToolError(mapped.code, mapped.message, mapped.data);
434
434
  }
435
+
436
+ /**
437
+ * Detecta call vazia (sem projectPath/action) e retorna help em vez de erro seco.
438
+ * Isso evita que modelos façam "tool probing" — uma call vazia para descobrir o schema.
439
+ * @param {object} args - Argumentos recebidos
440
+ * @param {object} inputSchema - Schema da tool
441
+ * @param {string} toolName - Nome da tool
442
+ * @param {object} example - Exemplo de uso mínimo
443
+ * @returns {object|null} - Resposta de help, ou null se args não estão vazios
444
+ */
445
+ export function handleEmptyCall(args, inputSchema, toolName, example) {
446
+ if (args && Object.keys(args).length > 0) return null;
447
+ return asToolResult({
448
+ help: true,
449
+ tool: toolName,
450
+ requiredParams: (inputSchema.required || []).join(", "),
451
+ example,
452
+ actions: inputSchema.properties?.action?.enum || [],
453
+ hint: `Sempre inclua ${(inputSchema.required || []).join(" e ")} na chamada.`
454
+ });
455
+ }