Skip to main content
Glama
cwente25

Knowledge Base MCP Server

by cwente25

add_note

Create a new note in a knowledge base with hierarchical categories, supporting markdown content and optional tags for organization.

Instructions

Create a new note in the knowledge base (supports hierarchical categories)

Input Schema

TableJSON Schema
NameRequiredDescriptionDefault
category_pathYesCategory path (e.g., 'work', 'work/clients/acme', 'personal/spiritual'). Category will be created if it doesn't exist.
titleYesNote title (becomes filename)
contentYesMarkdown content of the note
tagsNoComma-separated tags (optional)

Implementation Reference

  • The handler function that executes the add_note tool: extracts parameters, parses tags, calls storage.create_note, formats success/error response.
    async def handle_add_note(arguments: dict) -> list[TextContent]:
        """Handle add_note tool call."""
        try:
            category_path = arguments["category_path"]
            title = arguments["title"]
            content = arguments["content"]
            tags_str = arguments.get("tags", "")
    
            # Parse tags
            tags = [tag.strip() for tag in tags_str.split(",") if tag.strip()]
    
            # Create note (will auto-create category if needed)
            note = storage.create_note(
                category_path=category_path,
                title=title,
                content=content,
                tags=tags,
                create_category=True
            )
    
            filename = storage.sanitize_filename(title)
            result = f"βœ“ Note '{title}' created in {category_path or 'root'}/\n"
            result += f"  File: {filename}.md\n"
            if tags:
                result += f"  Tags: {', '.join(tags)}"
    
            return [TextContent(type="text", text=result)]
        except (DuplicateNoteError, CategoryNotFoundError, InvalidPathError, StorageError) as e:
            return [TextContent(type="text", text=str(e))]
        except Exception as e:
            return [TextContent(type="text", text=f"❌ Error: {str(e)}")]
  • Input schema definition for the add_note tool in the list_tools() response.
    Tool(
        name="add_note",
        description="Create a new note in the knowledge base (supports hierarchical categories)",
        inputSchema={
            "type": "object",
            "properties": {
                "category_path": {
                    "type": "string",
                    "description": "Category path (e.g., 'work', 'work/clients/acme', 'personal/spiritual'). Category will be created if it doesn't exist.",
                },
                "title": {
                    "type": "string",
                    "description": "Note title (becomes filename)",
                },
                "content": {
                    "type": "string",
                    "description": "Markdown content of the note",
                },
                "tags": {
                    "type": "string",
                    "description": "Comma-separated tags (optional)",
                    "default": "",
                },
            },
            "required": ["category_path", "title", "content"],
        },
    ),
  • Tool call dispatcher registers and routes 'add_note' calls to the handle_add_note function.
    elif name == "add_note":
        return await handle_add_note(arguments)
  • Core helper method in storage layer that creates the note file, handles path validation, frontmatter generation, and file writing. Called by the handler.
    def create_note(
        self,
        category_path: str,
        title: str,
        content: str,
        tags: list[str],
        metadata: Optional[dict] = None,
        create_category: bool = True
    ) -> Note:
        """
        Create a new note.
    
        Args:
            category_path: Category path (e.g., "work/clients/acme")
            title: Note title
            content: Markdown content
            tags: List of tags
            metadata: Additional metadata fields
            create_category: If True, create category if it doesn't exist
    
        Returns:
            Created Note object
    
        Raises:
            DuplicateNoteError: If note already exists
            InvalidPathError: If category path is invalid
            StorageError: If write fails
        """
        # Normalize and validate path
        normalized = normalize_path(category_path)
        is_valid, error_msg = validate_path(normalized) if normalized else (True, None)
        if not is_valid:
            raise InvalidPathError(error_msg)
    
        # Create category if needed
        if normalized and not self._category_exists(normalized):
            if create_category:
                self.create_category(normalized, create_parents=True)
            else:
                raise CategoryNotFoundError(
                    f"❌ Error: Category '{normalized}' does not exist\n"
                    f"πŸ’‘ Tip: Use create_category first or set create_category=True"
                )
    
        file_path = self._get_note_path(normalized, title)
    
        if file_path.exists():
            raise DuplicateNoteError(
                f"❌ Error: Note '{title}' already exists in {normalized or 'root'}/\n"
                f"πŸ’‘ Tip: Use update_note to modify existing notes"
            )
    
        # Create frontmatter
        frontmatter = NoteFrontmatter(
            tags=tags,
            category=normalized,
            metadata=metadata or {}
        )
    
        # Create note object
        note = Note(
            title=title,
            category=normalized,
            frontmatter=frontmatter,
            content=content,
            file_path=str(file_path)
        )
    
        # Write to file
        self._write_note_file(note, file_path, backup=False)
    
        return note
Behavior2/5

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

No annotations are provided, so the description carries the full burden of behavioral disclosure. It states the tool creates a note and supports hierarchical categories, but doesn't mention permissions required, whether the operation is idempotent, error handling, or what happens on success/failure. For a mutation tool with zero annotation coverage, this leaves significant gaps in understanding its behavior.

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 a single, efficient sentence that front-loads the core purpose ('Create a new note in the knowledge base') and adds a useful detail ('supports hierarchical categories') without unnecessary elaboration. Every word earns its place, making it easy for an agent to parse quickly.

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 the tool's moderate complexity (a mutation with 4 parameters) and no annotations or output schema, the description is minimally adequate. It covers the basic purpose and hints at category behavior, but lacks details on behavioral traits, error cases, or output format. For a creation tool in a knowledge base context, more completeness would be helpful, but it meets the minimum viable threshold.

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 description coverage is 100%, so the input schema fully documents all parameters. The description adds no additional parameter semantics beyond what's in the schemaβ€”it doesn't explain parameter interactions, constraints, or examples. With high schema coverage, the baseline score of 3 is appropriate, as the description doesn't compensate but also doesn't detract.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose4/5

Does the description clearly state what the tool does and how it differs from similar tools?

The description clearly states the action ('Create a new note') and resource ('in the knowledge base'), which is specific and unambiguous. It also mentions support for hierarchical categories, which adds useful context. However, it doesn't explicitly differentiate from sibling tools like 'create_category' or 'update_note', which would be needed for a perfect score.

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

Usage Guidelines2/5

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

The description provides no guidance on when to use this tool versus alternatives like 'create_category' (for categories only) or 'update_note' (for modifying existing notes). It mentions hierarchical categories but doesn't clarify if this is the only way to add notes or if there are prerequisites. Without explicit when/when-not instructions, the agent must infer usage from context.

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/cwente25/KnowledgeBaseMCP'

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