com.hjarni/hjarni
Markdown-based note-taking with a hosted MCP server. Your notes serve you and your AI.
Get an overview of the Second Brain: counts of notes, containers, tags, inbox items, and the 5 most recently updated notes. No parameters required.
Search across notes, containers, and tags in one call. Returns results grouped by type with pagination metadata (total_count, page, per_page, total_pages). Required: query (string). Optional: types (array, default all three), search_scope ('all'|'personal'|'team:<id>'), scope ('active'|'archived'), container_id (integer, ignored when search_scope is 'all'), tags (array, AND logic), tag_ids (array, AND logic), include_nested (boolean), page (integer, default 1), per_page (integer, default 25, max 100). Note results include a snippet of the matching portion.
List notes with optional filtering, sorting, and pagination. Returns paginated results. Optional: team_id (integer) to list team notes, scope ('active'|'archived'|'inbox'|'favorited'), container_id (integer) with include_nested (boolean), tags (array of strings, AND logic), tag_ids (array of integers, AND logic), sort ('recent'|'oldest'|'title'), page (integer, default 1), per_page (integer, max 100, default 25). Example: list ruby-tagged notes in a container: {container_id: 5, tags: ['ruby']}.
Get a single note by ID, including its full Markdown body, tags, container path, linked notes, file attachments, and inherited LLM instructions. Required: id (integer).
Create a new note. Required: title (string). Optional: body (Markdown with [[id:Note Title]] wiki-links), summary, source_url, container_id, tag_list (comma-separated), team_id (to create in a team). Example: {title: 'Meeting Notes', body: '## Agenda\n...', container_id: 5, tag_list: 'meetings, q4'}.
Update an existing note. Required: id (integer). Optional content: title, body (full replace), append_body (appends to existing body — mutually exclusive with body), summary, source_url. Optional organization: container_id (move note), archived (boolean, personal only), favorited (boolean). Optional tags: tag_list (full replace, comma-separated), add_tags (comma-separated tags to add), remove_tags (comma-separated tags to remove). tag_list takes precedence over add_tags/remove_tags if both provided. Example — append and add a tag: {id: 42, append_body: '\n## Update\nNew info here', add_tags: 'updated'}.
Permanently delete a note. This action is irreversible — the note and all its file attachments are destroyed. Required: id (integer).
List containers (folders) for organizing notes. Each container includes notes_count and children_count. Optional: team_id (integer) for team containers, scope ('roots' default|'all'|'archived'), page, per_page. Shared containers are automatically included when listing root-level personal containers.
Get a single container by ID, including notes_count, children_count, and LLM instructions if set. Optional: include_tree (boolean) to also get ancestor chain and children. Required: id (integer).
Create a new container (folder) for organizing notes. Required: name (string). Optional: description (string), parent_id (integer) for nesting inside another container. After creating, consider setting up LLM instructions with instructions-update.
Update an existing container — rename, change description, move to a different parent, or set display position. Required: id (integer). Optional: name, description, parent_id (null for root), position (integer, lower = first).
List all tags with their notes_count. Paginated. Optional: page (integer), per_page (integer).
Create a new tag. Check tags-list first to avoid duplicates. Required: name (string). Tag names are automatically lowercased.
List all teams the user is a member of, including members_count, notes_count, and containers_count for each team. No parameters required.
Get team details including the 10 most recent notes. Required: id (integer).
Get LLM instructions at the specified level. Call with level 'brain' early in conversations to learn user preferences. Required: level ('brain'|'personal_root'|'container'|'team'). Optional: id (integer, required for 'container' and 'team' levels). 'container' level returns the full inheritance chain (personal root -> ancestors -> container).
Update LLM instructions at the specified level. Required: level ('brain'|'personal_root'|'container'|'team'), instructions (string). Optional: id (integer, required for 'container' and 'team'), mode ('replace' default|'append'). In 'replace' mode (default), the provided text overwrites existing instructions. In 'append' mode, the text is appended to existing instructions with a newline separator. Always read current instructions first before replacing to avoid losing existing content.
Create or remove a bidirectional link between two notes. Required: action ('link'|'unlink'), source_note_id (integer), target_note_id (integer). Prefer wiki-link syntax [[id:Title]] in note bodies for inline linking — use this tool for programmatic links without modifying body text. Unlinking is destructive and cannot be undone.
Attach a file to a note via base64-encoded data. Prefer files-create_upload_url for large files to save tokens. Required: note_id (integer), filename (string), data (base64 string). Optional: content_type (MIME type, default: application/octet-stream), description.
Fetch a file from a public URL and attach it to a note. Follows one redirect. Required: note_id (integer), url (string). Optional: filename (default: derived from URL), content_type (default: from HTTP response), description.
Permanently remove a file attachment from a note. This action is irreversible. Required: note_id (integer), file_id (integer, from notes-get response).
Generate a one-time upload URL for attaching a file to a note. Share this URL with the user so they can upload directly in their browser — saves tokens by avoiding base64 encoding. The link expires after 30 minutes. Use files-check_upload to verify completion. Required: note_id (integer). Optional: description.
Check the status of a file upload created by files-create_upload_url. Returns status: 'pending' (not uploaded yet), 'completed' (file attached, includes file metadata), or 'expired' (link timed out). Required: token (string, from files-create_upload_url response).
Get a temporary download URL for a file attached to a note. Share the URL with the user to download in their browser. URL expires after a few minutes. Required: note_id (integer), file_id (integer, from notes-get response).
| Timestamp | Status | Latency | Conformance |
|---|---|---|---|
| Apr 4, 2026 | success | 149.8ms | Pass |
| Apr 4, 2026 | success | 502.9ms | Pass |
| Apr 4, 2026 | success | 518.9ms | Pass |
| Apr 4, 2026 | success | 410.9ms | Pass |
| Apr 4, 2026 | success | 175ms | Pass |
| Apr 4, 2026 | success | 204.2ms | Pass |
| Apr 4, 2026 | success | 156ms | Pass |
| Apr 4, 2026 | success | 725.2ms | Pass |
| Apr 4, 2026 | success | 154.5ms | Pass |
| Apr 4, 2026 | success | 647.4ms | Pass |