@andrebuzeli/git-mcp 7.3.3 → 7.4.0

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
@@ -1,11 +1,34 @@
1
1
  # GIT MCP Server
2
2
 
3
- Professional MCP (Model Context Protocol) server for Git operations with multi-provider support, enhanced security, comprehensive safety features, and **self-documenting resources**.
3
+ Professional MCP (Model Context Protocol) server for Git operations with multi-provider support, enhanced security, comprehensive safety features, and **universal IDE compatibility**.
4
+
5
+ ## ✨ NEW in v7.4.0 - Universal IDE Compatibility
6
+
7
+ **🎉 Now works with ALL IDEs and AI agents without parameter errors!**
8
+
9
+ - ✅ **VSCode** (all AI extensions)
10
+ - ✅ **Cursor AI**
11
+ - ✅ **Trae AI**
12
+ - ✅ **Kiro.dev**
13
+ - ✅ **Claude Desktop**
14
+ - ✅ **Any MCP-compatible client**
15
+
16
+ ### Problem Solved
17
+ Previously, different IDEs sent parameters in different formats causing `Error: action is required`. Now Git-MCP **automatically normalizes** parameters from any source!
18
+
19
+ ```javascript
20
+ // ALL these formats work now! ✅
21
+ { "command": "git status", "projectPath": "..." } // IDE format
22
+ { "action": "status", "projectPath": "..." } // Standard format
23
+ { "command": "status", "projectPath": "..." } // Simple format
24
+ { "projectPath": "..." } // Auto-detect (defaults to status)
25
+ ```
4
26
 
5
27
  ## Features
6
28
 
7
- - 🚀 **20 Specialized Git Tools** - Complete Git workflow coverage with safety warnings
8
- - 📚 **NEW: Self-Documenting Resources** - Complete documentation via MCP protocol
29
+ - 🌐 **NEW: Universal Parameter Normalization** - Accepts both 'action' and 'command' formats
30
+ - 🚀 **23 Specialized Git Tools** - Complete Git workflow coverage with 170+ actions
31
+ - 📚 **Self-Documenting Resources** - Complete documentation via MCP protocol
9
32
  - ⚡ **3 Powerful Tools with Full Traceability**
10
33
  - **git-upload** - Upload complete projects to GitHub + Gitea automatically
11
34
  - **git-update** - Complete update workflow (add + commit + push) with tracking
@@ -15,7 +38,7 @@ Professional MCP (Model Context Protocol) server for Git operations with multi-p
15
38
  - 🚨 **Safety Warnings** - Comprehensive warnings for destructive operations
16
39
  - 🛡️ **Enhanced Error Handling** - Detailed diagnostics with actionable solutions
17
40
  - 📋 **Comprehensive Validation** - Pre-execution validation with helpful guidance
18
- - 🔧 **IDE/Client Compatibility** - Universal aliases for different MCP client expectations
41
+ - 🔧 **IDE/Client Compatibility** - Works seamlessly with ANY IDE or AI agent
19
42
  - 📦 **NPM Distribution** - Easy installation via npx
20
43
  - 🤖 **AI Agent Integration** - Designed for AI agent workflows with safety controls
21
44
  - 📊 **Full Traceability** - Every operation tracked locally and remotely
@@ -1,12 +1,13 @@
1
1
  import { MCPError } from '../utils/errors.js';
2
2
  import axios from 'axios';
