Skip to main content
Glama
ImRieul

MySQL MCP Server

by ImRieul

add_comment

Add a comment to a MySQL table or column. Preview changes with dryRun before execution.

Instructions

Safely add a comment to a table or column. This tool only modifies comments — it cannot alter table structure, column types, or data. Set dryRun=true to preview the generated SQL without executing it. Use describe_table first to verify column names. Not available in read-only mode.

Input Schema

TableJSON Schema
NameRequiredDescriptionDefault
tableYesTable name.
columnNoColumn name. If omitted, sets a table-level comment.
commentYesComment text to set.
databaseNoDatabase name. Uses the current database if omitted.
dryRunNoIf true, returns the generated SQL without executing it. Defaults to false.

Implementation Reference

  • The main handler function for the add_comment tool. Accepts table, column (optional), comment, database (optional), and dryRun parameters. Validates identifiers, resolves the database, then either sets a table-level comment via ALTER TABLE ... COMMENT = '...' or sets a column-level comment by reconstructing the column definition and using ALTER TABLE MODIFY COLUMN. Supports dry-run mode to preview SQL without executing.
    export function createAddCommentHandler(runner: QueryRunner, isReadonly: boolean) {
      return async ({
        table,
        column,
        comment,
        database,
        dryRun,
      }: {
        table: string;
        column?: string;
        comment: string;
        database?: string;
        dryRun?: boolean;
      }) => {
        if (isReadonly) {
          return {
            isError: true as const,
            content: [
              {
                type: 'text' as const,
                text: 'Error: Server is in read-only mode. Modifying comments is not allowed.',
              },
            ],
          };
        }
    
        const tableValidation = validateIdentifier(table, 'Table');
        if (!tableValidation.valid) {
          return {
            isError: true as const,
            content: [{ type: 'text' as const, text: tableValidation.message! }],
          };
        }
    
        if (column) {
          const columnValidation = validateIdentifier(column, 'Column');
          if (!columnValidation.valid) {
            return {
              isError: true as const,
              content: [{ type: 'text' as const, text: columnValidation.message! }],
            };
          }
        }
    
        if (database) {
          const dbValidation = validateIdentifier(database, 'Database');
          if (!dbValidation.valid) {
            return {
              isError: true as const,
              content: [{ type: 'text' as const, text: dbValidation.message! }],
            };
          }
        }
    
        try {
          return await runner.withConnection(async (query) => {
            const db = await resolveDatabase(query, database);
            if (!db) {
              return {
                isError: true as const,
                content: [
                  {
                    type: 'text' as const,
                    text: 'Error: No database selected. Specify a database name or set MYSQL_DATABASE.',
                  },
                ],
              };
            }
    
            const fullName = `\`${db}\`.\`${table}\``;
            const escapedComment = escapeStringValue(comment);
    
            if (!column) {
              const sql = `ALTER TABLE ${fullName} COMMENT = '${escapedComment}'`;
              if (dryRun) {
                return {
                  content: [{ type: 'text' as const, text: `[dry-run] SQL preview:\n${sql}` }],
                };
              }
              await query(sql);
              return {
                content: [{ type: 'text' as const, text: `Table comment updated: ${table}` }],
              };
            }
    
            const colSql = `SELECT COLUMN_TYPE, IS_NULLABLE, COLUMN_DEFAULT, EXTRA FROM information_schema.COLUMNS WHERE TABLE_SCHEMA = ${quoteStringValue(db)} AND TABLE_NAME = ${quoteStringValue(table)} AND COLUMN_NAME = ${quoteStringValue(column)}`;
            const [rows] = await query(colSql);
            const colInfo = (rows as Record<string, unknown>[])[0];
    
            if (!colInfo) {
              return {
                isError: true as const,
                content: [
                  {
                    type: 'text' as const,
                    text: `Error: Column '${column}' doesn't exist in table '${table}'.\nHint: use describe_table to check available columns.`,
                  },
                ],
              };
            }
    
            let modifySql = `ALTER TABLE ${fullName} MODIFY COLUMN \`${column}\` ${colInfo.COLUMN_TYPE}`;
            if (colInfo.IS_NULLABLE === 'NO') modifySql += ' NOT NULL';
            if (colInfo.COLUMN_DEFAULT != null)
              modifySql += ` DEFAULT '${escapeStringValue(String(colInfo.COLUMN_DEFAULT))}'`;
            if (colInfo.EXTRA) modifySql += ` ${colInfo.EXTRA}`;
            modifySql += ` COMMENT '${escapedComment}'`;
    
            if (dryRun) {
              return {
                content: [{ type: 'text' as const, text: `[dry-run] SQL preview:\n${modifySql}` }],
              };
            }
    
            await query(modifySql);
            return {
              content: [{ type: 'text' as const, text: `Column comment updated: ${table}.${column}` }],
            };
          });
        } catch (error) {
          return {
            isError: true as const,
            content: [{ type: 'text' as const, text: formatError(error) }],
          };
        }
      };
    }
  • Schema and configuration for the add_comment tool. Defines input parameters: table (required string), column (optional string), comment (required string), database (optional string), dryRun (optional boolean).
    export const addCommentToolConfig = {
      title: 'Add Comment',
      description:
        'Safely add a comment to a table or column. This tool only modifies comments — it cannot alter table structure, column types, or data. ' +
        'Set dryRun=true to preview the generated SQL without executing it. ' +
        'Use describe_table first to verify column names. Not available in read-only mode.',
      inputSchema: {
        table: z.string().describe('Table name.'),
        column: z.string().optional().describe('Column name. If omitted, sets a table-level comment.'),
        comment: z.string().describe('Comment text to set.'),
        database: z.string().optional().describe('Database name. Uses the current database if omitted.'),
        dryRun: z
          .boolean()
          .optional()
          .describe('If true, returns the generated SQL without executing it. Defaults to false.'),
      },
    };
  • Registration of the add_comment tool with the MCP server. Uses addCommentToolName ('add_comment'), its description, input schema, and the handler created by createAddCommentHandler (passing readonly flag).
    server.tool(
      addCommentToolName,
      addCommentToolConfig.description,
      addCommentToolConfig.inputSchema,
      createAddCommentHandler(runner, readonly),
    );
  • The tool name constant 'add_comment' used for registration and identification.
    export const addCommentToolName = 'add_comment';
  • SQL escape utilities used by add_comment handler to safely escape comment strings and quoted values before embedding in SQL.
    export function escapeStringValue(value: string): string {
      return value.replace(/\\/g, '\\\\').replace(/'/g, "''");
    }
    
    export function quoteStringValue(value: string): string {
      return `'${escapeStringValue(value)}'`;
    }
Behavior4/5

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

With no annotations, the description carries full burden. It discloses safety, modification scope, preview capability, and read-only restriction. Could add detail on persistence (e.g., commits immediately) but sufficient.

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?

Four sentences, no redundancy, front-loaded with purpose. Every sentence serves a distinct function: purpose, constraints, usage tip, prerequisite, mode restriction.

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

Completeness5/5

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

For a simple tool with full schema coverage, the description covers safety, prerequisites, preview mode, and read-only restriction. No gaps given the tool's complexity.

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?

Schema coverage is 100% and already explains each parameter. The description adds no new semantic value beyond what the schema descriptions provide, meeting baseline but not exceeding.

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 that the tool adds comments to tables or columns, distinguishes its limited scope (cannot alter structure or data) from sibling tools like execute and query, and specifies the safety aspect.

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?

Provides explicit usage guidance: use describe_table first to verify column names, set dryRun=true for preview, and notes unavailability in read-only mode. Lacks explicit comparison to alternatives but covers key use cases.

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/ImRieul/mysql-mcp-server'

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