Merge pull request #29 from gerbal/feat/read-only-mode

feat: Add read-only mode support
This commit is contained in:
bbang-dduck
2025-04-02 11:22:04 +09:00
committed by GitHub
3 changed files with 213 additions and 185 deletions

View File

@ -10,7 +10,7 @@ GitLab MCP(Model Context Protocol) Server. **Includes bug fixes and improvements
## Usage
### Using with Claude App, Cline, Roo Code
### Using with Claude App, Cline, Roo Code, Cursor
When using with the Claude App, you need to set up your API key and URLs directly.
@ -22,23 +22,20 @@ When using with the Claude App, you need to set up your API key and URLs directl
"args": ["-y", "@zereight/mcp-gitlab"],
"env": {
"GITLAB_PERSONAL_ACCESS_TOKEN": "your_gitlab_token",
"GITLAB_API_URL": "your_gitlab_api_url"
"GITLAB_API_URL": "your_gitlab_api_url",
"GITLAB_READ_ONLY_MODE": "true"
}
}
}
}
```
### Using with Cursor
### Environment Variables
When using with Cursor, you can set up environment variables and run the server as follows:
```
env GITLAB_PERSONAL_ACCESS_TOKEN=your_gitlab_token GITLAB_API_URL=your_gitlab_api_url npx @zereight/mcp-gitlab
```
- `GITLAB_PERSONAL_ACCESS_TOKEN`: Your GitLab personal access token.
- `GITLAB_API_URL`: Your GitLab API URL. (Default: `https://gitlab.com/api/v4`)
- `GITLAB_READ_ONLY_MODE`: When set to 'true', restricts the server to only expose read-only operations. Useful for enhanced security or when write access is not needed. Also useful for using with Cursor and it's 40 tool limit.
## Tools 🛠️
@ -272,6 +269,7 @@ Before running the server, you need to set the following environment variables:
```
GITLAB_PERSONAL_ACCESS_TOKEN=your_gitlab_token
GITLAB_API_URL=your_gitlab_api_url # Default: https://gitlab.com/api/v4
GITLAB_READ_ONLY_MODE=true # Optional: Enable read-only mode
```
## License

380
index.ts
View File

