Skip to main content
Glama

brain_create_note

Create new notes with markdown content and frontmatter in an Obsidian vault, organizing them in designated folders for knowledge management.

Instructions

Create a new note in the vault.

By default notes are created in Notes/ per the vault workflow standard. Agent-created notes should always go to Notes/ first; promotion happens during manual vault review.

Args: params: Title, content (full markdown with frontmatter), and target folder.

Returns: Confirmation with the path of the created note, or an error if the note already exists.

Input Schema

TableJSON Schema
NameRequiredDescriptionDefault
paramsYes

Implementation Reference

  • The async handler function that implements the brain_create_note tool. It creates a new note file in the vault with the provided title, content, and folder, validates the path doesn't escape vault root, and returns JSON confirmation or error message.
    async def brain_create_note(params: CreateNoteInput) -> str:
        """Create a new note in the vault.
    
        By default notes are created in Notes/ per the vault workflow standard.
        Agent-created notes should always go to Notes/ first; promotion happens
        during manual vault review.
    
        Args:
            params: Title, content (full markdown with frontmatter), and target folder.
    
        Returns:
            Confirmation with the path of the created note, or an error if the
            note already exists.
        """
        try:
            folder = _resolve_path(params.folder)
            folder.mkdir(parents=True, exist_ok=True)
    
            filename = params.title if params.title.endswith(".md") else f"{params.title}.md"
            target = folder / filename
    
            if target.exists():
                return f"Error: Note already exists at {_vault_relative(target)}. Use brain_update_note to modify it."
    
            target.write_text(params.content, encoding="utf-8")
            logger.info("Created note: %s", _vault_relative(target))
    
            return json.dumps({
                "status": "created",
                "path": _vault_relative(target),
                "title": target.stem,
            }, indent=2)
        except ValueError as e:
            return f"Error: {e}"
        except OSError as e:
            return f"Error creating note: {e}"
  • Pydantic BaseModel defining the input schema for brain_create_note. Includes title (1-200 chars), content (full markdown with frontmatter), and folder (defaults to 'Notes'). Uses ConfigDict for string stripping.
    class CreateNoteInput(BaseModel):
        """Input for creating a new note. Notes are created in Notes/ by default."""
        model_config = ConfigDict(str_strip_whitespace=True)
    
        title: str = Field(
            ...,
            description="Note title (becomes the filename, e.g., '2026-03-12 - My Topic')",
            min_length=1,
            max_length=200,
        )
        content: str = Field(
            ...,
            description="Full markdown content including frontmatter (use --- delimiters)",
        )
        folder: str = Field(
            default="Notes",
            description="Vault-relative folder. Defaults to Notes/ per vault workflow.",
        )
  • brain_mcp.py:473-482 (registration)
    Registration of the brain_create_note tool with the MCP server using the @mcp.tool decorator. Includes metadata annotations for title and behavior hints (not read-only, not destructive, not idempotent, closed world).
    @mcp.tool(
        name="brain_create_note",
        annotations={
            "title": "Create a New Note",
            "readOnlyHint": False,
            "destructiveHint": False,
            "idempotentHint": False,
            "openWorldHint": False,
        },
    )
  • Helper utilities used by brain_create_note: _resolve_path validates and resolves vault-relative paths while preventing directory traversal attacks, and _vault_relative converts absolute paths back to vault-relative strings.
    def _resolve_path(relative: str) -> Path:
        """Resolve a vault-relative path, preventing directory traversal."""
        cleaned = relative.lstrip("/").lstrip("\\")
        full = (VAULT_ROOT / cleaned).resolve()
        if not str(full).startswith(str(VAULT_ROOT.resolve())):
            raise ValueError(f"Path escapes vault root: {relative}")
        return full
    
    
    def _vault_relative(absolute: Path) -> str:
        """Return vault-relative path string."""
        try:
            return str(absolute.resolve().relative_to(VAULT_ROOT.resolve()))
        except ValueError:
            return str(absolute)

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/delian-research/brain-mcp'

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