@andrebuzeli/git-mcp 10.0.4 → 10.0.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/dist/index.js CHANGED
@@ -3,6 +3,7 @@ import { Server } from '@modelcontextprotocol/sdk/server/index.js';
3
3
  import { StdioServerTransport } from '@modelcontextprotocol/sdk/server/stdio.js';
4
4
  import { CallToolRequestSchema, ListToolsRequestSchema, ListResourcesRequestSchema, ReadResourceRequestSchema, ListPromptsRequestSchema, GetPromptRequestSchema, } from '@modelcontextprotocol/sdk/types.js';
5
5
  import { ProviderManager } from './providers/providerManager.js';
6
+ import { MCPError } from './utils/errors.js';
6
7
  import { IsomorphicGitAdapter } from './utils/gitAdapter.js';
7
8
  import { GitFilesTool } from './tools/gitFiles.js';
8
9
  import { GitWorkflowTool } from './tools/gitWorkflow.js';
@@ -28,9 +29,11 @@ import { GitFixTool } from './tools/gitFix.tool.js';
28
29
  import { GitIgnoreTool } from './tools/gitIgnore.js';
29
30
  import { GIT_PROMPTS } from './prompts/gitPrompts.js';
30
31
  import TOOLS_GUIDE from './resources/toolsGuide.js';
