Summary
When markdown content passed to create_page or update_page (in append mode) contains an inline property (key:: value) on a line directly under a bullet, the parser creates a separate child block for the property line instead of attaching it as a property of the parent bullet. Result: the parent bullet is untagged, queries against the property surface a phantom block.
Reproduction
Call update_page with this markdown content:
- Investigating the X behavior
tags:: decisions, brag, my-project
- ## Rule
- X needs A and B
- ## Cases
- case 1 — not a bug
Resulting block tree in Logseq:
- Investigating the X behavior ← parent bullet (no tags)
- (empty content) ← phantom child block
tags:: decisions, brag, my-project ← property attached to the phantom
- ## Rule
- X needs A and B
- ## Cases
- case 1 — not a bug
Expected:
- Investigating the X behavior ← parent bullet
tags:: decisions, brag, my-project ← property of the parent
- ## Rule
- X needs A and B
- ## Cases
- case 1 — not a bug
Root cause
In src/mcp_logseq/parser.py, the _parse_list_item method handles nested content (math, tables, etc.) but has no case for LOGSEQ_PROPERTY_PATTERN. Property lines fall through to the default BlockNode constructor:
else:
nested_block = BlockNode(
content=next_line.strip(),
level=next_indent
)
list_block.children.append(nested_block)
This creates a separate block whose content is the literal key:: value text, which Logseq then interprets as a property of that empty block rather than of the parent.
Why this matters
This is the canonical pattern for tagging journal blocks in Logseq. Any AI agent or skill that writes structured journal entries with tags on the parent block hits this bug. The result is that hub queries ({{query [[my-tag]]}}) surface empty phantom bullets instead of the actual content blocks, defeating the purpose of tagging.
Distinct from #48 / #51 which are about page-level property updates via the properties parameter. This issue is about block-level properties via inline markdown content.
Workarounds users currently have to apply
- Move tags inline on the title:
- Title — [[tag1]] [[tag2]] (works but uglier)
- Skip
key:: value entirely and use only inline #tag / [[ref]] syntax
- Write outside the MCP and edit the markdown file directly
Suggested fix
In _parse_list_item's nested content loop, add a case for LOGSEQ_PROPERTY_PATTERN that appends the property to the parent block's properties dict instead of creating a child block:
elif LOGSEQ_PROPERTY_PATTERN.match(next_line):
key, value = parse_property(next_line)
list_block.properties[key] = value
i += 1
(Or whatever shape matches the existing property handling at the page level.)
Happy to send a PR if helpful — just wanted to flag the bug first.
Summary
When markdown content passed to
create_pageorupdate_page(in append mode) contains an inline property (key:: value) on a line directly under a bullet, the parser creates a separate child block for the property line instead of attaching it as a property of the parent bullet. Result: the parent bullet is untagged, queries against the property surface a phantom block.Reproduction
Call
update_pagewith this markdown content:Resulting block tree in Logseq:
Expected:
Root cause
In
src/mcp_logseq/parser.py, the_parse_list_itemmethod handles nested content (math, tables, etc.) but has no case forLOGSEQ_PROPERTY_PATTERN. Property lines fall through to the defaultBlockNodeconstructor:This creates a separate block whose content is the literal
key:: valuetext, which Logseq then interprets as a property of that empty block rather than of the parent.Why this matters
This is the canonical pattern for tagging journal blocks in Logseq. Any AI agent or skill that writes structured journal entries with tags on the parent block hits this bug. The result is that hub queries (
{{query [[my-tag]]}}) surface empty phantom bullets instead of the actual content blocks, defeating the purpose of tagging.Distinct from #48 / #51 which are about page-level property updates via the
propertiesparameter. This issue is about block-level properties via inline markdown content.Workarounds users currently have to apply
- Title — [[tag1]] [[tag2]](works but uglier)key:: valueentirely and use only inline#tag/[[ref]]syntaxSuggested fix
In
_parse_list_item's nested content loop, add a case forLOGSEQ_PROPERTY_PATTERNthat appends the property to the parent block'spropertiesdict instead of creating a child block:(Or whatever shape matches the existing property handling at the page level.)
Happy to send a PR if helpful — just wanted to flag the bug first.