@ -124,6 +124,205 @@ const server = new Server(
);
const GITLAB_PERSONAL_ACCESS_TOKEN = process.env.GITLAB_PERSONAL_ACCESS_TOKEN;
const GITLAB_READ_ONLY_MODE = process.env.GITLAB_READ_ONLY_MODE === 'true';
// Define all available tools
const allTools = [
{
name: "create_or_update_file",
description: "Create or update a single file in a GitLab project",
inputSchema: zodToJsonSchema(CreateOrUpdateFileSchema),
},
{
name: "search_repositories",
description: "Search for GitLab projects",
inputSchema: zodToJsonSchema(SearchRepositoriesSchema),
},
{
name: "create_repository",
description: "Create a new GitLab project",
inputSchema: zodToJsonSchema(CreateRepositorySchema),
},
{
name: "get_file_contents",
description:
"Get the contents of a file or directory from a GitLab project",
inputSchema: zodToJsonSchema(GetFileContentsSchema),
},
{
name: "push_files",
description:
"Push multiple files to a GitLab project in a single commit",
inputSchema: zodToJsonSchema(PushFilesSchema),
},
{
name: "create_issue",
description: "Create a new issue in a GitLab project",
inputSchema: zodToJsonSchema(CreateIssueSchema),
},
{
name: "create_merge_request",
description: "Create a new merge request in a GitLab project",
inputSchema: zodToJsonSchema(CreateMergeRequestSchema),
},
{
name: "fork_repository",
description:
"Fork a GitLab project to your account or specified namespace",
inputSchema: zodToJsonSchema(ForkRepositorySchema),
},
{
name: "create_branch",
description: "Create a new branch in a GitLab project",
inputSchema: zodToJsonSchema(CreateBranchSchema),
},
{
name: "get_merge_request",
description: "Get details of a merge request",
inputSchema: zodToJsonSchema(GetMergeRequestSchema),
},
{
name: "get_merge_request_diffs",
description: "Get the changes/diffs of a merge request",
inputSchema: zodToJsonSchema(GetMergeRequestDiffsSchema),
},
{
name: "update_merge_request",
description: "Update a merge request",
inputSchema: zodToJsonSchema(UpdateMergeRequestSchema),
},
{
name: "create_note",
description: "Create a new note (comment) to an issue or merge request",
inputSchema: zodToJsonSchema(CreateNoteSchema),
},
{
name: "list_merge_request_discussions",
description: "List discussion items for a merge request",
inputSchema: zodToJsonSchema(ListMergeRequestDiscussionsSchema),
},
{
name: "update_merge_request_note",
description: "Modify an existing merge request thread note",
inputSchema: zodToJsonSchema(UpdateMergeRequestNoteSchema),
},
{
name: "list_issues",
description: "List issues in a GitLab project with filtering options",
inputSchema: zodToJsonSchema(ListIssuesSchema),
},
{
name: "get_issue",
description: "Get details of a specific issue in a GitLab project",
inputSchema: zodToJsonSchema(GetIssueSchema),
},
{
name: "update_issue",
description: "Update an issue in a GitLab project",
inputSchema: zodToJsonSchema(UpdateIssueSchema),
},
{
name: "delete_issue",
description: "Delete an issue from a GitLab project",
inputSchema: zodToJsonSchema(DeleteIssueSchema),
},
{
name: "list_issue_links",
description: "List all issue links for a specific issue",
inputSchema: zodToJsonSchema(ListIssueLinksSchema),
},
{
name: "get_issue_link",
description: "Get a specific issue link",
inputSchema: zodToJsonSchema(GetIssueLinkSchema),
},
{
name: "create_issue_link",
description: "Create an issue link between two issues",
inputSchema: zodToJsonSchema(CreateIssueLinkSchema),
},
{
name: "delete_issue_link",
description: "Delete an issue link",
inputSchema: zodToJsonSchema(DeleteIssueLinkSchema),
},
{
name: "list_namespaces",
description: "List all namespaces available to the current user",
inputSchema: zodToJsonSchema(ListNamespacesSchema),
},
{
name: "get_namespace",
description: "Get details of a namespace by ID or path",
inputSchema: zodToJsonSchema(GetNamespaceSchema),
},
{
name: "verify_namespace",
description: "Verify if a namespace path exists",
inputSchema: zodToJsonSchema(VerifyNamespaceSchema),
},
{
name: "get_project",
description: "Get details of a specific project",
inputSchema: zodToJsonSchema(GetProjectSchema),
},
{
name: "list_projects",
description: "List projects accessible by the current user",
inputSchema: zodToJsonSchema(ListProjectsSchema),
},
{
name: "list_labels",
description: "List labels for a project",
inputSchema: zodToJsonSchema(ListLabelsSchema),
},
{
name: "get_label",
description: "Get a single label from a project",
inputSchema: zodToJsonSchema(GetLabelSchema),
},
{
name: "create_label",
description: "Create a new label in a project",
inputSchema: zodToJsonSchema(CreateLabelSchema),
},
{
name: "update_label",
description: "Update an existing label in a project",
inputSchema: zodToJsonSchema(UpdateLabelSchema),
},
{
name: "delete_label",
description: "Delete a label from a project",
inputSchema: zodToJsonSchema(DeleteLabelSchema),
},
{
name: "list_group_projects",
description: "List projects in a GitLab group with filtering options",
inputSchema: zodToJsonSchema(ListGroupProjectsSchema),
},
];
// Define which tools are read-only
const readOnlyTools = [
"search_repositories",
"get_file_contents",
"get_merge_request",
"get_merge_request_diffs",
"list_merge_request_discussions",
"list_issues",
"get_issue",
"list_issue_links",
"get_issue_link",
"list_namespaces",
"get_namespace",
"verify_namespace",
"get_project",
"list_projects",
"list_labels",
"get_label",
"list_group_projects"
];
/**
* Smart URL handling for GitLab API
@ -1508,182 +1707,13 @@ async function listGroupProjects(
}
server.setRequestHandler(ListToolsRequestSchema, async () => {
// If read-only mode is enabled, filter out write operations
const tools = GITLAB_READ_ONLY_MODE
? allTools.filter(tool => readOnlyTools.includes(tool.name))
: allTools;
return {
tools: [
{
name: "create_or_update_file",
description: "Create or update a single file in a GitLab project",
inputSchema: zodToJsonSchema(CreateOrUpdateFileSchema),
},
{
name: "search_repositories",
description: "Search for GitLab projects",
inputSchema: zodToJsonSchema(SearchRepositoriesSchema),
},
{
name: "create_repository",
description: "Create a new GitLab project",
inputSchema: zodToJsonSchema(CreateRepositorySchema),
},
{
name: "get_file_contents",
description:
"Get the contents of a file or directory from a GitLab project",
inputSchema: zodToJsonSchema(GetFileContentsSchema),
},
{
name: "push_files",
description:
"Push multiple files to a GitLab project in a single commit",
inputSchema: zodToJsonSchema(PushFilesSchema),
},
{
name: "create_issue",
description: "Create a new issue in a GitLab project",
inputSchema: zodToJsonSchema(CreateIssueSchema),
},
{
name: "create_merge_request",
description: "Create a new merge request in a GitLab project",
inputSchema: zodToJsonSchema(CreateMergeRequestSchema),
},
{
name: "fork_repository",
description:
"Fork a GitLab project to your account or specified namespace",
inputSchema: zodToJsonSchema(ForkRepositorySchema),
},
{
name: "create_branch",
description: "Create a new branch in a GitLab project",
inputSchema: zodToJsonSchema(CreateBranchSchema),
},
{
name: "get_merge_request",
description: "Get details of a merge request",
inputSchema: zodToJsonSchema(GetMergeRequestSchema),
},
{
name: "get_merge_request_diffs",
description: "Get the changes/diffs of a merge request",
inputSchema: zodToJsonSchema(GetMergeRequestDiffsSchema),
},
{
name: "update_merge_request",
description: "Update a merge request",
inputSchema: zodToJsonSchema(UpdateMergeRequestSchema),
},
{
name: "create_note",
description: "Create a new note (comment) to an issue or merge request",
inputSchema: zodToJsonSchema(CreateNoteSchema),
},
{
name: "list_merge_request_discussions",
description: "List discussion items for a merge request",
inputSchema: zodToJsonSchema(ListMergeRequestDiscussionsSchema),
},
{
name: "update_merge_request_note",
description: "Modify an existing merge request thread note",
inputSchema: zodToJsonSchema(UpdateMergeRequestNoteSchema),
},
{
name: "list_issues",
description: "List issues in a GitLab project with filtering options",
inputSchema: zodToJsonSchema(ListIssuesSchema),
},
{
name: "get_issue",
description: "Get details of a specific issue in a GitLab project",
inputSchema: zodToJsonSchema(GetIssueSchema),
},
{
name: "update_issue",
description: "Update an issue in a GitLab project",
inputSchema: zodToJsonSchema(UpdateIssueSchema),
},
{
name: "delete_issue",
description: "Delete an issue from a GitLab project",
inputSchema: zodToJsonSchema(DeleteIssueSchema),
},
{
name: "list_issue_links",
description: "List all issue links for a specific issue",
inputSchema: zodToJsonSchema(ListIssueLinksSchema),
},
{
name: "get_issue_link",
description: "Get a specific issue link",
inputSchema: zodToJsonSchema(GetIssueLinkSchema),
},
{
name: "create_issue_link",
description: "Create an issue link between two issues",
inputSchema: zodToJsonSchema(CreateIssueLinkSchema),
},
{
name: "delete_issue_link",
description: "Delete an issue link",
inputSchema: zodToJsonSchema(DeleteIssueLinkSchema),
},
{
name: "list_namespaces",
description: "List all namespaces available to the current user",
inputSchema: zodToJsonSchema(ListNamespacesSchema),
},
{
name: "get_namespace",
description: "Get details of a namespace by ID or path",
inputSchema: zodToJsonSchema(GetNamespaceSchema),
},
{
name: "verify_namespace",
description: "Verify if a namespace path exists",
inputSchema: zodToJsonSchema(VerifyNamespaceSchema),
},
{
name: "get_project",
description: "Get details of a specific project",
inputSchema: zodToJsonSchema(GetProjectSchema),
},
{
name: "list_projects",
description: "List projects accessible by the current user",
inputSchema: zodToJsonSchema(ListProjectsSchema),
},
{
name: "list_labels",
description: "List labels for a project",
inputSchema: zodToJsonSchema(ListLabelsSchema),
},
{
name: "get_label",
description: "Get a single label from a project",
inputSchema: zodToJsonSchema(GetLabelSchema),
},
{
name: "create_label",
description: "Create a new label in a project",
inputSchema: zodToJsonSchema(CreateLabelSchema),
},
{
name: "update_label",
description: "Update an existing label in a project",
inputSchema: zodToJsonSchema(UpdateLabelSchema),
},
{
name: "delete_label",
description: "Delete a label from a project",
inputSchema: zodToJsonSchema(DeleteLabelSchema),
},
{
name: "list_group_projects",
description: "List projects in a GitLab group with filtering options",
inputSchema: zodToJsonSchema(ListGroupProjectsSchema),
},
],
tools,
};
});

4
package-lock.json generated
View File

@ -1,12 +1,12 @@
{
"name": "@zereight/mcp-gitlab",
"version": "1.0.21",
"version": "1.0.24",
"lockfileVersion": 3,
"requires": true,
"packages": {
"": {
"name": "@zereight/mcp-gitlab",
"version": "1.0.21",
"version": "1.0.24",
"license": "MIT",
"dependencies": {
"@modelcontextprotocol/sdk": "1.8.0",