Skip to main content
Glama
ttpears

GitLab MCP Server

by ttpears

Create Note

create_note

Add comments or notes to GitLab issues and merge requests using Markdown formatting, with options for internal visibility and authentication.

Instructions

Add a comment/note to an issue or merge request (requires user authentication)

Input Schema

TableJSON Schema
NameRequiredDescriptionDefault
projectPathYesFull path of the project (e.g., "group/project-name")
noteableTypeYesType of item to add a note to
iidYesIssue or merge request IID
bodyYesNote body (supports Markdown)
internalNoWhether the note is internal/confidential (only visible to project members)
userCredentialsNoYour GitLab credentials (optional - uses shared token if not provided)

Implementation Reference

  • Tool definition and handler for 'create_note'. Defines input schema (projectPath, noteableType, iid, body, internal), validates user credentials, and calls the GitLab client's createNote method.
    const createNoteTool: Tool = {
      name: 'create_note',
      title: 'Create Note',
      description: 'Add a comment/note to an issue or merge request (requires user authentication)',
      requiresAuth: true,
      requiresWrite: true,
      annotations: {
        readOnlyHint: false,
        destructiveHint: false,
        idempotentHint: false,
      },
      inputSchema: withUserAuth(z.object({
        projectPath: z.string().describe('Full path of the project (e.g., "group/project-name")'),
        noteableType: z.enum(['issue', 'merge_request']).describe('Type of item to add a note to'),
        iid: z.string().describe('Issue or merge request IID'),
        body: z.string().min(1).describe('Note body (supports Markdown)'),
        internal: z.boolean().default(false).describe('Whether the note is internal/confidential (only visible to project members)'),
      })),
      handler: async (input, client, userConfig) => {
        const credentials = input.userCredentials ? validateUserConfig(input.userCredentials) : userConfig;
        if (!credentials) {
          throw new Error('User authentication is required for creating notes. Please provide your GitLab credentials.');
        }
        const result = await client.createNote(input.projectPath, input.noteableType, input.iid, input.body, input.internal, credentials);
        if (result.errors && result.errors.length > 0) {
          throw new Error(`Failed to create note: ${result.errors.join(', ')}`);
        }
        return result.note;
      },
    };
  • Core implementation of createNote in GitLabGraphQLClient. Introspects schema, resolves noteable IID to global ID, constructs GraphQL mutation, and executes it to create a note on issues or merge requests.
    async createNote(
      projectPath: string,
      noteableType: 'issue' | 'merge_request',
      iid: string,
      body: string,
      internal: boolean = false,
      userConfig?: UserConfig
    ): Promise<any> {
      await this.introspectSchema(userConfig);
      const mutationType = this.schema?.getMutationType();
      const fields = mutationType ? mutationType.getFields() : {};
    
      const fieldName = fields['createNote'] ? 'createNote' : null;
      if (!fieldName) {
        throw new Error('createNote mutation is not available on this GitLab instance');
      }
    
      // Resolve the noteable IID to a global ID
      const noteableId = noteableType === 'issue'
        ? await this.getIssueId(projectPath, iid, userConfig)
        : await this.getMergeRequestId(projectPath, iid, userConfig);
    
      const mutation = gql`
        mutation createNote($input: CreateNoteInput!) {
          createNote(input: $input) {
            note {
              id
              body
              author { username name }
              createdAt
              url
              internal
            }
            errors
          }
        }
      `;
    
      const input: any = {
        noteableId,
        body,
      };
      if (internal) {
        input.internal = true;
      }
    
      const result = await this.query(mutation, { input }, userConfig, true);
      return result.createNote;
    }
  • Input schema definition for create_note tool using Zod validation with user credentials wrapper
    inputSchema: withUserAuth(z.object({
      projectPath: z.string().describe('Full path of the project (e.g., "group/project-name")'),
      noteableType: z.enum(['issue', 'merge_request']).describe('Type of item to add a note to'),
      iid: z.string().describe('Issue or merge request IID'),
      body: z.string().min(1).describe('Note body (supports Markdown)'),
      internal: z.boolean().default(false).describe('Whether the note is internal/confidential (only visible to project members)'),
    })),
  • src/tools.ts:1317-1349 (registration)
    Tool registration in module exports. createNoteTool is exported in writeTools array and included in the main tools export for MCP server registration
    export const writeTools: Tool[] = [
      createIssueTool,
      createMergeRequestTool,
      createNoteTool,
      managePipelineTool,
    ];
    
    export const searchTools: Tool[] = [
      globalSearchTool,
      searchProjectsTool,
      searchIssuesTool,
      searchMergeRequestsTool,
      getUserIssuesTool,
      getUserMergeRequestsTool,
      searchUsersTool,
      searchGroupsTool,
      searchLabelsTool,
      browseRepositoryTool,
      getFileContentTool,
      listGroupMembersTool,
    ];
    
    export const tools: Tool[] = [
      ...readOnlyTools,
      ...userAuthTools,
      ...writeTools,
      updateIssueTool,
      updateMergeRequestTool,
      resolvePathTool,
      getGroupProjectsTool,
      getTypeFieldsTool,
      ...searchTools,
    ];
  • src/index.ts:83-96 (registration)
    MCP server tool registration handler. The setupToolHandlers method registers all tools including create_note with the MCP server for listing and execution
    private setupToolHandlers(server: Server): void {
      server.setRequestHandler(ListToolsRequestSchema, async () => {
        return {
          tools: tools.map(tool => ({
            name: tool.name,
            ...(tool.title && { title: tool.title }),
            description: tool.description,
            inputSchema: toJsonSchema(tool.inputSchema),
            ...(tool.outputSchema && { outputSchema: toJsonSchema(tool.outputSchema) }),
            ...(tool.annotations && { annotations: tool.annotations }),
            ...(tool.icon && { icon: tool.icon }),
          })),
        };
      });
Behavior3/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

Annotations already indicate this is a non-readOnly, non-idempotent, non-destructive operation. The description adds valuable context about authentication requirements ('requires user authentication') which isn't captured in annotations. However, it doesn't describe other behavioral aspects like rate limits, error conditions, or what happens when adding notes to different noteable types.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness5/5

Is the description appropriately sized, front-loaded, and free of redundancy?

The description is a single, efficient sentence that communicates the core purpose, target resources, and key constraint. Every word earns its place with zero waste or redundancy. It's appropriately sized for a tool with good schema documentation.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness4/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

For a mutation tool with no output schema, the description covers the essential purpose and authentication requirement well. The annotations provide safety context (non-destructive), and the schema thoroughly documents parameters. The main gap is lack of information about return values or what happens after note creation, but given the context, this is a minor omission.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters3/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

With 100% schema description coverage, the schema already documents all 6 parameters thoroughly. The description doesn't add any parameter-specific information beyond what's in the schema. The baseline of 3 is appropriate since the schema does the heavy lifting for parameter documentation.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose5/5

Does the description clearly state what the tool does and how it differs from similar tools?

The description clearly states the specific action ('Add a comment/note'), target resources ('to an issue or merge request'), and includes an important constraint ('requires user authentication'). It distinguishes from sibling tools like 'get_notes' (which retrieves notes) and 'update_issue/merge_request' (which modify the items themselves rather than adding comments).

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines4/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

The description provides clear context about when to use this tool ('to an issue or merge request') and mentions an important prerequisite ('requires user authentication'). However, it doesn't explicitly state when NOT to use it or name specific alternatives among the many sibling tools (e.g., when to use 'create_note' vs. 'update_issue' for adding comments).

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

Install Server

Other Tools

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/ttpears/gitlab-mcp'

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