Merge pull request #35 from BobMerkus/feat/list-repository
feat: Gitlab list repository tree tool
This commit is contained in:
56
index.ts
56
index.ts
@ -113,6 +113,10 @@ import {
|
|||||||
type UpdateWikiPageOptions,
|
type UpdateWikiPageOptions,
|
||||||
type DeleteWikiPageOptions,
|
type DeleteWikiPageOptions,
|
||||||
type GitLabWikiPage,
|
type GitLabWikiPage,
|
||||||
|
GitLabTreeItemSchema,
|
||||||
|
GetRepositoryTreeSchema,
|
||||||
|
type GitLabTreeItem,
|
||||||
|
type GetRepositoryTreeOptions,
|
||||||
} from "./schemas.js";
|
} from "./schemas.js";
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -389,6 +393,11 @@ const allTools = [
|
|||||||
description: "Delete a wiki page from a GitLab project",
|
description: "Delete a wiki page from a GitLab project",
|
||||||
inputSchema: zodToJsonSchema(DeleteWikiPageSchema),
|
inputSchema: zodToJsonSchema(DeleteWikiPageSchema),
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
name: "get_repository_tree",
|
||||||
|
description: "Get the repository tree for a GitLab project (list files and directories)",
|
||||||
|
inputSchema: zodToJsonSchema(GetRepositoryTreeSchema),
|
||||||
|
},
|
||||||
];
|
];
|
||||||
|
|
||||||
// Define which tools are read-only
|
// Define which tools are read-only
|
||||||
@ -2000,6 +2009,45 @@ async function deleteWikiPage(projectId: string, slug: string): Promise<void> {
|
|||||||
await handleGitLabError(response);
|
await handleGitLabError(response);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get the repository tree for a project
|
||||||
|
* @param {string} projectId - The ID or URL-encoded path of the project
|
||||||
|
* @param {GetRepositoryTreeOptions} options - Options for the tree
|
||||||
|
* @returns {Promise<GitLabTreeItem[]>}
|
||||||
|
*/
|
||||||
|
async function getRepositoryTree(
|
||||||
|
options: GetRepositoryTreeOptions
|
||||||
|
): Promise<GitLabTreeItem[]> {
|
||||||
|
const queryParams = new URLSearchParams();
|
||||||
|
if (options.path) queryParams.append("path", options.path);
|
||||||
|
if (options.ref) queryParams.append("ref", options.ref);
|
||||||
|
if (options.recursive) queryParams.append("recursive", "true");
|
||||||
|
if (options.per_page) queryParams.append("per_page", options.per_page.toString());
|
||||||
|
if (options.page_token) queryParams.append("page_token", options.page_token);
|
||||||
|
if (options.pagination) queryParams.append("pagination", options.pagination);
|
||||||
|
|
||||||
|
const response = await fetch(
|
||||||
|
`${GITLAB_API_URL}/projects/${encodeURIComponent(options.project_id)}/repository/tree?${queryParams.toString()}`,
|
||||||
|
{
|
||||||
|
headers: {
|
||||||
|
Authorization: `Bearer ${GITLAB_PERSONAL_ACCESS_TOKEN}`,
|
||||||
|
"Content-Type": "application/json",
|
||||||
|
},
|
||||||
|
}
|
||||||
|
);
|
||||||
|
|
||||||
|
if (response.status === 404) {
|
||||||
|
throw new Error("Repository or path not found");
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!response.ok) {
|
||||||
|
throw new Error(`Failed to get repository tree: ${response.statusText}`);
|
||||||
|
}
|
||||||
|
|
||||||
|
const data = await response.json();
|
||||||
|
return z.array(GitLabTreeItemSchema).parse(data);
|
||||||
|
}
|
||||||
|
|
||||||
server.setRequestHandler(ListToolsRequestSchema, async () => {
|
server.setRequestHandler(ListToolsRequestSchema, async () => {
|
||||||
// Apply read-only filter first
|
// Apply read-only filter first
|
||||||
const tools0 = GITLAB_READ_ONLY_MODE
|
const tools0 = GITLAB_READ_ONLY_MODE
|
||||||
@ -2579,6 +2627,14 @@ server.setRequestHandler(CallToolRequestSchema, async (request) => {
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
case "get_repository_tree": {
|
||||||
|
const args = GetRepositoryTreeSchema.parse(request.params.arguments);
|
||||||
|
const tree = await getRepositoryTree(args);
|
||||||
|
return {
|
||||||
|
content: [{ type: "text", text: JSON.stringify(tree, null, 2) }],
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
default:
|
default:
|
||||||
throw new Error(`Unknown tool: ${request.params.name}`);
|
throw new Error(`Unknown tool: ${request.params.name}`);
|
||||||
}
|
}
|
||||||
|
4
package-lock.json
generated
4
package-lock.json
generated
@ -1,12 +1,12 @@
|
|||||||
{
|
{
|
||||||
"name": "@zereight/mcp-gitlab",
|
"name": "@zereight/mcp-gitlab",
|
||||||
"version": "1.0.32",
|
"version": "1.0.33",
|
||||||
"lockfileVersion": 3,
|
"lockfileVersion": 3,
|
||||||
"requires": true,
|
"requires": true,
|
||||||
"packages": {
|
"packages": {
|
||||||
"": {
|
"": {
|
||||||
"name": "@zereight/mcp-gitlab",
|
"name": "@zereight/mcp-gitlab",
|
||||||
"version": "1.0.32",
|
"version": "1.0.33",
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@modelcontextprotocol/sdk": "1.8.0",
|
"@modelcontextprotocol/sdk": "1.8.0",
|
||||||
|
20
schemas.ts
20
schemas.ts
@ -160,17 +160,27 @@ 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({
|
||||||
@ -1033,3 +1043,5 @@ export type CreateWikiPageOptions = z.infer<typeof CreateWikiPageSchema>;
|
|||||||
export type UpdateWikiPageOptions = z.infer<typeof UpdateWikiPageSchema>;
|
export type UpdateWikiPageOptions = z.infer<typeof UpdateWikiPageSchema>;
|
||||||
export type DeleteWikiPageOptions = z.infer<typeof DeleteWikiPageSchema>;
|
export type DeleteWikiPageOptions = z.infer<typeof DeleteWikiPageSchema>;
|
||||||
export type GitLabWikiPage = z.infer<typeof GitLabWikiPageSchema>;
|
export type GitLabWikiPage = z.infer<typeof GitLabWikiPageSchema>;
|
||||||
|
export type GitLabTreeItem = z.infer<typeof GitLabTreeItemSchema>;
|
||||||
|
export type GetRepositoryTreeOptions = z.infer<typeof GetRepositoryTreeSchema>;
|
||||||
|
Reference in New Issue
Block a user