@cyanheads/git-mcp-server 2.0.7 → 2.0.8

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
@@ -2,7 +2,7 @@
2
2
 
3
3
  [![TypeScript](https://img.shields.io/badge/TypeScript-^5.8.3-blue.svg)](https://www.typescriptlang.org/)
4
4
  [![Model Context Protocol](https://img.shields.io/badge/MCP%20SDK-^1.11.0-green.svg)](https://modelcontextprotocol.io/)
5
- [![Version](https://img.shields.io/badge/Version-2.0.7-blue.svg)](./CHANGELOG.md)
5
+ [![Version](https://img.shields.io/badge/Version-2.0.8-blue.svg)](./CHANGELOG.md)
6
6
  [![License](https://img.shields.io/badge/License-Apache%202.0-blue.svg)](https://opensource.org/licenses/Apache-2.0)
7
7
  [![Status](https://img.shields.io/badge/Status-Stable-green.svg)](https://github.com/cyanheads/git-mcp-server/issues)
8
8
  [![GitHub](https://img.shields.io/github/stars/cyanheads/git-mcp-server?style=social)](https://github.com/cyanheads/git-mcp-server)
@@ -44,7 +44,7 @@ export async function addGitFiles(input, context // Add getter to context
44
44
  logger.debug(`Using session working directory: ${targetPath}`, { ...context, operation, sessionId: context.sessionId });
45
45
  }
46
46
  // Sanitize the resolved path
47
- const sanitizedPath = sanitization.sanitizePath(targetPath);
47
+ const sanitizedPath = sanitization.sanitizePath(targetPath, { allowAbsolute: true });
48
48
  logger.debug('Sanitized repository path', { ...context, operation, sanitizedPath });
49
49
  targetPath = sanitizedPath; // Use the sanitized path going forward
50
50
  }
@@ -56,7 +56,7 @@ export async function gitBranchLogic(input, context) {
56
56
  else {
57
57
  logger.debug(`Using provided path: ${targetPath}`, { ...context, operation });
58
58
  }
59
- targetPath = sanitization.sanitizePath(targetPath);
59
+ targetPath = sanitization.sanitizePath(targetPath, { allowAbsolute: true });
60
60
  logger.debug('Sanitized path', { ...context, operation, sanitizedPath: targetPath });
61
61
  }
62
62
  catch (error) {
@@ -41,7 +41,7 @@ export async function checkoutGit(input, context) {
41
41
  }
42
42
  targetPath = workingDir;
43
43
  }
44
- targetPath = sanitization.sanitizePath(targetPath);
44
+ targetPath = sanitization.sanitizePath(targetPath, { allowAbsolute: true });
45
45
  logger.debug('Sanitized path', { ...context, operation, sanitizedPath: targetPath });
46
46
  }
47
47
  catch (error) {
@@ -47,7 +47,7 @@ export async function gitCherryPickLogic(input, context) {
47
47
  else {
48
48
  logger.debug(`Using provided path: ${targetPath}`, { ...context, operation });
49
49
  }
50
- targetPath = sanitization.sanitizePath(targetPath);
50
+ targetPath = sanitization.sanitizePath(targetPath, { allowAbsolute: true });
51
51
  logger.debug('Sanitized path', { ...context, operation, sanitizedPath: targetPath });
52
52
  }
53
53
  catch (error) {
@@ -55,7 +55,7 @@ export async function gitCleanLogic(input, context) {
55
55
  else {
56
56
  logger.debug(`Using provided path: ${targetPath}`, { ...context, operation });
57
57
  }
58
- targetPath = sanitization.sanitizePath(targetPath);
58
+ targetPath = sanitization.sanitizePath(targetPath, { allowAbsolute: true });
59
59
  logger.debug('Sanitized path', { ...context, operation, sanitizedPath: targetPath });
60
60
  }
61
61
  catch (error) {
@@ -33,7 +33,7 @@ export async function gitCloneLogic(input, context) {
33
33
  let sanitizedRepoUrl;
34
34
  try {
35
35
  // Sanitize the target path (must be absolute)
36
- sanitizedTargetPath = sanitization.sanitizePath(input.targetPath);
36
+ sanitizedTargetPath = sanitization.sanitizePath(input.targetPath, { allowAbsolute: true });
37
37
  logger.debug('Sanitized target path', { ...context, operation, sanitizedTargetPath });
38
38
  // Basic sanitization/validation for URL (Zod already checks format)
39
39
  // Further sanitization might be needed depending on how it's used in the shell command
@@ -50,7 +50,7 @@ export async function commitGitChanges(input, context // Add getter to context
50
50
  logger.debug(`Using session working directory: ${targetPath}`, { ...context, operation, sessionId: context.sessionId });
51
51
  }
52
52
  // Sanitize the resolved path
53
- const sanitizedPath = sanitization.sanitizePath(targetPath);
53
+ const sanitizedPath = sanitization.sanitizePath(targetPath, { allowAbsolute: true });
54
54
  logger.debug('Sanitized path', { ...context, operation, sanitizedPath });
55
55
  targetPath = sanitizedPath; // Use the sanitized path going forward
56
56
  }
@@ -48,7 +48,7 @@ export async function diffGitChanges(input, context) {
48
48
  }
49
49
  targetPath = workingDir;
50
50
  }
51
- targetPath = sanitization.sanitizePath(targetPath);
51
+ targetPath = sanitization.sanitizePath(targetPath, { allowAbsolute: true });
52
52
  logger.debug('Sanitized path', { ...context, operation, sanitizedPath: targetPath });
53
53
  }
54
54
  catch (error) {
@@ -41,7 +41,7 @@ export async function fetchGitRemote(input, context) {
41
41
  }
42
42
  targetPath = workingDir;
43
43
  }
44
- targetPath = sanitization.sanitizePath(targetPath);
44
+ targetPath = sanitization.sanitizePath(targetPath, { allowAbsolute: true });
45
45
  logger.debug('Sanitized path', { ...context, operation, sanitizedPath: targetPath });
46
46
  }
47
47
  catch (error) {
@@ -31,7 +31,7 @@ export async function gitInitLogic(input, context) {
31
31
  let targetPath;
32
32
  try {
33
33
  // Sanitize the provided absolute path
34
- targetPath = sanitization.sanitizePath(input.path);
34
+ targetPath = sanitization.sanitizePath(input.path, { allowAbsolute: true });
35
35
  logger.debug('Sanitized path', { ...context, operation, sanitizedPath: targetPath });
36
36
  // Ensure the target directory exists before trying to init inside it
37
37
  // git init creates the directory if it doesn't exist, but we might want to ensure the parent exists
@@ -55,11 +55,11 @@ export const registerGitInitTool = async (server) => {
55
55
  let resolvedPath;
56
56
  try {
57
57
  if (path.isAbsolute(inputPath)) {
58
- resolvedPath = sanitization.sanitizePath(inputPath);
58
+ resolvedPath = sanitization.sanitizePath(inputPath, { allowAbsolute: true });
59
59
  logger.debug(`Using absolute path: ${resolvedPath}`, requestContext);
60
60
  }
61
61
  else if (sessionWorkingDirectory) {
62
- resolvedPath = sanitization.sanitizePath(path.resolve(sessionWorkingDirectory, inputPath));
62
+ resolvedPath = sanitization.sanitizePath(path.resolve(sessionWorkingDirectory, inputPath), { allowAbsolute: true });
63
63
  logger.debug(`Resolved relative path '${inputPath}' to absolute path: ${resolvedPath} using session CWD`, requestContext);
64
64
  }
65
65
  else {
@@ -56,7 +56,7 @@ export async function logGitHistory(input, context) {
56
56
  }
57
57
  targetPath = workingDir;
58
58
  }
59
- targetPath = sanitization.sanitizePath(targetPath);
59
+ targetPath = sanitization.sanitizePath(targetPath, { allowAbsolute: true });
60
60
  logger.debug('Sanitized path', { ...context, operation, sanitizedPath: targetPath });
61
61
  }
62
62
  catch (error) {
@@ -44,7 +44,7 @@ export async function pullGitChanges(input, context) {
44
44
  logger.debug(`Using session working directory: ${targetPath}`, { ...context, operation, sessionId: context.sessionId });
45
45
  }
46
46
  // Sanitize the resolved path
47
- targetPath = sanitization.sanitizePath(targetPath);
47
+ targetPath = sanitization.sanitizePath(targetPath, { allowAbsolute: true });
48
48
  logger.debug('Sanitized path', { ...context, operation, sanitizedPath: targetPath });
49
49
  }
50
50
  catch (error) {
@@ -45,7 +45,7 @@ export async function pushGitChanges(input, context) {
45
45
  }
46
46
  targetPath = workingDir;
47
47
  }
48
- targetPath = sanitization.sanitizePath(targetPath);
48
+ targetPath = sanitization.sanitizePath(targetPath, { allowAbsolute: true });
49
49
  logger.debug('Sanitized path', { ...context, operation, sanitizedPath: targetPath });
50
50
  }
51
51
  catch (error) {
@@ -55,7 +55,7 @@ export async function gitRebaseLogic(input, context) {
55
55
  else {
56
56
  logger.debug(`Using provided path: ${targetPath}`, { ...context, operation });
57
57
  }
58
- targetPath = sanitization.sanitizePath(targetPath);
58
+ targetPath = sanitization.sanitizePath(targetPath, { allowAbsolute: true });
59
59
  logger.debug('Sanitized path', { ...context, operation, sanitizedPath: targetPath });
60
60
  }
61
61
  catch (error) {
@@ -42,7 +42,7 @@ export async function gitRemoteLogic(input, context) {
42
42
  else {
43
43
  logger.debug(`Using provided path: ${targetPath}`, { ...context, operation });
44
44
  }
45
- targetPath = sanitization.sanitizePath(targetPath); // Sanitize the final resolved path
45
+ targetPath = sanitization.sanitizePath(targetPath, { allowAbsolute: true }); // Sanitize the final resolved path
46
46
  logger.debug('Sanitized path', { ...context, operation, sanitizedPath: targetPath });
47
47
  }
48
48
  catch (error) {
@@ -44,7 +44,7 @@ export async function resetGitState(input, context) {
44
44
  }
45
45
  targetPath = workingDir;
46
46
  }
47
- targetPath = sanitization.sanitizePath(targetPath);
47
+ targetPath = sanitization.sanitizePath(targetPath, { allowAbsolute: true });
48
48
  logger.debug('Sanitized path', { ...context, operation, sanitizedPath: targetPath });
49
49
  }
50
50
  catch (error) {
@@ -26,9 +26,9 @@ export async function gitSetWorkingDirLogic(input, context // Assuming context p
26
26
  logger.info('Executing git_set_working_dir logic', { ...context, operation, inputPath: input.path });
27
27
  let sanitizedPath;
28
28
  try {
29
- // Sanitize the path. By default, sanitizePath allows absolute paths.
29
+ // Sanitize the path. Must explicitly allow absolute paths for this tool.
30
30
  // It normalizes and checks for traversal issues.
31
- sanitizedPath = sanitization.sanitizePath(input.path);
31
+ sanitizedPath = sanitization.sanitizePath(input.path, { allowAbsolute: true });
32
32
  logger.debug(`Sanitized path: ${sanitizedPath}`, { ...context, operation });
33
33
  }
34
34
  catch (error) {
@@ -41,7 +41,7 @@ export async function gitShowLogic(input, context) {
41
41
  else {
42
42
  logger.debug(`Using provided path: ${targetPath}`, { ...context, operation });
43
43
  }
44
- targetPath = sanitization.sanitizePath(targetPath);
44
+ targetPath = sanitization.sanitizePath(targetPath, { allowAbsolute: true });
45
45
  logger.debug('Sanitized path', { ...context, operation, sanitizedPath: targetPath });
46
46
  }
47
47
  catch (error) {
@@ -47,7 +47,7 @@ export async function gitStashLogic(input, context) {
47
47
  else {
48
48
  logger.debug(`Using provided path: ${targetPath}`, { ...context, operation });
49
49
  }
50
- targetPath = sanitization.sanitizePath(targetPath);
50
+ targetPath = sanitization.sanitizePath(targetPath, { allowAbsolute: true });
51
51
  logger.debug('Sanitized path', { ...context, operation, sanitizedPath: targetPath });
52
52
  }
53
53
  catch (error) {
@@ -160,7 +160,7 @@ export async function getGitStatus(input, context // Add getter to context
160
160
  logger.debug(`Using session working directory: ${targetPath}`, { ...context, operation, sessionId: context.sessionId });
161
161
  }
162
162
  // Sanitize the resolved path
163
- const sanitizedPath = sanitization.sanitizePath(targetPath);
163
+ const sanitizedPath = sanitization.sanitizePath(targetPath, { allowAbsolute: true });
164
164
  logger.debug('Sanitized path', { ...context, operation, sanitizedPath });
165
165
  targetPath = sanitizedPath; // Use the sanitized path going forward
166
166
  }
@@ -55,7 +55,7 @@ export async function gitTagLogic(input, context) {
55
55
  else {
56
56
  logger.debug(`Using provided path: ${targetPath}`, { ...context, operation });
57
57
  }
58
- targetPath = sanitization.sanitizePath(targetPath);
58
+ targetPath = sanitization.sanitizePath(targetPath, { allowAbsolute: true });
59
59
  logger.debug('Sanitized path', { ...context, operation, sanitizedPath: targetPath });
60
60
  }
61
61
  catch (error) {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@cyanheads/git-mcp-server",
3
- "version": "2.0.7",
3
+ "version": "2.0.8",
4
4
  "description": "An MCP (Model Context Protocol) server providing tools to interact with Git repositories. Enables LLMs and AI agents to perform Git operations like clone, commit, push, pull, branch, diff, log, status, and more via the MCP standard.",
5
5
  "type": "module",
6
6
  "license": "Apache-2.0",
@@ -38,7 +38,7 @@
38
38
  "dependencies": {
39
39
  "@modelcontextprotocol/sdk": "^1.11.0",
40
40
  "@types/jsonwebtoken": "^9.0.9",
41
- "@types/node": "^22.15.9",
41
+ "@types/node": "^22.15.15",
42
42
  "@types/sanitize-html": "^2.16.0",
43
43
  "@types/validator": "^13.15.0",
44
44
  "chrono-node": "^2.8.0",