32
+ import { Logger, logToolExecution, logSecurityEvent, logPerformanceMetric } from './utils/logger.js';
31
33
  async function main() {
32
34
  const providerManager = new ProviderManager();
33
35
  const gitAdapter = new IsomorphicGitAdapter(providerManager);
36
+ const logger = Logger.getInstance();
34
37
  // Skip validation on startup to prevent hanging (validation happens on first use)
35
38
  // Provider validation moved to lazy initialization
36
39
  // Register all 22 Git tools
@@ -64,17 +67,18 @@ async function main() {
64
67
  ];
65
68
  // Silent mode for MCP clients - only log to stderr in debug mode
66
69
  if (process.env.DEBUG) {
67
- console.error(`Registered ${tools.length} Git tools`);
68
- console.error(`Registered ${resources.length} resource(s)`);
69
- console.error(`Registered ${GIT_PROMPTS.length} prompt(s)`);
70
+ logger.info(`Registered ${tools.length} Git tools`);
71
+ logger.info(`Registered ${resources.length} resource(s)`);
72
+ logger.info(`Registered ${GIT_PROMPTS.length} prompt(s)`);
70
73
  }
71
74
  // Create MCP Server with STDIO transport
72
75
  const server = new Server({
73
76
  name: '@andrebuzeli/git-mcp',
74
- version: '10.0.1',
77
+ version: '10.0.6',
75
78
  });
76
79
  // Register tool list handler
77
80
  server.setRequestHandler(ListToolsRequestSchema, async () => {
81
+ logger.debug('Listing available tools');
78
82
  return {
79
83
  tools: tools.map(tool => ({
80
84
  name: tool.name,
@@ -87,15 +91,42 @@ async function main() {
87
91
  })),
88
92
  };
89
93
  });
90
- // Register tool execution handler
94
+ // Register tool execution handler with logging e segurança aprimorados
91
95
  server.setRequestHandler(CallToolRequestSchema, async (request) => {
92
96
  const toolName = request.params.name;
93
97
  const tool = tools.find(t => t.name === toolName);
98
+ const startTime = Date.now();
94
99
  if (!tool) {
100
+ logSecurityEvent('TOOL_NOT_FOUND', { toolName });
95
101
  throw new Error(`Tool not found: ${toolName}`);
96
102
  }
97
103
  try {
98
- const result = await tool.handle(request.params.arguments ?? {}, { providerManager, gitAdapter });
104
+ // Validar argumentos contra o schema da ferramenta
105
+ const args = request.params.arguments ?? {};
106
+ // Validação básica de segurança
107
+ if (typeof args !== 'object' || args === null) {
108
+ logSecurityEvent('INVALID_ARGUMENTS', { toolName, args });
109
+ throw new MCPError('VALIDATION_ERROR', 'Arguments must be an object');
110
+ }
111
+ // Validar projectPath se existir
112
+ if ('projectPath' in args) {
113
+ const projectPath = args.projectPath;
114
+ if (typeof projectPath !== 'string') {
115
+ logSecurityEvent('INVALID_PROJECT_PATH_TYPE', { toolName, projectPath });
116
+ throw new MCPError('VALIDATION_ERROR', 'projectPath must be a string');
117
+ }
118
+ if (!projectPath || projectPath.includes('..')) {
119
+ logSecurityEvent('PATH_TRAVERSION_ATTEMPT', { toolName, projectPath });
120
+ throw new MCPError('VALIDATION_ERROR', 'Invalid project path');
121
+ }
122
+ }
123
+ // Log da execução
124
+ logger.info(`Executing tool: ${toolName}`, { args }, toolName);
125
+ // Executar a ferramenta
126
+ const result = await tool.handle(args, { providerManager, gitAdapter });
127
+ const duration = Date.now() - startTime;
128
+ logPerformanceMetric(`tool_${toolName}`, duration, { success: true });
129
+ logToolExecution(toolName, args, result);
99
130
  return {
100
131
  content: [
101
132
  {
@@ -106,6 +137,9 @@ async function main() {
106
137
  };
107
138
  }
108
139
  catch (error) {
140
+ const duration = Date.now() - startTime;
141
+ logPerformanceMetric(`tool_${toolName}`, duration, { success: false, error: error.message });
142
+ logToolExecution(toolName, request.params.arguments ?? {}, undefined, error);
109
143
  return {
110
144
  content: [
111
145
  {
@@ -119,6 +153,7 @@ async function main() {
119
153
  });
120
154
  // Register resource list handler
121
155
  server.setRequestHandler(ListResourcesRequestSchema, async () => {
156
+ logger.debug('Listing available resources');
122
157
  return {
123
158
  resources: resources.map(resource => ({
124
159
  uri: resource.uri,
@@ -133,8 +168,10 @@ async function main() {
133
168
  const uri = request.params.uri;
134
169
  const resource = resources.find(r => r.uri === uri);
135
170
  if (!resource) {
171
+ logger.warn(`Resource not found: ${uri}`);
136
172
  throw new Error(`Resource not found: ${uri}`);
137
173
  }
174
+ logger.debug(`Reading resource: ${uri}`);
138
175
  return {
139
176
  contents: [
140
177
  {
@@ -147,6 +184,7 @@ async function main() {
147
184
  });
148
185
  // Register prompt list handler
149
186
  server.setRequestHandler(ListPromptsRequestSchema, async () => {
187
+ logger.debug('Listing available prompts');
150
188
  return {
151
189
  prompts: GIT_PROMPTS.map(prompt => ({
152
190
  name: prompt.name,
@@ -160,8 +198,10 @@ async function main() {
160
198
  const promptName = request.params.name;
161
199
  const prompt = GIT_PROMPTS.find(p => p.name === promptName);
162
200
  if (!prompt) {
201
+ logger.warn(`Prompt not found: ${promptName}`);
163
202
  throw new Error(`Prompt not found: ${promptName}`);
164
203
  }
204
+ logger.debug(`Generating prompt: ${promptName}`);
165
205
  const result = await prompt.generate(request.params.arguments ?? {}, { providerManager, gitAdapter });
166
206
  return {
167
207
  description: result.description,
@@ -172,10 +212,10 @@ async function main() {
172
212
  await server.connect(transport);
173
213
  // Only log in debug mode
174
214
  if (process.env.DEBUG) {
175
- console.error(`✅ git-mcp MCP server running via STDIO`);
176
- console.error(`Tools: ${tools.length} registered`);
177
- console.error(`Resources: ${resources.length} registered`);
178
- console.error(`Prompts: ${GIT_PROMPTS.length} registered`);
215
+ logger.info(`✅ git-mcp MCP server running via STDIO`);
216
+ logger.info(`Tools: ${tools.length} registered`);
217
+ logger.info(`Resources: ${resources.length} registered`);
218
+ logger.info(`Prompts: ${GIT_PROMPTS.length} registered`);
179
219
  }
180
220
  }
181
221
  main().catch(err => {
@@ -0,0 +1,2 @@
1
+ #!/usr/bin/env node
2
+ export {};
@@ -0,0 +1,224 @@
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 { CallToolRequestSchema, ListToolsRequestSchema, ListResourcesRequestSchema, ReadResourceRequestSchema, ListPromptsRequestSchema, GetPromptRequestSchema, } from '@modelcontextprotocol/sdk/types.js';
5
+ import { ProviderManager } from './providers/providerManager.js';
6
+ import { MCPError } from './utils/errors.js';
7
+ import { IsomorphicGitAdapter } from './utils/gitAdapter.js';
8
+ import { GitFilesTool } from './tools/gitFiles.js';
9
+ import { GitWorkflowTool } from './tools/gitWorkflow.js';
10
+ import { GitBranchesTool } from './tools/gitBranches.js';
11
+ import { GitIssuesTool } from './tools/gitIssues.js';
12
+ import { GitPullsTool } from './tools/gitPulls.js';
13
+ import { GitTagsTool } from './tools/gitTags.js';
14
+ import { GitReleaseTool } from './tools/gitRelease.js';
15
+ import { GitRemoteTool } from './tools/gitRemote.js';
16
+ import { GitResetTool } from './tools/gitReset.js';
17
+ import { GitStashTool } from './tools/gitStash.js';
18
+ import { GitConfigTool } from './tools/gitConfig.js';
19
+ import { GitMonitorTool } from './tools/gitMonitor.js';
20
+ import { GitBackupTool } from './tools/gitBackup.js';
21
+ import { GitArchiveTool } from './tools/gitArchive.js';
22
+ import { GitSyncTool } from './tools/gitSync.js';
23
+ import { GitPackagesTool } from './tools/gitPackages.js';
24
+ import { GitAnalyticsTool } from './tools/gitAnalytics.js';
25
+ import { GitUploadTool } from './tools/gitUpload.js';
26
+ import { GitUpdateTool } from './tools/gitUpdate.js';
27
+ import { GitHistoryTool } from './tools/gitHistory.js';
28
+ import { GitFixTool } from './tools/gitFix.tool.js';
29
+ import { GitIgnoreTool } from './tools/gitIgnore.js';
30
+ import { GIT_PROMPTS } from './prompts/gitPrompts.js';
31
+ import TOOLS_GUIDE from './resources/toolsGuide.js';
32
+ import { Logger, logToolExecution, logSecurityEvent, logPerformanceMetric } from './utils/logger.js';
33
+ async function main() {
34
+ const providerManager = new ProviderManager();
35
+ const gitAdapter = new IsomorphicGitAdapter(providerManager);
36
+ const logger = Logger.getInstance();
37
+ // Skip validation on startup to prevent hanging (validation happens on first use)
38
+ // Provider validation moved to lazy initialization
39
+ // Register all 22 Git tools
40
+ const tools = [
41
+ new GitWorkflowTool(),
42
+ new GitFilesTool(),
43
+ new GitBranchesTool(),
44
+ new GitIssuesTool(),
45
+ new GitPullsTool(),
46
+ new GitTagsTool(),
47
+ new GitReleaseTool(),
48
+ new GitRemoteTool(),
49
+ new GitResetTool(),
50
+ new GitStashTool(),
51
+ new GitConfigTool(),
52
+ new GitMonitorTool(),
53
+ new GitBackupTool(),
54
+ new GitArchiveTool(),
55
+ new GitSyncTool(),
56
+ new GitPackagesTool(),
57
+ new GitAnalyticsTool(),
58
+ new GitUploadTool(),
59
+ new GitUpdateTool(),
60
+ new GitHistoryTool(),
61
+ new GitFixTool(),
62
+ new GitIgnoreTool(),
63
+ ];
64
+ // Register resources
65
+ const resources = [
66
+ TOOLS_GUIDE
67
+ ];
68
+ // Silent mode for MCP clients - only log to stderr in debug mode
69
+ if (process.env.DEBUG) {
70
+ logger.info(`Registered ${tools.length} Git tools`);
71
+ logger.info(`Registered ${resources.length} resource(s)`);
72
+ logger.info(`Registered ${GIT_PROMPTS.length} prompt(s)`);
73
+ }
74
+ // Create MCP Server with STDIO transport
75
+ const server = new Server({
76
+ name: '@andrebuzeli/git-mcp',
77
+ version: '10.0.4',
78
+ });
79
+ // Register tool list handler
80
+ server.setRequestHandler(ListToolsRequestSchema, async () => {
81
+ logger.debug('Listing available tools');
82
+ return {
83
+ tools: tools.map(tool => ({
84
+ name: tool.name,
85
+ description: tool.description,
86
+ inputSchema: tool.inputSchema || {
87
+ type: 'object',
88
+ properties: {},
89
+ additionalProperties: true,
90
+ },
91
+ })),
92
+ };
93
+ });
94
+ // Register tool execution handler with logging e segurança aprimorados
95
+ server.setRequestHandler(CallToolRequestSchema, async (request) => {
96
+ const toolName = request.params.name;
97
+ const tool = tools.find(t => t.name === toolName);
98
+ const startTime = Date.now();
99
+ if (!tool) {
100
+ logSecurityEvent('TOOL_NOT_FOUND', { toolName });
101
+ throw new Error(`Tool not found: ${toolName}`);
102
+ }
103
+ try {
104
+ // Validar argumentos contra o schema da ferramenta
105
+ const args = request.params.arguments ?? {};
106
+ // Validação básica de segurança
107
+ if (typeof args !== 'object' || args === null) {
108
+ logSecurityEvent('INVALID_ARGUMENTS', { toolName, args });
109
+ throw new MCPError('VALIDATION_ERROR', 'Arguments must be an object');
110
+ }
111
+ // Validar projectPath se existir
112
+ if ('projectPath' in args) {
113
+ const projectPath = args.projectPath;
114
+ if (typeof projectPath !== 'string') {
115
+ logSecurityEvent('INVALID_PROJECT_PATH_TYPE', { toolName, projectPath });
116
+ throw new MCPError('VALIDATION_ERROR', 'projectPath must be a string');
117
+ }
118
+ if (!projectPath || projectPath.includes('..')) {
119
+ logSecurityEvent('PATH_TRAVERSION_ATTEMPT', { toolName, projectPath });
120
+ throw new MCPError('VALIDATION_ERROR', 'Invalid project path');
121
+ }
122
+ }
123
+ // Log da execução
124
+ logger.info(`Executing tool: ${toolName}`, { args }, toolName);
125
+ // Executar a ferramenta
126
+ const result = await tool.handle(args, { providerManager, gitAdapter });
127
+ const duration = Date.now() - startTime;
128
+ logPerformanceMetric(`tool_${toolName}`, duration, { success: true });
129
+ logToolExecution(toolName, args, result);
130
+ return {
131
+ content: [
132
+ {
133
+ type: 'text',
134
+ text: typeof result === 'string' ? result : JSON.stringify(result, null, 2),
135
+ },
136
+ ],
137
+ };
138
+ }
139
+ catch (error) {
140
+ const duration = Date.now() - startTime;
141
+ logPerformanceMetric(`tool_${toolName}`, duration, { success: false, error: error.message });
142
+ logToolExecution(toolName, request.params.arguments ?? {}, undefined, error);
143
+ return {
144
+ content: [
145
+ {
146
+ type: 'text',
147
+ text: `Error: ${error.message || String(error)}`,
148
+ },
149
+ ],
150
+ isError: true,
151
+ };
152
+ }
153
+ });
154
+ // Register resource list handler
155
+ server.setRequestHandler(ListResourcesRequestSchema, async () => {
156
+ logger.debug('Listing available resources');
157
+ return {
158
+ resources: resources.map(resource => ({
159
+ uri: resource.uri,
160
+ name: resource.name,
161
+ description: resource.description,
162
+ mimeType: resource.mimeType,
163
+ })),
164
+ };
165
+ });
166
+ // Register resource read handler
167
+ server.setRequestHandler(ReadResourceRequestSchema, async (request) => {
168
+ const uri = request.params.uri;
169
+ const resource = resources.find(r => r.uri === uri);
170
+ if (!resource) {
171
+ logger.warn(`Resource not found: ${uri}`);
172
+ throw new Error(`Resource not found: ${uri}`);
173
+ }
174
+ logger.debug(`Reading resource: ${uri}`);
175
+ return {
176
+ contents: [
177
+ {
178
+ uri: resource.uri,
179
+ mimeType: resource.mimeType,
180
+ text: resource.content,
181
+ },
182
+ ],
183
+ };
184
+ });
185
+ // Register prompt list handler
186
+ server.setRequestHandler(ListPromptsRequestSchema, async () => {
187
+ logger.debug('Listing available prompts');
188
+ return {
189
+ prompts: GIT_PROMPTS.map(prompt => ({
190
+ name: prompt.name,
191
+ description: prompt.description,
192
+ arguments: prompt.arguments,
193
+ })),
194
+ };
195
+ });
196
+ // Register prompt get handler
197
+ server.setRequestHandler(GetPromptRequestSchema, async (request) => {
198
+ const promptName = request.params.name;
199
+ const prompt = GIT_PROMPTS.find(p => p.name === promptName);
200
+ if (!prompt) {
201
+ logger.warn(`Prompt not found: ${promptName}`);
202
+ throw new Error(`Prompt not found: ${promptName}`);
203
+ }
204
+ logger.debug(`Generating prompt: ${promptName}`);
205
+ const result = await prompt.generate(request.params.arguments ?? {}, { providerManager, gitAdapter });
206
+ return {
207
+ description: result.description,
208
+ messages: result.messages,
209
+ };
210
+ });
211
+ const transport = new StdioServerTransport();
212
+ await server.connect(transport);
213
+ // Only log in debug mode
214
+ if (process.env.DEBUG) {
215
+ logger.info(`✅ git-mcp MCP server running via STDIO`);
216
+ logger.info(`Tools: ${tools.length} registered`);
217
+ logger.info(`Resources: ${resources.length} registered`);
218
+ logger.info(`Prompts: ${GIT_PROMPTS.length} registered`);
219
+ }
220
+ }
221
+ main().catch(err => {
222
+ console.error('❌ Failed to start git-mcp:', err);
223
+ process.exit(1);
224
+ });
@@ -0,0 +1,89 @@
1
+ import { Tool } from '../types.js';
2
+ export declare class GitFilesTool implements Tool {
3
+ name: string;
4
+ description: string;
5
+ inputSchema: {
6
+ type: "object";
7
+ properties: {
8
+ action: {
9
+ type: string;
10
+ enum: string[];
11
+ description: string;
12
+ };
13
+ projectPath: {
14
+ type: string;
15
+ description: string;
16
+ };
17
+ filePath: {
18
+ type: string;
19
+ description: string;
20
+ };
21
+ directoryPath: {
22
+ type: string;
23
+ description: string;
24
+ };
25
+ content: {
26
+ type: string;
27
+ description: string;
28
+ };
29
+ comment: {
30
+ type: string;
31
+ description: string;
32
+ };
33
+ patterns: {
34
+ type: string;
35
+ items: {
36
+ type: string;
37
+ };
38
+ description: string;
39
+ };
40
+ searchText: {
41
+ type: string;
42
+ description: string;
43
+ };
44
+ query: {
45
+ type: string;
46
+ description: string;
47
+ };
48
+ searchPath: {
49
+ type: string;
50
+ description: string;
51
+ };
52
+ };
53
+ required: string[];
54
+ additionalProperties: boolean;
55
+ };
56
+ handle(params: Record<string, any>): Promise<any>;
57
+ /**
58
+ * Lê arquivo com cache
59
+ */
60
+ private handleRead;
61
+ /**
62
+ * Lista diretório com cache
63
+ */
64
+ private handleList;
65
+ /**
66
+ * Cria arquivo com validação de segurança
67
+ */
68
+ private handleCreate;
69
+ /**
70
+ * Atualiza arquivo com validação de segurança
71
+ */
72
+ private handleUpdate;
73
+ /**
74
+ * Deleta arquivo com validação de segurança
75
+ */
76
+ private handleDelete;
77
+ /**
78
+ * Busca texto em arquivos com cache
79
+ */
80
+ private handleSearch;
81
+ /**
82
+ * Busca recursivamente em diretórios
83
+ */
84
+ private searchInDirectory;
85
+ /**
86
+ * Verifica se arquivo é buscável
87
+ */
88
+ private isSearchableFile;
89
+ }