Skip to main content
Glama
disnet
by disnet

update_note

Modify existing notes in Flint Note by updating content, metadata, or both, supporting single or batch operations with optimistic locking.

Instructions

Update one or more existing notes

Input Schema

TableJSON Schema
NameRequiredDescriptionDefault
identifierNoNote identifier in format "type/filename" or full path - only used for single note update
contentNoNew content for the note - only used for single note update
content_hashNoContent hash of the current note for optimistic locking - required for single note update
metadataNoMetadata fields to update - only used for single note update
updatesNoArray of note updates (must specify content, metadata, or both) - used for batch updates
vault_idNoOptional vault ID to operate on. If not provided, uses the current active vault.

Implementation Reference

  • MCP tool handler for 'update_note'. Validates args, handles single or batch updates by calling NoteManager methods (updateNote, updateNoteWithMetadata, batchUpdateNotes), returns JSON result.
    handleUpdateNote = async (args: UpdateNoteArgs) => {
      // Validate arguments
      validateToolArgs('update_note', args);
    
      const { noteManager } = await this.resolveVaultContext(args.vault_id);
    
      // Handle batch updates if updates array is provided
      if (args.updates) {
        const result = await noteManager.batchUpdateNotes(args.updates);
        return {
          content: [
            {
              type: 'text',
              text: JSON.stringify(result, null, 2)
            }
          ]
        };
      }
    
      // Handle single note update
      // Note: validation already handled by validateToolArgs
      const identifier = args.identifier!; // Safe after validation
      const contentHash = args.content_hash!; // Safe after validation
    
      let result;
      if (args.content !== undefined && args.metadata !== undefined) {
        // Both content and metadata update
        result = await noteManager.updateNoteWithMetadata(
          identifier,
          args.content,
          args.metadata as NoteMetadata,
          contentHash
        );
      } else if (args.content !== undefined) {
        // Content-only update
        result = await noteManager.updateNote(identifier, args.content, contentHash);
      } else if (args.metadata !== undefined) {
        // Metadata-only update
        const currentNote = await noteManager.getNote(identifier);
        if (!currentNote) {
          throw new Error(`Note '${identifier}' not found`);
        }
        result = await noteManager.updateNoteWithMetadata(
          identifier,
          currentNote.content,
          args.metadata as NoteMetadata,
          contentHash
        );
      } else {
        throw new Error('Either content or metadata must be provided for update');
      }
    
      return {
        content: [
          {
            type: 'text',
            text: JSON.stringify(result, null, 2)
          }
        ]
      };
    };
  • Registration of 'update_note' tool in MCP server's CallToolRequestSchema handler switch statement. Routes to NoteHandlers.handleUpdateNote.
    case 'update_note':
      return await this.noteHandlers.handleUpdateNote(
        args as unknown as UpdateNoteArgs
      );
  • Input schema definition for 'update_note' tool advertised in ListToolsRequestSchema response.
    {
      name: 'update_note',
      description: 'Update one or more existing notes',
      inputSchema: {
        type: 'object',
        properties: {
          identifier: {
            type: 'string',
            description:
              'Note identifier in format "type/filename" or full path - only used for single note update'
          },
          content: {
            type: 'string',
            description:
              'New content for the note - only used for single note update'
          },
          content_hash: {
            type: 'string',
            description:
              'Content hash of the current note for optimistic locking - required for single note update'
          },
          metadata: {
            type: 'object',
            description:
              'Metadata fields to update - only used for single note update',
            additionalProperties: true
          },
          updates: {
            type: 'array',
            items: {
              type: 'object',
              properties: {
                identifier: {
                  type: 'string',
                  description:
                    'Note identifier in format "type/filename" or full path'
                },
                content: {
                  type: 'string',
                  description: 'New content for the note'
                },
                content_hash: {
                  type: 'string',
                  description: 'Content hash for optimistic locking'
                },
                metadata: {
                  type: 'object',
                  description: 'Metadata fields to update',
                  additionalProperties: true
                }
              },
              required: ['identifier', 'content_hash']
            },
            description:
              'Array of note updates (must specify content, metadata, or both) - used for batch updates'
          },
          vault_id: {
            type: 'string',
            description:
              'Optional vault ID to operate on. If not provided, uses the current active vault.'
          }
        },
        required: []
      }
    },
  • TypeScript interface UpdateNoteArgs defining the input parameters for the update_note tool handler.
    export interface UpdateNoteArgs {
      identifier?: string;
      content?: string;
      metadata?: Record<string, unknown>;
      content_hash?: string;
      updates?: Array<{
        identifier: string;
        content?: string;
        metadata?: Record<string, unknown>;
        content_hash: string;
      }>;
      vault_id?: string;
    }
  • Core NoteManager.updateNote method: handles content-only updates with optimistic locking via content hash, preserves metadata, updates search index.
    async updateNote(
      identifier: string,
      newContent: string,
      contentHash: string
    ): Promise<UpdateResult> {
      try {
        if (!contentHash) {
          throw new MissingContentHashError('note update');
        }
    
        const {
          typeName: _typeName,
          filename: _filename,
          notePath
        } = this.parseNoteIdentifier(identifier);
    
        // Check if note exists
        try {
          await fs.access(notePath);
        } catch {
          throw new Error(`Note '${identifier}' does not exist`);
        }
    
        // Read current content to preserve metadata
        const currentContent = await fs.readFile(notePath, 'utf-8');
        const parsed = this.parseNoteContent(currentContent);
    
        // Validate content hash to prevent conflicts
        validateContentHash(parsed.content, contentHash);
    
        // Update the content while preserving metadata
        const updatedMetadata = {
          ...parsed.metadata,
          updated: new Date().toISOString()
        };
    
        const updatedContent = this.formatUpdatedNoteContent(updatedMetadata, newContent);
    
        // Write updated content
        await fs.writeFile(notePath, updatedContent, 'utf-8');
    
        // Update search index
        await this.updateSearchIndex(notePath, updatedContent);
    
        return {
          id: identifier,
          updated: true,
          timestamp: updatedMetadata.updated
        };
      } catch (error) {
        const errorMessage = error instanceof Error ? error.message : 'Unknown error';
        throw new Error(`Failed to update note '${identifier}': ${errorMessage}`);
      }
    }
  • Core NoteManager.updateNoteWithMetadata: handles content + metadata updates, protects critical fields like title/filename unless bypassed.
    async updateNoteWithMetadata(
      identifier: string,
      content: string,
      metadata: NoteMetadata,
      contentHash: string,
      bypassProtection: boolean = false
    ): Promise<UpdateResult> {
      try {
        if (!contentHash) {
          throw new MissingContentHashError('note metadata update');
        }
    
        const {
          typeName: _typeName,
          filename: _filename,
          notePath
        } = this.parseNoteIdentifier(identifier);
    
        // Check if note exists
        try {
          await fs.access(notePath);
        } catch {
          throw new Error(`Note '${identifier}' does not exist`);
        }
    
        // Read current content to preserve existing metadata
        const currentContent = await fs.readFile(notePath, 'utf-8');
        const parsed = this.parseNoteContent(currentContent);
    
        // Validate content hash to prevent conflicts
        validateContentHash(parsed.content, contentHash);
    
        // Check for protected fields unless bypassing protection
        if (!bypassProtection) {
          this.#validateNoProtectedFields(metadata);
        }
    
        // Merge metadata with existing metadata
        const updatedMetadata = {
          ...parsed.metadata,
          ...metadata,
          updated: new Date().toISOString()
        };
    
        // Format content with metadata
        const formattedContent = this.formatUpdatedNoteContent(updatedMetadata, content);
    
        // Write updated content
        await fs.writeFile(notePath, formattedContent, 'utf-8');
    
        // Update search index
        await this.updateSearchIndex(notePath, formattedContent);
    
        return {
          id: identifier,
          updated: true,
          timestamp: updatedMetadata.updated
        };
      } catch (error) {
        const errorMessage = error instanceof Error ? error.message : 'Unknown error';
        throw new Error(`Failed to update note '${identifier}': ${errorMessage}`);
      }
    }

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/disnet/flint-note'

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