Project Events
list_project_eventsRetrieve activity events for a GitLab project, such as commits, merge requests, and issue updates. Filter by action type, target, or date range to get specific event history.
Instructions
List activity events for a single GitLab project — commits pushed, MRs opened/merged, issues touched, notes added. Accepts project full path or numeric ID.
Input Schema
| Name | Required | Description | Default |
|---|---|---|---|
| project | Yes | Project full path (e.g. "group/my-project") or numeric project ID | |
| action | No | Filter by action type | |
| target_type | No | Filter by target resource type | |
| before | No | Only events before this date (YYYY-MM-DD) | |
| after | No | Only events after this date (YYYY-MM-DD) | |
| sort | No | Sort order (default desc — newest first) | desc |
| page | No | Page number (1-based) | |
| per_page | No | Results per page | |
| userCredentials | No | Your GitLab credentials (optional — falls back to the configured env token if not provided) |
Implementation Reference
- src/tools.ts:1907-1927 (handler)MCP tool definition for 'list_project_events' — defines name, description, input schema (project path/ID + events common fields), and handler that calls GitLabGraphQLClient.listProjectEvents() via REST API
const listProjectEventsTool: Tool = { name: 'list_project_events', title: 'Project Events', description: 'List activity events for a single GitLab project — commits pushed, MRs opened/merged, issues touched, notes added. Accepts project full path or numeric ID.', requiresAuth: false, requiresWrite: false, annotations: { readOnlyHint: true, destructiveHint: false, idempotentHint: true }, inputSchema: withUserAuth(z.object({ project: z .string() .min(1) .describe('Project full path (e.g. "group/my-project") or numeric project ID'), ...EventCommonFields, })), handler: async (input, client, userConfig) => { const credentials = input.userCredentials ? validateUserConfig(input.userCredentials) : userConfig; const { userCredentials, project, ...params } = input; return client.listProjectEvents(project.trim(), params, credentials); }, }; - src/tools.ts:1850-1858 (schema)Common input schema fields shared by list_project_events (and other event tools) — action filter, target_type filter, date range, sort, pagination
const EventCommonFields = { action: EventActionEnum, target_type: EventTargetTypeEnum, before: z.string().optional().describe('Only events before this date (YYYY-MM-DD)'), after: z.string().optional().describe('Only events after this date (YYYY-MM-DD)'), sort: z.enum(['asc', 'desc']).default('desc').describe('Sort order (default desc — newest first)'), page: z.number().int().min(1).default(1).describe('Page number (1-based)'), per_page: z.number().int().min(1).max(100).default(20).describe('Results per page'), }; - src/tools.ts:2272-2300 (registration)listProjectEventsTool is exported in the readOnlyTools array, which is included in the exported tools array — the registration that makes it available to the MCP server
export const readOnlyTools: Tool[] = [ getProjectTool, getIssuesTool, getMergeRequestsTool, executeCustomQueryTool, getAvailableQueriesTools, getMergeRequestPipelinesTool, getPipelineJobsTool, getMergeRequestDiffsTool, getMergeRequestCommitsTool, getNotesTool, getIssueContextTool, getMergeRequestContextTool, listMilestonesTool, listIterationsTool, getTimeTrackingTool, getMergeRequestReviewersTool, getProjectStatisticsTool, listBroadcastMessagesTool, getBroadcastMessageTool, getWorkItemTool, listWorkItemsTool, listUserEventsTool, listProjectEventsTool, listMyEventsTool, analyticsUserSummaryTool, analyticsGroupSummaryTool, analyticsReviewBottlenecksTool, ]; - src/index.ts:103-146 (registration)MCP server CallTool handler that matches tool name 'list_project_events' to listProjectEventsTool and invokes its handler
server.setRequestHandler(CallToolRequestSchema, async (request, extra) => { const { name, arguments: args } = request.params; const tool = tools.find(t => t.name === name); if (!tool) { throw new McpError(ErrorCode.MethodNotFound, `Tool ${name} not found`); } try { const validatedInput = tool.inputSchema.parse(args || {}); // Extract user credentials: prioritize args, fallback to session-specific config let userConfig = validatedInput.userCredentials; // If no credentials in args, try to get from session context. // The MCP SDK exposes the transport session id at extra.sessionId // (top-level), not under extra._meta — see RequestHandlerExtra in // @modelcontextprotocol/sdk/shared/protocol.d.ts. if (!userConfig && extra?.sessionId) { const sessionData = this.httpSessions.get(extra.sessionId as string); if (sessionData?.userConfig) { userConfig = sessionData.userConfig; } } delete validatedInput.userCredentials; // Remove from input to avoid passing to handler const result = await tool.handler(validatedInput, this.gitlabClient, userConfig); return { content: [ { type: 'text', text: JSON.stringify(result, null, 2), }, ], }; } catch (error) { if (error instanceof Error) { throw new McpError(ErrorCode.InternalError, error.message); } throw new McpError(ErrorCode.InternalError, 'Unknown error occurred'); } }); - src/gitlab-client.ts:2758-2783 (helper)GitLabGraphQLClient.listProjectEvents() — makes a REST API call to GET /projects/:id/events with filtering/pagination params
async listProjectEvents( projectIdOrPath: string | number, params: { action?: string; target_type?: string; before?: string; after?: string; sort?: 'asc' | 'desc'; page?: number; per_page?: number; }, userConfig?: UserConfig ): Promise<any> { return this.restRequest('GET', `/projects/${encodeURIComponent(String(projectIdOrPath))}/events`, { query: { action: params.action, target_type: params.target_type, before: params.before, after: params.after, sort: params.sort, page: params.page ?? 1, per_page: Math.min(params.per_page ?? 20, this.config.maxPageSize), }, userConfig, }); }