Skip to main content
Glama

write_note

Create or update notes in your personal knowledge system by specifying a file path and content, with optional tags for organization.

Instructions

Create a new note or overwrite an existing note with content. Path should be relative to your notes directory. Optionally include tags that will be merged with any existing tags in the note.

Input Schema

TableJSON Schema
NameRequiredDescriptionDefault
pathYesPath where the note should be saved, relative to notes directory
contentYesContent to write to the note
tagsNoTags must follow these rules: - Can contain letters, numbers, underscore (_), hyphen (-), and forward slash (/) - Must contain at least one non-numerical character - Cannot contain spaces (use camelCase, PascalCase, snake_case, or kebab-case) - Are case-insensitive (stored as lowercase) Tags to add to the note's frontmatter. Will be merged with existing tags if present.

Implementation Reference

  • The handler function for the 'write_note' tool. Validates arguments, creates and saves a Note object with the provided content and tags, and appends a wikilink to the daily log.
    case "write_note": {
      try {
        const writeNoteArgs = args as WriteNoteArgs;
        
        // Validate parameters
        if (!writeNoteArgs.path) {
          throw new Error("'path' parameter is required");
        }
        
        if (writeNoteArgs.content === undefined) {
          throw new Error("'content' parameter is required");
        }
        
        try {
          // Create a Note instance with content only
          const note = new Note(notesPath, writeNoteArgs.path, {
            content: writeNoteArgs.content
          });
          
          // Add tags separately to handle validation errors
          if (writeNoteArgs.tags && writeNoteArgs.tags.length > 0) {
            note.addTags(writeNoteArgs.tags);
          }
          
          // Save the note
          const result = await note.save();
        
        if (!result.success) {
          return {
            content: [{ type: "text", text: `Error writing note: ${result.error}` }],
            isError: true
          };
        }
        
        // After successfully saving the note, append an entry to the daily log
        try {
          // Create a LogNote instance for today
          const logNote = new LogNote(notesPath);
          
          // Load existing content if available
          await logNote.load();
          
          // Format the note path for wikilink
          // Remove file extension if present and get the base name
          const notePath = writeNoteArgs.path;
          const noteBaseName = path.basename(notePath, path.extname(notePath));
          
          // Create wikilink using Obsidian convention
          const wikilink = `[[${noteBaseName}]]`;
          
          // Create log entry with the wikilink
          const logEntry = `Created note: ${wikilink}`;
          
          // Append the entry to the log
          await logNote.appendEntry(logEntry);
          
          return {
            content: [{ 
              type: "text", 
              text: `Successfully wrote note to: ${writeNoteArgs.path} and updated daily log with link` 
            }]
          };
        } catch (logError) {
          const errorMessage = logError instanceof Error ? logError.message : String(logError);
          console.error("Error updating log with note link:", logError);
          
          // Still return success for the note creation even if log update fails
          return {
            content: [{ 
              type: "text", 
              text: `Successfully wrote note to: ${writeNoteArgs.path} (but failed to update daily log: ${errorMessage})` 
            }]
          };
        }
        } catch (tagError) {
          const errorMessage = tagError instanceof Error ? tagError.message : String(tagError);
          return {
            content: [{ type: "text", text: `Error writing note: ${errorMessage}` }],
            isError: true
          };
        }
      } catch (error) {
        const errorMessage = error instanceof Error ? error.message : String(error);
        return {
          content: [{ type: "text", text: `Error writing note: ${errorMessage}` }],
          isError: true
        };
      }
    }
  • Registration of the 'write_note' tool in the getToolDefinitions() function, including name, description, and input schema.
    {
      name: "write_note",
      description: "Create a new note or overwrite an existing note with content. " +
        "Path should be relative to your notes directory. " +
        "Optionally include tags that will be merged with any existing tags in the note.",
      inputSchema: {
        type: "object",
        properties: {
          path: { 
            type: "string",
            description: "Path where the note should be saved, relative to notes directory" 
          },
          content: {
            type: "string",
            description: "Content to write to the note"
          },
          tags: {
            type: "array",
            items: { type: "string" },
            description: `${TAG_VALIDATION_DESCRIPTION}
            
            Tags to add to the note's frontmatter. Will be merged with existing tags if present.`
          }
        },
        required: ["path", "content"]
      },
    },
  • TypeScript interface defining the input arguments for the write_note tool.
    interface WriteNoteArgs {
      path: string;
      content: string;
      tags?: string[];
    }
Behavior3/5

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

With no annotations provided, the description carries the full burden of behavioral disclosure. It describes key behaviors: creation/overwriting of notes, path relativity, and tag merging. However, it lacks details on permissions, error handling, rate limits, or what happens on conflicts (e.g., if the note already has different content). This is adequate but has clear gaps for a mutation tool.

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 two sentences, front-loaded with the core purpose and followed by essential details about path and tags. Every sentence adds necessary information without redundancy, making it efficient and well-structured for quick comprehension.

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?

Given no annotations, no output schema, and a mutation tool with 3 parameters, the description is moderately complete. It covers the basic operation and key parameters but lacks information on return values, error cases, or system constraints. This is the minimum viable for such a tool, with clear room for improvement.

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?

Schema description coverage is 100%, so the baseline is 3. The description adds value by clarifying that tags are 'merged with any existing tags in the note,' which provides semantic context beyond the schema's technical rules. However, it does not explain parameter interactions or default behaviors, keeping it from a perfect score.

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 ('Create a new note or overwrite an existing note') and resource ('note with content'), distinguishing it from siblings like read_note, read_multiple_notes, and search_files. It explicitly mentions both creation and overwriting behavior, which is precise and actionable.

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?

The description implies usage by specifying 'Path should be relative to your notes directory' and mentions tags merging, but it does not explicitly state when to use this tool versus alternatives like create_directory or log. There is no guidance on prerequisites, error conditions, or exclusions, leaving usage context somewhat vague.

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/mikeysrecipes/mcp-notes'

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