@andrebuzeli/git-mcp 5.8.3 → 5.9.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/dist/index.js CHANGED
@@ -1,43 +1,10 @@
1
1
  #!/usr/bin/env node
2
2
  "use strict";
3
- var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
4
- if (k2 === undefined) k2 = k;
5
- var desc = Object.getOwnPropertyDescriptor(m, k);
6
- if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
7
- desc = { enumerable: true, get: function() { return m[k]; } };
8
- }
9
- Object.defineProperty(o, k2, desc);
10
- }) : (function(o, m, k, k2) {
11
- if (k2 === undefined) k2 = k;
12
- o[k2] = m[k];
13
- }));
14
- var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
15
- Object.defineProperty(o, "default", { enumerable: true, value: v });
16
- }) : function(o, v) {
17
- o["default"] = v;
18
- });
19
- var __importStar = (this && this.__importStar) || (function () {
20
- var ownKeys = function(o) {
21
- ownKeys = Object.getOwnPropertyNames || function (o) {
22
- var ar = [];
23
- for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
24
- return ar;
25
- };
26
- return ownKeys(o);
27
- };
28
- return function (mod) {
29
- if (mod && mod.__esModule) return mod;
30
- var result = {};
31
- if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
32
- __setModuleDefault(result, mod);
33
- return result;
34
- };
35
- })();
36
3
  var __importDefault = (this && this.__importDefault) || function (mod) {
37
4
  return (mod && mod.__esModule) ? mod : { "default": mod };
38
5
  };
39
6
  Object.defineProperty(exports, "__esModule", { value: true });
40
- const readline = __importStar(require("readline"));
7
+ const server_1 = require("./server");
41
8
  const providerManager_1 = require("./providers/providerManager");
42
9
  const config_1 = require("./config");
43
10
  const gitFiles_1 = require("./tools/gitFiles");