3
- import { getRepoInfo } from '../utils/repoHelpers.js';
3
+ import { getRepoInfo, normalizeToolParams } from '../utils/repoHelpers.js';
4
4
  export class GitAnalyticsTool {
5
5
  constructor() {
6
6
  this.name = 'git-analytics';
7
7
  this.description = 'Repository analytics and statistics - automatic dual-provider execution using GitHub and Gitea APIs';
8
8
  }
9
9
  async handle(params, ctx) {
10
+ params = normalizeToolParams(params);
10
11
  const action = params.action;
11
12
  const projectPath = params.projectPath;
12
13
  if (!action)
@@ -9,6 +9,10 @@ export declare class GitConfigTool implements Tool {
9
9
  message?: undefined;
10
10
  scope?: undefined;
11
11
  configs?: undefined;
12
+ configFile?: undefined;
13
+ content?: undefined;
14
+ lines?: undefined;
15
+ note?: undefined;
12
16
  } | {
13
17
  success: boolean;
14
18
  key: any;
@@ -16,6 +20,10 @@ export declare class GitConfigTool implements Tool {
16
20
  value?: undefined;
17
21
  scope?: undefined;
18
22
  configs?: undefined;
23
+ configFile?: undefined;
24
+ content?: undefined;
25
+ lines?: undefined;
26
+ note?: undefined;
19
27
  } | {
20
28
  success: boolean;
21
29
  scope: string;
@@ -23,6 +31,10 @@ export declare class GitConfigTool implements Tool {
23
31
  key?: undefined;
24
32
  value?: undefined;
25
33
  message?: undefined;
34
+ configFile?: undefined;
35
+ content?: undefined;
36
+ lines?: undefined;
37
+ note?: undefined;
26
38
  } | {
27
39
  success: boolean;
28
40
  key: any;
@@ -30,5 +42,20 @@ export declare class GitConfigTool implements Tool {
30
42
  scope: string | undefined;
31
43
  message?: undefined;
32
44
  configs?: undefined;
45
+ configFile?: undefined;
46
+ content?: undefined;
47
+ lines?: undefined;
48
+ note?: undefined;
49
+ } | {
50
+ success: boolean;
51
+ configFile: string;
52
+ scope: string;
53
+ content: string;
54
+ lines: number;
55
+ message: string;
56
+ note: string;
57
+ key?: undefined;
58
+ value?: undefined;
59
+ configs?: undefined;
33
60
  }>;
34
61
  }
@@ -1,5 +1,7 @@
1
1
  import simpleGit from 'simple-git';
2
2
  import { MCPError } from '../utils/errors.js';
3
+ import * as fs from 'fs/promises';
4
+ import * as path from 'path';
3
5
  export class GitConfigTool {
4
6
  constructor() {
5
7
  this.name = 'git-config';
@@ -57,8 +59,30 @@ export class GitConfigTool {
57
59
  scope: params.showScope ? scope : undefined,
58
60
  };
59
61
  }
60
- case 'edit':
61
- throw new MCPError('NOT_IMPLEMENTED', 'Edit action requires manual editing of config file');
62
+ case 'edit': {
63
+ // Return config file path and instructions for manual editing
64
+ const configFile = scope === 'global'
65
+ ? path.join(require('os').homedir(), '.gitconfig')
66
+ : scope === 'system'
67
+ ? '/etc/gitconfig'
68
+ : path.join(projectPath, '.git', 'config');
69
+ try {
70
+ await fs.access(configFile);
71
+ const content = await fs.readFile(configFile, 'utf-8');
72
+ return {
73
+ success: true,
74
+ configFile,
75
+ scope,
76
+ content,
77
+ lines: content.split('\n').length,
78
+ message: 'Config file content retrieved. Edit and use "set" action to update values.',
79
+ note: 'For direct file editing, use your preferred text editor',
80
+ };
81
+ }
82
+ catch (error) {
83
+ throw new MCPError('FILE_ERROR', `Config file not accessible: ${error.message}`);
84
+ }
85
+ }
62
86
  default:
63
87
  throw new MCPError('VALIDATION_ERROR', `Unsupported action: ${action}`);
64
88
  }
@@ -7,6 +7,10 @@ export declare class GitFilesTool implements Tool {
7
7
  path: string;
8
8
  content: string;
9
9
  files?: undefined;
10
+ created?: undefined;
11
+ size?: undefined;
12
+ updated?: undefined;
13
+ deleted?: undefined;
10
14
  matches?: undefined;
11
15
  count?: undefined;
12
16
  } | {
@@ -14,6 +18,43 @@ export declare class GitFilesTool implements Tool {
14
18
  files: string[];
15
19
  path?: undefined;
16
20
  content?: undefined;
21
+ created?: undefined;
22
+ size?: undefined;
23
+ updated?: undefined;
24
+ deleted?: undefined;
25
+ matches?: undefined;
26
+ count?: undefined;
27
+ } | {
28
+ success: boolean;
29
+ created: boolean;
30
+ path: string;
31
+ size: any;
32
+ content?: undefined;
33
+ files?: undefined;
34
+ updated?: undefined;
35
+ deleted?: undefined;
36
+ matches?: undefined;
37
+ count?: undefined;
38
+ } | {
39
+ success: boolean;
40
+ updated: boolean;
41
+ path: string;
42
+ size: any;
43
+ content?: undefined;
44
+ files?: undefined;
45
+ created?: undefined;
46
+ deleted?: undefined;
47
+ matches?: undefined;
48
+ count?: undefined;
49
+ } | {
50
+ success: boolean;
51
+ deleted: boolean;
52
+ path: string;
53
+ content?: undefined;
54
+ files?: undefined;
55
+ created?: undefined;
56
+ size?: undefined;
57
+ updated?: undefined;
17
58
  matches?: undefined;
18
59
  count?: undefined;
19
60
  } | {
@@ -26,5 +67,9 @@ export declare class GitFilesTool implements Tool {
26
67
  path?: undefined;
27
68
  content?: undefined;
28
69
  files?: undefined;
70
+ created?: undefined;
71
+ size?: undefined;
72
+ updated?: undefined;
73
+ deleted?: undefined;
29
74
  }>;
30
75
  }
@@ -21,9 +21,86 @@ export class GitFilesTool {
21
21
  const files = await fs.readdir(dirPath);
22
22
  return { success: true, files };
23
23
  }
24
- // Blocked operations
25
- if (['create', 'update', 'delete'].includes(action)) {
26
- throw new MCPError('OPERATION_RESTRICTED', 'File modification operations are blocked via MCP.');
24
+ // File modification operations with security validations
25
+ if (action === 'create') {
26
+ const filePath = params.filePath;
27
+ const content = params.content || '';
28
+ if (!filePath)
29
+ throw new MCPError('VALIDATION_ERROR', 'filePath is required');
30
+ // Security: ensure file is within projectPath
31
+ const targetPath = path.resolve(projectPath, filePath);
32
+ if (!targetPath.startsWith(path.resolve(projectPath))) {
33
+ throw new MCPError('SECURITY_ERROR', 'File path must be within project directory');
34
+ }
35
+ try {
36
+ // Create directory if needed
37
+ const dir = path.dirname(targetPath);
38
+ await fs.mkdir(dir, { recursive: true });
39
+ await fs.writeFile(targetPath, content, 'utf-8');
40
+ return {
41
+ success: true,
42
+ created: true,
43
+ path: targetPath,
44
+ size: content.length,
45
+ };
46
+ }
47
+ catch (error) {
48
+ throw new MCPError('FILE_ERROR', `Failed to create file: ${error.message}`);
49
+ }
50
+ }
51
+ if (action === 'update') {
52
+ const filePath = params.filePath;
53
+ const content = params.content;
54
+ if (!filePath)
55
+ throw new MCPError('VALIDATION_ERROR', 'filePath is required');
56
+ if (content === undefined)
57
+ throw new MCPError('VALIDATION_ERROR', 'content is required');
58
+ // Security: ensure file is within projectPath
59
+ const targetPath = path.resolve(projectPath, filePath);
60
+ if (!targetPath.startsWith(path.resolve(projectPath))) {
61
+ throw new MCPError('SECURITY_ERROR', 'File path must be within project directory');
62
+ }
63
+ try {
64
+ // Check if file exists
65
+ await fs.access(targetPath);
66
+ await fs.writeFile(targetPath, content, 'utf-8');
67
+ return {
68
+ success: true,
69
+ updated: true,
70
+ path: targetPath,
71
+ size: content.length,
72
+ };
73
+ }
74
+ catch (error) {
75
+ if (error.code === 'ENOENT') {
76
+ throw new MCPError('FILE_NOT_FOUND', 'File does not exist. Use create action.');
77
+ }
78
+ throw new MCPError('FILE_ERROR', `Failed to update file: ${error.message}`);
79
+ }
80
+ }
81
+ if (action === 'delete') {
82
+ const filePath = params.filePath;
83
+ if (!filePath)
84
+ throw new MCPError('VALIDATION_ERROR', 'filePath is required');
85
+ // Security: ensure file is within projectPath
86
+ const targetPath = path.resolve(projectPath, filePath);
87
+ if (!targetPath.startsWith(path.resolve(projectPath))) {
88
+ throw new MCPError('SECURITY_ERROR', 'File path must be within project directory');
89
+ }
90
+ try {
91
+ await fs.unlink(targetPath);
92
+ return {
93
+ success: true,
94
+ deleted: true,
95
+ path: targetPath,
96
+ };
97
+ }
98
+ catch (error) {
99
+ if (error.code === 'ENOENT') {
100
+ throw new MCPError('FILE_NOT_FOUND', 'File does not exist');
101
+ }
102
+ throw new MCPError('FILE_ERROR', `Failed to delete file: ${error.message}`);
103
+ }
27
104
  }
28
105
  if (action === 'search') {
29
106
  // Simple string search within files in projectPath (non-recursive)
@@ -1,11 +1,12 @@
1
1
  import { MCPError } from '../utils/errors.js';
2
- import { getRepoInfo } from '../utils/repoHelpers.js';
2
+ import { getRepoInfo, normalizeToolParams } from '../utils/repoHelpers.js';
3
3
  export class GitIssuesTool {
4
4
  constructor() {
5
5
  this.name = 'git-issues';
6
6
  this.description = 'Issue management for GitHub and Gitea - automatic dual-provider execution';
7
7
  }
8
8
  async handle(params, ctx) {
9
+ params = normalizeToolParams(params);
9
10
  const action = params.action;
10
11
  if (!action)
11
12
  throw new MCPError('VALIDATION_ERROR', 'action is required');
@@ -1,12 +1,14 @@
1
1
  import fs from 'fs/promises';
2
2
  import path from 'path';
3
3
  import { MCPError } from '../utils/errors.js';
4
+ import { normalizeToolParams } from '../utils/repoHelpers.js';
4
5
  export class GitPackagesTool {
5
6
  constructor() {
6
7
  this.name = 'git-packages';
7
8
  this.description = 'Package management operations';
8
9
  }
9
10
  async handle(params, ctx) {
11
+ params = normalizeToolParams(params);
10
12
  const action = params.action;
11
13
  const projectPath = params.projectPath;
12
14
  if (!action)
@@ -1,11 +1,13 @@
1
1
  import { MCPError } from '../utils/errors.js';
2
2
  import axios from 'axios';
3
+ import { normalizeToolParams } from '../utils/repoHelpers.js';
3
4
  export class GitPullsTool {
4
5
  constructor() {
5
6
  this.name = 'git-pulls';
6
7
  this.description = 'Pull request management for GitHub and Gitea - automatic dual-provider execution';
7
8
  }
8
9
  async handle(params, ctx) {
10
+ params = normalizeToolParams(params);
9
11
  const action = params.action;
10
12
  if (!action)
11
13
  throw new MCPError('VALIDATION_ERROR', 'action is required');
@@ -1,5 +1,6 @@
1
1
  import simpleGit from 'simple-git';
2
2
  import { MCPError } from '../utils/errors.js';
3
+ import { normalizeToolParams } from '../utils/repoHelpers.js';
3
4
  import axios from 'axios';
4
5
  export class GitReleaseTool {
5
6
  constructor() {
@@ -7,6 +8,7 @@ export class GitReleaseTool {
7
8
  this.description = 'Release management operations - automatic dual-provider execution';
8
9
  }
9
10
  async handle(params, ctx) {
11
+ params = normalizeToolParams(params);
10
12
  const action = params.action;
11
13
  const projectPath = params.projectPath;
12
14
  if (!action)
@@ -1,5 +1,6 @@
1
1
  import simpleGit from 'simple-git';
2
2
  import { MCPError } from '../utils/errors.js';
3
+ import { normalizeToolParams } from '../utils/repoHelpers.js';
3
4
  import axios from 'axios';
4
5
  export class GitWorkflowTool {
5
6
  constructor() {
@@ -7,9 +8,11 @@ export class GitWorkflowTool {
7
8
  this.description = 'Core Git operations including init, status, commit, sync, backup, and remote operations - automatic dual-provider for remote ops';
8
9
  }
9
10
  async handle(params, ctx) {
11
+ // Normalize parameters to handle different IDE/agent formats
12
+ params = normalizeToolParams(params);
10
13
  const action = params.action;
11
14
  if (!action)
12
- throw new MCPError('VALIDATION_ERROR', 'action is required');
15
+ throw new MCPError('VALIDATION_ERROR', 'action is required. You can use either "action" or "command" parameter.');
13
16
  const projectPath = params.projectPath;
14
17
  const git = projectPath ? simpleGit({ baseDir: projectPath }) : null;
15
18
  switch (action) {
@@ -36,3 +36,9 @@ export declare function getRepoInfo(projectPath: string): {
36
36
  githubUrl: string | undefined;
37
37
  giteaUrl: string | undefined;
38
38
  };
39
+ /**
40
+ * Normalize parameters from different IDEs/agents
41
+ * Maps common Git commands to tool actions
42
+ * Handles both 'action' and 'command' parameters
43
+ */
44
+ export declare function normalizeToolParams(params: Record<string, any>): Record<string, any>;
@@ -67,3 +67,56 @@ export function getRepoInfo(projectPath) {
67
67
  giteaUrl: giteaOwner ? buildGiteaUrl(giteaOwner, repoName) : undefined,
68
68
  };
69
69
  }
70
+ /**
71
+ * Normalize parameters from different IDEs/agents
72
+ * Maps common Git commands to tool actions
73
+ * Handles both 'action' and 'command' parameters
74
+ */
75
+ export function normalizeToolParams(params) {
76
+ const normalized = { ...params };
77
+ // If 'command' is provided but not 'action', try to map it
78
+ if (params.command && !params.action) {
79
+ const command = params.command.toLowerCase().trim();
80
+ // Map common git commands to actions
81
+ const commandMap = {
82
+ // git-workflow commands
83
+ 'git status': 'status',
84
+ 'status': 'status',
85
+ 'git init': 'init',
86
+ 'init': 'init',
87
+ 'git commit': 'commit',
88
+ 'commit': 'commit',
89
+ 'git push': 'push',
90
+ 'push': 'push',
91
+ 'git pull': 'sync',
92
+ 'pull': 'sync',
93
+ 'git sync': 'sync',
94
+ 'sync': 'sync',
95
+ // git-branches commands
96
+ 'git branch': 'list',
97
+ 'branch': 'list',
98
+ 'branches': 'list',
99
+ // git-remote commands
100
+ 'git remote': 'list',
101
+ 'remote': 'list',
102
+ 'remotes': 'list',
103
+ // git-tags commands
104
+ 'git tag': 'list',
105
+ 'tag': 'list',
106
+ 'tags': 'list',
107
+ // git-stash commands
108
+ 'git stash': 'list',
109
+ 'stash': 'list',
110
+ // git-config commands
111
+ 'git config': 'get',
112
+ 'config': 'get',
113
+ };
114
+ normalized.action = commandMap[command] || command.replace(/^git\s+/, '');
115
+ }
116
+ // If still no action, provide sensible defaults based on tool context
117
+ if (!normalized.action && params.projectPath) {
118
+ // Default to 'status' for workflow operations
119
+ normalized.action = 'status';
120
+ }
121
+ return normalized;
122
+ }
package/package.json CHANGED
@@ -1,8 +1,8 @@
1
1
  {
2
2
  "name": "@andrebuzeli/git-mcp",
3
- "version": "7.3.3",
3
+ "version": "7.4.0",
4
4
  "type": "module",
5
- "description": "Professional MCP server for Git operations - STDIO UNIVERSAL: works in ANY IDE (Cursor, VSCode, Claude Desktop). Fully autonomous DUAL execution (GitHub + Gitea APIs) with automatic username detection. All tools execute on BOTH providers simultaneously. No manual parameters needed.",
5
+ "description": "Professional MCP server for Git operations - STDIO UNIVERSAL: works in ANY IDE (Cursor, VSCode, Claude Desktop, Trae AI, Kiro.dev). Fully autonomous DUAL execution (GitHub + Gitea APIs) with automatic username detection. Smart parameter normalization handles both 'action' and 'command' formats. All tools execute on BOTH providers simultaneously. No manual parameters needed.",
6
6
  "main": "dist/index.js",
7
7
  "types": "dist/index.d.ts",
8
8
  "bin": {