Skip to main content
Glama

update_frontmatter

Update frontmatter in markdown files by adding, modifying, or removing keys. Control whether changes merge with or replace existing content.

Instructions

Sets and/or removes frontmatter keys. Pass { path, fields?, remove?, merge? }. fields sets key-value pairs (null is a real value, pass-through to schema validation). remove is a list of keys to delete. merge (default true) merges with existing frontmatter; false replaces all fields. Returns { root, path, frontmatter }.

Input Schema

TableJSON Schema
NameRequiredDescriptionDefault

No arguments

Implementation Reference

  • The main tool handler for update_frontmatter. Parses input (path, fields, remove, merge), delegates to frontmatter service's updateFields, re-reads the note, and returns updated frontmatter.
    function makeUpdateFrontmatterTool(container: ServiceContainer): ToolHandler {
      return {
        name: "update_frontmatter",
        description:
          "Sets and/or removes frontmatter keys. Pass `{ path, fields?, remove?, merge? }`. `fields` sets key-value pairs (null is a real value, pass-through to schema validation). `remove` is a list of keys to delete. `merge` (default true) merges with existing frontmatter; false replaces all fields. Returns `{ root, path, frontmatter }`.",
        inputSchema: UpdateFrontmatterSchema,
        async handler(args): Promise<ToolResponse> {
          try {
            const services = requireServices(container);
            const { path: notePath, fields, remove, merge } = UpdateFrontmatterSchema.parse(args);
            log.info(
              {
                notePath,
                fieldCount: Object.keys(fields).length,
                removeCount: remove.length,
                merge,
              },
              "update_frontmatter called",
            );
            await services.frontmatter.updateFields(notePath, fields, merge, remove);
            const updatedNote = await services.file.readNote(notePath);
            log.info({ path: notePath }, "update_frontmatter complete");
            return {
              content: [
                {
                  type: "text",
                  text: JSON.stringify(
                    { root: getRoot(container), path: notePath, frontmatter: updatedNote.frontmatter },
                    null,
                    2,
                  ),
                },
              ],
            };
          } catch (err) {
            log.error({ err }, "update_frontmatter failed");
            return {
              content: [{ type: "text", text: JSON.stringify({
                root: getRoot(container),
                error: err instanceof Error ? err.message : String(err),
                possibleSolutions: ["Check the path with list_directory", "Verify the file exists with read_note", "Ensure field values are valid YAML types"],
              }) }],
              isError: true,
            };
          }
        },
      };
    }
  • Zod input schema for update_frontmatter: path (required), fields (optional key-value pairs), remove (optional string array), merge (optional boolean, default true).
    const UpdateFrontmatterSchema = z.object({
      path: z.string().describe("Root-relative path to the note."),
      fields: z
        .record(z.string(), z.unknown())
        .optional()
        .default({})
        .describe("Key-value pairs to set in the frontmatter. `null` is a valid value (not a delete sentinel) — use `remove` to drop keys."),
      remove: z
        .array(z.string())
        .optional()
        .default([])
        .describe("Keys to delete from the frontmatter. Runs after the merge/replace step, so a key in both `fields` and `remove` ends up removed."),
      merge: z
        .boolean()
        .optional()
        .default(true)
        .describe("If true (default), merge with existing frontmatter. If false, replace all fields."),
    });
  • Registration function that adds update_frontmatter (along with other frontmatter tools) to the tool registry.
    export function registerFrontmatterTools(
      registry: Map<string, ToolHandler>,
      container: ServiceContainer,
    ): void {
      const tools = [
        makeGetFrontmatterTool(container),
        makeUpdateFrontmatterTool(container),
        makeManageTagsTool(container),
      ];
    
      for (const tool of tools) {
        registry.set(tool.name, tool);
      }
    }
  • Helper service method called by the handler. Reads the note, merges/replaces frontmatter fields, deletes keys in 'remove', stringifies and atomically writes back.
    async updateFields(
      notePath: string,
      fields: Record<string, unknown>,
      merge = true,
      remove: string[] = [],
    ): Promise<void> {
      log.info(
        {
          path: notePath,
          merge,
          fieldCount: Object.keys(fields).length,
          removeCount: remove.length,
        },
        "updateFields",
      );
    
      const note = await this.file.readNote(notePath);
      const { frontmatter, content } = note;
    
      const updatedFrontmatter: Record<string, unknown> = merge
        ? { ...frontmatter, ...fields }
        : { ...fields };
      for (const key of remove) {
        delete updatedFrontmatter[key];
      }
    
      const newRaw = this.stringify(updatedFrontmatter, content);
      const fullPath = this.file.resolvePath(notePath);
      await this.file.atomicWrite(fullPath, newRaw);
    
      log.info({ path: notePath, merge }, "updateFields complete");
    }
  • TypeScript interface definition for the updateFields method on FrontmatterService, used by the tool handler.
    updateFields(
      path: string,
      fields: Record<string, unknown>,
      merge?: boolean,
      remove?: string[],
    ): Promise<void>;
Behavior4/5

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

No annotations provided, so description carries full burden. Explains parameters, merge vs replace behavior, and return value. Could mention that it modifies the file on disk.

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

Conciseness4/5

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

Three sentences efficiently cover purpose, parameters, and return value. Slightly verbose in the middle sentence but overall concise.

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

Completeness3/5

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

Output schema missing, but description explains return shape. Lacks error handling info and prerequisites (e.g., note must exist). Adequate for typical use.

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

Parameters4/5

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

Input schema has 100% coverage, but description adds extra meaning: 'null is a real value' clarifies fields semantics, and explains merge default behavior. Adds value beyond schema.

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?

Description clearly states 'Sets and/or removes frontmatter keys' with specific verbs and resource, and distinguishes from sibling tools like get_frontmatter (read-only) and write_note (writes entire note).

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

Usage Guidelines3/5

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

No explicit when-to-use or when-not-to-use guidance. Does not mention alternatives like write_note or patch_note for modifying frontmatter alongside note body.

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/Erodenn/markscribe'

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