Skip to main content
Glama
by Alosies
server.ts12 kB
import { Server } from "@modelcontextprotocol/sdk/server/index.js"; import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio.js"; import { CallToolRequestSchema, ListToolsRequestSchema, } from "@modelcontextprotocol/sdk/types.js"; // Import all tools import { allTools } from "./tools/index.js"; // Import client and handlers import { GitLabClient } from "./client.js"; import { ProjectHandlers, IssueHandlers, MergeRequestHandlers, RepositoryHandlers, PipelineHandlers, JobHandlers, UserHandlers, } from "./handlers/index.js"; // Import configuration import { ConfigManager } from "./config.js"; // Import all types import type { GitLabConfig, IGitLabMCPServer, ListProjectsParams, GetProjectParams, ListIssuesParams, GetIssueParams, CreateIssueParams, ListMergeRequestsParams, GetMergeRequestParams, CreateMergeRequestParams, UpdateMergeRequestParams, GetMergeRequestDiffsParams, ListMergeRequestDiffsParams, GetBranchDiffsParams, ListMRNotesParams, ListMRDiscussionsParams, CreateMRNoteParams, CreateMRDiscussionParams, ReplyToMRDiscussionParams, ResolveMRDiscussionParams, UpdateMRDiscussionNoteParams, CreateMRDiscussionNoteParams, DeleteMRDiscussionNoteParams, MarkMRAsDraftParams, MarkMRAsReadyParams, ListMRTemplatesParams, GetMRTemplateParams, ListProjectBranchesParams, GetProjectCommitsParams, GetCommitParams, GetCommitDiffParams, ListPipelinesParams, GetPipelineParams, CreatePipelineParams, PipelineActionParams, ListPipelineJobsParams, GetPipelineVariablesParams, GetJobLogsParams, GetJobTraceParams, } from "./types.js"; export class GitLabMCPServer implements IGitLabMCPServer { private server: Server; private client: GitLabClient; private config: GitLabConfig; private configManager: ConfigManager; // Handler instances private projectHandlers: ProjectHandlers; private issueHandlers: IssueHandlers; private mergeRequestHandlers: MergeRequestHandlers; private repositoryHandlers: RepositoryHandlers; private pipelineHandlers: PipelineHandlers; private jobHandlers: JobHandlers; private userHandlers: UserHandlers; constructor(configPath?: string) { // Load configuration (optional) this.configManager = new ConfigManager(configPath); const validation = this.configManager.validate(); if (!validation.valid) { throw new Error( `Configuration validation failed:\n${validation.errors.join("\n")}` ); } const mcpConfig = this.configManager.get(); // Token is required, but can come from env or config const token = mcpConfig.gitlab.token || process.env.NPM_CONFIG_TOKEN || ""; if (!token) { throw new Error( "GitLab token is required. Set NPM_CONFIG_TOKEN environment variable." ); } this.config = { baseUrl: mcpConfig.gitlab.baseUrl!, token: token, }; // Initialize GitLab client this.client = new GitLabClient(this.config); // Initialize handlers this.projectHandlers = new ProjectHandlers(this.client, this.configManager); this.issueHandlers = new IssueHandlers(this.client); this.mergeRequestHandlers = new MergeRequestHandlers(this.client); this.repositoryHandlers = new RepositoryHandlers(this.client); this.pipelineHandlers = new PipelineHandlers(this.client); this.jobHandlers = new JobHandlers(this.client); this.userHandlers = new UserHandlers(this.client); // Initialize MCP server this.server = new Server( { name: mcpConfig.server.name!, version: mcpConfig.server.version!, }, { capabilities: { tools: {}, }, } ); this.setupToolHandlers(); } private setupToolHandlers() { // Register all tools from modular structure this.server.setRequestHandler(ListToolsRequestSchema, async () => { return { tools: allTools, }; }); // Handle tool calls this.server.setRequestHandler(CallToolRequestSchema, async (request) => { const { name, arguments: args } = request.params; try { switch (name) { // Project tools case "list_projects": return await this.projectHandlers.listProjects( args as unknown as ListProjectsParams ); case "get_project": return await this.projectHandlers.getProject( args as unknown as GetProjectParams ); // Issue tools case "list_issues": return await this.issueHandlers.listIssues( args as unknown as ListIssuesParams ); case "get_issue": return await this.issueHandlers.getIssue( args as unknown as GetIssueParams ); case "create_issue": return await this.issueHandlers.createIssue( args as unknown as CreateIssueParams ); // Merge request tools case "list_merge_requests": return await this.mergeRequestHandlers.listMergeRequests( args as unknown as ListMergeRequestsParams ); case "get_merge_request": return await this.mergeRequestHandlers.getMergeRequest( args as unknown as GetMergeRequestParams ); case "create_merge_request": return await this.mergeRequestHandlers.createMergeRequest( args as unknown as CreateMergeRequestParams ); case "update_merge_request": return await this.mergeRequestHandlers.updateMergeRequest( args as unknown as UpdateMergeRequestParams ); case "get_merge_request_diffs": return await this.mergeRequestHandlers.getMergeRequestDiffs( args as unknown as GetMergeRequestDiffsParams ); case "list_merge_request_diffs": return await this.mergeRequestHandlers.listMergeRequestDiffs( args as unknown as ListMergeRequestDiffsParams ); case "get_branch_diffs": return await this.mergeRequestHandlers.getBranchDiffs( args as unknown as GetBranchDiffsParams ); // Merge request notes/discussions tools case "list_mr_notes": return await this.mergeRequestHandlers.listMRNotes( args as unknown as ListMRNotesParams ); case "list_mr_discussions": return await this.mergeRequestHandlers.listMRDiscussions( args as unknown as ListMRDiscussionsParams ); case "create_mr_note": return await this.mergeRequestHandlers.createMRNote( args as unknown as CreateMRNoteParams ); case "create_mr_discussion": return await this.mergeRequestHandlers.createMRDiscussion( args as unknown as CreateMRDiscussionParams ); case "reply_to_mr_discussion": return await this.mergeRequestHandlers.replyToMRDiscussion( args as unknown as ReplyToMRDiscussionParams ); case "resolve_mr_discussion": return await this.mergeRequestHandlers.resolveMRDiscussion( args as unknown as ResolveMRDiscussionParams ); case "unresolve_mr_discussion": return await this.mergeRequestHandlers.unresolveMRDiscussion( args as unknown as ResolveMRDiscussionParams ); case "update_mr_discussion_note": return await this.mergeRequestHandlers.updateMRDiscussionNote( args as unknown as UpdateMRDiscussionNoteParams ); case "create_mr_discussion_note": return await this.mergeRequestHandlers.createMRDiscussionNote( args as unknown as CreateMRDiscussionNoteParams ); case "delete_mr_discussion_note": return await this.mergeRequestHandlers.deleteMRDiscussionNote( args as unknown as DeleteMRDiscussionNoteParams ); case "mark_mr_as_draft": return await this.mergeRequestHandlers.markMRAsDraft( args as unknown as MarkMRAsDraftParams ); case "mark_mr_as_ready": return await this.mergeRequestHandlers.markMRAsReady( args as unknown as MarkMRAsReadyParams ); case "list_mr_templates": return await this.mergeRequestHandlers.listMRTemplates( args as unknown as ListMRTemplatesParams ); case "get_mr_template": return await this.mergeRequestHandlers.getMRTemplate( args as unknown as GetMRTemplateParams ); // User tools case "get_user": return await this.userHandlers.getUser(); // Repository tools case "list_project_branches": return await this.repositoryHandlers.listProjectBranches( args as unknown as ListProjectBranchesParams ); case "get_project_commits": return await this.repositoryHandlers.getProjectCommits( args as unknown as GetProjectCommitsParams ); case "get_commit": return await this.repositoryHandlers.getCommit( args as unknown as GetCommitParams ); case "get_commit_diff": return await this.repositoryHandlers.getCommitDiff( args as unknown as GetCommitDiffParams ); // Pipeline tools case "list_pipelines": return await this.pipelineHandlers.listPipelines( args as unknown as ListPipelinesParams ); case "get_pipeline": return await this.pipelineHandlers.getPipeline( args as unknown as GetPipelineParams ); case "create_pipeline": return await this.pipelineHandlers.createPipeline( args as unknown as CreatePipelineParams ); case "retry_pipeline": return await this.pipelineHandlers.retryPipeline( args as unknown as PipelineActionParams ); case "cancel_pipeline": return await this.pipelineHandlers.cancelPipeline( args as unknown as PipelineActionParams ); case "delete_pipeline": return await this.pipelineHandlers.deletePipeline( args as unknown as PipelineActionParams ); case "get_pipeline_variables": return await this.pipelineHandlers.getPipelineVariables( args as unknown as GetPipelineVariablesParams ); // Job tools case "list_pipeline_jobs": return await this.jobHandlers.listPipelineJobs( args as unknown as ListPipelineJobsParams ); case "get_job_logs": return await this.jobHandlers.getJobLogs( args as unknown as GetJobLogsParams ); case "get_job_trace": return await this.jobHandlers.getJobTrace( args as unknown as GetJobTraceParams ); default: throw new Error(`Unknown tool: ${name}`); } } catch (error) { const errorMessage = error instanceof Error ? error.message : "Unknown error"; return { content: [ { type: "text", text: `Error: ${errorMessage}`, }, ], isError: true, }; } }); } async run() { const transport = new StdioServerTransport(); await this.server.connect(transport); console.error("GitLab MCP server running on stdio"); } }

Latest Blog Posts

MCP directory API

We provide all the information about MCP servers via our MCP API.

curl -X GET 'https://glama.ai/api/mcp/v1/servers/Alosies/gitlab-mcp-server'

If you have feedback or need assistance with the MCP directory API, please join our Discord server