@andrebuzeli/git-mcp 10.0.9 → 11.0.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.
Files changed (137) hide show
  1. package/README.md +34 -428
  2. package/bin/git-mcp.js +21 -0
  3. package/docs/TOOLS.md +110 -0
  4. package/mcp.json.template +12 -0
  5. package/package.json +9 -76
  6. package/src/local/git.js +14 -0
  7. package/src/providers/gitea.js +13 -0
  8. package/src/providers/github.js +13 -0
  9. package/src/server.js +63 -0
  10. package/src/tools/git-actions.js +19 -0
  11. package/src/tools/git-activity.js +28 -0
  12. package/src/tools/git-admin.js +20 -0
  13. package/src/tools/git-checks.js +14 -0
  14. package/src/tools/git-commits.js +34 -0
  15. package/src/tools/git-contents.js +30 -0
  16. package/src/tools/git-deployments.js +21 -0
  17. package/src/tools/git-gists.js +15 -0
  18. package/src/tools/git-gitdata.js +19 -0
  19. package/src/tools/git-issues-prs.js +44 -0
  20. package/src/tools/git-issues.js +12 -0
  21. package/src/tools/git-local.js +66 -0
  22. package/src/tools/git-meta.js +19 -0
  23. package/src/tools/git-misc.js +21 -0
  24. package/src/tools/git-orgs.js +26 -0
  25. package/src/tools/git-packages.js +12 -0
  26. package/src/tools/git-raw.js +14 -0
  27. package/src/tools/git-releases.js +17 -0
  28. package/src/tools/git-remote.js +29 -0
  29. package/src/tools/git-repos.js +60 -0
  30. package/src/tools/git-search.js +18 -0
  31. package/src/tools/git-sync.js +40 -0
  32. package/src/tools/git-user.js +26 -0
  33. package/src/tools/schema.js +3 -0
  34. package/src/utils/fs.js +29 -0
  35. package/src/utils/project.js +7 -0
  36. package/tests/errors.js +26 -0
  37. package/tests/full_suite.js +98 -0
  38. package/tests/run.js +50 -0
  39. package/LICENSE +0 -21
  40. package/dist/index.d.ts +0 -2
  41. package/dist/index.js +0 -224
  42. package/dist/prompts/gitPrompts.d.ts +0 -93
  43. package/dist/prompts/gitPrompts.js +0 -177
  44. package/dist/providers/giteaProvider.d.ts +0 -3
  45. package/dist/providers/giteaProvider.js +0 -6
  46. package/dist/providers/githubProvider.d.ts +0 -2
  47. package/dist/providers/githubProvider.js +0 -4
  48. package/dist/providers/providerManager.d.ts +0 -11
  49. package/dist/providers/providerManager.js +0 -49
  50. package/dist/resources/toolsGuide.d.ts +0 -12
  51. package/dist/resources/toolsGuide.js +0 -1713
  52. package/dist/scripts/test_e2e.d.ts +0 -1
  53. package/dist/scripts/test_e2e.js +0 -199
  54. package/dist/scripts/test_exhaustive.d.ts +0 -1
  55. package/dist/scripts/test_exhaustive.js +0 -275
  56. package/dist/scripts/test_gitea_creation.d.ts +0 -1
  57. package/dist/scripts/test_gitea_creation.js +0 -116
  58. package/dist/scripts/verify_setup.d.ts +0 -1
  59. package/dist/scripts/verify_setup.js +0 -61
  60. package/dist/server.d.ts +0 -9
  61. package/dist/server.js +0 -73
  62. package/dist/tools/gitAnalytics.d.ts +0 -35
  63. package/dist/tools/gitAnalytics.js +0 -220
  64. package/dist/tools/gitArchive.d.ts +0 -119
  65. package/dist/tools/gitArchive.js +0 -150
  66. package/dist/tools/gitBackup.d.ts +0 -116
  67. package/dist/tools/gitBackup.js +0 -156
  68. package/dist/tools/gitBranches.d.ts +0 -54
  69. package/dist/tools/gitBranches.js +0 -282
  70. package/dist/tools/gitChangelog.d.ts +0 -37
  71. package/dist/tools/gitChangelog.js +0 -67
  72. package/dist/tools/gitConfig.d.ts +0 -97
  73. package/dist/tools/gitConfig.js +0 -125
  74. package/dist/tools/gitFiles.d.ts +0 -129
  75. package/dist/tools/gitFiles.js +0 -213
  76. package/dist/tools/gitFix.d.ts +0 -4
  77. package/dist/tools/gitFix.js +0 -159
  78. package/dist/tools/gitFix.tool.d.ts +0 -31
  79. package/dist/tools/gitFix.tool.js +0 -92
  80. package/dist/tools/gitHistory.d.ts +0 -41
  81. package/dist/tools/gitHistory.js +0 -349
  82. package/dist/tools/gitIgnore.d.ts +0 -214
  83. package/dist/tools/gitIgnore.js +0 -338
  84. package/dist/tools/gitIssues.d.ts +0 -80
  85. package/dist/tools/gitIssues.js +0 -363
  86. package/dist/tools/gitLog.d.ts +0 -30
  87. package/dist/tools/gitLog.js +0 -46
  88. package/dist/tools/gitMonitor.d.ts +0 -30
  89. package/dist/tools/gitMonitor.js +0 -284
  90. package/dist/tools/gitPackages.d.ts +0 -180
  91. package/dist/tools/gitPackages.js +0 -214
  92. package/dist/tools/gitPulls.d.ts +0 -66
  93. package/dist/tools/gitPulls.js +0 -347
  94. package/dist/tools/gitPush.d.ts +0 -40
  95. package/dist/tools/gitPush.js +0 -59
  96. package/dist/tools/gitRelease.d.ts +0 -49
  97. package/dist/tools/gitRelease.js +0 -359
  98. package/dist/tools/gitRemote.d.ts +0 -47
  99. package/dist/tools/gitRemote.js +0 -111
  100. package/dist/tools/gitReset.d.ts +0 -57
  101. package/dist/tools/gitReset.js +0 -79
  102. package/dist/tools/gitStash.d.ts +0 -61
  103. package/dist/tools/gitStash.js +0 -80
  104. package/dist/tools/gitSync.d.ts +0 -34
  105. package/dist/tools/gitSync.js +0 -182
  106. package/dist/tools/gitTags.d.ts +0 -45
  107. package/dist/tools/gitTags.js +0 -251
  108. package/dist/tools/gitUpdate.d.ts +0 -60
  109. package/dist/tools/gitUpdate.js +0 -474
  110. package/dist/tools/gitUpload.d.ts +0 -35
  111. package/dist/tools/gitUpload.js +0 -385
  112. package/dist/tools/gitWorkflow.d.ts +0 -117
  113. package/dist/tools/gitWorkflow.js +0 -472
  114. package/dist/types.d.ts +0 -20
  115. package/dist/types.js +0 -1
  116. package/dist/utils/agentHelpers.d.ts +0 -11
  117. package/dist/utils/agentHelpers.js +0 -41
  118. package/dist/utils/apiHelpers.d.ts +0 -29
  119. package/dist/utils/apiHelpers.js +0 -125
  120. package/dist/utils/cache.d.ts +0 -96
  121. package/dist/utils/cache.js +0 -208
  122. package/dist/utils/contextDetector.d.ts +0 -0
  123. package/dist/utils/contextDetector.js +0 -1
  124. package/dist/utils/errors.d.ts +0 -13
  125. package/dist/utils/errors.js +0 -17
  126. package/dist/utils/gitAdapter.d.ts +0 -224
  127. package/dist/utils/gitAdapter.js +0 -1162
  128. package/dist/utils/logger.d.ts +0 -45
  129. package/dist/utils/logger.js +0 -140
  130. package/dist/utils/rateLimiter.d.ts +0 -113
  131. package/dist/utils/rateLimiter.js +0 -257
  132. package/dist/utils/repoHelpers.d.ts +0 -44
  133. package/dist/utils/repoHelpers.js +0 -122
  134. package/dist/utils/safetyController.d.ts +0 -1
  135. package/dist/utils/safetyController.js +0 -12
  136. package/dist/utils/validation.d.ts +0 -115
  137. package/dist/utils/validation.js +0 -270
