Compare commits
67 Commits
feature/fi
...
v1.0.45
Author | SHA1 | Date | |
---|---|---|---|
8ba33986f3 | |||
64a936446e | |||
8ab0ac7145 | |||
ea06c21f29 | |||
140620397b | |||
3d7aa8035d | |||
25be1947b9 | |||
864ee77ae6 | |||
dc6cc59434 | |||
5924fd3ed4 | |||
f4b265bf2e | |||
b326f4c3c3 | |||
1350a024b5 | |||
4c57c37888 | |||
e4a28a9a47 | |||
9f1e7b5bca | |||
f37e210ee8 | |||
6f789692be | |||
1bb70dccb9 | |||
676bbcd4dd | |||
0bb59a3217 | |||
b908f03801 | |||
5024a2a5af | |||
d2cced1b38 | |||
2fec95d469 | |||
3565d1b397 | |||
353e62a401 | |||
3f2b35535e | |||
026dd58887 | |||
bde83c0a91 | |||
08ab1357a0 | |||
651072dfd7 | |||
bf250b0d88 | |||
3a25e7c5e8 | |||
23a9bbc728 | |||
5398526f94 | |||
bccd5f29c3 | |||
8071fef6c4 | |||
f0eac83788 | |||
7b8cbc0806 | |||
20f62756c1 | |||
95d8118ea5 | |||
340a5ffdc8 | |||
152dc1c984 | |||
42419bae24 | |||
06e9f0225d | |||
2ca34a6b34 | |||
f562cd65ef | |||
7c2578fd4b | |||
ac4056370b | |||
dd8311717c | |||
11685d7a90 | |||
a7a8149008 | |||
6858e1cf4a | |||
c69f8416ac | |||
440a47404f | |||
1e143291c0 | |||
e3300f099b | |||
5e93e273f8 | |||
7be17b7afc | |||
61ee1244f4 | |||
2235953426 | |||
cd686966ef | |||
f6076d3702 | |||
74bb384a37 | |||
bb8d553567 | |||
3c2f52c9f8 |
1
.gitignore
vendored
1
.gitignore
vendored
@ -1,2 +1,3 @@
|
|||||||
node_modules
|
node_modules
|
||||||
.DS_Store
|
.DS_Store
|
||||||
|
build
|
35
CHANGELOG.md
Normal file
35
CHANGELOG.md
Normal file
@ -0,0 +1,35 @@
|
|||||||
|
## [1.0.45] - 2025-05-24
|
||||||
|
|
||||||
|
### Added
|
||||||
|
|
||||||
|
- 🔄 **Pipeline Management Tools**: Added GitLab pipeline status monitoring and management functionality
|
||||||
|
- `list_pipelines`: List project pipelines with various filtering options
|
||||||
|
- `get_pipeline`: Get detailed information about a specific pipeline
|
||||||
|
- `list_pipeline_jobs`: List all jobs in a specific pipeline
|
||||||
|
- `get_pipeline_job`: Get detailed information about a specific pipeline job
|
||||||
|
- `get_pipeline_job_output`: Get execution logs/output from pipeline jobs
|
||||||
|
- 📊 Pipeline status summary and analysis support
|
||||||
|
- Example: "How many of the last N pipelines are successful?"
|
||||||
|
- Example: "Can you make a summary of the output in the last pipeline?"
|
||||||
|
- See: [PR #52](https://github.com/zereight/gitlab-mcp/pull/52)
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## [1.0.42] - 2025-05-22
|
||||||
|
|
||||||
|
### Added
|
||||||
|
|
||||||
|
- Added support for creating and updating issue notes (comments) in GitLab.
|
||||||
|
- You can now add or edit comments on issues.
|
||||||
|
- See: [PR #47](https://github.com/zereight/gitlab-mcp/pull/47)
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## [1.0.38] - 2025-05-17
|
||||||
|
|
||||||
|
### Fixed
|
||||||
|
|
||||||
|
- Added `expanded` property to `start` and `end` in `GitLabDiscussionNoteSchema`
|
||||||
|
Now you can expand or collapse more information at the start and end of discussion notes.
|
||||||
|
Example: In code review, you can choose to show or hide specific parts of the discussion.
|
||||||
|
(See: [PR #40](https://github.com/zereight/gitlab-mcp/pull/40))
|
39
Dockerfile
39
Dockerfile
@ -1,37 +1,24 @@
|
|||||||
# Generated by https://smithery.ai. See: https://smithery.ai/docs/config#dockerfile
|
FROM node:22.15-alpine AS builder
|
||||||
# Use an official Node.js image as the base image
|
|
||||||
FROM node:16-alpine AS builder
|
COPY . /app
|
||||||
|
COPY tsconfig.json /tsconfig.json
|
||||||
|
|
||||||
# Set the working directory
|
|
||||||
WORKDIR /app
|
WORKDIR /app
|
||||||
|
|
||||||
# Copy package.json and package-lock.json files
|
RUN --mount=type=cache,target=/root/.npm npm install
|
||||||
COPY package.json package-lock.json ./
|
|
||||||
|
|
||||||
# Install dependencies
|
RUN --mount=type=cache,target=/root/.npm-production npm ci --ignore-scripts --omit-dev
|
||||||
RUN npm install --ignore-scripts
|
|
||||||
|
|
||||||
# Copy the rest of the application code
|
FROM node:22.12-alpine AS release
|
||||||
COPY . .
|
|
||||||
|
|
||||||
# Build the application
|
|
||||||
RUN npm run build
|
|
||||||
|
|
||||||
# Use a smaller image for the runtime
|
|
||||||
FROM node:16-alpine AS runner
|
|
||||||
|
|
||||||
# Set the working directory
|
|
||||||
WORKDIR /app
|
WORKDIR /app
|
||||||
|
|
||||||
# Copy the build output and package.json
|
COPY --from=builder /app/build /app/build
|
||||||
COPY --from=builder /app/build ./build
|
COPY --from=builder /app/package.json /app/package.json
|
||||||
COPY --from=builder /app/package.json ./
|
COPY --from=builder /app/package-lock.json /app/package-lock.json
|
||||||
|
|
||||||
# Set environment variables
|
ENV NODE_ENV=production
|
||||||
ENV GITLAB_API_URL=https://gitlab.com/api/v4
|
|
||||||
|
RUN npm ci --ignore-scripts --omit-dev
|
||||||
|
|
||||||
# Define the command to run the application
|
|
||||||
ENTRYPOINT ["node", "build/index.js"]
|
ENTRYPOINT ["node", "build/index.js"]
|
||||||
|
|
||||||
# This image requires the following environment variable at runtime:
|
|
||||||
# - GITLAB_PERSONAL_ACCESS_TOKEN: Your GitLab personal access token
|
|
||||||
|
21
LICENSE
Normal file
21
LICENSE
Normal file
@ -0,0 +1,21 @@
|
|||||||
|
MIT License
|
||||||
|
|
||||||
|
Copyright (c) 2025 Roo
|
||||||
|
|
||||||
|
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||||
|
of this software and associated documentation files (the "Software"), to deal
|
||||||
|
in the Software without restriction, including without limitation the rights
|
||||||
|
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||||
|
copies of the Software, and to permit persons to whom the Software is
|
||||||
|
furnished to do so, subject to the following conditions:
|
||||||
|
|
||||||
|
The above copyright notice and this permission notice shall be included in all
|
||||||
|
copies or substantial portions of the Software.
|
||||||
|
|
||||||
|
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||||
|
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||||
|
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||||
|
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||||
|
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||||
|
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||||
|
SOFTWARE.
|
333
README.md
333
README.md
@ -10,10 +10,12 @@ GitLab MCP(Model Context Protocol) Server. **Includes bug fixes and improvements
|
|||||||
|
|
||||||
## Usage
|
## 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.
|
When using with the Claude App, you need to set up your API key and URLs directly.
|
||||||
|
|
||||||
|
#### npx
|
||||||
|
|
||||||
```json
|
```json
|
||||||
{
|
{
|
||||||
"mcpServers": {
|
"mcpServers": {
|
||||||
@ -22,258 +24,105 @@ When using with the Claude App, you need to set up your API key and URLs directl
|
|||||||
"args": ["-y", "@zereight/mcp-gitlab"],
|
"args": ["-y", "@zereight/mcp-gitlab"],
|
||||||
"env": {
|
"env": {
|
||||||
"GITLAB_PERSONAL_ACCESS_TOKEN": "your_gitlab_token",
|
"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": "false",
|
||||||
|
"USE_GITLAB_WIKI": "true"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
### Using with Cursor
|
#### Docker
|
||||||
|
|
||||||
When using with Cursor, you can set up environment variables and run the server as follows:
|
```json
|
||||||
|
{
|
||||||
|
"mcpServers": {
|
||||||
|
"GitLab communication server": {
|
||||||
|
"command": "docker",
|
||||||
|
"args": [
|
||||||
|
"run",
|
||||||
|
"-i",
|
||||||
|
"--rm",
|
||||||
|
"-e",
|
||||||
|
"GITLAB_PERSONAL_ACCESS_TOKEN",
|
||||||
|
"-e",
|
||||||
|
"GITLAB_API_URL",
|
||||||
|
"-e",
|
||||||
|
"GITLAB_READ_ONLY_MODE",
|
||||||
|
"-e",
|
||||||
|
"USE_GITLAB_WIKI",
|
||||||
|
"nkwd/gitlab-mcp"
|
||||||
|
],
|
||||||
|
"env": {
|
||||||
|
"GITLAB_PERSONAL_ACCESS_TOKEN": "your_gitlab_token",
|
||||||
|
"GITLAB_API_URL": "https://gitlab.com/api/v4", // Optional, for self-hosted GitLab
|
||||||
|
"GITLAB_READ_ONLY_MODE": "false",
|
||||||
|
"USE_GITLAB_WIKI": "true"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
```
|
### Environment Variables
|
||||||
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_PERSONAL_ACCESS_TOKEN`: Your GitLab personal access token.
|
||||||
- `GITLAB_API_URL`: Your GitLab API URL. (Default: `https://gitlab.com/api/v4`)
|
- `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.
|
||||||
|
- `USE_GITLAB_WIKI`: When set to 'true', enables the wiki-related tools (list_wiki_pages, get_wiki_page, create_wiki_page, update_wiki_page, delete_wiki_page). By default, wiki features are disabled.
|
||||||
|
|
||||||
## Tools 🛠️
|
## Tools 🛠️
|
||||||
|
|
||||||
1. `create_or_update_file`
|
+<!-- TOOLS-START -->
|
||||||
|
1. `create_or_update_file` - Create or update a single file in a GitLab project
|
||||||
- Create or update a single file in a GitLab project. 📝
|
2. `search_repositories` - Search for GitLab projects
|
||||||
- Inputs:
|
3. `create_repository` - Create a new GitLab project
|
||||||
- `project_id` (string): Project ID or namespace/project_path
|
4. `get_file_contents` - Get the contents of a file or directory from a GitLab project
|
||||||
- `file_path` (string): Path to create/update the file
|
5. `push_files` - Push multiple files to a GitLab project in a single commit
|
||||||
- `content` (string): File content
|
6. `create_issue` - Create a new issue in a GitLab project
|
||||||
- `commit_message` (string): Commit message
|
7. `create_merge_request` - Create a new merge request in a GitLab project
|
||||||
- `branch` (string): Branch to create/update the file in
|
8. `fork_repository` - Fork a GitLab project to your account or specified namespace
|
||||||
- `previous_path` (optional string): Previous file path when renaming a file
|
9. `create_branch` - Create a new branch in a GitLab project
|
||||||
- Returns: File content and commit details
|
10. `get_merge_request` - Get details of a merge request (Either mergeRequestIid or branchName must be provided)
|
||||||
|
11. `get_merge_request_diffs` - Get the changes/diffs of a merge request (Either mergeRequestIid or branchName must be provided)
|
||||||
2. `push_files`
|
12. `update_merge_request` - Update a merge request (Either mergeRequestIid or branchName must be provided)
|
||||||
|
13. `create_note` - Create a new note (comment) to an issue or merge request
|
||||||
- Push multiple files in a single commit. 📤
|
14. `create_merge_request_thread` - Create a new thread on a merge request
|
||||||
- Inputs:
|
15. `mr_discussions` - List discussion items for a merge request
|
||||||
- `project_id` (string): Project ID or namespace/project_path
|
16. `update_merge_request_note` - Modify an existing merge request thread note
|
||||||
- `branch` (string): Branch to push to
|
17. `create_merge_request_note` - Add a new note to an existing merge request thread
|
||||||
- `files` (array): Array of files to push, each with `file_path` and `content` properties
|
18. `update_issue_note` - Modify an existing issue thread note
|
||||||
- `commit_message` (string): Commit message
|
19. `create_issue_note` - Add a new note to an existing issue thread
|
||||||
- Returns: Updated branch reference
|
20. `list_issues` - List issues in a GitLab project with filtering options
|
||||||
|
21. `get_issue` - Get details of a specific issue in a GitLab project
|
||||||
3. `search_repositories`
|
22. `update_issue` - Update an issue in a GitLab project
|
||||||
|
23. `delete_issue` - Delete an issue from a GitLab project
|
||||||
- Search for GitLab projects. 🔍
|
24. `list_issue_links` - List all issue links for a specific issue
|
||||||
- Inputs:
|
25. `list_issue_discussions` - List discussions for an issue in a GitLab project
|
||||||
- `search` (string): Search query
|
26. `get_issue_link` - Get a specific issue link
|
||||||
- `page` (optional number): Page number (default: 1)
|
27. `create_issue_link` - Create an issue link between two issues
|
||||||
- `per_page` (optional number): Results per page (default: 20, max: 100)
|
28. `delete_issue_link` - Delete an issue link
|
||||||
- Returns: Project search results
|
29. `list_namespaces` - List all namespaces available to the current user
|
||||||
|
30. `get_namespace` - Get details of a namespace by ID or path
|
||||||
4. `create_repository`
|
31. `verify_namespace` - Verify if a namespace path exists
|
||||||
|
32. `get_project` - Get details of a specific project
|
||||||
- Create a new GitLab project. ➕
|
33. `list_projects` - List projects accessible by the current user
|
||||||
- Inputs:
|
34. `list_labels` - List labels for a project
|
||||||
- `name` (string): Project name
|
35. `get_label` - Get a single label from a project
|
||||||
- `description` (optional string): Project description
|
36. `create_label` - Create a new label in a project
|
||||||
- `visibility` (optional string): Project visibility level (public, private, internal)
|
37. `update_label` - Update an existing label in a project
|
||||||
- `initialize_with_readme` (optional boolean): Initialize with README
|
38. `delete_label` - Delete a label from a project
|
||||||
- Returns: Details of the created project
|
39. `list_group_projects` - List projects in a GitLab group with filtering options
|
||||||
|
40. `list_wiki_pages` - List wiki pages in a GitLab project
|
||||||
5. `get_file_contents`
|
41. `get_wiki_page` - Get details of a specific wiki page
|
||||||
|
42. `create_wiki_page` - Create a new wiki page in a GitLab project
|
||||||
- Get the contents of a file or directory. 📂
|
43. `update_wiki_page` - Update an existing wiki page in a GitLab project
|
||||||
- Inputs:
|
44. `delete_wiki_page` - Delete a wiki page from a GitLab project
|
||||||
- `project_id` (string): Project ID or namespace/project_path
|
45. `get_repository_tree` - Get the repository tree for a GitLab project (list files and directories)
|
||||||
- `file_path` (string): Path to the file/directory
|
46. `list_pipelines` - List pipelines in a GitLab project with filtering options
|
||||||
- `ref` (optional string): Branch, tag, or commit SHA (default: default branch)
|
47. `get_pipeline` - Get details of a specific pipeline in a GitLab project
|
||||||
- Returns: File/directory content
|
48. `list_pipeline_jobs` - List all jobs in a specific pipeline
|
||||||
|
49. `get_pipeline_job` - Get details of a GitLab pipeline job number
|
||||||
6. `create_issue`
|
50. `get_pipeline_job_output` - Get the output/trace of a GitLab pipeline job number
|
||||||
|
<!-- TOOLS-END -->
|
||||||
- Create a new issue. 🐛
|
|
||||||
- Inputs:
|
|
||||||
- `project_id` (string): Project ID or namespace/project_path
|
|
||||||
- `title` (string): Issue title
|
|
||||||
- `description` (string): Issue description
|
|
||||||
- `assignee_ids` (optional number[]): Array of assignee IDs
|
|
||||||
- `milestone_id` (optional number): Milestone ID
|
|
||||||
- `labels` (optional string[]): Array of labels
|
|
||||||
- Returns: Details of the created issue
|
|
||||||
|
|
||||||
7. `create_merge_request`
|
|
||||||
|
|
||||||
- Create a new merge request. 🚀
|
|
||||||
- Inputs:
|
|
||||||
- `project_id` (string): Project ID or namespace/project_path
|
|
||||||
- `title` (string): Merge request title
|
|
||||||
- `description` (string): Merge request description
|
|
||||||
- `source_branch` (string): Branch with changes
|
|
||||||
- `target_branch` (string): Branch to merge into
|
|
||||||
- `allow_collaboration` (optional boolean): Allow collaborators to push commits to the source branch
|
|
||||||
- `draft` (optional boolean): Create as a draft merge request
|
|
||||||
- Returns: Details of the created merge request
|
|
||||||
|
|
||||||
8. `fork_repository`
|
|
||||||
|
|
||||||
- Fork a project. 🍴
|
|
||||||
- Inputs:
|
|
||||||
- `project_id` (string): Project ID or namespace/project_path to fork
|
|
||||||
- `namespace` (optional string): Namespace to fork into (default: user namespace)
|
|
||||||
- Returns: Details of the forked project
|
|
||||||
|
|
||||||
9. `create_branch`
|
|
||||||
|
|
||||||
- Create a new branch. 🌿
|
|
||||||
- Inputs:
|
|
||||||
- `project_id` (string): Project ID or namespace/project_path
|
|
||||||
- `name` (string): New branch name
|
|
||||||
- `ref` (optional string): Ref to create the branch from (branch, tag, commit SHA, default: default branch)
|
|
||||||
- Returns: Created branch reference
|
|
||||||
|
|
||||||
10. `get_merge_request`
|
|
||||||
|
|
||||||
- Get details of a merge request. ℹ️
|
|
||||||
- Inputs:
|
|
||||||
- `project_id` (string): Project ID or namespace/project_path
|
|
||||||
- `merge_request_iid` (number): Merge request IID
|
|
||||||
- Returns: Merge request details
|
|
||||||
|
|
||||||
11. `get_merge_request_diffs`
|
|
||||||
|
|
||||||
- Get changes (diffs) of a merge request. diff
|
|
||||||
- Inputs:
|
|
||||||
- `project_id` (string): Project ID or namespace/project_path
|
|
||||||
- `merge_request_iid` (number): Merge request IID
|
|
||||||
- `view` (optional string): Diff view type ('inline' or 'parallel')
|
|
||||||
- Returns: Array of merge request diff information
|
|
||||||
|
|
||||||
12. `update_merge_request`
|
|
||||||
|
|
||||||
- Update a merge request. 🔄
|
|
||||||
- Inputs:
|
|
||||||
- `project_id` (string): Project ID or namespace/project_path
|
|
||||||
- `merge_request_iid` (number): Merge request IID
|
|
||||||
- `title` (optional string): New title
|
|
||||||
- `description` (string): New description
|
|
||||||
- `target_branch` (optional string): New target branch
|
|
||||||
- `state_event` (optional string): Merge request state change event ('close', 'reopen')
|
|
||||||
- `remove_source_branch` (optional boolean): Remove source branch after merge
|
|
||||||
- `allow_collaboration` (optional boolean): Allow collaborators to push commits to the source branch
|
|
||||||
- Returns: Updated merge request details
|
|
||||||
|
|
||||||
13. `create_note`
|
|
||||||
- Create a new note (comment) to an issue or merge request. 💬
|
|
||||||
- Inputs:
|
|
||||||
- `project_id` (string): Project ID or namespace/project_path
|
|
||||||
- `noteable_type` (string): Type of noteable ("issue" or "merge_request")
|
|
||||||
- `noteable_iid` (number): IID of the issue or merge request
|
|
||||||
- `body` (string): Note content
|
|
||||||
- Returns: Details of the created note
|
|
||||||
|
|
||||||
14. `list_projects`
|
|
||||||
- List accessible projects with rich filtering options 📊
|
|
||||||
- Inputs:
|
|
||||||
- Search/filtering:
|
|
||||||
- `search`
|
|
||||||
- `owned`
|
|
||||||
- `membership`
|
|
||||||
- `archived`
|
|
||||||
- `visibility`
|
|
||||||
- Features filtering:
|
|
||||||
- `with_issues_enabled`
|
|
||||||
- `with_merge_requests_enabled`
|
|
||||||
- Sorting:
|
|
||||||
- `order_by`
|
|
||||||
- `sort`
|
|
||||||
- Access control:
|
|
||||||
- `min_access_level`
|
|
||||||
- Pagination:
|
|
||||||
- `page`
|
|
||||||
- `per_page`
|
|
||||||
- `simple`
|
|
||||||
- Returns: Array of projects
|
|
||||||
15. `list_labels`
|
|
||||||
- List all labels for a project with filtering options 🏷️
|
|
||||||
- Inputs:
|
|
||||||
- `project_id` (string): Project ID or path
|
|
||||||
- `with_counts` (optional): Include issue and merge request counts
|
|
||||||
- `include_ancestor_groups` (optional): Include ancestor groups
|
|
||||||
- `search` (optional): Filter labels by keyword
|
|
||||||
- Returns: Array of labels
|
|
||||||
16. `get_label`
|
|
||||||
- Get a single label from a project
|
|
||||||
- Inputs:
|
|
||||||
- `project_id` (string): Project ID or path
|
|
||||||
- `label_id` (number/string): Label ID or name
|
|
||||||
- `include_ancestor_groups` (optional): Include ancestor groups
|
|
||||||
- Returns: label details
|
|
||||||
17. `create_label`
|
|
||||||
- Create a new label in an object 🏷️➕
|
|
||||||
- Inputs:
|
|
||||||
- `project_id` (string): Project ID or path
|
|
||||||
- `name` (string): Label name
|
|
||||||
- `color` (string): Color in hex format (e.g., "#FF0000")
|
|
||||||
- `description` (optional): Label description
|
|
||||||
- `priority` (optional): Label priority
|
|
||||||
- Returns: Created label details
|
|
||||||
18. `update_label`
|
|
||||||
- Update an existing label in a project 🏷️✏️
|
|
||||||
- Inputs:
|
|
||||||
- `project_id` (string): Project ID or path
|
|
||||||
- `label_id` (number/string): Label ID or name
|
|
||||||
- `new_name` (optional): New label name
|
|
||||||
- `color` (optional): New color in hex format
|
|
||||||
- `description` (optional): New description
|
|
||||||
- `priority` (optional): New priority
|
|
||||||
- Returns: Updated label details
|
|
||||||
19. `delete_label`
|
|
||||||
- Delete a label from a project 🏷️❌
|
|
||||||
- Inputs:
|
|
||||||
- `project_id` (string): Project ID or path
|
|
||||||
- `label_id` (number/string): Label ID or name
|
|
||||||
- Returns: Success message
|
|
||||||
|
|
||||||
14. `list_group_projects`
|
|
||||||
|
|
||||||
- List all projects in a GitLab group. 📂
|
|
||||||
- Inputs:
|
|
||||||
- `group_id` (string): Project ID or namespace/project_path
|
|
||||||
- Filtering options:
|
|
||||||
- `include_subgroups` (optional boolean): Include projects from subgroups
|
|
||||||
- `search` (optional string): Search term to filter projects
|
|
||||||
- `archived` (optional boolean): Filter for archived projects
|
|
||||||
- `visibility` (optional string): Filter by project visibility (public/internal/private)
|
|
||||||
- `with_programming_language` (optional string): Filter by programming language
|
|
||||||
- `starred` (optional boolean): Filter by starred projects
|
|
||||||
- Feature filtering:
|
|
||||||
- `with_issues_enabled` (optional boolean): Filter projects with issues feature enabled
|
|
||||||
- `with_merge_requests_enabled` (optional boolean): Filter projects with merge requests feature enabled
|
|
||||||
- `min_access_level` (optional number): Filter by minimum access level
|
|
||||||
- Pagination:
|
|
||||||
- `page` (optional number): Page number
|
|
||||||
- `per_page` (optional number): Results per page
|
|
||||||
- Sorting:
|
|
||||||
- `order_by` (optional string): Field to sort by
|
|
||||||
- `sort` (optional string): Sort direction (asc/desc)
|
|
||||||
- Additional data:
|
|
||||||
- `statistics` (optional boolean): Include project statistics
|
|
||||||
- `with_custom_attributes` (optional boolean): Include custom attributes
|
|
||||||
- `with_security_reports` (optional boolean): Include security reports
|
|
||||||
- Returns: List of projects
|
|
||||||
|
|
||||||
## Environment Variable Configuration
|
|
||||||
|
|
||||||
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
|
|
||||||
```
|
|
||||||
|
|
||||||
## License
|
|
||||||
|
|
||||||
MIT License
|
|
||||||
|
1589
build/index.js
1589
build/index.js
File diff suppressed because it is too large
Load Diff
684
build/schemas.js
684
build/schemas.js
@ -1,684 +0,0 @@
|
|||||||
import { z } from "zod";
|
|
||||||
// Base schemas for common types
|
|
||||||
export const GitLabAuthorSchema = z.object({
|
|
||||||
name: z.string(),
|
|
||||||
email: z.string(),
|
|
||||||
date: z.string(),
|
|
||||||
});
|
|
||||||
// Namespace related schemas
|
|
||||||
// Base schema for project-related operations
|
|
||||||
const ProjectParamsSchema = z.object({
|
|
||||||
project_id: z.string().describe("Project ID or URL-encoded path"), // Changed from owner/repo to match GitLab API
|
|
||||||
});
|
|
||||||
export const GitLabNamespaceSchema = z.object({
|
|
||||||
id: z.number(),
|
|
||||||
name: z.string(),
|
|
||||||
path: z.string(),
|
|
||||||
kind: z.enum(["user", "group"]),
|
|
||||||
full_path: z.string(),
|
|
||||||
parent_id: z.number().nullable(),
|
|
||||||
avatar_url: z.string().nullable(),
|
|
||||||
web_url: z.string(),
|
|
||||||
members_count_with_descendants: z.number().optional(),
|
|
||||||
billable_members_count: z.number().optional(),
|
|
||||||
max_seats_used: z.number().optional(),
|
|
||||||
seats_in_use: z.number().optional(),
|
|
||||||
plan: z.string().optional(),
|
|
||||||
end_date: z.string().nullable().optional(),
|
|
||||||
trial_ends_on: z.string().nullable().optional(),
|
|
||||||
trial: z.boolean().optional(),
|
|
||||||
root_repository_size: z.number().optional(),
|
|
||||||
projects_count: z.number().optional(),
|
|
||||||
});
|
|
||||||
export const GitLabNamespaceExistsResponseSchema = z.object({
|
|
||||||
exists: z.boolean(),
|
|
||||||
suggests: z.array(z.string()).optional(),
|
|
||||||
});
|
|
||||||
// Repository related schemas
|
|
||||||
export const GitLabOwnerSchema = z.object({
|
|
||||||
username: z.string(), // Changed from login to match GitLab API
|
|
||||||
id: z.number(),
|
|
||||||
avatar_url: z.string(),
|
|
||||||
web_url: z.string(), // Changed from html_url to match GitLab API
|
|
||||||
name: z.string(), // Added as GitLab includes full name
|
|
||||||
state: z.string(), // Added as GitLab includes user state
|
|
||||||
});
|
|
||||||
export const GitLabRepositorySchema = z.object({
|
|
||||||
id: z.number(),
|
|
||||||
name: z.string(),
|
|
||||||
path_with_namespace: z.string(),
|
|
||||||
visibility: z.string().optional(),
|
|
||||||
owner: GitLabOwnerSchema.optional(),
|
|
||||||
web_url: z.string().optional(),
|
|
||||||
description: z.string().nullable(),
|
|
||||||
fork: z.boolean().optional(),
|
|
||||||
ssh_url_to_repo: z.string().optional(),
|
|
||||||
http_url_to_repo: z.string().optional(),
|
|
||||||
created_at: z.string().optional(),
|
|
||||||
last_activity_at: z.string().optional(),
|
|
||||||
default_branch: z.string().optional(),
|
|
||||||
namespace: z.object({
|
|
||||||
id: z.number(),
|
|
||||||
name: z.string(),
|
|
||||||
path: z.string(),
|
|
||||||
kind: z.string(),
|
|
||||||
full_path: z.string(),
|
|
||||||
avatar_url: z.string().nullable().optional(),
|
|
||||||
web_url: z.string().optional(),
|
|
||||||
}).optional(),
|
|
||||||
readme_url: z.string().optional().nullable(),
|
|
||||||
topics: z.array(z.string()).optional(),
|
|
||||||
tag_list: z.array(z.string()).optional(), // deprecated but still present
|
|
||||||
open_issues_count: z.number().optional(),
|
|
||||||
archived: z.boolean().optional(),
|
|
||||||
forks_count: z.number().optional(),
|
|
||||||
star_count: z.number().optional(),
|
|
||||||
permissions: z.object({
|
|
||||||
project_access: z.object({
|
|
||||||
access_level: z.number(),
|
|
||||||
notification_level: z.number().optional(),
|
|
||||||
}).optional().nullable(),
|
|
||||||
group_access: z.object({
|
|
||||||
access_level: z.number(),
|
|
||||||
notification_level: z.number().optional(),
|
|
||||||
}).optional().nullable(),
|
|
||||||
}).optional(),
|
|
||||||
container_registry_enabled: z.boolean().optional(),
|
|
||||||
container_registry_access_level: z.string().optional(),
|
|
||||||
issues_enabled: z.boolean().optional(),
|
|
||||||
merge_requests_enabled: z.boolean().optional(),
|
|
||||||
wiki_enabled: z.boolean().optional(),
|
|
||||||
jobs_enabled: z.boolean().optional(),
|
|
||||||
snippets_enabled: z.boolean().optional(),
|
|
||||||
can_create_merge_request_in: z.boolean().optional(),
|
|
||||||
resolve_outdated_diff_discussions: z.boolean().optional(),
|
|
||||||
shared_runners_enabled: z.boolean().optional(),
|
|
||||||
shared_with_groups: z.array(z.object({
|
|
||||||
group_id: z.number(),
|
|
||||||
group_name: z.string(),
|
|
||||||
group_full_path: z.string(),
|
|
||||||
group_access_level: z.number(),
|
|
||||||
})).optional(),
|
|
||||||
});
|
|
||||||
// Project schema (extended from repository schema)
|
|
||||||
export const GitLabProjectSchema = GitLabRepositorySchema;
|
|
||||||
// File content schemas
|
|
||||||
export const GitLabFileContentSchema = z.object({
|
|
||||||
file_name: z.string(), // Changed from name to match GitLab API
|
|
||||||
file_path: z.string(), // Changed from path to match GitLab API
|
|
||||||
size: z.number(),
|
|
||||||
encoding: z.string(),
|
|
||||||
content: z.string(),
|
|
||||||
content_sha256: z.string(), // Changed from sha to match GitLab API
|
|
||||||
ref: z.string(), // Added as GitLab requires branch reference
|
|
||||||
blob_id: z.string(), // Added to match GitLab API
|
|
||||||
commit_id: z.string(), // ID of the current file version
|
|
||||||
last_commit_id: z.string(), // Added to match GitLab API
|
|
||||||
execute_filemode: z.boolean().optional(), // Added to match GitLab API
|
|
||||||
});
|
|
||||||
export const GitLabDirectoryContentSchema = z.object({
|
|
||||||
name: z.string(),
|
|
||||||
path: z.string(),
|
|
||||||
type: z.string(),
|
|
||||||
mode: z.string(),
|
|
||||||
id: z.string(), // Changed from sha to match GitLab API
|
|
||||||
web_url: z.string(), // Changed from html_url to match GitLab API
|
|
||||||
});
|
|
||||||
export const GitLabContentSchema = z.union([
|
|
||||||
GitLabFileContentSchema,
|
|
||||||
z.array(GitLabDirectoryContentSchema),
|
|
||||||
]);
|
|
||||||
// Operation schemas
|
|
||||||
export const FileOperationSchema = z.object({
|
|
||||||
path: z.string(),
|
|
||||||
content: z.string(),
|
|
||||||
});
|
|
||||||
// Tree and commit schemas
|
|
||||||
export const GitLabTreeEntrySchema = z.object({
|
|
||||||
id: z.string(), // Changed from sha to match GitLab API
|
|
||||||
name: z.string(),
|
|
||||||
type: z.enum(["blob", "tree"]),
|
|
||||||
path: z.string(),
|
|
||||||
mode: z.string(),
|
|
||||||
});
|
|
||||||
export const GitLabTreeSchema = z.object({
|
|
||||||
id: z.string(), // Changed from sha to match GitLab API
|
|
||||||
tree: z.array(GitLabTreeEntrySchema),
|
|
||||||
});
|
|
||||||
export const GitLabCommitSchema = z.object({
|
|
||||||
id: z.string(), // Changed from sha to match GitLab API
|
|
||||||
short_id: z.string(), // Added to match GitLab API
|
|
||||||
title: z.string(), // Changed from message to match GitLab API
|
|
||||||
author_name: z.string(),
|
|
||||||
author_email: z.string(),
|
|
||||||
authored_date: z.string(),
|
|
||||||
committer_name: z.string(),
|
|
||||||
committer_email: z.string(),
|
|
||||||
committed_date: z.string(),
|
|
||||||
web_url: z.string(), // Changed from html_url to match GitLab API
|
|
||||||
parent_ids: z.array(z.string()), // Changed from parents to match GitLab API
|
|
||||||
});
|
|
||||||
// Reference schema
|
|
||||||
export const GitLabReferenceSchema = z.object({
|
|
||||||
name: z.string(), // Changed from ref to match GitLab API
|
|
||||||
commit: z.object({
|
|
||||||
id: z.string(), // Changed from sha to match GitLab API
|
|
||||||
web_url: z.string(), // Changed from url to match GitLab API
|
|
||||||
}),
|
|
||||||
});
|
|
||||||
// Input schemas for operations
|
|
||||||
export const CreateRepositoryOptionsSchema = z.object({
|
|
||||||
name: z.string(),
|
|
||||||
description: z.string().optional(),
|
|
||||||
visibility: z.enum(["private", "internal", "public"]).optional(), // Changed from private to match GitLab API
|
|
||||||
initialize_with_readme: z.boolean().optional(), // Changed from auto_init to match GitLab API
|
|
||||||
});
|
|
||||||
export const CreateIssueOptionsSchema = z.object({
|
|
||||||
title: z.string(),
|
|
||||||
description: z.string().optional(), // Changed from body to match GitLab API
|
|
||||||
assignee_ids: z.array(z.number()).optional(), // Changed from assignees to match GitLab API
|
|
||||||
milestone_id: z.number().optional(), // Changed from milestone to match GitLab API
|
|
||||||
labels: z.array(z.string()).optional(),
|
|
||||||
});
|
|
||||||
export const CreateMergeRequestOptionsSchema = z.object({
|
|
||||||
// Changed from CreatePullRequestOptionsSchema
|
|
||||||
title: z.string(),
|
|
||||||
description: z.string().optional(), // Changed from body to match GitLab API
|
|
||||||
source_branch: z.string(), // Changed from head to match GitLab API
|
|
||||||
target_branch: z.string(), // Changed from base to match GitLab API
|
|
||||||
allow_collaboration: z.boolean().optional(), // Changed from maintainer_can_modify to match GitLab API
|
|
||||||
draft: z.boolean().optional(),
|
|
||||||
});
|
|
||||||
export const CreateBranchOptionsSchema = z.object({
|
|
||||||
name: z.string(), // Changed from ref to match GitLab API
|
|
||||||
ref: z.string(), // The source branch/commit for the new branch
|
|
||||||
});
|
|
||||||
// Response schemas for operations
|
|
||||||
export const GitLabCreateUpdateFileResponseSchema = z.object({
|
|
||||||
file_path: z.string(),
|
|
||||||
branch: z.string(),
|
|
||||||
commit_id: z.string().optional(), // Optional since it's not always returned by the API
|
|
||||||
content: GitLabFileContentSchema.optional(),
|
|
||||||
});
|
|
||||||
export const GitLabSearchResponseSchema = z.object({
|
|
||||||
count: z.number().optional(),
|
|
||||||
total_pages: z.number().optional(),
|
|
||||||
current_page: z.number().optional(),
|
|
||||||
items: z.array(GitLabRepositorySchema),
|
|
||||||
});
|
|
||||||
// Issue related schemas
|
|
||||||
export const GitLabLabelSchema = z.object({
|
|
||||||
id: z.number(),
|
|
||||||
name: z.string(),
|
|
||||||
color: z.string(),
|
|
||||||
text_color: z.string(),
|
|
||||||
description: z.string().nullable(),
|
|
||||||
description_html: z.string().nullable(),
|
|
||||||
open_issues_count: z.number().optional(),
|
|
||||||
closed_issues_count: z.number().optional(),
|
|
||||||
open_merge_requests_count: z.number().optional(),
|
|
||||||
subscribed: z.boolean().optional(),
|
|
||||||
priority: z.number().nullable().optional(),
|
|
||||||
is_project_label: z.boolean().optional(),
|
|
||||||
});
|
|
||||||
export const GitLabUserSchema = z.object({
|
|
||||||
username: z.string(), // Changed from login to match GitLab API
|
|
||||||
id: z.number(),
|
|
||||||
name: z.string(),
|
|
||||||
avatar_url: z.string(),
|
|
||||||
web_url: z.string(), // Changed from html_url to match GitLab API
|
|
||||||
});
|
|
||||||
export const GitLabMilestoneSchema = z.object({
|
|
||||||
id: z.number(),
|
|
||||||
iid: z.number(), // Added to match GitLab API
|
|
||||||
title: z.string(),
|
|
||||||
description: z.string(),
|
|
||||||
state: z.string(),
|
|
||||||
web_url: z.string(), // Changed from html_url to match GitLab API
|
|
||||||
});
|
|
||||||
export const GitLabIssueSchema = z.object({
|
|
||||||
id: z.number(),
|
|
||||||
iid: z.number(), // Added to match GitLab API
|
|
||||||
project_id: z.number(), // Added to match GitLab API
|
|
||||||
title: z.string(),
|
|
||||||
description: z.string(), // Changed from body to match GitLab API
|
|
||||||
state: z.string(),
|
|
||||||
author: GitLabUserSchema,
|
|
||||||
assignees: z.array(GitLabUserSchema),
|
|
||||||
labels: z.array(GitLabLabelSchema).or(z.array(z.string())), // Support both label objects and strings
|
|
||||||
milestone: GitLabMilestoneSchema.nullable(),
|
|
||||||
created_at: z.string(),
|
|
||||||
updated_at: z.string(),
|
|
||||||
closed_at: z.string().nullable(),
|
|
||||||
web_url: z.string(), // Changed from html_url to match GitLab API
|
|
||||||
references: z.object({
|
|
||||||
short: z.string(),
|
|
||||||
relative: z.string(),
|
|
||||||
full: z.string(),
|
|
||||||
}).optional(),
|
|
||||||
time_stats: z.object({
|
|
||||||
time_estimate: z.number(),
|
|
||||||
total_time_spent: z.number(),
|
|
||||||
human_time_estimate: z.string().nullable(),
|
|
||||||
human_total_time_spent: z.string().nullable(),
|
|
||||||
}).optional(),
|
|
||||||
confidential: z.boolean().optional(),
|
|
||||||
due_date: z.string().nullable().optional(),
|
|
||||||
discussion_locked: z.boolean().nullable().optional(),
|
|
||||||
weight: z.number().nullable().optional(),
|
|
||||||
});
|
|
||||||
// NEW SCHEMA: For issue with link details (used in listing issue links)
|
|
||||||
export const GitLabIssueWithLinkDetailsSchema = GitLabIssueSchema.extend({
|
|
||||||
issue_link_id: z.number(),
|
|
||||||
link_type: z.enum(['relates_to', 'blocks', 'is_blocked_by']),
|
|
||||||
link_created_at: z.string(),
|
|
||||||
link_updated_at: z.string(),
|
|
||||||
});
|
|
||||||
// Fork related schemas
|
|
||||||
export const GitLabForkParentSchema = z.object({
|
|
||||||
name: z.string(),
|
|
||||||
path_with_namespace: z.string(), // Changed from full_name to match GitLab API
|
|
||||||
owner: z.object({
|
|
||||||
username: z.string(), // Changed from login to match GitLab API
|
|
||||||
id: z.number(),
|
|
||||||
avatar_url: z.string(),
|
|
||||||
}).optional(), // Made optional to handle cases where GitLab API doesn't include it
|
|
||||||
web_url: z.string(), // Changed from html_url to match GitLab API
|
|
||||||
});
|
|
||||||
export const GitLabForkSchema = GitLabRepositorySchema.extend({
|
|
||||||
forked_from_project: GitLabForkParentSchema.optional(), // Made optional to handle cases where GitLab API doesn't include it
|
|
||||||
});
|
|
||||||
// Merge Request related schemas (equivalent to Pull Request)
|
|
||||||
export const GitLabMergeRequestDiffRefSchema = z.object({
|
|
||||||
base_sha: z.string(),
|
|
||||||
head_sha: z.string(),
|
|
||||||
start_sha: z.string(),
|
|
||||||
});
|
|
||||||
export const GitLabMergeRequestSchema = z.object({
|
|
||||||
id: z.number(),
|
|
||||||
iid: z.number(),
|
|
||||||
project_id: z.number(),
|
|
||||||
title: z.string(),
|
|
||||||
description: z.string().nullable(),
|
|
||||||
state: z.string(),
|
|
||||||
merged: z.boolean().optional(),
|
|
||||||
draft: z.boolean().optional(),
|
|
||||||
author: GitLabUserSchema,
|
|
||||||
assignees: z.array(GitLabUserSchema).optional(),
|
|
||||||
source_branch: z.string(),
|
|
||||||
target_branch: z.string(),
|
|
||||||
diff_refs: GitLabMergeRequestDiffRefSchema.nullable().optional(),
|
|
||||||
web_url: z.string(),
|
|
||||||
created_at: z.string(),
|
|
||||||
updated_at: z.string(),
|
|
||||||
merged_at: z.string().nullable(),
|
|
||||||
closed_at: z.string().nullable(),
|
|
||||||
merge_commit_sha: z.string().nullable(),
|
|
||||||
detailed_merge_status: z.string().optional(),
|
|
||||||
merge_status: z.string().optional(),
|
|
||||||
merge_error: z.string().nullable().optional(),
|
|
||||||
work_in_progress: z.boolean().optional(),
|
|
||||||
blocking_discussions_resolved: z.boolean().optional(),
|
|
||||||
should_remove_source_branch: z.boolean().nullable().optional(),
|
|
||||||
force_remove_source_branch: z.boolean().nullable().optional(),
|
|
||||||
allow_collaboration: z.boolean().optional(),
|
|
||||||
allow_maintainer_to_push: z.boolean().optional(),
|
|
||||||
changes_count: z.string().nullable().optional(),
|
|
||||||
merge_when_pipeline_succeeds: z.boolean().optional(),
|
|
||||||
squash: z.boolean().optional(),
|
|
||||||
labels: z.array(z.string()).optional(),
|
|
||||||
});
|
|
||||||
// Discussion related schemas
|
|
||||||
export const GitLabDiscussionNoteSchema = z.object({
|
|
||||||
id: z.number(),
|
|
||||||
type: z.enum(["DiscussionNote", "DiffNote", "Note"]).nullable(), // Allow null type for regular notes
|
|
||||||
body: z.string(),
|
|
||||||
attachment: z.any().nullable(), // Can be string or object, handle appropriately
|
|
||||||
author: GitLabUserSchema,
|
|
||||||
created_at: z.string(),
|
|
||||||
updated_at: z.string(),
|
|
||||||
system: z.boolean(),
|
|
||||||
noteable_id: z.number(),
|
|
||||||
noteable_type: z.enum(["Issue", "MergeRequest", "Snippet", "Commit", "Epic"]),
|
|
||||||
project_id: z.number().optional(), // Optional for group-level discussions like Epics
|
|
||||||
noteable_iid: z.number().nullable(),
|
|
||||||
resolvable: z.boolean().optional(),
|
|
||||||
resolved: z.boolean().optional(),
|
|
||||||
resolved_by: GitLabUserSchema.nullable().optional(),
|
|
||||||
resolved_at: z.string().nullable().optional(),
|
|
||||||
position: z.object({
|
|
||||||
base_sha: z.string(),
|
|
||||||
start_sha: z.string(),
|
|
||||||
head_sha: z.string(),
|
|
||||||
old_path: z.string(),
|
|
||||||
new_path: z.string(),
|
|
||||||
position_type: z.enum(["text", "image", "file"]),
|
|
||||||
old_line: z.number().nullable(),
|
|
||||||
new_line: z.number().nullable(),
|
|
||||||
line_range: z.object({
|
|
||||||
start: z.object({
|
|
||||||
line_code: z.string(),
|
|
||||||
type: z.enum(["new", "old"]),
|
|
||||||
old_line: z.number().nullable(),
|
|
||||||
new_line: z.number().nullable(),
|
|
||||||
}),
|
|
||||||
end: z.object({
|
|
||||||
line_code: z.string(),
|
|
||||||
type: z.enum(["new", "old"]),
|
|
||||||
old_line: z.number().nullable(),
|
|
||||||
new_line: z.number().nullable(),
|
|
||||||
}),
|
|
||||||
}).nullable().optional(), // For multi-line diff notes
|
|
||||||
width: z.number().optional(), // For image diff notes
|
|
||||||
height: z.number().optional(), // For image diff notes
|
|
||||||
x: z.number().optional(), // For image diff notes
|
|
||||||
y: z.number().optional(), // For image diff notes
|
|
||||||
}).optional(),
|
|
||||||
});
|
|
||||||
export const GitLabDiscussionSchema = z.object({
|
|
||||||
id: z.string(),
|
|
||||||
individual_note: z.boolean(),
|
|
||||||
notes: z.array(GitLabDiscussionNoteSchema),
|
|
||||||
});
|
|
||||||
// Input schema for listing merge request discussions
|
|
||||||
export const ListMergeRequestDiscussionsSchema = ProjectParamsSchema.extend({
|
|
||||||
merge_request_iid: z.number().describe("The IID of a merge request"),
|
|
||||||
});
|
|
||||||
// Input schema for updating a merge request discussion note
|
|
||||||
export const UpdateMergeRequestNoteSchema = ProjectParamsSchema.extend({
|
|
||||||
merge_request_iid: z.number().describe("The IID of a merge request"),
|
|
||||||
discussion_id: z.string().describe("The ID of a thread"),
|
|
||||||
note_id: z.number().describe("The ID of a thread note"),
|
|
||||||
body: z.string().describe("The content of the note or reply"),
|
|
||||||
resolved: z.boolean().optional().describe("Resolve or unresolve the note"), // Optional based on API docs
|
|
||||||
});
|
|
||||||
// API Operation Parameter Schemas
|
|
||||||
export const CreateOrUpdateFileSchema = ProjectParamsSchema.extend({
|
|
||||||
file_path: z.string().describe("Path where to create/update the file"),
|
|
||||||
content: z.string().describe("Content of the file"),
|
|
||||||
commit_message: z.string().describe("Commit message"),
|
|
||||||
branch: z.string().describe("Branch to create/update the file in"),
|
|
||||||
previous_path: z
|
|
||||||
.string()
|
|
||||||
.optional()
|
|
||||||
.describe("Path of the file to move/rename"),
|
|
||||||
last_commit_id: z
|
|
||||||
.string()
|
|
||||||
.optional()
|
|
||||||
.describe("Last known file commit ID"),
|
|
||||||
commit_id: z
|
|
||||||
.string()
|
|
||||||
.optional()
|
|
||||||
.describe("Current file commit ID (for update operations)"),
|
|
||||||
});
|
|
||||||
export const SearchRepositoriesSchema = z.object({
|
|
||||||
search: z.string().describe("Search query"), // Changed from query to match GitLab API
|
|
||||||
page: z
|
|
||||||
.number()
|
|
||||||
.optional()
|
|
||||||
.describe("Page number for pagination (default: 1)"),
|
|
||||||
per_page: z
|
|
||||||
.number()
|
|
||||||
.optional()
|
|
||||||
.describe("Number of results per page (default: 20)"),
|
|
||||||
});
|
|
||||||
export const CreateRepositorySchema = z.object({
|
|
||||||
name: z.string().describe("Repository name"),
|
|
||||||
description: z.string().optional().describe("Repository description"),
|
|
||||||
visibility: z
|
|
||||||
.enum(["private", "internal", "public"])
|
|
||||||
.optional()
|
|
||||||
.describe("Repository visibility level"),
|
|
||||||
initialize_with_readme: z
|
|
||||||
.boolean()
|
|
||||||
.optional()
|
|
||||||
.describe("Initialize with README.md"),
|
|
||||||
});
|
|
||||||
export const GetFileContentsSchema = ProjectParamsSchema.extend({
|
|
||||||
file_path: z.string().describe("Path to the file or directory"),
|
|
||||||
ref: z.string().optional().describe("Branch/tag/commit to get contents from"),
|
|
||||||
});
|
|
||||||
export const PushFilesSchema = ProjectParamsSchema.extend({
|
|
||||||
branch: z.string().describe("Branch to push to"),
|
|
||||||
files: z
|
|
||||||
.array(z.object({
|
|
||||||
file_path: z.string().describe("Path where to create the file"),
|
|
||||||
content: z.string().describe("Content of the file"),
|
|
||||||
}))
|
|
||||||
.describe("Array of files to push"),
|
|
||||||
commit_message: z.string().describe("Commit message"),
|
|
||||||
});
|
|
||||||
export const CreateIssueSchema = ProjectParamsSchema.extend({
|
|
||||||
title: z.string().describe("Issue title"),
|
|
||||||
description: z.string().optional().describe("Issue description"),
|
|
||||||
assignee_ids: z
|
|
||||||
.array(z.number())
|
|
||||||
.optional()
|
|
||||||
.describe("Array of user IDs to assign"),
|
|
||||||
labels: z.array(z.string()).optional().describe("Array of label names"),
|
|
||||||
milestone_id: z.number().optional().describe("Milestone ID to assign"),
|
|
||||||
});
|
|
||||||
export const CreateMergeRequestSchema = ProjectParamsSchema.extend({
|
|
||||||
title: z.string().describe("Merge request title"),
|
|
||||||
description: z.string().optional().describe("Merge request description"),
|
|
||||||
source_branch: z.string().describe("Branch containing changes"),
|
|
||||||
target_branch: z.string().describe("Branch to merge into"),
|
|
||||||
draft: z.boolean().optional().describe("Create as draft merge request"),
|
|
||||||
allow_collaboration: z
|
|
||||||
.boolean()
|
|
||||||
.optional()
|
|
||||||
.describe("Allow commits from upstream members"),
|
|
||||||
});
|
|
||||||
export const ForkRepositorySchema = ProjectParamsSchema.extend({
|
|
||||||
namespace: z.string().optional().describe("Namespace to fork to (full path)"),
|
|
||||||
});
|
|
||||||
export const CreateBranchSchema = ProjectParamsSchema.extend({
|
|
||||||
branch: z.string().describe("Name for the new branch"),
|
|
||||||
ref: z.string().optional().describe("Source branch/commit for new branch"),
|
|
||||||
});
|
|
||||||
export const GitLabMergeRequestDiffSchema = z.object({
|
|
||||||
old_path: z.string(),
|
|
||||||
new_path: z.string(),
|
|
||||||
a_mode: z.string(),
|
|
||||||
b_mode: z.string(),
|
|
||||||
diff: z.string(),
|
|
||||||
new_file: z.boolean(),
|
|
||||||
renamed_file: z.boolean(),
|
|
||||||
deleted_file: z.boolean(),
|
|
||||||
});
|
|
||||||
export const GetMergeRequestSchema = ProjectParamsSchema.extend({
|
|
||||||
merge_request_iid: z
|
|
||||||
.number()
|
|
||||||
.describe("The internal ID of the merge request"),
|
|
||||||
});
|
|
||||||
export const UpdateMergeRequestSchema = GetMergeRequestSchema.extend({
|
|
||||||
title: z.string().optional().describe("The title of the merge request"),
|
|
||||||
description: z
|
|
||||||
.string()
|
|
||||||
.optional()
|
|
||||||
.describe("The description of the merge request"),
|
|
||||||
target_branch: z.string().optional().describe("The target branch"),
|
|
||||||
assignee_ids: z
|
|
||||||
.array(z.number())
|
|
||||||
.optional()
|
|
||||||
.describe("The ID of the users to assign the MR to"),
|
|
||||||
labels: z.array(z.string()).optional().describe("Labels for the MR"),
|
|
||||||
state_event: z
|
|
||||||
.enum(["close", "reopen"])
|
|
||||||
.optional()
|
|
||||||
.describe("New state (close/reopen) for the MR"),
|
|
||||||
remove_source_branch: z
|
|
||||||
.boolean()
|
|
||||||
.optional()
|
|
||||||
.describe("Flag indicating if the source branch should be removed"),
|
|
||||||
squash: z
|
|
||||||
.boolean()
|
|
||||||
.optional()
|
|
||||||
.describe("Squash commits into a single commit when merging"),
|
|
||||||
draft: z.boolean().optional().describe("Work in progress merge request"),
|
|
||||||
});
|
|
||||||
export const GetMergeRequestDiffsSchema = GetMergeRequestSchema.extend({
|
|
||||||
view: z.enum(["inline", "parallel"]).optional().describe("Diff view type"),
|
|
||||||
});
|
|
||||||
export const CreateNoteSchema = z.object({
|
|
||||||
project_id: z.string().describe("Project ID or namespace/project_path"),
|
|
||||||
noteable_type: z
|
|
||||||
.enum(["issue", "merge_request"])
|
|
||||||
.describe("Type of noteable (issue or merge_request)"),
|
|
||||||
noteable_iid: z.number().describe("IID of the issue or merge request"),
|
|
||||||
body: z.string().describe("Note content"),
|
|
||||||
});
|
|
||||||
// Issues API operation schemas
|
|
||||||
export const ListIssuesSchema = z.object({
|
|
||||||
project_id: z.string().describe("Project ID or URL-encoded path"),
|
|
||||||
assignee_id: z.number().optional().describe("Return issues assigned to the given user ID"),
|
|
||||||
assignee_username: z.string().optional().describe("Return issues assigned to the given username"),
|
|
||||||
author_id: z.number().optional().describe("Return issues created by the given user ID"),
|
|
||||||
author_username: z.string().optional().describe("Return issues created by the given username"),
|
|
||||||
confidential: z.boolean().optional().describe("Filter confidential or public issues"),
|
|
||||||
created_after: z.string().optional().describe("Return issues created after the given time"),
|
|
||||||
created_before: z.string().optional().describe("Return issues created before the given time"),
|
|
||||||
due_date: z.string().optional().describe("Return issues that have the due date"),
|
|
||||||
label_name: z.array(z.string()).optional().describe("Array of label names"),
|
|
||||||
milestone: z.string().optional().describe("Milestone title"),
|
|
||||||
scope: z.enum(['created-by-me', 'assigned-to-me', 'all']).optional().describe("Return issues from a specific scope"),
|
|
||||||
search: z.string().optional().describe("Search for specific terms"),
|
|
||||||
state: z.enum(['opened', 'closed', 'all']).optional().describe("Return issues with a specific state"),
|
|
||||||
updated_after: z.string().optional().describe("Return issues updated after the given time"),
|
|
||||||
updated_before: z.string().optional().describe("Return issues updated before the given time"),
|
|
||||||
with_labels_details: z.boolean().optional().describe("Return more details for each label"),
|
|
||||||
page: z.number().optional().describe("Page number for pagination"),
|
|
||||||
per_page: z.number().optional().describe("Number of items per page"),
|
|
||||||
});
|
|
||||||
export const GetIssueSchema = z.object({
|
|
||||||
project_id: z.string().describe("Project ID or URL-encoded path"),
|
|
||||||
issue_iid: z.number().describe("The internal ID of the project issue"),
|
|
||||||
});
|
|
||||||
export const UpdateIssueSchema = z.object({
|
|
||||||
project_id: z.string().describe("Project ID or URL-encoded path"),
|
|
||||||
issue_iid: z.number().describe("The internal ID of the project issue"),
|
|
||||||
title: z.string().optional().describe("The title of the issue"),
|
|
||||||
description: z.string().optional().describe("The description of the issue"),
|
|
||||||
assignee_ids: z.array(z.number()).optional().describe("Array of user IDs to assign issue to"),
|
|
||||||
confidential: z.boolean().optional().describe("Set the issue to be confidential"),
|
|
||||||
discussion_locked: z.boolean().optional().describe("Flag to lock discussions"),
|
|
||||||
due_date: z.string().optional().describe("Date the issue is due (YYYY-MM-DD)"),
|
|
||||||
labels: z.array(z.string()).optional().describe("Array of label names"),
|
|
||||||
milestone_id: z.number().optional().describe("Milestone ID to assign"),
|
|
||||||
state_event: z.enum(['close', 'reopen']).optional().describe("Update issue state (close/reopen)"),
|
|
||||||
weight: z.number().optional().describe("Weight of the issue (0-9)"),
|
|
||||||
});
|
|
||||||
export const DeleteIssueSchema = z.object({
|
|
||||||
project_id: z.string().describe("Project ID or URL-encoded path"),
|
|
||||||
issue_iid: z.number().describe("The internal ID of the project issue"),
|
|
||||||
});
|
|
||||||
// Issue links related schemas
|
|
||||||
export const GitLabIssueLinkSchema = z.object({
|
|
||||||
source_issue: GitLabIssueSchema,
|
|
||||||
target_issue: GitLabIssueSchema,
|
|
||||||
link_type: z.enum(['relates_to', 'blocks', 'is_blocked_by']),
|
|
||||||
});
|
|
||||||
export const ListIssueLinksSchema = z.object({
|
|
||||||
project_id: z.string().describe("Project ID or URL-encoded path"),
|
|
||||||
issue_iid: z.number().describe("The internal ID of a project's issue"),
|
|
||||||
});
|
|
||||||
export const GetIssueLinkSchema = z.object({
|
|
||||||
project_id: z.string().describe("Project ID or URL-encoded path"),
|
|
||||||
issue_iid: z.number().describe("The internal ID of a project's issue"),
|
|
||||||
issue_link_id: z.number().describe("ID of an issue relationship"),
|
|
||||||
});
|
|
||||||
export const CreateIssueLinkSchema = z.object({
|
|
||||||
project_id: z.string().describe("Project ID or URL-encoded path"),
|
|
||||||
issue_iid: z.number().describe("The internal ID of a project's issue"),
|
|
||||||
target_project_id: z.string().describe("The ID or URL-encoded path of a target project"),
|
|
||||||
target_issue_iid: z.number().describe("The internal ID of a target project's issue"),
|
|
||||||
link_type: z.enum(['relates_to', 'blocks', 'is_blocked_by']).optional().describe("The type of the relation, defaults to relates_to"),
|
|
||||||
});
|
|
||||||
export const DeleteIssueLinkSchema = z.object({
|
|
||||||
project_id: z.string().describe("Project ID or URL-encoded path"),
|
|
||||||
issue_iid: z.number().describe("The internal ID of a project's issue"),
|
|
||||||
issue_link_id: z.number().describe("The ID of an issue relationship"),
|
|
||||||
});
|
|
||||||
// Namespace API operation schemas
|
|
||||||
export const ListNamespacesSchema = z.object({
|
|
||||||
search: z.string().optional().describe("Search term for namespaces"),
|
|
||||||
page: z.number().optional().describe("Page number for pagination"),
|
|
||||||
per_page: z.number().optional().describe("Number of items per page"),
|
|
||||||
owned: z.boolean().optional().describe("Filter for namespaces owned by current user"),
|
|
||||||
});
|
|
||||||
export const GetNamespaceSchema = z.object({
|
|
||||||
namespace_id: z.string().describe("Namespace ID or full path"),
|
|
||||||
});
|
|
||||||
export const VerifyNamespaceSchema = z.object({
|
|
||||||
path: z.string().describe("Namespace path to verify"),
|
|
||||||
});
|
|
||||||
// Project API operation schemas
|
|
||||||
export const GetProjectSchema = z.object({
|
|
||||||
project_id: z.string().describe("Project ID or URL-encoded path"),
|
|
||||||
});
|
|
||||||
export const ListProjectsSchema = z.object({
|
|
||||||
search: z.string().optional().describe("Search term for projects"),
|
|
||||||
page: z.number().optional().describe("Page number for pagination"),
|
|
||||||
per_page: z.number().optional().describe("Number of items per page"),
|
|
||||||
owned: z.boolean().optional().describe("Filter for projects owned by current user"),
|
|
||||||
membership: z.boolean().optional().describe("Filter for projects where current user is a member"),
|
|
||||||
simple: z.boolean().optional().describe("Return only limited fields"),
|
|
||||||
archived: z.boolean().optional().describe("Filter for archived projects"),
|
|
||||||
visibility: z.enum(["public", "internal", "private"]).optional().describe("Filter by project visibility"),
|
|
||||||
order_by: z.enum(["id", "name", "path", "created_at", "updated_at", "last_activity_at"]).optional().describe("Return projects ordered by field"),
|
|
||||||
sort: z.enum(["asc", "desc"]).optional().describe("Return projects sorted in ascending or descending order"),
|
|
||||||
with_issues_enabled: z.boolean().optional().describe("Filter projects with issues feature enabled"),
|
|
||||||
with_merge_requests_enabled: z.boolean().optional().describe("Filter projects with merge requests feature enabled"),
|
|
||||||
min_access_level: z.number().optional().describe("Filter by minimum access level"),
|
|
||||||
});
|
|
||||||
// Label operation schemas
|
|
||||||
export const ListLabelsSchema = z.object({
|
|
||||||
project_id: z.string().describe("Project ID or URL-encoded path"),
|
|
||||||
with_counts: z.boolean().optional().describe("Whether or not to include issue and merge request counts"),
|
|
||||||
include_ancestor_groups: z.boolean().optional().describe("Include ancestor groups"),
|
|
||||||
search: z.string().optional().describe("Keyword to filter labels by"),
|
|
||||||
});
|
|
||||||
export const GetLabelSchema = z.object({
|
|
||||||
project_id: z.string().describe("Project ID or URL-encoded path"),
|
|
||||||
label_id: z.union([z.number(), z.string()]).describe("The ID or title of a project's label"),
|
|
||||||
include_ancestor_groups: z.boolean().optional().describe("Include ancestor groups"),
|
|
||||||
});
|
|
||||||
export const CreateLabelSchema = z.object({
|
|
||||||
project_id: z.string().describe("Project ID or URL-encoded path"),
|
|
||||||
name: z.string().describe("The name of the label"),
|
|
||||||
color: z.string().describe("The color of the label given in 6-digit hex notation with leading '#' sign"),
|
|
||||||
description: z.string().optional().describe("The description of the label"),
|
|
||||||
priority: z.number().nullable().optional().describe("The priority of the label"),
|
|
||||||
});
|
|
||||||
export const UpdateLabelSchema = z.object({
|
|
||||||
project_id: z.string().describe("Project ID or URL-encoded path"),
|
|
||||||
label_id: z.union([z.number(), z.string()]).describe("The ID or title of a project's label"),
|
|
||||||
new_name: z.string().optional().describe("The new name of the label"),
|
|
||||||
color: z.string().optional().describe("The color of the label given in 6-digit hex notation with leading '#' sign"),
|
|
||||||
description: z.string().optional().describe("The new description of the label"),
|
|
||||||
priority: z.number().nullable().optional().describe("The new priority of the label"),
|
|
||||||
});
|
|
||||||
export const DeleteLabelSchema = z.object({
|
|
||||||
project_id: z.string().describe("Project ID or URL-encoded path"),
|
|
||||||
label_id: z.union([z.number(), z.string()]).describe("The ID or title of a project's label"),
|
|
||||||
});
|
|
||||||
// Group projects schema
|
|
||||||
export const ListGroupProjectsSchema = z.object({
|
|
||||||
group_id: z.string().describe("Group ID or path"),
|
|
||||||
include_subgroups: z.boolean().optional().describe("Include projects from subgroups"),
|
|
||||||
search: z.string().optional().describe("Search term to filter projects"),
|
|
||||||
order_by: z.enum(['name', 'path', 'created_at', 'updated_at', 'last_activity_at']).optional().describe("Field to sort by"),
|
|
||||||
sort: z.enum(['asc', 'desc']).optional().describe("Sort direction"),
|
|
||||||
page: z.number().optional().describe("Page number"),
|
|
||||||
per_page: z.number().optional().describe("Number of results per page"),
|
|
||||||
archived: z.boolean().optional().describe("Filter for archived projects"),
|
|
||||||
visibility: z.enum(["public", "internal", "private"]).optional().describe("Filter by project visibility"),
|
|
||||||
with_issues_enabled: z.boolean().optional().describe("Filter projects with issues feature enabled"),
|
|
||||||
with_merge_requests_enabled: z.boolean().optional().describe("Filter projects with merge requests feature enabled"),
|
|
||||||
min_access_level: z.number().optional().describe("Filter by minimum access level"),
|
|
||||||
with_programming_language: z.string().optional().describe("Filter by programming language"),
|
|
||||||
starred: z.boolean().optional().describe("Filter by starred projects"),
|
|
||||||
statistics: z.boolean().optional().describe("Include project statistics"),
|
|
||||||
with_custom_attributes: z.boolean().optional().describe("Include custom attributes"),
|
|
||||||
with_security_reports: z.boolean().optional().describe("Include security reports")
|
|
||||||
});
|
|
@ -1,54 +0,0 @@
|
|||||||
/**
|
|
||||||
* This test file verifies that the createNote function works correctly
|
|
||||||
* with the fixed endpoint URL construction that uses plural resource names
|
|
||||||
* (issues instead of issue, merge_requests instead of merge_request).
|
|
||||||
*/
|
|
||||||
import fetch from "node-fetch";
|
|
||||||
// GitLab API configuration (replace with actual values when testing)
|
|
||||||
const GITLAB_API_URL = process.env.GITLAB_API_URL || "https://gitlab.com";
|
|
||||||
const GITLAB_PERSONAL_ACCESS_TOKEN = process.env.GITLAB_TOKEN || "";
|
|
||||||
const PROJECT_ID = process.env.PROJECT_ID || "your/project";
|
|
||||||
const ISSUE_IID = Number(process.env.ISSUE_IID || "1");
|
|
||||||
async function testCreateIssueNote() {
|
|
||||||
try {
|
|
||||||
// Using plural form "issues" in the URL
|
|
||||||
const url = new URL(`${GITLAB_API_URL}/api/v4/projects/${encodeURIComponent(PROJECT_ID)}/issues/${ISSUE_IID}/notes`);
|
|
||||||
const response = await fetch(url.toString(), {
|
|
||||||
method: "POST",
|
|
||||||
headers: {
|
|
||||||
Accept: "application/json",
|
|
||||||
"Content-Type": "application/json",
|
|
||||||
Authorization: `Bearer ${GITLAB_PERSONAL_ACCESS_TOKEN}`,
|
|
||||||
},
|
|
||||||
body: JSON.stringify({ body: "Test note from API - with plural endpoint" }),
|
|
||||||
});
|
|
||||||
if (!response.ok) {
|
|
||||||
const errorBody = await response.text();
|
|
||||||
throw new Error(`GitLab API error: ${response.status} ${response.statusText}\n${errorBody}`);
|
|
||||||
}
|
|
||||||
const data = await response.json();
|
|
||||||
console.log("Successfully created note:");
|
|
||||||
console.log(JSON.stringify(data, null, 2));
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
catch (error) {
|
|
||||||
console.error("Error creating note:", error);
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
// Only run the test if executed directly
|
|
||||||
if (require.main === module) {
|
|
||||||
console.log("Testing note creation with plural 'issues' endpoint...");
|
|
||||||
testCreateIssueNote().then(success => {
|
|
||||||
if (success) {
|
|
||||||
console.log("✅ Test successful!");
|
|
||||||
process.exit(0);
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
console.log("❌ Test failed!");
|
|
||||||
process.exit(1);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
|
||||||
// Export for use in other tests
|
|
||||||
export { testCreateIssueNote };
|
|
106
package-lock.json
generated
106
package-lock.json
generated
@ -1,17 +1,21 @@
|
|||||||
{
|
{
|
||||||
"name": "@zereight/mcp-gitlab",
|
"name": "@zereight/mcp-gitlab",
|
||||||
"version": "1.0.21",
|
"version": "1.0.38",
|
||||||
"lockfileVersion": 3,
|
"lockfileVersion": 3,
|
||||||
"requires": true,
|
"requires": true,
|
||||||
"packages": {
|
"packages": {
|
||||||
"": {
|
"": {
|
||||||
"name": "@zereight/mcp-gitlab",
|
"name": "@zereight/mcp-gitlab",
|
||||||
"version": "1.0.21",
|
"version": "1.0.38",
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@modelcontextprotocol/sdk": "1.8.0",
|
"@modelcontextprotocol/sdk": "1.8.0",
|
||||||
"@types/node-fetch": "^2.6.12",
|
"@types/node-fetch": "^2.6.12",
|
||||||
|
"form-data": "^4.0.0",
|
||||||
|
"http-proxy-agent": "^7.0.2",
|
||||||
|
"https-proxy-agent": "^7.0.6",
|
||||||
"node-fetch": "^3.3.2",
|
"node-fetch": "^3.3.2",
|
||||||
|
"socks-proxy-agent": "^8.0.5",
|
||||||
"zod-to-json-schema": "^3.23.5"
|
"zod-to-json-schema": "^3.23.5"
|
||||||
},
|
},
|
||||||
"bin": {
|
"bin": {
|
||||||
@ -79,6 +83,15 @@
|
|||||||
"node": ">= 0.6"
|
"node": ">= 0.6"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"node_modules/agent-base": {
|
||||||
|
"version": "7.1.3",
|
||||||
|
"resolved": "https://registry.npmjs.org/agent-base/-/agent-base-7.1.3.tgz",
|
||||||
|
"integrity": "sha512-jRR5wdylq8CkOe6hei19GGZnxM6rBGwFl3Bg0YItGDimvjGtAvdZk4Pu6Cl4u4Igsws4a1fd1Vq3ezrhn4KmFw==",
|
||||||
|
"license": "MIT",
|
||||||
|
"engines": {
|
||||||
|
"node": ">= 14"
|
||||||
|
}
|
||||||
|
},
|
||||||
"node_modules/asynckit": {
|
"node_modules/asynckit": {
|
||||||
"version": "0.4.0",
|
"version": "0.4.0",
|
||||||
"resolved": "https://registry.npmjs.org/asynckit/-/asynckit-0.4.0.tgz",
|
"resolved": "https://registry.npmjs.org/asynckit/-/asynckit-0.4.0.tgz",
|
||||||
@ -713,6 +726,32 @@
|
|||||||
"node": ">= 0.8"
|
"node": ">= 0.8"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"node_modules/http-proxy-agent": {
|
||||||
|
"version": "7.0.2",
|
||||||
|
"resolved": "https://registry.npmjs.org/http-proxy-agent/-/http-proxy-agent-7.0.2.tgz",
|
||||||
|
"integrity": "sha512-T1gkAiYYDWYx3V5Bmyu7HcfcvL7mUrTWiM6yOfa3PIphViJ/gFPbvidQ+veqSOHci/PxBcDabeUNCzpOODJZig==",
|
||||||
|
"license": "MIT",
|
||||||
|
"dependencies": {
|
||||||
|
"agent-base": "^7.1.0",
|
||||||
|
"debug": "^4.3.4"
|
||||||
|
},
|
||||||
|
"engines": {
|
||||||
|
"node": ">= 14"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/https-proxy-agent": {
|
||||||
|
"version": "7.0.6",
|
||||||
|
"resolved": "https://registry.npmjs.org/https-proxy-agent/-/https-proxy-agent-7.0.6.tgz",
|
||||||
|
"integrity": "sha512-vK9P5/iUfdl95AI+JVyUuIcVtd4ofvtrOr3HNtM2yxC9bnMbEdp3x01OhQNnjb8IJYi38VlTE3mBXwcfvywuSw==",
|
||||||
|
"license": "MIT",
|
||||||
|
"dependencies": {
|
||||||
|
"agent-base": "^7.1.2",
|
||||||
|
"debug": "4"
|
||||||
|
},
|
||||||
|
"engines": {
|
||||||
|
"node": ">= 14"
|
||||||
|
}
|
||||||
|
},
|
||||||
"node_modules/iconv-lite": {
|
"node_modules/iconv-lite": {
|
||||||
"version": "0.6.3",
|
"version": "0.6.3",
|
||||||
"resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.6.3.tgz",
|
"resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.6.3.tgz",
|
||||||
@ -731,6 +770,19 @@
|
|||||||
"integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==",
|
"integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==",
|
||||||
"license": "ISC"
|
"license": "ISC"
|
||||||
},
|
},
|
||||||
|
"node_modules/ip-address": {
|
||||||
|
"version": "9.0.5",
|
||||||
|
"resolved": "https://registry.npmjs.org/ip-address/-/ip-address-9.0.5.tgz",
|
||||||
|
"integrity": "sha512-zHtQzGojZXTwZTHQqra+ETKd4Sn3vgi7uBmlPoXVWZqYvuKmtI0l/VZTjqGmJY9x88GGOaZ9+G9ES8hC4T4X8g==",
|
||||||
|
"license": "MIT",
|
||||||
|
"dependencies": {
|
||||||
|
"jsbn": "1.1.0",
|
||||||
|
"sprintf-js": "^1.1.3"
|
||||||
|
},
|
||||||
|
"engines": {
|
||||||
|
"node": ">= 12"
|
||||||
|
}
|
||||||
|
},
|
||||||
"node_modules/ipaddr.js": {
|
"node_modules/ipaddr.js": {
|
||||||
"version": "1.9.1",
|
"version": "1.9.1",
|
||||||
"resolved": "https://registry.npmjs.org/ipaddr.js/-/ipaddr.js-1.9.1.tgz",
|
"resolved": "https://registry.npmjs.org/ipaddr.js/-/ipaddr.js-1.9.1.tgz",
|
||||||
@ -752,6 +804,12 @@
|
|||||||
"integrity": "sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw==",
|
"integrity": "sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw==",
|
||||||
"license": "ISC"
|
"license": "ISC"
|
||||||
},
|
},
|
||||||
|
"node_modules/jsbn": {
|
||||||
|
"version": "1.1.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/jsbn/-/jsbn-1.1.0.tgz",
|
||||||
|
"integrity": "sha512-4bYVV3aAMtDTTu4+xsDYa6sy9GyJ69/amsu9sYF2zqjiEoZA5xJi3BrfX3uY+/IekIu7MwdObdbDWpoZdBv3/A==",
|
||||||
|
"license": "MIT"
|
||||||
|
},
|
||||||
"node_modules/math-intrinsics": {
|
"node_modules/math-intrinsics": {
|
||||||
"version": "1.1.0",
|
"version": "1.1.0",
|
||||||
"resolved": "https://registry.npmjs.org/math-intrinsics/-/math-intrinsics-1.1.0.tgz",
|
"resolved": "https://registry.npmjs.org/math-intrinsics/-/math-intrinsics-1.1.0.tgz",
|
||||||
@ -1201,6 +1259,50 @@
|
|||||||
"url": "https://github.com/sponsors/ljharb"
|
"url": "https://github.com/sponsors/ljharb"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"node_modules/smart-buffer": {
|
||||||
|
"version": "4.2.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/smart-buffer/-/smart-buffer-4.2.0.tgz",
|
||||||
|
"integrity": "sha512-94hK0Hh8rPqQl2xXc3HsaBoOXKV20MToPkcXvwbISWLEs+64sBq5kFgn2kJDHb1Pry9yrP0dxrCI9RRci7RXKg==",
|
||||||
|
"license": "MIT",
|
||||||
|
"engines": {
|
||||||
|
"node": ">= 6.0.0",
|
||||||
|
"npm": ">= 3.0.0"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/socks": {
|
||||||
|
"version": "2.8.4",
|
||||||
|
"resolved": "https://registry.npmjs.org/socks/-/socks-2.8.4.tgz",
|
||||||
|
"integrity": "sha512-D3YaD0aRxR3mEcqnidIs7ReYJFVzWdd6fXJYUM8ixcQcJRGTka/b3saV0KflYhyVJXKhb947GndU35SxYNResQ==",
|
||||||
|
"license": "MIT",
|
||||||
|
"dependencies": {
|
||||||
|
"ip-address": "^9.0.5",
|
||||||
|
"smart-buffer": "^4.2.0"
|
||||||
|
},
|
||||||
|
"engines": {
|
||||||
|
"node": ">= 10.0.0",
|
||||||
|
"npm": ">= 3.0.0"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/socks-proxy-agent": {
|
||||||
|
"version": "8.0.5",
|
||||||
|
"resolved": "https://registry.npmjs.org/socks-proxy-agent/-/socks-proxy-agent-8.0.5.tgz",
|
||||||
|
"integrity": "sha512-HehCEsotFqbPW9sJ8WVYB6UbmIMv7kUUORIF2Nncq4VQvBfNBLibW9YZR5dlYCSUhwcD628pRllm7n+E+YTzJw==",
|
||||||
|
"license": "MIT",
|
||||||
|
"dependencies": {
|
||||||
|
"agent-base": "^7.1.2",
|
||||||
|
"debug": "^4.3.4",
|
||||||
|
"socks": "^2.8.3"
|
||||||
|
},
|
||||||
|
"engines": {
|
||||||
|
"node": ">= 14"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/sprintf-js": {
|
||||||
|
"version": "1.1.3",
|
||||||
|
"resolved": "https://registry.npmjs.org/sprintf-js/-/sprintf-js-1.1.3.tgz",
|
||||||
|
"integrity": "sha512-Oo+0REFV59/rz3gfJNKQiBlwfHaSESl1pcGyABQsnnIfWOFt6JNj5gCog2U6MLZ//IGYD+nA8nI+mTShREReaA==",
|
||||||
|
"license": "BSD-3-Clause"
|
||||||
|
},
|
||||||
"node_modules/statuses": {
|
"node_modules/statuses": {
|
||||||
"version": "2.0.1",
|
"version": "2.0.1",
|
||||||
"resolved": "https://registry.npmjs.org/statuses/-/statuses-2.0.1.tgz",
|
"resolved": "https://registry.npmjs.org/statuses/-/statuses-2.0.1.tgz",
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"name": "@zereight/mcp-gitlab",
|
"name": "@zereight/mcp-gitlab",
|
||||||
"version": "1.0.22",
|
"version": "1.0.45",
|
||||||
"description": "MCP server for using the GitLab API",
|
"description": "MCP server for using the GitLab API",
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"author": "zereight",
|
"author": "zereight",
|
||||||
@ -19,12 +19,17 @@
|
|||||||
"build": "tsc && node -e \"require('fs').chmodSync('build/index.js', '755')\"",
|
"build": "tsc && node -e \"require('fs').chmodSync('build/index.js', '755')\"",
|
||||||
"prepare": "npm run build",
|
"prepare": "npm run build",
|
||||||
"watch": "tsc --watch",
|
"watch": "tsc --watch",
|
||||||
"deploy": "npm run build && npm publish"
|
"deploy": "npm publish --access public",
|
||||||
|
"generate-tools": "npx ts-node scripts/generate-tools-readme.ts"
|
||||||
},
|
},
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@modelcontextprotocol/sdk": "1.8.0",
|
"@modelcontextprotocol/sdk": "1.8.0",
|
||||||
|
"form-data": "^4.0.0",
|
||||||
"@types/node-fetch": "^2.6.12",
|
"@types/node-fetch": "^2.6.12",
|
||||||
|
"http-proxy-agent": "^7.0.2",
|
||||||
|
"https-proxy-agent": "^7.0.6",
|
||||||
"node-fetch": "^3.3.2",
|
"node-fetch": "^3.3.2",
|
||||||
|
"socks-proxy-agent": "^8.0.5",
|
||||||
"zod-to-json-schema": "^3.23.5"
|
"zod-to-json-schema": "^3.23.5"
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
|
5
release-notes.md
Normal file
5
release-notes.md
Normal file
@ -0,0 +1,5 @@
|
|||||||
|
### 1.0.40 (2025-05-21)
|
||||||
|
|
||||||
|
- Added support for listing discussions (comments/notes) on GitLab issues.
|
||||||
|
- Example: You can now easily fetch all conversations (comments) attached to an issue via the API.
|
||||||
|
- Related PR: [#44](https://github.com/zereight/gitlab-mcp/pull/44)
|
641
schemas.ts
641
schemas.ts
@ -7,6 +7,119 @@ export const GitLabAuthorSchema = z.object({
|
|||||||
date: z.string(),
|
date: z.string(),
|
||||||
});
|
});
|
||||||
|
|
||||||
|
// Pipeline related schemas
|
||||||
|
export const GitLabPipelineSchema = z.object({
|
||||||
|
id: z.number(),
|
||||||
|
project_id: z.number(),
|
||||||
|
sha: z.string(),
|
||||||
|
ref: z.string(),
|
||||||
|
status: z.string(),
|
||||||
|
source: z.string().optional(),
|
||||||
|
created_at: z.string(),
|
||||||
|
updated_at: z.string(),
|
||||||
|
web_url: z.string(),
|
||||||
|
duration: z.number().nullable().optional(),
|
||||||
|
started_at: z.string().nullable().optional(),
|
||||||
|
finished_at: z.string().nullable().optional(),
|
||||||
|
coverage: z.number().nullable().optional(),
|
||||||
|
user: z.object({
|
||||||
|
id: z.number(),
|
||||||
|
name: z.string(),
|
||||||
|
username: z.string(),
|
||||||
|
avatar_url: z.string().nullable().optional(),
|
||||||
|
}).optional(),
|
||||||
|
detailed_status: z.object({
|
||||||
|
icon: z.string().optional(),
|
||||||
|
text: z.string().optional(),
|
||||||
|
label: z.string().optional(),
|
||||||
|
group: z.string().optional(),
|
||||||
|
tooltip: z.string().optional(),
|
||||||
|
has_details: z.boolean().optional(),
|
||||||
|
details_path: z.string().optional(),
|
||||||
|
illustration: z.object({
|
||||||
|
image: z.string().optional(),
|
||||||
|
size: z.string().optional(),
|
||||||
|
title: z.string().optional(),
|
||||||
|
}).optional(),
|
||||||
|
favicon: z.string().optional(),
|
||||||
|
}).optional(),
|
||||||
|
});
|
||||||
|
|
||||||
|
// Pipeline job related schemas
|
||||||
|
export const GitLabPipelineJobSchema = z.object({
|
||||||
|
id: z.number(),
|
||||||
|
status: z.string(),
|
||||||
|
stage: z.string(),
|
||||||
|
name: z.string(),
|
||||||
|
ref: z.string(),
|
||||||
|
tag: z.boolean(),
|
||||||
|
coverage: z.number().nullable().optional(),
|
||||||
|
created_at: z.string(),
|
||||||
|
started_at: z.string().nullable().optional(),
|
||||||
|
finished_at: z.string().nullable().optional(),
|
||||||
|
duration: z.number().nullable().optional(),
|
||||||
|
user: z.object({
|
||||||
|
id: z.number(),
|
||||||
|
name: z.string(),
|
||||||
|
username: z.string(),
|
||||||
|
avatar_url: z.string().nullable().optional(),
|
||||||
|
}).optional(),
|
||||||
|
commit: z.object({
|
||||||
|
id: z.string(),
|
||||||
|
short_id: z.string(),
|
||||||
|
title: z.string(),
|
||||||
|
author_name: z.string(),
|
||||||
|
author_email: z.string(),
|
||||||
|
}).optional(),
|
||||||
|
pipeline: z.object({
|
||||||
|
id: z.number(),
|
||||||
|
project_id: z.number(),
|
||||||
|
status: z.string(),
|
||||||
|
ref: z.string(),
|
||||||
|
sha: z.string(),
|
||||||
|
}).optional(),
|
||||||
|
web_url: z.string().optional(),
|
||||||
|
});
|
||||||
|
|
||||||
|
// Schema for listing pipelines
|
||||||
|
export const ListPipelinesSchema = z.object({
|
||||||
|
project_id: z.string().describe("Project ID or URL-encoded path"),
|
||||||
|
scope: z.enum(['running', 'pending', 'finished', 'branches', 'tags']).optional().describe("The scope of pipelines"),
|
||||||
|
status: z.enum(['created', 'waiting_for_resource', 'preparing', 'pending', 'running', 'success', 'failed', 'canceled', 'skipped', 'manual', 'scheduled']).optional().describe("The status of pipelines"),
|
||||||
|
ref: z.string().optional().describe("The ref of pipelines"),
|
||||||
|
sha: z.string().optional().describe("The SHA of pipelines"),
|
||||||
|
yaml_errors: z.boolean().optional().describe("Returns pipelines with invalid configurations"),
|
||||||
|
username: z.string().optional().describe("The username of the user who triggered pipelines"),
|
||||||
|
updated_after: z.string().optional().describe("Return pipelines updated after the specified date"),
|
||||||
|
updated_before: z.string().optional().describe("Return pipelines updated before the specified date"),
|
||||||
|
order_by: z.enum(['id', 'status', 'ref', 'updated_at', 'user_id']).optional().describe("Order pipelines by"),
|
||||||
|
sort: z.enum(['asc', 'desc']).optional().describe("Sort pipelines"),
|
||||||
|
page: z.number().optional().describe("Page number for pagination"),
|
||||||
|
per_page: z.number().optional().describe("Number of items per page (max 100)"),
|
||||||
|
});
|
||||||
|
|
||||||
|
// Schema for getting a specific pipeline
|
||||||
|
export const GetPipelineSchema = z.object({
|
||||||
|
project_id: z.string().describe("Project ID or URL-encoded path"),
|
||||||
|
pipeline_id: z.number().describe("The ID of the pipeline"),
|
||||||
|
});
|
||||||
|
|
||||||
|
// Schema for listing jobs in a pipeline
|
||||||
|
export const ListPipelineJobsSchema = z.object({
|
||||||
|
project_id: z.string().describe("Project ID or URL-encoded path"),
|
||||||
|
pipeline_id: z.number().describe("The ID of the pipeline"),
|
||||||
|
scope: z.enum(['created', 'pending', 'running', 'failed', 'success', 'canceled', 'skipped', 'manual']).optional().describe("The scope of jobs to show"),
|
||||||
|
include_retried: z.boolean().optional().describe("Whether to include retried jobs"),
|
||||||
|
page: z.number().optional().describe("Page number for pagination"),
|
||||||
|
per_page: z.number().optional().describe("Number of items per page (max 100)"),
|
||||||
|
});
|
||||||
|
|
||||||
|
// Schema for the input parameters for pipeline job operations
|
||||||
|
export const GetPipelineJobOutputSchema = z.object({
|
||||||
|
project_id: z.string().describe("Project ID or URL-encoded path"),
|
||||||
|
job_id: z.number().describe("The ID of the job"),
|
||||||
|
});
|
||||||
|
|
||||||
// Namespace related schemas
|
// Namespace related schemas
|
||||||
|
|
||||||
// Base schema for project-related operations
|
// Base schema for project-related operations
|
||||||
@ -63,7 +176,8 @@ export const GitLabRepositorySchema = z.object({
|
|||||||
created_at: z.string().optional(),
|
created_at: z.string().optional(),
|
||||||
last_activity_at: z.string().optional(),
|
last_activity_at: z.string().optional(),
|
||||||
default_branch: z.string().optional(),
|
default_branch: z.string().optional(),
|
||||||
namespace: z.object({
|
namespace: z
|
||||||
|
.object({
|
||||||
id: z.number(),
|
id: z.number(),
|
||||||
name: z.string(),
|
name: z.string(),
|
||||||
path: z.string(),
|
path: z.string(),
|
||||||
@ -71,7 +185,8 @@ export const GitLabRepositorySchema = z.object({
|
|||||||
full_path: z.string(),
|
full_path: z.string(),
|
||||||
avatar_url: z.string().nullable().optional(),
|
avatar_url: z.string().nullable().optional(),
|
||||||
web_url: z.string().optional(),
|
web_url: z.string().optional(),
|
||||||
}).optional(),
|
})
|
||||||
|
.optional(),
|
||||||
readme_url: z.string().optional().nullable(),
|
readme_url: z.string().optional().nullable(),
|
||||||
topics: z.array(z.string()).optional(),
|
topics: z.array(z.string()).optional(),
|
||||||
tag_list: z.array(z.string()).optional(), // deprecated but still present
|
tag_list: z.array(z.string()).optional(), // deprecated but still present
|
||||||
@ -79,16 +194,24 @@ export const GitLabRepositorySchema = z.object({
|
|||||||
archived: z.boolean().optional(),
|
archived: z.boolean().optional(),
|
||||||
forks_count: z.number().optional(),
|
forks_count: z.number().optional(),
|
||||||
star_count: z.number().optional(),
|
star_count: z.number().optional(),
|
||||||
permissions: z.object({
|
permissions: z
|
||||||
project_access: z.object({
|
.object({
|
||||||
|
project_access: z
|
||||||
|
.object({
|
||||||
access_level: z.number(),
|
access_level: z.number(),
|
||||||
notification_level: z.number().optional(),
|
notification_level: z.number().optional(),
|
||||||
}).optional().nullable(),
|
})
|
||||||
group_access: z.object({
|
.optional()
|
||||||
|
.nullable(),
|
||||||
|
group_access: z
|
||||||
|
.object({
|
||||||
access_level: z.number(),
|
access_level: z.number(),
|
||||||
notification_level: z.number().optional(),
|
notification_level: z.number().optional(),
|
||||||
}).optional().nullable(),
|
})
|
||||||
}).optional(),
|
.optional()
|
||||||
|
.nullable(),
|
||||||
|
})
|
||||||
|
.optional(),
|
||||||
container_registry_enabled: z.boolean().optional(),
|
container_registry_enabled: z.boolean().optional(),
|
||||||
container_registry_access_level: z.string().optional(),
|
container_registry_access_level: z.string().optional(),
|
||||||
issues_enabled: z.boolean().optional(),
|
issues_enabled: z.boolean().optional(),
|
||||||
@ -97,14 +220,18 @@ export const GitLabRepositorySchema = z.object({
|
|||||||
jobs_enabled: z.boolean().optional(),
|
jobs_enabled: z.boolean().optional(),
|
||||||
snippets_enabled: z.boolean().optional(),
|
snippets_enabled: z.boolean().optional(),
|
||||||
can_create_merge_request_in: z.boolean().optional(),
|
can_create_merge_request_in: z.boolean().optional(),
|
||||||
resolve_outdated_diff_discussions: z.boolean().optional(),
|
resolve_outdated_diff_discussions: z.boolean().nullable().optional(),
|
||||||
shared_runners_enabled: z.boolean().optional(),
|
shared_runners_enabled: z.boolean().optional(),
|
||||||
shared_with_groups: z.array(z.object({
|
shared_with_groups: z
|
||||||
|
.array(
|
||||||
|
z.object({
|
||||||
group_id: z.number(),
|
group_id: z.number(),
|
||||||
group_name: z.string(),
|
group_name: z.string(),
|
||||||
group_full_path: z.string(),
|
group_full_path: z.string(),
|
||||||
group_access_level: z.number(),
|
group_access_level: z.number(),
|
||||||
})).optional(),
|
})
|
||||||
|
)
|
||||||
|
.optional(),
|
||||||
});
|
});
|
||||||
|
|
||||||
// Project schema (extended from repository schema)
|
// Project schema (extended from repository schema)
|
||||||
@ -146,17 +273,41 @@ export const FileOperationSchema = z.object({
|
|||||||
});
|
});
|
||||||
|
|
||||||
// Tree and commit schemas
|
// Tree and commit schemas
|
||||||
export const GitLabTreeEntrySchema = z.object({
|
export const GitLabTreeItemSchema = z.object({
|
||||||
id: z.string(), // Changed from sha to match GitLab API
|
id: z.string(),
|
||||||
name: z.string(),
|
name: z.string(),
|
||||||
type: z.enum(["blob", "tree"]),
|
type: z.enum(["tree", "blob"]),
|
||||||
path: z.string(),
|
path: z.string(),
|
||||||
mode: z.string(),
|
mode: z.string(),
|
||||||
});
|
});
|
||||||
|
|
||||||
|
export const GetRepositoryTreeSchema = z.object({
|
||||||
|
project_id: z.string().describe("The ID or URL-encoded path of the project"),
|
||||||
|
path: z.string().optional().describe("The path inside the repository"),
|
||||||
|
ref: z
|
||||||
|
.string()
|
||||||
|
.optional()
|
||||||
|
.describe(
|
||||||
|
"The name of a repository branch or tag. Defaults to the default branch."
|
||||||
|
),
|
||||||
|
recursive: z
|
||||||
|
.boolean()
|
||||||
|
.optional()
|
||||||
|
.describe("Boolean value to get a recursive tree"),
|
||||||
|
per_page: z
|
||||||
|
.number()
|
||||||
|
.optional()
|
||||||
|
.describe("Number of results to show per page"),
|
||||||
|
page_token: z
|
||||||
|
.string()
|
||||||
|
.optional()
|
||||||
|
.describe("The tree record ID for pagination"),
|
||||||
|
pagination: z.string().optional().describe("Pagination method (keyset)"),
|
||||||
|
});
|
||||||
|
|
||||||
export const GitLabTreeSchema = z.object({
|
export const GitLabTreeSchema = z.object({
|
||||||
id: z.string(), // Changed from sha to match GitLab API
|
id: z.string(), // Changed from sha to match GitLab API
|
||||||
tree: z.array(GitLabTreeEntrySchema),
|
tree: z.array(GitLabTreeItemSchema),
|
||||||
});
|
});
|
||||||
|
|
||||||
export const GitLabCommitSchema = z.object({
|
export const GitLabCommitSchema = z.object({
|
||||||
@ -276,17 +427,21 @@ export const GitLabIssueSchema = z.object({
|
|||||||
updated_at: z.string(),
|
updated_at: z.string(),
|
||||||
closed_at: z.string().nullable(),
|
closed_at: z.string().nullable(),
|
||||||
web_url: z.string(), // Changed from html_url to match GitLab API
|
web_url: z.string(), // Changed from html_url to match GitLab API
|
||||||
references: z.object({
|
references: z
|
||||||
|
.object({
|
||||||
short: z.string(),
|
short: z.string(),
|
||||||
relative: z.string(),
|
relative: z.string(),
|
||||||
full: z.string(),
|
full: z.string(),
|
||||||
}).optional(),
|
})
|
||||||
time_stats: z.object({
|
.optional(),
|
||||||
|
time_stats: z
|
||||||
|
.object({
|
||||||
time_estimate: z.number(),
|
time_estimate: z.number(),
|
||||||
total_time_spent: z.number(),
|
total_time_spent: z.number(),
|
||||||
human_time_estimate: z.string().nullable(),
|
human_time_estimate: z.string().nullable(),
|
||||||
human_total_time_spent: z.string().nullable(),
|
human_total_time_spent: z.string().nullable(),
|
||||||
}).optional(),
|
})
|
||||||
|
.optional(),
|
||||||
confidential: z.boolean().optional(),
|
confidential: z.boolean().optional(),
|
||||||
due_date: z.string().nullable().optional(),
|
due_date: z.string().nullable().optional(),
|
||||||
discussion_locked: z.boolean().nullable().optional(),
|
discussion_locked: z.boolean().nullable().optional(),
|
||||||
@ -296,7 +451,7 @@ export const GitLabIssueSchema = z.object({
|
|||||||
// NEW SCHEMA: For issue with link details (used in listing issue links)
|
// NEW SCHEMA: For issue with link details (used in listing issue links)
|
||||||
export const GitLabIssueWithLinkDetailsSchema = GitLabIssueSchema.extend({
|
export const GitLabIssueWithLinkDetailsSchema = GitLabIssueSchema.extend({
|
||||||
issue_link_id: z.number(),
|
issue_link_id: z.number(),
|
||||||
link_type: z.enum(['relates_to', 'blocks', 'is_blocked_by']),
|
link_type: z.enum(["relates_to", "blocks", "is_blocked_by"]),
|
||||||
link_created_at: z.string(),
|
link_created_at: z.string(),
|
||||||
link_updated_at: z.string(),
|
link_updated_at: z.string(),
|
||||||
});
|
});
|
||||||
@ -305,11 +460,13 @@ export const GitLabIssueWithLinkDetailsSchema = GitLabIssueSchema.extend({
|
|||||||
export const GitLabForkParentSchema = z.object({
|
export const GitLabForkParentSchema = z.object({
|
||||||
name: z.string(),
|
name: z.string(),
|
||||||
path_with_namespace: z.string(), // Changed from full_name to match GitLab API
|
path_with_namespace: z.string(), // Changed from full_name to match GitLab API
|
||||||
owner: z.object({
|
owner: z
|
||||||
|
.object({
|
||||||
username: z.string(), // Changed from login to match GitLab API
|
username: z.string(), // Changed from login to match GitLab API
|
||||||
id: z.number(),
|
id: z.number(),
|
||||||
avatar_url: z.string(),
|
avatar_url: z.string(),
|
||||||
}).optional(), // Made optional to handle cases where GitLab API doesn't include it
|
})
|
||||||
|
.optional(), // Made optional to handle cases where GitLab API doesn't include it
|
||||||
web_url: z.string(), // Changed from html_url to match GitLab API
|
web_url: z.string(), // Changed from html_url to match GitLab API
|
||||||
});
|
});
|
||||||
|
|
||||||
@ -377,7 +534,9 @@ export const GitLabDiscussionNoteSchema = z.object({
|
|||||||
resolved: z.boolean().optional(),
|
resolved: z.boolean().optional(),
|
||||||
resolved_by: GitLabUserSchema.nullable().optional(),
|
resolved_by: GitLabUserSchema.nullable().optional(),
|
||||||
resolved_at: z.string().nullable().optional(),
|
resolved_at: z.string().nullable().optional(),
|
||||||
position: z.object({ // Only present for DiffNote
|
position: z
|
||||||
|
.object({
|
||||||
|
// Only present for DiffNote
|
||||||
base_sha: z.string(),
|
base_sha: z.string(),
|
||||||
start_sha: z.string(),
|
start_sha: z.string(),
|
||||||
head_sha: z.string(),
|
head_sha: z.string(),
|
||||||
@ -386,25 +545,29 @@ export const GitLabDiscussionNoteSchema = z.object({
|
|||||||
position_type: z.enum(["text", "image", "file"]),
|
position_type: z.enum(["text", "image", "file"]),
|
||||||
old_line: z.number().nullable(),
|
old_line: z.number().nullable(),
|
||||||
new_line: z.number().nullable(),
|
new_line: z.number().nullable(),
|
||||||
line_range: z.object({
|
line_range: z
|
||||||
|
.object({
|
||||||
start: z.object({
|
start: z.object({
|
||||||
line_code: z.string(),
|
line_code: z.string(),
|
||||||
type: z.enum(["new", "old"]),
|
type: z.enum(["new", "old", "expanded"]),
|
||||||
old_line: z.number().nullable(),
|
old_line: z.number().nullable(),
|
||||||
new_line: z.number().nullable(),
|
new_line: z.number().nullable(),
|
||||||
}),
|
}),
|
||||||
end: z.object({
|
end: z.object({
|
||||||
line_code: z.string(),
|
line_code: z.string(),
|
||||||
type: z.enum(["new", "old"]),
|
type: z.enum(["new", "old", "expanded"]),
|
||||||
old_line: z.number().nullable(),
|
old_line: z.number().nullable(),
|
||||||
new_line: z.number().nullable(),
|
new_line: z.number().nullable(),
|
||||||
}),
|
}),
|
||||||
}).nullable().optional(), // For multi-line diff notes
|
})
|
||||||
|
.nullable()
|
||||||
|
.optional(), // For multi-line diff notes
|
||||||
width: z.number().optional(), // For image diff notes
|
width: z.number().optional(), // For image diff notes
|
||||||
height: z.number().optional(), // For image diff notes
|
height: z.number().optional(), // For image diff notes
|
||||||
x: z.number().optional(), // For image diff notes
|
x: z.number().optional(), // For image diff notes
|
||||||
y: z.number().optional(), // For image diff notes
|
y: z.number().optional(), // For image diff notes
|
||||||
}).optional(),
|
})
|
||||||
|
.optional(),
|
||||||
});
|
});
|
||||||
export type GitLabDiscussionNote = z.infer<typeof GitLabDiscussionNoteSchema>;
|
export type GitLabDiscussionNote = z.infer<typeof GitLabDiscussionNoteSchema>;
|
||||||
|
|
||||||
@ -425,8 +588,36 @@ export const UpdateMergeRequestNoteSchema = ProjectParamsSchema.extend({
|
|||||||
merge_request_iid: z.number().describe("The IID of a merge request"),
|
merge_request_iid: z.number().describe("The IID of a merge request"),
|
||||||
discussion_id: z.string().describe("The ID of a thread"),
|
discussion_id: z.string().describe("The ID of a thread"),
|
||||||
note_id: z.number().describe("The ID of a thread note"),
|
note_id: z.number().describe("The ID of a thread note"),
|
||||||
|
body: z.string().optional().describe("The content of the note or reply"),
|
||||||
|
resolved: z.boolean().optional().describe("Resolve or unresolve the note"),
|
||||||
|
}).refine(data => data.body !== undefined || data.resolved !== undefined, {
|
||||||
|
message: "At least one of 'body' or 'resolved' must be provided"
|
||||||
|
}).refine(data => !(data.body !== undefined && data.resolved !== undefined), {
|
||||||
|
message: "Only one of 'body' or 'resolved' can be provided, not both"
|
||||||
|
});
|
||||||
|
|
||||||
|
// Input schema for adding a note to an existing merge request discussion
|
||||||
|
export const CreateMergeRequestNoteSchema = ProjectParamsSchema.extend({
|
||||||
|
merge_request_iid: z.number().describe("The IID of a merge request"),
|
||||||
|
discussion_id: z.string().describe("The ID of a thread"),
|
||||||
body: z.string().describe("The content of the note or reply"),
|
body: z.string().describe("The content of the note or reply"),
|
||||||
resolved: z.boolean().optional().describe("Resolve or unresolve the note"), // Optional based on API docs
|
created_at: z.string().optional().describe("Date the note was created at (ISO 8601 format)"),
|
||||||
|
});
|
||||||
|
|
||||||
|
// Input schema for updating an issue discussion note
|
||||||
|
export const UpdateIssueNoteSchema = ProjectParamsSchema.extend({
|
||||||
|
issue_iid: z.number().describe("The IID of an issue"),
|
||||||
|
discussion_id: z.string().describe("The ID of a thread"),
|
||||||
|
note_id: z.number().describe("The ID of a thread note"),
|
||||||
|
body: z.string().describe("The content of the note or reply"),
|
||||||
|
});
|
||||||
|
|
||||||
|
// Input schema for adding a note to an existing issue discussion
|
||||||
|
export const CreateIssueNoteSchema = ProjectParamsSchema.extend({
|
||||||
|
issue_iid: z.number().describe("The IID of an issue"),
|
||||||
|
discussion_id: z.string().describe("The ID of a thread"),
|
||||||
|
body: z.string().describe("The content of the note or reply"),
|
||||||
|
created_at: z.string().optional().describe("Date the note was created at (ISO 8601 format)"),
|
||||||
});
|
});
|
||||||
|
|
||||||
// API Operation Parameter Schemas
|
// API Operation Parameter Schemas
|
||||||
@ -440,10 +631,7 @@ export const CreateOrUpdateFileSchema = ProjectParamsSchema.extend({
|
|||||||
.string()
|
.string()
|
||||||
.optional()
|
.optional()
|
||||||
.describe("Path of the file to move/rename"),
|
.describe("Path of the file to move/rename"),
|
||||||
last_commit_id: z
|
last_commit_id: z.string().optional().describe("Last known file commit ID"),
|
||||||
.string()
|
|
||||||
.optional()
|
|
||||||
.describe("Last known file commit ID"),
|
|
||||||
commit_id: z
|
commit_id: z
|
||||||
.string()
|
.string()
|
||||||
.optional()
|
.optional()
|
||||||
@ -539,7 +727,9 @@ export const GitLabMergeRequestDiffSchema = z.object({
|
|||||||
export const GetMergeRequestSchema = ProjectParamsSchema.extend({
|
export const GetMergeRequestSchema = ProjectParamsSchema.extend({
|
||||||
merge_request_iid: z
|
merge_request_iid: z
|
||||||
.number()
|
.number()
|
||||||
.describe("The internal ID of the merge request"),
|
.optional()
|
||||||
|
.describe("The IID of a merge request"),
|
||||||
|
source_branch: z.string().optional().describe("Source branch name"),
|
||||||
});
|
});
|
||||||
|
|
||||||
export const UpdateMergeRequestSchema = GetMergeRequestSchema.extend({
|
export const UpdateMergeRequestSchema = GetMergeRequestSchema.extend({
|
||||||
@ -585,22 +775,61 @@ export const CreateNoteSchema = z.object({
|
|||||||
// Issues API operation schemas
|
// Issues API operation schemas
|
||||||
export const ListIssuesSchema = z.object({
|
export const ListIssuesSchema = z.object({
|
||||||
project_id: z.string().describe("Project ID or URL-encoded path"),
|
project_id: z.string().describe("Project ID or URL-encoded path"),
|
||||||
assignee_id: z.number().optional().describe("Return issues assigned to the given user ID"),
|
assignee_id: z
|
||||||
assignee_username: z.string().optional().describe("Return issues assigned to the given username"),
|
.number()
|
||||||
author_id: z.number().optional().describe("Return issues created by the given user ID"),
|
.optional()
|
||||||
author_username: z.string().optional().describe("Return issues created by the given username"),
|
.describe("Return issues assigned to the given user ID"),
|
||||||
confidential: z.boolean().optional().describe("Filter confidential or public issues"),
|
assignee_username: z
|
||||||
created_after: z.string().optional().describe("Return issues created after the given time"),
|
.string()
|
||||||
created_before: z.string().optional().describe("Return issues created before the given time"),
|
.optional()
|
||||||
due_date: z.string().optional().describe("Return issues that have the due date"),
|
.describe("Return issues assigned to the given username"),
|
||||||
|
author_id: z
|
||||||
|
.number()
|
||||||
|
.optional()
|
||||||
|
.describe("Return issues created by the given user ID"),
|
||||||
|
author_username: z
|
||||||
|
.string()
|
||||||
|
.optional()
|
||||||
|
.describe("Return issues created by the given username"),
|
||||||
|
confidential: z
|
||||||
|
.boolean()
|
||||||
|
.optional()
|
||||||
|
.describe("Filter confidential or public issues"),
|
||||||
|
created_after: z
|
||||||
|
.string()
|
||||||
|
.optional()
|
||||||
|
.describe("Return issues created after the given time"),
|
||||||
|
created_before: z
|
||||||
|
.string()
|
||||||
|
.optional()
|
||||||
|
.describe("Return issues created before the given time"),
|
||||||
|
due_date: z
|
||||||
|
.string()
|
||||||
|
.optional()
|
||||||
|
.describe("Return issues that have the due date"),
|
||||||
label_name: z.array(z.string()).optional().describe("Array of label names"),
|
label_name: z.array(z.string()).optional().describe("Array of label names"),
|
||||||
milestone: z.string().optional().describe("Milestone title"),
|
milestone: z.string().optional().describe("Milestone title"),
|
||||||
scope: z.enum(['created-by-me', 'assigned-to-me', 'all']).optional().describe("Return issues from a specific scope"),
|
scope: z
|
||||||
|
.enum(["created-by-me", "assigned-to-me", "all"])
|
||||||
|
.optional()
|
||||||
|
.describe("Return issues from a specific scope"),
|
||||||
search: z.string().optional().describe("Search for specific terms"),
|
search: z.string().optional().describe("Search for specific terms"),
|
||||||
state: z.enum(['opened', 'closed', 'all']).optional().describe("Return issues with a specific state"),
|
state: z
|
||||||
updated_after: z.string().optional().describe("Return issues updated after the given time"),
|
.enum(["opened", "closed", "all"])
|
||||||
updated_before: z.string().optional().describe("Return issues updated before the given time"),
|
.optional()
|
||||||
with_labels_details: z.boolean().optional().describe("Return more details for each label"),
|
.describe("Return issues with a specific state"),
|
||||||
|
updated_after: z
|
||||||
|
.string()
|
||||||
|
.optional()
|
||||||
|
.describe("Return issues updated after the given time"),
|
||||||
|
updated_before: z
|
||||||
|
.string()
|
||||||
|
.optional()
|
||||||
|
.describe("Return issues updated before the given time"),
|
||||||
|
with_labels_details: z
|
||||||
|
.boolean()
|
||||||
|
.optional()
|
||||||
|
.describe("Return more details for each label"),
|
||||||
page: z.number().optional().describe("Page number for pagination"),
|
page: z.number().optional().describe("Page number for pagination"),
|
||||||
per_page: z.number().optional().describe("Number of items per page"),
|
per_page: z.number().optional().describe("Number of items per page"),
|
||||||
});
|
});
|
||||||
@ -615,13 +844,28 @@ export const UpdateIssueSchema = z.object({
|
|||||||
issue_iid: z.number().describe("The internal ID of the project issue"),
|
issue_iid: z.number().describe("The internal ID of the project issue"),
|
||||||
title: z.string().optional().describe("The title of the issue"),
|
title: z.string().optional().describe("The title of the issue"),
|
||||||
description: z.string().optional().describe("The description of the issue"),
|
description: z.string().optional().describe("The description of the issue"),
|
||||||
assignee_ids: z.array(z.number()).optional().describe("Array of user IDs to assign issue to"),
|
assignee_ids: z
|
||||||
confidential: z.boolean().optional().describe("Set the issue to be confidential"),
|
.array(z.number())
|
||||||
discussion_locked: z.boolean().optional().describe("Flag to lock discussions"),
|
.optional()
|
||||||
due_date: z.string().optional().describe("Date the issue is due (YYYY-MM-DD)"),
|
.describe("Array of user IDs to assign issue to"),
|
||||||
|
confidential: z
|
||||||
|
.boolean()
|
||||||
|
.optional()
|
||||||
|
.describe("Set the issue to be confidential"),
|
||||||
|
discussion_locked: z
|
||||||
|
.boolean()
|
||||||
|
.optional()
|
||||||
|
.describe("Flag to lock discussions"),
|
||||||
|
due_date: z
|
||||||
|
.string()
|
||||||
|
.optional()
|
||||||
|
.describe("Date the issue is due (YYYY-MM-DD)"),
|
||||||
labels: z.array(z.string()).optional().describe("Array of label names"),
|
labels: z.array(z.string()).optional().describe("Array of label names"),
|
||||||
milestone_id: z.number().optional().describe("Milestone ID to assign"),
|
milestone_id: z.number().optional().describe("Milestone ID to assign"),
|
||||||
state_event: z.enum(['close', 'reopen']).optional().describe("Update issue state (close/reopen)"),
|
state_event: z
|
||||||
|
.enum(["close", "reopen"])
|
||||||
|
.optional()
|
||||||
|
.describe("Update issue state (close/reopen)"),
|
||||||
weight: z.number().optional().describe("Weight of the issue (0-9)"),
|
weight: z.number().optional().describe("Weight of the issue (0-9)"),
|
||||||
});
|
});
|
||||||
|
|
||||||
@ -634,7 +878,7 @@ export const DeleteIssueSchema = z.object({
|
|||||||
export const GitLabIssueLinkSchema = z.object({
|
export const GitLabIssueLinkSchema = z.object({
|
||||||
source_issue: GitLabIssueSchema,
|
source_issue: GitLabIssueSchema,
|
||||||
target_issue: GitLabIssueSchema,
|
target_issue: GitLabIssueSchema,
|
||||||
link_type: z.enum(['relates_to', 'blocks', 'is_blocked_by']),
|
link_type: z.enum(["relates_to", "blocks", "is_blocked_by"]),
|
||||||
});
|
});
|
||||||
|
|
||||||
export const ListIssueLinksSchema = z.object({
|
export const ListIssueLinksSchema = z.object({
|
||||||
@ -642,6 +886,15 @@ export const ListIssueLinksSchema = z.object({
|
|||||||
issue_iid: z.number().describe("The internal ID of a project's issue"),
|
issue_iid: z.number().describe("The internal ID of a project's issue"),
|
||||||
});
|
});
|
||||||
|
|
||||||
|
export const ListIssueDiscussionsSchema = z.object({
|
||||||
|
project_id: z.string().describe("Project ID or URL-encoded path"),
|
||||||
|
issue_iid: z.number().describe("The internal ID of the project issue"),
|
||||||
|
page: z.number().optional().describe("Page number for pagination"),
|
||||||
|
per_page: z.number().optional().describe("Number of items per page"),
|
||||||
|
sort: z.enum(["asc", "desc"]).optional().describe("Return issue discussions sorted in ascending or descending order"),
|
||||||
|
order_by: z.enum(["created_at", "updated_at"]).optional().describe("Return issue discussions ordered by created_at or updated_at fields"),
|
||||||
|
});
|
||||||
|
|
||||||
export const GetIssueLinkSchema = z.object({
|
export const GetIssueLinkSchema = z.object({
|
||||||
project_id: z.string().describe("Project ID or URL-encoded path"),
|
project_id: z.string().describe("Project ID or URL-encoded path"),
|
||||||
issue_iid: z.number().describe("The internal ID of a project's issue"),
|
issue_iid: z.number().describe("The internal ID of a project's issue"),
|
||||||
@ -651,9 +904,16 @@ export const GetIssueLinkSchema = z.object({
|
|||||||
export const CreateIssueLinkSchema = z.object({
|
export const CreateIssueLinkSchema = z.object({
|
||||||
project_id: z.string().describe("Project ID or URL-encoded path"),
|
project_id: z.string().describe("Project ID or URL-encoded path"),
|
||||||
issue_iid: z.number().describe("The internal ID of a project's issue"),
|
issue_iid: z.number().describe("The internal ID of a project's issue"),
|
||||||
target_project_id: z.string().describe("The ID or URL-encoded path of a target project"),
|
target_project_id: z
|
||||||
target_issue_iid: z.number().describe("The internal ID of a target project's issue"),
|
.string()
|
||||||
link_type: z.enum(['relates_to', 'blocks', 'is_blocked_by']).optional().describe("The type of the relation, defaults to relates_to"),
|
.describe("The ID or URL-encoded path of a target project"),
|
||||||
|
target_issue_iid: z
|
||||||
|
.number()
|
||||||
|
.describe("The internal ID of a target project's issue"),
|
||||||
|
link_type: z
|
||||||
|
.enum(["relates_to", "blocks", "is_blocked_by"])
|
||||||
|
.optional()
|
||||||
|
.describe("The type of the relation, defaults to relates_to"),
|
||||||
});
|
});
|
||||||
|
|
||||||
export const DeleteIssueLinkSchema = z.object({
|
export const DeleteIssueLinkSchema = z.object({
|
||||||
@ -667,7 +927,10 @@ export const ListNamespacesSchema = z.object({
|
|||||||
search: z.string().optional().describe("Search term for namespaces"),
|
search: z.string().optional().describe("Search term for namespaces"),
|
||||||
page: z.number().optional().describe("Page number for pagination"),
|
page: z.number().optional().describe("Page number for pagination"),
|
||||||
per_page: z.number().optional().describe("Number of items per page"),
|
per_page: z.number().optional().describe("Number of items per page"),
|
||||||
owned: z.boolean().optional().describe("Filter for namespaces owned by current user"),
|
owned: z
|
||||||
|
.boolean()
|
||||||
|
.optional()
|
||||||
|
.describe("Filter for namespaces owned by current user"),
|
||||||
});
|
});
|
||||||
|
|
||||||
export const GetNamespaceSchema = z.object({
|
export const GetNamespaceSchema = z.object({
|
||||||
@ -687,99 +950,291 @@ export const ListProjectsSchema = z.object({
|
|||||||
search: z.string().optional().describe("Search term for projects"),
|
search: z.string().optional().describe("Search term for projects"),
|
||||||
page: z.number().optional().describe("Page number for pagination"),
|
page: z.number().optional().describe("Page number for pagination"),
|
||||||
per_page: z.number().optional().describe("Number of items per page"),
|
per_page: z.number().optional().describe("Number of items per page"),
|
||||||
owned: z.boolean().optional().describe("Filter for projects owned by current user"),
|
search_namespaces: z
|
||||||
membership: z.boolean().optional().describe("Filter for projects where current user is a member"),
|
.boolean()
|
||||||
|
.optional()
|
||||||
|
.describe("Needs to be true if search is full path"),
|
||||||
|
owned: z
|
||||||
|
.boolean()
|
||||||
|
.optional()
|
||||||
|
.describe("Filter for projects owned by current user"),
|
||||||
|
membership: z
|
||||||
|
.boolean()
|
||||||
|
.optional()
|
||||||
|
.describe("Filter for projects where current user is a member"),
|
||||||
simple: z.boolean().optional().describe("Return only limited fields"),
|
simple: z.boolean().optional().describe("Return only limited fields"),
|
||||||
archived: z.boolean().optional().describe("Filter for archived projects"),
|
archived: z.boolean().optional().describe("Filter for archived projects"),
|
||||||
visibility: z.enum(["public", "internal", "private"]).optional().describe("Filter by project visibility"),
|
visibility: z
|
||||||
order_by: z.enum(["id", "name", "path", "created_at", "updated_at", "last_activity_at"]).optional().describe("Return projects ordered by field"),
|
.enum(["public", "internal", "private"])
|
||||||
sort: z.enum(["asc", "desc"]).optional().describe("Return projects sorted in ascending or descending order"),
|
.optional()
|
||||||
with_issues_enabled: z.boolean().optional().describe("Filter projects with issues feature enabled"),
|
.describe("Filter by project visibility"),
|
||||||
with_merge_requests_enabled: z.boolean().optional().describe("Filter projects with merge requests feature enabled"),
|
order_by: z
|
||||||
min_access_level: z.number().optional().describe("Filter by minimum access level"),
|
.enum([
|
||||||
|
"id",
|
||||||
|
"name",
|
||||||
|
"path",
|
||||||
|
"created_at",
|
||||||
|
"updated_at",
|
||||||
|
"last_activity_at",
|
||||||
|
])
|
||||||
|
.optional()
|
||||||
|
.describe("Return projects ordered by field"),
|
||||||
|
sort: z
|
||||||
|
.enum(["asc", "desc"])
|
||||||
|
.optional()
|
||||||
|
.describe("Return projects sorted in ascending or descending order"),
|
||||||
|
with_issues_enabled: z
|
||||||
|
.boolean()
|
||||||
|
.optional()
|
||||||
|
.describe("Filter projects with issues feature enabled"),
|
||||||
|
with_merge_requests_enabled: z
|
||||||
|
.boolean()
|
||||||
|
.optional()
|
||||||
|
.describe("Filter projects with merge requests feature enabled"),
|
||||||
|
min_access_level: z
|
||||||
|
.number()
|
||||||
|
.optional()
|
||||||
|
.describe("Filter by minimum access level"),
|
||||||
});
|
});
|
||||||
|
|
||||||
// Label operation schemas
|
// Label operation schemas
|
||||||
export const ListLabelsSchema = z.object({
|
export const ListLabelsSchema = z.object({
|
||||||
project_id: z.string().describe("Project ID or URL-encoded path"),
|
project_id: z.string().describe("Project ID or URL-encoded path"),
|
||||||
with_counts: z.boolean().optional().describe("Whether or not to include issue and merge request counts"),
|
with_counts: z
|
||||||
include_ancestor_groups: z.boolean().optional().describe("Include ancestor groups"),
|
.boolean()
|
||||||
|
.optional()
|
||||||
|
.describe("Whether or not to include issue and merge request counts"),
|
||||||
|
include_ancestor_groups: z
|
||||||
|
.boolean()
|
||||||
|
.optional()
|
||||||
|
.describe("Include ancestor groups"),
|
||||||
search: z.string().optional().describe("Keyword to filter labels by"),
|
search: z.string().optional().describe("Keyword to filter labels by"),
|
||||||
});
|
});
|
||||||
|
|
||||||
export const GetLabelSchema = z.object({
|
export const GetLabelSchema = z.object({
|
||||||
project_id: z.string().describe("Project ID or URL-encoded path"),
|
project_id: z.string().describe("Project ID or URL-encoded path"),
|
||||||
label_id: z.union([z.number(), z.string()]).describe("The ID or title of a project's label"),
|
label_id: z.string().describe("The ID or title of a project's label"),
|
||||||
include_ancestor_groups: z.boolean().optional().describe("Include ancestor groups"),
|
include_ancestor_groups: z
|
||||||
|
.boolean()
|
||||||
|
.optional()
|
||||||
|
.describe("Include ancestor groups"),
|
||||||
});
|
});
|
||||||
|
|
||||||
export const CreateLabelSchema = z.object({
|
export const CreateLabelSchema = z.object({
|
||||||
project_id: z.string().describe("Project ID or URL-encoded path"),
|
project_id: z.string().describe("Project ID or URL-encoded path"),
|
||||||
name: z.string().describe("The name of the label"),
|
name: z.string().describe("The name of the label"),
|
||||||
color: z.string().describe("The color of the label given in 6-digit hex notation with leading '#' sign"),
|
color: z
|
||||||
|
.string()
|
||||||
|
.describe(
|
||||||
|
"The color of the label given in 6-digit hex notation with leading '#' sign"
|
||||||
|
),
|
||||||
description: z.string().optional().describe("The description of the label"),
|
description: z.string().optional().describe("The description of the label"),
|
||||||
priority: z.number().nullable().optional().describe("The priority of the label"),
|
priority: z
|
||||||
|
.number()
|
||||||
|
.nullable()
|
||||||
|
.optional()
|
||||||
|
.describe("The priority of the label"),
|
||||||
});
|
});
|
||||||
|
|
||||||
export const UpdateLabelSchema = z.object({
|
export const UpdateLabelSchema = z.object({
|
||||||
project_id: z.string().describe("Project ID or URL-encoded path"),
|
project_id: z.string().describe("Project ID or URL-encoded path"),
|
||||||
label_id: z.union([z.number(), z.string()]).describe("The ID or title of a project's label"),
|
label_id: z.string().describe("The ID or title of a project's label"),
|
||||||
new_name: z.string().optional().describe("The new name of the label"),
|
new_name: z.string().optional().describe("The new name of the label"),
|
||||||
color: z.string().optional().describe("The color of the label given in 6-digit hex notation with leading '#' sign"),
|
color: z
|
||||||
description: z.string().optional().describe("The new description of the label"),
|
.string()
|
||||||
priority: z.number().nullable().optional().describe("The new priority of the label"),
|
.optional()
|
||||||
|
.describe(
|
||||||
|
"The color of the label given in 6-digit hex notation with leading '#' sign"
|
||||||
|
),
|
||||||
|
description: z
|
||||||
|
.string()
|
||||||
|
.optional()
|
||||||
|
.describe("The new description of the label"),
|
||||||
|
priority: z
|
||||||
|
.number()
|
||||||
|
.nullable()
|
||||||
|
.optional()
|
||||||
|
.describe("The new priority of the label"),
|
||||||
});
|
});
|
||||||
|
|
||||||
export const DeleteLabelSchema = z.object({
|
export const DeleteLabelSchema = z.object({
|
||||||
project_id: z.string().describe("Project ID or URL-encoded path"),
|
project_id: z.string().describe("Project ID or URL-encoded path"),
|
||||||
label_id: z.union([z.number(), z.string()]).describe("The ID or title of a project's label"),
|
label_id: z.string().describe("The ID or title of a project's label"),
|
||||||
});
|
});
|
||||||
|
|
||||||
// Group projects schema
|
// Group projects schema
|
||||||
export const ListGroupProjectsSchema = z.object({
|
export const ListGroupProjectsSchema = z.object({
|
||||||
group_id: z.string().describe("Group ID or path"),
|
group_id: z.string().describe("Group ID or path"),
|
||||||
include_subgroups: z.boolean().optional().describe("Include projects from subgroups"),
|
include_subgroups: z
|
||||||
|
.boolean()
|
||||||
|
.optional()
|
||||||
|
.describe("Include projects from subgroups"),
|
||||||
search: z.string().optional().describe("Search term to filter projects"),
|
search: z.string().optional().describe("Search term to filter projects"),
|
||||||
order_by: z.enum(['name', 'path', 'created_at', 'updated_at', 'last_activity_at']).optional().describe("Field to sort by"),
|
order_by: z
|
||||||
sort: z.enum(['asc', 'desc']).optional().describe("Sort direction"),
|
.enum(["name", "path", "created_at", "updated_at", "last_activity_at"])
|
||||||
|
.optional()
|
||||||
|
.describe("Field to sort by"),
|
||||||
|
sort: z.enum(["asc", "desc"]).optional().describe("Sort direction"),
|
||||||
page: z.number().optional().describe("Page number"),
|
page: z.number().optional().describe("Page number"),
|
||||||
per_page: z.number().optional().describe("Number of results per page"),
|
per_page: z.number().optional().describe("Number of results per page"),
|
||||||
archived: z.boolean().optional().describe("Filter for archived projects"),
|
archived: z.boolean().optional().describe("Filter for archived projects"),
|
||||||
visibility: z.enum(["public", "internal", "private"]).optional().describe("Filter by project visibility"),
|
visibility: z
|
||||||
with_issues_enabled: z.boolean().optional().describe("Filter projects with issues feature enabled"),
|
.enum(["public", "internal", "private"])
|
||||||
with_merge_requests_enabled: z.boolean().optional().describe("Filter projects with merge requests feature enabled"),
|
.optional()
|
||||||
min_access_level: z.number().optional().describe("Filter by minimum access level"),
|
.describe("Filter by project visibility"),
|
||||||
with_programming_language: z.string().optional().describe("Filter by programming language"),
|
with_issues_enabled: z
|
||||||
|
.boolean()
|
||||||
|
.optional()
|
||||||
|
.describe("Filter projects with issues feature enabled"),
|
||||||
|
with_merge_requests_enabled: z
|
||||||
|
.boolean()
|
||||||
|
.optional()
|
||||||
|
.describe("Filter projects with merge requests feature enabled"),
|
||||||
|
min_access_level: z
|
||||||
|
.number()
|
||||||
|
.optional()
|
||||||
|
.describe("Filter by minimum access level"),
|
||||||
|
with_programming_language: z
|
||||||
|
.string()
|
||||||
|
.optional()
|
||||||
|
.describe("Filter by programming language"),
|
||||||
starred: z.boolean().optional().describe("Filter by starred projects"),
|
starred: z.boolean().optional().describe("Filter by starred projects"),
|
||||||
statistics: z.boolean().optional().describe("Include project statistics"),
|
statistics: z.boolean().optional().describe("Include project statistics"),
|
||||||
with_custom_attributes: z.boolean().optional().describe("Include custom attributes"),
|
with_custom_attributes: z
|
||||||
with_security_reports: z.boolean().optional().describe("Include security reports")
|
.boolean()
|
||||||
|
.optional()
|
||||||
|
.describe("Include custom attributes"),
|
||||||
|
with_security_reports: z
|
||||||
|
.boolean()
|
||||||
|
.optional()
|
||||||
|
.describe("Include security reports"),
|
||||||
|
});
|
||||||
|
|
||||||
|
// Add wiki operation schemas
|
||||||
|
export const ListWikiPagesSchema = z.object({
|
||||||
|
project_id: z.string().describe("Project ID or URL-encoded path"),
|
||||||
|
page: z.number().optional().describe("Page number for pagination"),
|
||||||
|
per_page: z.number().optional().describe("Number of items per page"),
|
||||||
|
});
|
||||||
|
export const GetWikiPageSchema = z.object({
|
||||||
|
project_id: z.string().describe("Project ID or URL-encoded path"),
|
||||||
|
slug: z.string().describe("URL-encoded slug of the wiki page"),
|
||||||
|
});
|
||||||
|
export const CreateWikiPageSchema = z.object({
|
||||||
|
project_id: z.string().describe("Project ID or URL-encoded path"),
|
||||||
|
title: z.string().describe("Title of the wiki page"),
|
||||||
|
content: z.string().describe("Content of the wiki page"),
|
||||||
|
format: z
|
||||||
|
.string()
|
||||||
|
.optional()
|
||||||
|
.describe("Content format, e.g., markdown, rdoc"),
|
||||||
|
});
|
||||||
|
export const UpdateWikiPageSchema = z.object({
|
||||||
|
project_id: z.string().describe("Project ID or URL-encoded path"),
|
||||||
|
slug: z.string().describe("URL-encoded slug of the wiki page"),
|
||||||
|
title: z.string().optional().describe("New title of the wiki page"),
|
||||||
|
content: z.string().optional().describe("New content of the wiki page"),
|
||||||
|
format: z
|
||||||
|
.string()
|
||||||
|
.optional()
|
||||||
|
.describe("Content format, e.g., markdown, rdoc"),
|
||||||
|
});
|
||||||
|
export const DeleteWikiPageSchema = z.object({
|
||||||
|
project_id: z.string().describe("Project ID or URL-encoded path"),
|
||||||
|
slug: z.string().describe("URL-encoded slug of the wiki page"),
|
||||||
|
});
|
||||||
|
|
||||||
|
// Define wiki response schemas
|
||||||
|
export const GitLabWikiPageSchema = z.object({
|
||||||
|
title: z.string(),
|
||||||
|
slug: z.string(),
|
||||||
|
format: z.string(),
|
||||||
|
content: z.string(),
|
||||||
|
created_at: z.string().optional(),
|
||||||
|
updated_at: z.string().optional(),
|
||||||
|
});
|
||||||
|
|
||||||
|
// Merge Request Thread position schema - used for diff notes
|
||||||
|
export const MergeRequestThreadPositionSchema = z.object({
|
||||||
|
base_sha: z.string().describe("Base commit SHA in the source branch"),
|
||||||
|
head_sha: z.string().describe("SHA referencing HEAD of the source branch"),
|
||||||
|
start_sha: z.string().describe("SHA referencing the start commit of the source branch"),
|
||||||
|
position_type: z.enum(["text", "image", "file"]).describe("Type of position reference"),
|
||||||
|
new_path: z.string().optional().describe("File path after change"),
|
||||||
|
old_path: z.string().optional().describe("File path before change"),
|
||||||
|
new_line: z.number().nullable().optional().describe("Line number after change"),
|
||||||
|
old_line: z.number().nullable().optional().describe("Line number before change"),
|
||||||
|
width: z.number().optional().describe("Width of the image (for image diffs)"),
|
||||||
|
height: z.number().optional().describe("Height of the image (for image diffs)"),
|
||||||
|
x: z.number().optional().describe("X coordinate on the image (for image diffs)"),
|
||||||
|
y: z.number().optional().describe("Y coordinate on the image (for image diffs)"),
|
||||||
|
});
|
||||||
|
|
||||||
|
// Schema for creating a new merge request thread
|
||||||
|
export const CreateMergeRequestThreadSchema = ProjectParamsSchema.extend({
|
||||||
|
merge_request_iid: z.number().describe("The IID of a merge request"),
|
||||||
|
body: z.string().describe("The content of the thread"),
|
||||||
|
position: MergeRequestThreadPositionSchema.optional().describe("Position when creating a diff note"),
|
||||||
|
created_at: z.string().optional().describe("Date the thread was created at (ISO 8601 format)"),
|
||||||
});
|
});
|
||||||
|
|
||||||
// Export types
|
// Export types
|
||||||
export type GitLabAuthor = z.infer<typeof GitLabAuthorSchema>;
|
export type GitLabAuthor = z.infer<typeof GitLabAuthorSchema>;
|
||||||
export type GitLabFork = z.infer<typeof GitLabForkSchema>;
|
export type GitLabFork = z.infer<typeof GitLabForkSchema>;
|
||||||
export type GitLabIssue = z.infer<typeof GitLabIssueSchema>;
|
export type GitLabIssue = z.infer<typeof GitLabIssueSchema>;
|
||||||
export type GitLabIssueWithLinkDetails = z.infer<typeof GitLabIssueWithLinkDetailsSchema>;
|
export type GitLabIssueWithLinkDetails = z.infer<
|
||||||
|
typeof GitLabIssueWithLinkDetailsSchema
|
||||||
|
>;
|
||||||
export type GitLabMergeRequest = z.infer<typeof GitLabMergeRequestSchema>;
|
export type GitLabMergeRequest = z.infer<typeof GitLabMergeRequestSchema>;
|
||||||
export type GitLabRepository = z.infer<typeof GitLabRepositorySchema>;
|
export type GitLabRepository = z.infer<typeof GitLabRepositorySchema>;
|
||||||
export type GitLabFileContent = z.infer<typeof GitLabFileContentSchema>;
|
export type GitLabFileContent = z.infer<typeof GitLabFileContentSchema>;
|
||||||
export type GitLabDirectoryContent = z.infer<typeof GitLabDirectoryContentSchema>;
|
export type GitLabDirectoryContent = z.infer<
|
||||||
|
typeof GitLabDirectoryContentSchema
|
||||||
|
>;
|
||||||
export type GitLabContent = z.infer<typeof GitLabContentSchema>;
|
export type GitLabContent = z.infer<typeof GitLabContentSchema>;
|
||||||
export type FileOperation = z.infer<typeof FileOperationSchema>;
|
export type FileOperation = z.infer<typeof FileOperationSchema>;
|
||||||
export type GitLabTree = z.infer<typeof GitLabTreeSchema>;
|
export type GitLabTree = z.infer<typeof GitLabTreeSchema>;
|
||||||
export type GitLabCommit = z.infer<typeof GitLabCommitSchema>;
|
export type GitLabCommit = z.infer<typeof GitLabCommitSchema>;
|
||||||
export type GitLabReference = z.infer<typeof GitLabReferenceSchema>;
|
export type GitLabReference = z.infer<typeof GitLabReferenceSchema>;
|
||||||
export type CreateRepositoryOptions = z.infer<typeof CreateRepositoryOptionsSchema>;
|
export type CreateRepositoryOptions = z.infer<
|
||||||
|
typeof CreateRepositoryOptionsSchema
|
||||||
|
>;
|
||||||
export type CreateIssueOptions = z.infer<typeof CreateIssueOptionsSchema>;
|
export type CreateIssueOptions = z.infer<typeof CreateIssueOptionsSchema>;
|
||||||
export type CreateMergeRequestOptions = z.infer<typeof CreateMergeRequestOptionsSchema>;
|
export type CreateMergeRequestOptions = z.infer<
|
||||||
|
typeof CreateMergeRequestOptionsSchema
|
||||||
|
>;
|
||||||
export type CreateBranchOptions = z.infer<typeof CreateBranchOptionsSchema>;
|
export type CreateBranchOptions = z.infer<typeof CreateBranchOptionsSchema>;
|
||||||
export type GitLabCreateUpdateFileResponse = z.infer<typeof GitLabCreateUpdateFileResponseSchema>;
|
export type GitLabCreateUpdateFileResponse = z.infer<
|
||||||
|
typeof GitLabCreateUpdateFileResponseSchema
|
||||||
|
>;
|
||||||
export type GitLabSearchResponse = z.infer<typeof GitLabSearchResponseSchema>;
|
export type GitLabSearchResponse = z.infer<typeof GitLabSearchResponseSchema>;
|
||||||
export type GitLabMergeRequestDiff = z.infer<typeof GitLabMergeRequestDiffSchema>;
|
export type GitLabMergeRequestDiff = z.infer<
|
||||||
|
typeof GitLabMergeRequestDiffSchema
|
||||||
|
>;
|
||||||
export type CreateNoteOptions = z.infer<typeof CreateNoteSchema>;
|
export type CreateNoteOptions = z.infer<typeof CreateNoteSchema>;
|
||||||
export type GitLabIssueLink = z.infer<typeof GitLabIssueLinkSchema>;
|
export type GitLabIssueLink = z.infer<typeof GitLabIssueLinkSchema>;
|
||||||
|
export type ListIssueDiscussionsOptions = z.infer<typeof ListIssueDiscussionsSchema>;
|
||||||
|
export type UpdateIssueNoteOptions = z.infer<typeof UpdateIssueNoteSchema>;
|
||||||
|
export type CreateIssueNoteOptions = z.infer<typeof CreateIssueNoteSchema>;
|
||||||
export type GitLabNamespace = z.infer<typeof GitLabNamespaceSchema>;
|
export type GitLabNamespace = z.infer<typeof GitLabNamespaceSchema>;
|
||||||
export type GitLabNamespaceExistsResponse = z.infer<typeof GitLabNamespaceExistsResponseSchema>;
|
export type GitLabNamespaceExistsResponse = z.infer<
|
||||||
|
typeof GitLabNamespaceExistsResponseSchema
|
||||||
|
>;
|
||||||
export type GitLabProject = z.infer<typeof GitLabProjectSchema>;
|
export type GitLabProject = z.infer<typeof GitLabProjectSchema>;
|
||||||
export type GitLabLabel = z.infer<typeof GitLabLabelSchema>;
|
export type GitLabLabel = z.infer<typeof GitLabLabelSchema>;
|
||||||
|
export type ListWikiPagesOptions = z.infer<typeof ListWikiPagesSchema>;
|
||||||
|
export type GetWikiPageOptions = z.infer<typeof GetWikiPageSchema>;
|
||||||
|
export type CreateWikiPageOptions = z.infer<typeof CreateWikiPageSchema>;
|
||||||
|
export type UpdateWikiPageOptions = z.infer<typeof UpdateWikiPageSchema>;
|
||||||
|
export type DeleteWikiPageOptions = z.infer<typeof DeleteWikiPageSchema>;
|
||||||
|
export type GitLabWikiPage = z.infer<typeof GitLabWikiPageSchema>;
|
||||||
|
export type GitLabTreeItem = z.infer<typeof GitLabTreeItemSchema>;
|
||||||
|
export type GetRepositoryTreeOptions = z.infer<typeof GetRepositoryTreeSchema>;
|
||||||
|
export type MergeRequestThreadPosition = z.infer<typeof MergeRequestThreadPositionSchema>;
|
||||||
|
export type CreateMergeRequestThreadOptions = z.infer<typeof CreateMergeRequestThreadSchema>;
|
||||||
|
export type CreateMergeRequestNoteOptions = z.infer<typeof CreateMergeRequestNoteSchema>;
|
||||||
|
export type GitLabPipelineJob = z.infer<typeof GitLabPipelineJobSchema>;
|
||||||
|
export type GitLabPipeline = z.infer<typeof GitLabPipelineSchema>;
|
||||||
|
export type ListPipelinesOptions = z.infer<typeof ListPipelinesSchema>;
|
||||||
|
export type GetPipelineOptions = z.infer<typeof GetPipelineSchema>;
|
||||||
|
export type ListPipelineJobsOptions = z.infer<typeof ListPipelineJobsSchema>;
|
||||||
|
53
scripts/generate-tools-readme.ts
Normal file
53
scripts/generate-tools-readme.ts
Normal file
@ -0,0 +1,53 @@
|
|||||||
|
import fs from 'fs';
|
||||||
|
import path from 'path';
|
||||||
|
import { fileURLToPath } from 'url';
|
||||||
|
|
||||||
|
const __filename = fileURLToPath(import.meta.url);
|
||||||
|
const __dirname = path.dirname(__filename);
|
||||||
|
|
||||||
|
async function main() {
|
||||||
|
const repoRoot = path.resolve(__dirname, '..');
|
||||||
|
const indexPath = path.join(repoRoot, 'index.ts');
|
||||||
|
const readmePath = path.join(repoRoot, 'README.md');
|
||||||
|
|
||||||
|
// 1. Read index.ts
|
||||||
|
const code = fs.readFileSync(indexPath, 'utf-8');
|
||||||
|
|
||||||
|
// 2. Extract allTools array block
|
||||||
|
const match = code.match(/const allTools = \[([\s\S]*?)\];/);
|
||||||
|
if (!match) {
|
||||||
|
console.error('Unable to locate allTools array in index.ts');
|
||||||
|
process.exit(1);
|
||||||
|
}
|
||||||
|
const toolsBlock = match[1];
|
||||||
|
|
||||||
|
// 3. Parse tool entries
|
||||||
|
const toolRegex = /name:\s*"([^"]+)",[\s\S]*?description:\s*"([^"]+)"/g;
|
||||||
|
const tools: { name: string; description: string }[] = [];
|
||||||
|
let m: RegExpExecArray | null;
|
||||||
|
while ((m = toolRegex.exec(toolsBlock)) !== null) {
|
||||||
|
tools.push({ name: m[1], description: m[2] });
|
||||||
|
}
|
||||||
|
|
||||||
|
// 4. Generate markdown
|
||||||
|
const lines = tools.map((tool, index) => {
|
||||||
|
return `${index + 1}. \`${tool.name}\` - ${tool.description}`;
|
||||||
|
});
|
||||||
|
const markdown = lines.join('\n');
|
||||||
|
|
||||||
|
// 5. Read README.md and replace between markers
|
||||||
|
const readme = fs.readFileSync(readmePath, 'utf-8');
|
||||||
|
const updated = readme.replace(
|
||||||
|
/<!-- TOOLS-START -->([\s\S]*?)<!-- TOOLS-END -->/,
|
||||||
|
`<!-- TOOLS-START -->\n${markdown}\n<!-- TOOLS-END -->`
|
||||||
|
);
|
||||||
|
|
||||||
|
// 6. Write back
|
||||||
|
fs.writeFileSync(readmePath, updated, 'utf-8');
|
||||||
|
console.log('README.md tools section updated.');
|
||||||
|
}
|
||||||
|
|
||||||
|
main().catch(err => {
|
||||||
|
console.error(err);
|
||||||
|
process.exit(1);
|
||||||
|
});
|
Reference in New Issue
Block a user