@@ -98,148 +65,63 @@ async function main() {
98
65
  const resources = [
99
66
  toolsGuide_1.default
100
67
  ];
101
- const toolRegistry = new Map();
102
- for (const t of tools)
103
- toolRegistry.set(t.name, t);
104
- const resourceRegistry = new Map();
105
- for (const r of resources)
106
- resourceRegistry.set(r.uri, r);
107
68
  // Silent mode for MCP clients - only log to stderr in debug mode
108
69
  if (process.env.DEBUG) {
109
70
  console.error(`Registered ${tools.length} Git tools`);
110
71
  console.error(`Registered ${resources.length} resource(s)`);
111
72
  }
112
- // MCP JSON-RPC over stdio
113
- const rl = readline.createInterface({
114
- input: process.stdin,
115
- output: process.stdout,
116
- terminal: false
117
- });
118
- rl.on('line', async (line) => {
119
- let request;
120
- let id = null;
121
- try {
122
- request = JSON.parse(line);
123
- id = request.id ?? null;
124
- const { jsonrpc, method, params } = request;
125
- let response = { jsonrpc: '2.0', id };
126
- switch (method) {
127
- case 'initialize':
128
- response.result = {
129
- protocolVersion: '2024-11-05',
130
- capabilities: {
131
- tools: {},
132
- resources: {}
133
- },
134
- serverInfo: {
135
- name: 'git-mcp',
136
- version: '5.8.1'
137
- }
138
- };
139
- break;
140
- case 'tools/list':
141
- response.result = {
142
- tools: tools.map(t => ({
143
- name: t.name,
144
- description: t.description,
145
- inputSchema: {
146
- type: 'object',
147
- properties: {},
148
- required: []
149
- }
150
- }))
151
- };
152
- break;
153
- case 'tools/call':
154
- const toolName = params?.name;
155
- const tool = toolRegistry.get(toolName);
156
- if (!tool) {
157
- response.error = {
158
- code: -32601,
159
- message: `Tool not found: ${toolName}`
160
- };
161
- }
162
- else {
163
- try {
164
- const result = await tool.handle(params?.arguments ?? {}, { providerManager });
165
- response.result = {
166
- content: [
167
- {
168
- type: 'text',
169
- text: JSON.stringify(result, null, 2)
170
- }
171
- ]
172
- };
173
- }
174
- catch (err) {
175
- response.error = {
176
- code: -32603,
177
- message: err.message || String(err)
178
- };
179
- }
180
- }
181
- break;
182
- case 'resources/list':
183
- response.result = {
184
- resources: Array.from(resourceRegistry.values()).map(r => ({
185
- uri: r.uri,
186
- name: r.name,
187
- description: r.description,
188
- mimeType: r.mimeType
189
- }))
190
- };
191
- break;
192
- case 'resources/read':
193
- const uri = params?.uri;
194
- const resource = resourceRegistry.get(uri);
195
- if (!resource) {
196
- response.error = {
197
- code: -32601,
198
- message: `Resource not found: ${uri}`
199
- };
200
- }
201
- else {
202
- response.result = {
203
- contents: [
204
- {
205
- uri: resource.uri,
206
- mimeType: resource.mimeType,
207
- text: resource.content
208
- }
209
- ]
210
- };
211
- }
212
- break;
213
- default:
214
- response.error = {
215
- code: -32601,
216
- message: `Method not found: ${method}`
217
- };
218
- }
219
- console.log(JSON.stringify(response));
220
- }
221
- catch (err) {
222
- // Send error response with id if we have it
223
- const errorResponse = {
224
- jsonrpc: '2.0',
225
- id: id,
226
- error: {
227
- code: -32700,
228
- message: `Parse error: ${err.message || String(err)}`
73
+ const app = (0, server_1.createServer)({ tools, providerManager, resources });
74
+ // Try default port, then find available port if occupied
75
+ let port = parseInt(process.env.PORT || '3210');
76
+ const startServer = (attemptPort) => {
77
+ return new Promise((resolve, reject) => {
78
+ const server = app.listen(attemptPort, () => {
79
+ // Send success message to stderr (MCP clients expect JSON on stdout)
80
+ if (process.env.DEBUG) {
81
+ console.error(`✅ git-mcp server ready on http://localhost:${attemptPort}`);
82
+ console.error(`Tools: ${tools.map(t => t.name).join(', ')}`);
83
+ console.error(`Resources: ${resources.map(r => r.uri).join(', ')}`);
229
84
  }
230
- };
231
- console.log(JSON.stringify(errorResponse));
232
- if (process.env.DEBUG) {
233
- console.error('Error processing request:', err);
234
- }
85
+ resolve(server);
86
+ });
87
+ server.on('error', (err) => {
88
+ if (err.code === 'EADDRINUSE') {
89
+ // Port in use, try next port
90
+ server.close();
91
+ resolve(null);
92
+ }
93
+ else {
94
+ reject(err);
95
+ }
96
+ });
97
+ });
98
+ };
99
+ // Try to start server on available port
100
+ let server = null;
101
+ const maxAttempts = 10;
102
+ for (let attempt = 0; attempt < maxAttempts; attempt++) {
103
+ const tryPort = port + attempt;
104
+ server = await startServer(tryPort);
105
+ if (server) {
106
+ port = tryPort;
107
+ break;
235
108
  }
109
+ }
110
+ if (!server) {
111
+ console.error(`❌ Failed to find available port after ${maxAttempts} attempts`);
112
+ process.exit(1);
113
+ }
114
+ server.on('error', (err) => {
115
+ console.error('❌ Server error:', err);
116
+ process.exit(1);
236
117
  });
237
118
  // Keep process alive
238
119
  process.on('SIGINT', () => {
239
- if (process.env.DEBUG) {
240
- console.error('\n👋 Shutting down server...');
241
- }
242
- process.exit(0);
120
+ console.log('\n👋 Shutting down server...');
121
+ server.close(() => {
122
+ console.log('Server closed');
123
+ process.exit(0);
124
+ });
243
125
  });
244
126
  }
245
127
  main().catch(err => {
@@ -2,6 +2,7 @@
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.GitIssuesTool = void 0;
4
4
  const errors_1 = require("../utils/errors");
5
+ const repoHelpers_1 = require("../utils/repoHelpers");
5
6
  class GitIssuesTool {
6
7
  constructor() {
7
8
  this.name = 'git-issues';
@@ -11,18 +12,29 @@ class GitIssuesTool {
11
12
  const action = params.action;
12
13
  if (!action)
13
14
  throw new errors_1.MCPError('VALIDATION_ERROR', 'action is required');
14
- const owner = params.owner;
15
- const repo = params.repo;
15
+ // Auto-extract repo info if projectPath is provided
16
+ let owner = params.owner;
17
+ let repo = params.repo;
18
+ if (!repo && params.projectPath) {
19
+ const repoInfo = (0, repoHelpers_1.getRepoInfo)(params.projectPath);
20
+ repo = repoInfo.repoName;
21
+ owner = owner || repoInfo.githubOwner || repoInfo.giteaOwner;
22
+ }
23
+ // Use env vars as fallback
24
+ const githubOwner = owner || process.env.GITHUB_USERNAME;
25
+ const giteaOwner = owner || process.env.GITEA_USERNAME;
16
26
  switch (action) {
17
27
  case 'create': {
18
28
  if (!params.title)
19
29
  throw new errors_1.MCPError('VALIDATION_ERROR', 'title is required');
30
+ if (!repo)
31
+ throw new errors_1.MCPError('VALIDATION_ERROR', 'repo is required (or provide projectPath)');
20
32
  const results = { success: true, providers: {} };
21
33
  // GitHub
22
- if (ctx.providerManager.github) {
34
+ if (ctx.providerManager.github && githubOwner) {
23
35
  try {
24
36
  const result = await ctx.providerManager.github.rest.issues.create({
25
- owner: owner || process.env.GITHUB_USERNAME,
37
+ owner: githubOwner,
26
38
  repo: repo,
27
39
  title: params.title,
28
40
  body: params.body,
@@ -37,10 +49,10 @@ class GitIssuesTool {
37
49
  }
38
50
  }
39
51
  // Gitea
40
- if (ctx.providerManager.giteaBaseUrl) {
52
+ if (ctx.providerManager.giteaBaseUrl && giteaOwner) {
41
53
  try {
42
54
  const axios = require('axios');
43
- const result = await axios.post(`${ctx.providerManager.giteaBaseUrl}/api/v1/repos/${owner || process.env.GITEA_USERNAME}/${repo}/issues`, {
55
+ const result = await axios.post(`${ctx.providerManager.giteaBaseUrl}/api/v1/repos/${giteaOwner}/${repo}/issues`, {
44
56
  title: params.title,
45
57
  body: params.body,
46
58
  labels: params.labels?.map((l) => ({ name: l })),
@@ -57,12 +69,14 @@ class GitIssuesTool {
57
69
  return results;
58
70
  }
59
71
  case 'list': {
72
+ if (!repo)
73
+ throw new errors_1.MCPError('VALIDATION_ERROR', 'repo is required (or provide projectPath)');
60
74
  const results = { success: true, providers: {} };
61
75
  // GitHub
62
- if (ctx.providerManager.github) {
76
+ if (ctx.providerManager.github && githubOwner) {
63
77
  try {
64
78
  const result = await ctx.providerManager.github.rest.issues.listForRepo({
65
- owner: owner || process.env.GITHUB_USERNAME,
79
+ owner: githubOwner,
66
80
  repo: repo,
67
81
  state: params.state_filter || 'open',
68
82
  sort: params.sort || 'created',
@@ -76,10 +90,10 @@ class GitIssuesTool {
76
90
  }
77
91
  }
78
92
  // Gitea
79
- if (ctx.providerManager.giteaBaseUrl) {
93
+ if (ctx.providerManager.giteaBaseUrl && giteaOwner) {
80
94
  try {
81
95
  const axios = require('axios');
82
- const result = await axios.get(`${ctx.providerManager.giteaBaseUrl}/api/v1/repos/${owner || process.env.GITEA_USERNAME}/${repo}/issues`, {
96
+ const result = await axios.get(`${ctx.providerManager.giteaBaseUrl}/api/v1/repos/${giteaOwner}/${repo}/issues`, {
83
97
  params: {
84
98
  state: params.state_filter || 'open',
85
99
  sort: params.sort || 'created',
@@ -99,12 +113,14 @@ class GitIssuesTool {
99
113
  const issue_number = params.issue_number;
100
114
  if (!issue_number)
101
115
  throw new errors_1.MCPError('VALIDATION_ERROR', 'issue_number is required');
116
+ if (!repo)
117
+ throw new errors_1.MCPError('VALIDATION_ERROR', 'repo is required (or provide projectPath)');
102
118
  const results = { success: true, providers: {} };
103
119
  // GitHub
104
- if (ctx.providerManager.github) {
120
+ if (ctx.providerManager.github && githubOwner) {
105
121
  try {
106
122
  const result = await ctx.providerManager.github.rest.issues.get({
107
- owner: owner || process.env.GITHUB_USERNAME,
123
+ owner: githubOwner,
108
124
  repo: repo,
109
125
  issue_number,
110
126
  });
@@ -115,10 +131,10 @@ class GitIssuesTool {
115
131
  }
116
132
  }
117
133
  // Gitea
118
- if (ctx.providerManager.giteaBaseUrl) {
134
+ if (ctx.providerManager.giteaBaseUrl && giteaOwner) {
119
135
  try {
120
136
  const axios = require('axios');
121
- const result = await axios.get(`${ctx.providerManager.giteaBaseUrl}/api/v1/repos/${owner || process.env.GITEA_USERNAME}/${repo}/issues/${issue_number}`, {
137
+ const result = await axios.get(`${ctx.providerManager.giteaBaseUrl}/api/v1/repos/${giteaOwner}/${repo}/issues/${issue_number}`, {
122
138
  headers: { Authorization: `token ${ctx.providerManager.giteaToken}` }
123
139
  });
124
140
  results.providers.gitea = { success: true, issue: result.data };
@@ -133,20 +149,19 @@ class GitIssuesTool {
133
149
  const issue_number = params.issue_number;
134
150
  if (!issue_number)
135
151
  throw new errors_1.MCPError('VALIDATION_ERROR', 'issue_number is required');
152
+ if (!repo)
153
+ throw new errors_1.MCPError('VALIDATION_ERROR', 'repo is required (or provide projectPath)');
136
154
  const results = { success: true, providers: {} };
137
155
  // GitHub
138
- if (ctx.providerManager.github) {
156
+ if (ctx.providerManager.github && githubOwner) {
139
157
  try {
140
158
  const result = await ctx.providerManager.github.rest.issues.update({
141
- owner: owner || process.env.GITHUB_USERNAME,
159
+ owner: githubOwner,
142
160
  repo: repo,
143
- issue_number,
161
+ issue_number: issue_number,
144
162
  title: params.title,
145
163
  body: params.body,
146
164
  state: params.state,
147
- labels: params.labels,
148
- assignees: params.assignees,
149
- milestone: params.milestone,
150
165
  });
151
166
  results.providers.github = { success: true, issue: result.data };
152
167
  }
@@ -155,10 +170,10 @@ class GitIssuesTool {
155
170
  }
156
171
  }
157
172
  // Gitea
158
- if (ctx.providerManager.giteaBaseUrl) {
173
+ if (ctx.providerManager.giteaBaseUrl && giteaOwner) {
159
174
  try {
160
175
  const axios = require('axios');
161
- const result = await axios.patch(`${ctx.providerManager.giteaBaseUrl}/api/v1/repos/${owner || process.env.GITEA_USERNAME}/${repo}/issues/${issue_number}`, {
176
+ const result = await axios.patch(`${ctx.providerManager.giteaBaseUrl}/api/v1/repos/${giteaOwner}/${repo}/issues/${issue_number}`, {
162
177
  title: params.title,
163
178
  body: params.body,
164
179
  state: params.state,
@@ -177,12 +192,14 @@ class GitIssuesTool {
177
192
  const issue_number = params.issue_number;
178
193
  if (!issue_number)
179
194
  throw new errors_1.MCPError('VALIDATION_ERROR', 'issue_number is required');
195
+ if (!repo)
196
+ throw new errors_1.MCPError('VALIDATION_ERROR', 'repo is required (or provide projectPath)');
180
197
  const results = { success: true, providers: {} };
181
198
  // GitHub
182
- if (ctx.providerManager.github) {
199
+ if (ctx.providerManager.github && githubOwner) {
183
200
  try {
184
201
  const result = await ctx.providerManager.github.rest.issues.update({
185
- owner: owner || process.env.GITHUB_USERNAME,
202
+ owner: githubOwner,
186
203
  repo: repo,
187
204
  issue_number,
188
205
  state: 'closed',
@@ -194,10 +211,10 @@ class GitIssuesTool {
194
211
  }
195
212
  }
196
213
  // Gitea
197
- if (ctx.providerManager.giteaBaseUrl) {
214
+ if (ctx.providerManager.giteaBaseUrl && giteaOwner) {
198
215
  try {
199
216
  const axios = require('axios');
200
- const result = await axios.patch(`${ctx.providerManager.giteaBaseUrl}/api/v1/repos/${owner || process.env.GITEA_USERNAME}/${repo}/issues/${issue_number}`, { state: 'closed' }, {
217
+ const result = await axios.patch(`${ctx.providerManager.giteaBaseUrl}/api/v1/repos/${giteaOwner}/${repo}/issues/${issue_number}`, { state: 'closed' }, {
201
218
  headers: { Authorization: `token ${ctx.providerManager.giteaToken}` }
202
219
  });
203
220
  results.providers.gitea = { success: true, issue: result.data };
@@ -215,12 +232,14 @@ class GitIssuesTool {
215
232
  throw new errors_1.MCPError('VALIDATION_ERROR', 'issue_number is required');
216
233
  if (!comment_body)
217
234
  throw new errors_1.MCPError('VALIDATION_ERROR', 'comment_body is required');
235
+ if (!repo)
236
+ throw new errors_1.MCPError('VALIDATION_ERROR', 'repo is required (or provide projectPath)');
218
237
  const results = { success: true, providers: {} };
219
238
  // GitHub
220
- if (ctx.providerManager.github) {
239
+ if (ctx.providerManager.github && githubOwner) {
221
240
  try {
222
241
  const result = await ctx.providerManager.github.rest.issues.createComment({
223
- owner: owner || process.env.GITHUB_USERNAME,
242
+ owner: githubOwner,
224
243
  repo: repo,
225
244
  issue_number,
226
245
  body: comment_body,
@@ -232,10 +251,10 @@ class GitIssuesTool {
232
251
  }
233
252
  }
234
253
  // Gitea
235
- if (ctx.providerManager.giteaBaseUrl) {
254
+ if (ctx.providerManager.giteaBaseUrl && giteaOwner) {
236
255
  try {
237
256
  const axios = require('axios');
238
- const result = await axios.post(`${ctx.providerManager.giteaBaseUrl}/api/v1/repos/${owner || process.env.GITEA_USERNAME}/${repo}/issues/${issue_number}/comments`, { body: comment_body }, {
257
+ const result = await axios.post(`${ctx.providerManager.giteaBaseUrl}/api/v1/repos/${giteaOwner}/${repo}/issues/${issue_number}/comments`, { body: comment_body }, {
239
258
  headers: { Authorization: `token ${ctx.providerManager.giteaToken}` }
240
259
  });
241
260
  results.providers.gitea = { success: true, comment: result.data };
@@ -250,12 +269,14 @@ class GitIssuesTool {
250
269
  const query = params.query;
251
270
  if (!query)
252
271
  throw new errors_1.MCPError('VALIDATION_ERROR', 'query is required');
272
+ if (!repo)
273
+ throw new errors_1.MCPError('VALIDATION_ERROR', 'repo is required (or provide projectPath)');
253
274
  const results = { success: true, providers: {} };
254
275
  // GitHub
255
- if (ctx.providerManager.github) {
276
+ if (ctx.providerManager.github && githubOwner) {
256
277
  try {
257
278
  const result = await ctx.providerManager.github.rest.search.issuesAndPullRequests({
258
- q: `${query} repo:${owner || process.env.GITHUB_USERNAME}/${repo} type:issue`,
279
+ q: `${query} repo:${githubOwner}/${repo} type:issue`,
259
280
  sort: params.search_sort || 'created',
260
281
  order: params.search_order || 'desc',
261
282
  });
@@ -6,6 +6,7 @@ Object.defineProperty(exports, "__esModule", { value: true });
6
6
  exports.GitRemoteTool = void 0;
7
7
  const simple_git_1 = __importDefault(require("simple-git"));
8
8
  const errors_1 = require("../utils/errors");
9
+ const repoHelpers_1 = require("../utils/repoHelpers");
9
10
  class GitRemoteTool {
10
11
  constructor() {
11
12
  this.name = 'git-remote';
@@ -20,10 +21,25 @@ class GitRemoteTool {
20
21
  const git = (0, simple_git_1.default)({ baseDir: projectPath });
21
22
  switch (action) {
22
23
  case 'add': {
23
- const name = params.name;
24
- const url = params.url;
25
- if (!name || !url)
26
- throw new errors_1.MCPError('VALIDATION_ERROR', 'name and url are required');
24
+ const name = params.name || 'origin';
25
+ let url = params.url;
26
+ // Auto-construct URL if not provided
27
+ if (!url) {
28
+ const { repoName, githubOwner, giteaOwner } = (0, repoHelpers_1.getRepoInfo)(projectPath);
29
+ if (name === 'github' && githubOwner) {
30
+ url = (0, repoHelpers_1.buildGitHubUrl)(githubOwner, repoName);
31
+ }
32
+ else if (name === 'gitea' && giteaOwner) {
33
+ url = (0, repoHelpers_1.buildGiteaUrl)(giteaOwner, repoName);
34
+ }
35
+ else if (name === 'origin' && githubOwner) {
36
+ // Default to GitHub for 'origin'
37
+ url = (0, repoHelpers_1.buildGitHubUrl)(githubOwner, repoName);
38
+ }
39
+ else {
40
+ throw new errors_1.MCPError('VALIDATION_ERROR', 'url is required or set GITHUB_USERNAME/GITEA_USERNAME in environment');
41
+ }
42
+ }
27
43
  await git.addRemote(name, url);
28
44
  return { success: true, remote: name, url };
29
45
  }
@@ -48,10 +64,25 @@ class GitRemoteTool {
48
64
  return { success: true, remotes };
49
65
  }
50
66
  case 'set-url': {
51
- const name = params.name;
52
- const url = params.url;
53
- if (!name || !url)
54
- throw new errors_1.MCPError('VALIDATION_ERROR', 'name and url are required');
67
+ const name = params.name || 'origin';
68
+ let url = params.url;
69
+ // Auto-construct URL if not provided
70
+ if (!url) {
71
+ const { repoName, githubOwner, giteaOwner } = (0, repoHelpers_1.getRepoInfo)(projectPath);
72
+ if (name === 'github' && githubOwner) {
73
+ url = (0, repoHelpers_1.buildGitHubUrl)(githubOwner, repoName);
74
+ }
75
+ else if (name === 'gitea' && giteaOwner) {
76
+ url = (0, repoHelpers_1.buildGiteaUrl)(giteaOwner, repoName);
77
+ }
78
+ else if (name === 'origin' && githubOwner) {
79
+ // Default to GitHub for 'origin'
80
+ url = (0, repoHelpers_1.buildGitHubUrl)(githubOwner, repoName);
81
+ }
82
+ else {
83
+ throw new errors_1.MCPError('VALIDATION_ERROR', 'url is required or set GITHUB_USERNAME/GITEA_USERNAME in environment');
84
+ }
85
+ }
55
86
  await git.remote(['set-url', name, url]);
56
87
  return { success: true, remote: name, url };
57
88
  }
@@ -0,0 +1,37 @@
1
+ /**
2
+ * Helper functions to extract repository information automatically
3
+ */
4
+ /**
5
+ * Extract repository name from project path
6
+ */
7
+ export declare function getRepoNameFromPath(projectPath: string): string;
8
+ /**
9
+ * Get GitHub owner from environment
10
+ */
11
+ export declare function getGitHubOwner(): string | undefined;
12
+ /**
13
+ * Get Gitea owner from environment
14
+ */
15
+ export declare function getGiteaOwner(): string | undefined;
16
+ /**
17
+ * Get Gitea base URL from environment
18
+ */
19
+ export declare function getGiteaUrl(): string | undefined;
20
+ /**
21
+ * Build GitHub repository URL
22
+ */
23
+ export declare function buildGitHubUrl(owner: string, repo: string): string;
24
+ /**
25
+ * Build Gitea repository URL with credentials
26
+ */
27
+ export declare function buildGiteaUrl(owner: string, repo: string): string;
28
+ /**
29
+ * Get repository info from project path and environment
30
+ */
31
+ export declare function getRepoInfo(projectPath: string): {
32
+ repoName: string;
33
+ githubOwner: string | undefined;
34
+ giteaOwner: string | undefined;
35
+ githubUrl: string | undefined;
36
+ giteaUrl: string | undefined;
37
+ };
@@ -0,0 +1,77 @@
1
+ "use strict";
2
+ var __importDefault = (this && this.__importDefault) || function (mod) {
3
+ return (mod && mod.__esModule) ? mod : { "default": mod };
4
+ };
5
+ Object.defineProperty(exports, "__esModule", { value: true });
6
+ exports.getRepoNameFromPath = getRepoNameFromPath;
7
+ exports.getGitHubOwner = getGitHubOwner;
8
+ exports.getGiteaOwner = getGiteaOwner;
9
+ exports.getGiteaUrl = getGiteaUrl;
10
+ exports.buildGitHubUrl = buildGitHubUrl;
11
+ exports.buildGiteaUrl = buildGiteaUrl;
12
+ exports.getRepoInfo = getRepoInfo;
13
+ const path_1 = __importDefault(require("path"));
14
+ /**
15
+ * Helper functions to extract repository information automatically
16
+ */
17
+ /**
18
+ * Extract repository name from project path
19
+ */
20
+ function getRepoNameFromPath(projectPath) {
21
+ return path_1.default.basename(projectPath).replace(/\s+/g, '-');
22
+ }
23
+ /**
24
+ * Get GitHub owner from environment
25
+ */
26
+ function getGitHubOwner() {
27
+ return process.env.GITHUB_USERNAME;
28
+ }
29
+ /**
30
+ * Get Gitea owner from environment
31
+ */
32
+ function getGiteaOwner() {
33
+ return process.env.GITEA_USERNAME;
34
+ }
35
+ /**
36
+ * Get Gitea base URL from environment
37
+ */
38
+ function getGiteaUrl() {
39
+ return process.env.GITEA_URL;
40
+ }
41
+ /**
42
+ * Build GitHub repository URL
43
+ */
44
+ function buildGitHubUrl(owner, repo) {
45
+ return `https://github.com/${owner}/${repo}.git`;
46
+ }
47
+ /**
48
+ * Build Gitea repository URL with credentials
49
+ */
50
+ function buildGiteaUrl(owner, repo) {
51
+ const baseUrl = getGiteaUrl();
52
+ const token = process.env.GITEA_TOKEN;
53
+ if (!baseUrl) {
54
+ throw new Error('GITEA_URL not configured');
55
+ }
56
+ if (!token) {
57
+ throw new Error('GITEA_TOKEN not configured');
58
+ }
59
+ // Remove protocol from baseUrl
60
+ const urlWithoutProtocol = baseUrl.replace(/^https?:\/\//, '');
61
+ return `http://${owner}:${token}@${urlWithoutProtocol}/${owner}/${repo}.git`;
62
+ }
63
+ /**
64
+ * Get repository info from project path and environment
65
+ */
66
+ function getRepoInfo(projectPath) {
67
+ const repoName = getRepoNameFromPath(projectPath);
68
+ const githubOwner = getGitHubOwner();
69
+ const giteaOwner = getGiteaOwner();
70
+ return {
71
+ repoName,
72
+ githubOwner,
73
+ giteaOwner,
74
+ githubUrl: githubOwner ? buildGitHubUrl(githubOwner, repoName) : undefined,
75
+ giteaUrl: giteaOwner ? buildGiteaUrl(giteaOwner, repoName) : undefined,
76
+ };
77
+ }
package/package.json CHANGED
@@ -1,84 +1,84 @@
1
- {
2
- "name": "@andrebuzeli/git-mcp",
3
- "version": "5.8.3",
4
- "description": "Professional MCP server for Git operations - automatic dual-provider execution (GitHub + Gitea), no provider parameter needed, organized responses by provider, enhanced security and safety features",
5
- "main": "dist/index.js",
6
- "types": "dist/index.d.ts",
7
- "bin": {
8
- "git-mcp": "dist/index.js"
9
- },
10
- "files": [
11
- "dist/",
12
- "README.md",
13
- "LICENSE",
14
- "package.json"
15
- ],
16
- "scripts": {
17
- "build": "tsc",
18
- "start": "node dist/index.js",
19
- "dev": "ts-node src/index.ts",
20
- "test": "jest",
21
- "test:watch": "jest --watch",
22
- "semantic-release": "semantic-release",
23
- "prepublishOnly": "npm run build",
24
- "clean": "rimraf dist",
25
- "release": "npm run build && npm version patch && git push origin --follow-tags"
26
- },
27
- "keywords": [
28
- "mcp",
29
- "git",
30
- "github",
31
- "gitea",
32
- "universal-mode",
33
- "multi-provider",
34
- "model-context-protocol",
35
- "ai-agent",
36
- "version-control",
37
- "automation",
38
- "cli",
39
- "developer-tools",
40
- "workflow",
41
- "repository-management"
42
- ],
43
- "author": "Andre Buzeli",
44
- "license": "MIT",
45
- "repository": {
46
- "type": "git",
47
- "url": "https://github.com/andrebuzeli/git-mcp.git"
48
- },
49
- "bugs": {
50
- "url": "https://github.com/andrebuzeli/git-mcp/issues"
51
- },
52
- "homepage": "https://github.com/andrebuzeli/git-mcp#readme",
53
- "dependencies": {
54
- "@modelcontextprotocol/sdk": "^0.4.0",
55
- "@octokit/rest": "^20.0.0",
56
- "axios": "^1.6.0",
57
- "simple-git": "^3.20.0",
58
- "express": "^4.18.2",
59
- "body-parser": "^1.20.2",
60
- "ajv": "^8.12.0"
61
- },
62
- "devDependencies": {
63
- "semantic-release": "^20.1.0",
64
- "@semantic-release/npm": "^10.0.0",
65
- "@semantic-release/github": "^9.0.0",
66
- "@semantic-release/commit-analyzer": "^10.0.0",
67
- "@semantic-release/release-notes-generator": "^10.0.0",
68
- "@types/node": "^20.0.0",
69
- "@types/express": "^4.17.17",
70
- "@types/body-parser": "^1.19.2",
71
- "@types/jest": "^29.0.0",
72
- "typescript": "^5.0.0",
73
- "jest": "^29.0.0",
74
- "ts-node": "^10.0.0",
75
- "ts-jest": "^29.0.0",
76
- "rimraf": "^5.0.0"
77
- },
78
- "engines": {
79
- "node": ">=18.0.0"
80
- },
81
- "publishConfig": {
82
- "access": "public"
83
- }
84
- }
1
+ {
2
+ "name": "@andrebuzeli/git-mcp",
3
+ "version": "5.9.0",
4
+ "description": "Professional MCP server for Git operations - automatic dual-provider execution (GitHub + Gitea), intelligent parameter extraction from environment and projectPath, no redundant parameters needed, organized responses by provider, enhanced security and safety features",
5
+ "main": "dist/index.js",
6
+ "types": "dist/index.d.ts",
7
+ "bin": {
8
+ "git-mcp": "dist/index.js"
9
+ },
10
+ "files": [
11
+ "dist/",
12
+ "README.md",
13
+ "LICENSE",
14
+ "package.json"
15
+ ],
16
+ "scripts": {
17
+ "build": "tsc",
18
+ "start": "node dist/index.js",
19
+ "dev": "ts-node src/index.ts",
20
+ "test": "jest",
21
+ "test:watch": "jest --watch",
22
+ "semantic-release": "semantic-release",
23
+ "prepublishOnly": "npm run build",
24
+ "clean": "rimraf dist",
25
+ "release": "npm run build && npm version patch && git push origin --follow-tags"
26
+ },
27
+ "keywords": [
28
+ "mcp",
29
+ "git",
30
+ "github",
31
+ "gitea",
32
+ "universal-mode",
33
+ "multi-provider",
34
+ "model-context-protocol",
35
+ "ai-agent",
36
+ "version-control",
37
+ "automation",
38
+ "cli",
39
+ "developer-tools",
40
+ "workflow",
41
+ "repository-management"
42
+ ],
43
+ "author": "Andre Buzeli",
44
+ "license": "MIT",
45
+ "repository": {
46
+ "type": "git",
47
+ "url": "https://github.com/andrebuzeli/git-mcp.git"
48
+ },
49
+ "bugs": {
50
+ "url": "https://github.com/andrebuzeli/git-mcp/issues"
51
+ },
52
+ "homepage": "https://github.com/andrebuzeli/git-mcp#readme",
53
+ "dependencies": {
54
+ "@modelcontextprotocol/sdk": "^0.4.0",
55
+ "@octokit/rest": "^20.0.0",
56
+ "axios": "^1.6.0",
57
+ "simple-git": "^3.20.0",
58
+ "express": "^4.18.2",
59
+ "body-parser": "^1.20.2",
60
+ "ajv": "^8.12.0"
61
+ },
62
+ "devDependencies": {
63
+ "semantic-release": "^20.1.0",
64
+ "@semantic-release/npm": "^10.0.0",
65
+ "@semantic-release/github": "^9.0.0",
66
+ "@semantic-release/commit-analyzer": "^10.0.0",
67
+ "@semantic-release/release-notes-generator": "^10.0.0",
68
+ "@types/node": "^20.0.0",
69
+ "@types/express": "^4.17.17",
70
+ "@types/body-parser": "^1.19.2",
71
+ "@types/jest": "^29.0.0",
72
+ "typescript": "^5.0.0",
73
+ "jest": "^29.0.0",
74
+ "ts-node": "^10.0.0",
75
+ "ts-jest": "^29.0.0",
76
+ "rimraf": "^5.0.0"
77
+ },
78
+ "engines": {
79
+ "node": ">=18.0.0"
80
+ },
81
+ "publishConfig": {
82
+ "access": "public"
83
+ }
84
+ }