@@ -1,61 +0,0 @@
1
- import { Tool, MCPContext } from '../types.js';
2
- export declare class GitStashTool implements Tool {
3
- name: string;
4
- description: string;
5
- inputSchema: {
6
- type: "object";
7
- properties: {
8
- projectPath: {
9
- type: string;
10
- description: string;
11
- };
12
- action: {
13
- type: string;
14
- enum: string[];
15
- description: string;
16
- };
17
- includeUntracked: {
18
- type: string;
19
- description: string;
20
- };
21
- message: {
22
- type: string;
23
- description: string;
24
- };
25
- confirm: {
26
- type: string;
27
- description: string;
28
- };
29
- stashRef: {
30
- type: string;
31
- description: string;
32
- };
33
- };
34
- required: string[];
35
- };
36
- handle(params: Record<string, any>, ctx: MCPContext): Promise<{
37
- success: boolean;
38
- message: string;
39
- stash?: undefined;
40
- stashes?: undefined;
41
- dropped?: undefined;
42
- } | {
43
- success: boolean;
44
- stash: any;
45
- message: string;
46
- stashes?: undefined;
47
- dropped?: undefined;
48
- } | {
49
- success: boolean;
50
- stashes: import("../utils/gitAdapter.js").StashEntry[];
51
- message?: undefined;
52
- stash?: undefined;
53
- dropped?: undefined;
54
- } | {
55
- success: boolean;
56
- dropped: any;
57
- message?: undefined;
58
- stash?: undefined;
59
- stashes?: undefined;
60
- }>;
61
- }
@@ -1,80 +0,0 @@
1
- import { MCPError } from '../utils/errors.js';
2
- export class GitStashTool {
3
- constructor() {
4
- this.name = 'git-stash';
5
- this.description = 'Stash management operations - local Git operations';
6
- this.inputSchema = {
7
- type: "object",
8
- properties: {
9
- projectPath: {
10
- type: "string",
11
- description: "The absolute path to the Git repository directory on the local filesystem. This should be the root directory containing the .git folder. For example: '/home/user/my-project' on Linux/Mac or 'C:\\Users\\user\\my-project' on Windows."
12
- },
13
- action: {
14
- type: "string",
15
- enum: ["save", "list", "apply", "pop", "drop", "clear"],
16
- description: "Stash operation to perform: save (stash changes), list (list stashes), apply (apply stash), pop (apply and remove stash), drop (remove stash), clear (remove all stashes)"
17
- },
18
- includeUntracked: {
19
- type: "boolean",
20
- description: "Include untracked files (optional for save)"
21
- },
22
- message: {
23
- type: "string",
24
- description: "Stash message (optional for save)"
25
- },
26
- confirm: {
27
- type: "boolean",
28
- description: "Confirm destructive operations (optional for drop/clear)"
29
- },
30
- stashRef: {
31
- type: "string",
32
- description: "Stash reference (optional for apply/pop/drop, default: stash@{0})"
33
- }
34
- },
35
- required: ["projectPath", "action"]
36
- };
37
- }
38
- async handle(params, ctx) {
39
- const action = params.action;
40
- const projectPath = params.projectPath;
41
- if (!action || !projectPath) {
42
- throw new MCPError('VALIDATION_ERROR', 'action and projectPath are required');
43
- }
44
- const git = ctx.gitAdapter;
45
- switch (action) {
46
- case 'save':
47
- case 'stash': { // Support both for compatibility
48
- const message = params.message;
49
- const includeUntracked = params.includeUntracked;
50
- await git.saveStash(projectPath, message, includeUntracked);
51
- return { success: true, message: 'Changes stashed' };
52
- }
53
- case 'pop': {
54
- const stashRef = params.stashRef || 'stash@{0}';
55
- await git.popStash(projectPath, stashRef);
56
- return { success: true, stash: stashRef, message: 'Stash applied and removed' };
57
- }
58
- case 'apply': {
59
- const stashRef = params.stashRef || 'stash@{0}';
60
- await git.applyStash(projectPath, stashRef);
61
- return { success: true, stash: stashRef, message: 'Stash applied (kept in list)' };
62
- }
63
- case 'list': {
64
- const stashes = await git.listStash(projectPath);
65
- return { success: true, stashes };
66
- }
67
- case 'drop': {
68
- const stashRef = params.stashRef || 'stash@{0}';
69
- await git.dropStash(projectPath, stashRef);
70
- return { success: true, dropped: stashRef };
71
- }
72
- case 'clear': {
73
- await git.clearStash(projectPath);
74
- return { success: true, message: 'All stashes cleared' };
75
- }
76
- default:
77
- throw new MCPError('VALIDATION_ERROR', `Unsupported action: ${action}`);
78
- }
79
- }
80
- }
@@ -1,34 +0,0 @@
1
- import { Tool, MCPContext } from '../types.js';
2
- export declare class GitSyncTool implements Tool {
3
- name: string;
4
- description: string;
5
- inputSchema: {
6
- type: "object";
7
- properties: {
8
- projectPath: {
9
- type: string;
10
- description: string;
11
- };
12
- action: {
13
- type: string;
14
- enum: string[];
15
- description: string;
16
- };
17
- branch: {
18
- type: string;
19
- description: string;
20
- };
21
- force: {
22
- type: string;
23
- description: string;
24
- };
25
- remote: {
26
- type: string;
27
- description: string;
28
- };
29
- };
30
- required: string[];
31
- additionalProperties: boolean;
32
- };
33
- handle(params: Record<string, any>, ctx: MCPContext): Promise<any>;
34
- }
@@ -1,182 +0,0 @@
1
- import { MCPError } from '../utils/errors.js';
2
- export class GitSyncTool {
3
- constructor() {
4
- this.name = 'git-sync';
5
- this.description = 'Repository synchronization operations - local Git operations';
6
- this.inputSchema = {
7
- type: "object",
8
- properties: {
9
- projectPath: {
10
- type: "string",
11
- description: "The absolute path to the Git repository directory on the local filesystem. This should be the root directory containing the .git folder. For example: '/home/user/my-project' on Linux/Mac or 'C:\\Users\\user\\my-project' on Windows."
12
- },
13
- action: {
14
- type: "string",
15
- enum: ["fetch", "pull", "push", "sync", "status", "one-shot"],
16
- description: "Sync operation to perform: fetch (fetch from remote), pull (pull changes), push (push changes), sync (fetch + push), status (get sync status), one-shot (complete sync cycle)"
17
- },
18
- branch: {
19
- type: "string",
20
- description: "Branch name (optional, default: current branch)"
21
- },
22
- force: {
23
- type: "boolean",
24
- description: "Force push (optional for push action)"
25
- },
26
- remote: {
27
- type: "string",
28
- description: "Remote name (optional, default: origin)"
29
- }
30
- },
31
- required: ["projectPath", "action"],
32
- additionalProperties: true
33
- };
34
- }
35
- async handle(params, ctx) {
36
- const action = params.action;
37
- const projectPath = params.projectPath;
38
- if (!action || !projectPath) {
39
- throw new MCPError('VALIDATION_ERROR', 'action and projectPath are required');
40
- }
41
- if (!ctx.gitAdapter) {
42
- throw new MCPError('INTERNAL_ERROR', 'Git adapter not available');
43
- }
44
- switch (action) {
45
- case 'fetch': {
46
- const remote = params.remote || 'origin';
47
- try {
48
- await ctx.gitAdapter.fetch(projectPath, remote);
49
- return { success: true, projectPath, remote, action: 'fetch' };
50
- }
51
- catch (err) {
52
- throw new MCPError('FETCH_ERROR', `Failed to fetch from ${remote}: ${err.message}`);
53
- }
54
- }
55
- case 'pull': {
56
- const remote = params.remote || 'origin';
57
- let branch = params.branch;
58
- try {
59
- if (!branch) {
60
- branch = await ctx.gitAdapter.getCurrentBranch(projectPath);
61
- }
62
- await ctx.gitAdapter.pull(projectPath, remote, branch);
63
- return { success: true, projectPath, remote, branch, action: 'pull' };
64
- }
65
- catch (err) {
66
- throw new MCPError('PULL_ERROR', `Failed to pull from ${remote}: ${err.message}`);
67
- }
68
- }
69
- case 'push': {
70
- const remote = params.remote || 'origin';
71
- let branch = params.branch;
72
- const force = params.force || false;
73
- try {
74
- if (!branch) {
75
- branch = await ctx.gitAdapter.getCurrentBranch(projectPath);
76
- }
77
- await ctx.gitAdapter.push(projectPath, remote, branch, force);
78
- return {
79
- success: true,
80
- projectPath,
81
- remote,
82
- branch,
83
- action: 'push',
84
- message: 'Push successful'
85
- };
86
- }
87
- catch (err) {
88
- throw new MCPError('PUSH_ERROR', `Failed to push to ${remote}: ${err.message}`);
89
- }
90
- }
91
- case 'sync': {
92
- const remote = params.remote || 'origin';
93
- let branch = params.branch;
94
- try {
95
- if (!branch) {
96
- branch = await ctx.gitAdapter.getCurrentBranch(projectPath);
97
- }
98
- // Checkout if needed (not strictly necessary if we are already on the branch, but good for safety)
99
- const currentBranch = await ctx.gitAdapter.getCurrentBranch(projectPath);
100
- if (branch !== currentBranch) {
101
- await ctx.gitAdapter.checkout(projectPath, branch);
102
- }
103
- await ctx.gitAdapter.fetch(projectPath, remote);
104
- await ctx.gitAdapter.pull(projectPath, remote, branch);
105
- await ctx.gitAdapter.push(projectPath, remote, branch);
106
- return { success: true, projectPath, remote, branch, message: 'Repository synced' };
107
- }
108
- catch (err) {
109
- throw new MCPError('SYNC_ERROR', `Failed to sync with ${remote}: ${err.message}`);
110
- }
111
- }
112
- case 'status': {
113
- try {
114
- const status = await ctx.gitAdapter.status(projectPath);
115
- const remotes = await ctx.gitAdapter.listRemotes(projectPath);
116
- return {
117
- success: true,
118
- projectPath,
119
- status: {
120
- branch: status.current,
121
- ahead: status.ahead,
122
- behind: status.behind,
123
- modified: status.modified,
124
- created: status.created,
125
- deleted: status.deleted,
126
- clean: status.isClean,
127
- },
128
- remotes,
129
- };
130
- }
131
- catch (err) {
132
- throw new MCPError('STATUS_ERROR', `Failed to get status: ${err.message}`);
133
- }
134
- }
135
- case 'one-shot': {
136
- // One-shot sync: fetch, pull, and push in a single operation
137
- const remote = params.remote || 'origin';
138
- let branch = params.branch;
139
- const results = {
140
- success: true,
141
- projectPath,
142
- remote,
143
- branch: branch || 'current',
144
- steps: [],
145
- };
146
- try {
147
- if (!branch) {
148
- branch = await ctx.gitAdapter.getCurrentBranch(projectPath);
149
- results.branch = branch;
150
- }
151
- // Step 1: Fetch
152
- results.steps.push({ action: 'fetch', timestamp: new Date().toISOString() });
153
- await ctx.gitAdapter.fetch(projectPath, remote);
154
- // Step 2: Pull
155
- results.steps.push({ action: 'pull', timestamp: new Date().toISOString() });
156
- await ctx.gitAdapter.pull(projectPath, remote, branch);
157
- // Step 3: Push
158
- results.steps.push({ action: 'push', timestamp: new Date().toISOString() });
159
- await ctx.gitAdapter.push(projectPath, remote, branch, false, true);
160
- results.pushResult = {
161
- pushed: true, // Isomorphic git doesn't return detailed push stats easily
162
- message: 'Push successful'
163
- };
164
- // Step 4: Final status
165
- const finalStatus = await ctx.gitAdapter.status(projectPath);
166
- results.finalStatus = {
167
- branch: finalStatus.current,
168
- ahead: finalStatus.ahead,
169
- behind: finalStatus.behind,
170
- clean: finalStatus.isClean,
171
- };
172
- return results;
173
- }
174
- catch (err) {
175
- throw new MCPError('ONE_SHOT_ERROR', `Failed during one-shot sync: ${err.message}`);
176
- }
177
- }
178
- default:
179
- throw new MCPError('VALIDATION_ERROR', `Unsupported action: ${action}`);
180
- }
181
- }
182
- }
@@ -1,45 +0,0 @@
1
- import { Tool, MCPContext } from '../types.js';
2
- export declare class GitTagsTool implements Tool {
3
- name: string;
4
- description: string;
5
- inputSchema: {
6
- type: "object";
7
- properties: {
8
- projectPath: {
9
- type: string;
10
- description: string;
11
- };
12
- action: {
13
- type: string;
14
- enum: string[];
15
- description: string;
16
- };
17
- tagName: {
18
- type: string;
19
- description: string;
20
- };
21
- ref: {
22
- type: string;
23
- description: string;
24
- };
25
- message: {
26
- type: string;
27
- description: string;
28
- };
29
- annotated: {
30
- type: string;
31
- description: string;
32
- };
33
- force: {
34
- type: string;
35
- description: string;
36
- };
37
- remote: {
38
- type: string;
39
- description: string;
40
- };
41
- };
42
- required: string[];
43
- };
44
- handle(params: Record<string, any>, ctx: MCPContext): Promise<any>;
45
- }
@@ -1,251 +0,0 @@
1
- import { MCPError } from '../utils/errors.js';
2
- import axios from 'axios';
3
- import { getRepoInfo } from '../utils/repoHelpers.js';
4
- export class GitTagsTool {
5
- constructor() {
6
- this.name = 'git-tags';
7
- this.description = 'Tag management operations - automatic dual-provider execution for remote queries';
8
- this.inputSchema = {
9
- type: "object",
10
- properties: {
11
- projectPath: {
12
- type: "string",
13
- description: "The absolute path to the Git repository directory on the local filesystem. This should be the root directory containing the .git folder. For example: '/home/user/my-project' on Linux/Mac or 'C:\\Users\\user\\my-project' on Windows."
14
- },
15
- action: {
16
- type: "string",
17
- enum: ["create", "list", "get", "delete", "push"],
18
- description: "Tag operation to perform: create (create tag), list (list tags), get (get tag details), delete (delete tag), push (push tag to remote)"
19
- },
20
- tagName: {
21
- type: "string",
22
- description: "Tag name (required for create/get/delete/push)"
23
- },
24
- ref: {
25
- type: "string",
26
- description: "Git reference to tag (optional for create, default: HEAD)"
27
- },
28
- message: {
29
- type: "string",
30
- description: "Tag annotation message (optional for create)"
31
- },
32
- annotated: {
33
- type: "boolean",
34
- description: "Create annotated tag (optional for create, default: false)"
35
- },
36
- force: {
37
- type: "boolean",
38
- description: "Force create/delete/push tag (default: true)"
39
- },
40
- remote: {
41
- type: "string",
42
- description: "Remote name (optional for push, default: origin)"
43
- }
44
- },
45
- required: ["projectPath", "action"]
46
- };
47
- }
48
- async handle(params, ctx) {
49
- const action = params.action;
50
- const projectPath = params.projectPath;
51
- if (!action || !projectPath) {
52
- throw new MCPError('VALIDATION_ERROR', 'action and projectPath are required');
53
- }
54
- if (!ctx.gitAdapter) {
55
- throw new MCPError('INTERNAL_ERROR', 'Git adapter not available');
56
- }
57
- switch (action) {
58
- case 'create': {
59
- const tagName = params.tagName;
60
- if (!tagName)
61
- throw new MCPError('VALIDATION_ERROR', 'tagName is required');
62
- const ref = params.ref || 'HEAD';
63
- const message = params.annotated ? (params.message || tagName) : undefined;
64
- await ctx.gitAdapter.createTag(projectPath, tagName, ref, message);
65
- return { success: true, tag: tagName, local: true };
66
- }
67
- case 'list': {
68
- const localTags = await ctx.gitAdapter.listTags(projectPath);
69
- const results = {
70
- success: true,
71
- local: { tags: localTags },
72
- providers: {}
73
- };
74
- // Also query remote APIs
75
- const repoInfo = getRepoInfo(projectPath);
76
- const repo = params.repo || repoInfo.repoName;
77
- const githubOwner = params.owner || process.env.GITHUB_USERNAME;
78
- const giteaOwner = params.owner || process.env.GITEA_USERNAME;
79
- // GitHub
80
- if (ctx.providerManager.github && githubOwner) {
81
- try {
82
- const tags = await ctx.providerManager.github.rest.repos.listTags({
83
- owner: githubOwner,
84
- repo: repo,
85
- });
86
- results.providers.github = {
87
- success: true,
88
- tags: tags.data.map((t) => ({
89
- name: t.name,
90
- sha: t.commit.sha,
91
- zipball_url: t.zipball_url,
92
- tarball_url: t.tarball_url,
93
- })),
94
- };
95
- }
96
- catch (err) {
97
- results.providers.github = { success: false, error: err.message };
98
- }
99
- }
100
- // Gitea
101
- if (ctx.providerManager.giteaBaseUrl && giteaOwner) {
102
- try {
103
- const tags = await axios.get(`${ctx.providerManager.giteaBaseUrl}/api/v1/repos/${giteaOwner}/${repo}/tags`, { headers: { Authorization: `token ${ctx.providerManager.giteaToken}` } });
104
- results.providers.gitea = {
105
- success: true,
106
- tags: tags.data.map((t) => ({
107
- name: t.name,
108
- sha: t.commit?.id || t.id,
109
- zipball_url: t.zipball_url,
110
- tarball_url: t.tarball_url,
111
- })),
112
- };
113
- }
114
- catch (err) {
115
- results.providers.gitea = { success: false, error: err.message };
116
- }
117
- }
118
- return results;
119
- }
120
- case 'get': {
121
- const tagName = params.tagName;
122
- if (!tagName)
123
- throw new MCPError('VALIDATION_ERROR', 'tagName is required');
124
- const localTags = await ctx.gitAdapter.listTags(projectPath);
125
- const localTag = localTags.find(t => t === tagName);
126
- const results = {
127
- success: true,
128
- local: localTag ? { found: true, tag: tagName } : { found: false },
129
- providers: {}
130
- };
131
- // Also query remote APIs
132
- const repoInfo = getRepoInfo(projectPath);
133
- const repo = params.repo || repoInfo.repoName;
134
- const githubOwner = params.owner || process.env.GITHUB_USERNAME;
135
- const giteaOwner = params.owner || process.env.GITEA_USERNAME;
136
- // GitHub
137
- if (ctx.providerManager.github && githubOwner) {
138
- try {
139
- const tag = await ctx.providerManager.github.rest.git.getRef({
140
- owner: githubOwner,
141
- repo: repo,
142
- ref: `tags/${tagName}`,
143
- });
144
- results.providers.github = {
145
- success: true,
146
- tag: {
147
- name: tagName,
148
- sha: tag.data.object.sha,
149
- type: tag.data.object.type,
150
- url: tag.data.url,
151
- },
152
- };
153
- }
154
- catch (err) {
155
- results.providers.github = { success: false, error: err.message };
156
- }
157
- }
158
- // Gitea
159
- if (ctx.providerManager.giteaBaseUrl && giteaOwner) {
160
- try {
161
- const tags = await axios.get(`${ctx.providerManager.giteaBaseUrl}/api/v1/repos/${giteaOwner}/${repo}/tags`, { headers: { Authorization: `token ${ctx.providerManager.giteaToken}` } });
162
- const tag = tags.data.find((t) => t.name === tagName);
163
- if (tag) {
164
- results.providers.gitea = {
165
- success: true,
166
- tag: {
167
- name: tag.name,
168
- sha: tag.commit?.id || tag.id,
169
- message: tag.message,
170
- },
171
- };
172
- }
173
- else {
174
- results.providers.gitea = { success: false, error: 'Tag not found' };
175
- }
176
- }
177
- catch (err) {
178
- results.providers.gitea = { success: false, error: err.message };
179
- }
180
- }
181
- return results;
182
- }
183
- case 'delete': {
184
- const tagName = params.tagName;
185
- if (!tagName)
186
- throw new MCPError('VALIDATION_ERROR', 'tagName is required');
187
- await ctx.gitAdapter.deleteTag(projectPath, tagName);
188
- return { success: true, deleted: tagName, local: true };
189
- }
190
- case 'push': {
191
- const tagName = params.tagName;
192
- if (!tagName)
193
- throw new MCPError('VALIDATION_ERROR', 'tagName is required');
194
- const remote = params.remote || 'origin';
195
- await ctx.gitAdapter.pushTag(projectPath, remote, tagName);
196
- return { success: true, pushed: tagName, remote };
197
- }
198
- case 'search': {
199
- const pattern = params.pattern;
200
- if (!pattern)
201
- throw new MCPError('VALIDATION_ERROR', 'pattern is required');
202
- const localTags = await ctx.gitAdapter.listTags(projectPath);
203
- const filtered = localTags.filter(t => t.includes(pattern));
204
- const results = {
205
- success: true,
206
- local: { tags: filtered },
207
- providers: {}
208
- };
209
- // Also search remote APIs
210
- const repoInfo = getRepoInfo(projectPath);
211
- const repo = params.repo || repoInfo.repoName;
212
- const githubOwner = params.owner || process.env.GITHUB_USERNAME;
213
- const giteaOwner = params.owner || process.env.GITEA_USERNAME;
214
- // GitHub
215
- if (ctx.providerManager.github && githubOwner) {
216
- try {
217
- const tags = await ctx.providerManager.github.rest.repos.listTags({
218
- owner: githubOwner,
219
- repo: repo,
220
- });
221
- const matchedTags = tags.data.filter((t) => t.name.includes(pattern));
222
- results.providers.github = {
223
- success: true,
224
- tags: matchedTags.map((t) => t.name),
225
- };
226
- }
227
- catch (err) {
228
- results.providers.github = { success: false, error: err.message };
229
- }
230
- }
231
- // Gitea
232
- if (ctx.providerManager.giteaBaseUrl && giteaOwner) {
233
- try {
234
- const tags = await axios.get(`${ctx.providerManager.giteaBaseUrl}/api/v1/repos/${giteaOwner}/${repo}/tags`, { headers: { Authorization: `token ${ctx.providerManager.giteaToken}` } });
235
- const matchedTags = tags.data.filter((t) => t.name.includes(pattern));
236
- results.providers.gitea = {
237
- success: true,
238
- tags: matchedTags.map((t) => t.name),
239
- };
240
- }
241
- catch (err) {
242
- results.providers.gitea = { success: false, error: err.message };
243
- }
244
- }
245
- return results;
246
- }
247
- default:
248
- throw new MCPError('VALIDATION_ERROR', `Unsupported action: ${action}`);
249
- }
250
- }
251
- }