get_links
Retrieves all outgoing links from a note path, including both resolved and dangling links. Helps identify dependencies and broken references in your Obsidian vault.
Instructions
Outgoing links from path — both resolved and dangling.
Useful for "what does this note depend on?" or finding broken references that need follow-up notes.
Args: path: Vault-relative path to the source note.
Input Schema
| Name | Required | Description | Default |
|---|---|---|---|
| path | Yes |
Output Schema
| Name | Required | Description | Default |
|---|---|---|---|
| result | Yes |
Implementation Reference
- src/mcp_server/tools.py:366-414 (handler)Core implementation of the get_links tool. Queries the note_links table (NoteLink model) for all outgoing links from a given note path, categorizing them into resolved (target_note_id is not null) and dangling (target_note_id is null). Uses current_user_id context var for multi-tenant isolation.
@_tracked("get_links", ["path"]) async def get_links_impl(path: str) -> str: """Outgoing links from `path` — both resolved and dangling.""" from sqlalchemy import select from sqlalchemy.orm import aliased from src.models.db import NoteLink, NoteMetadata uid = current_user_id.get() async with async_session() as session: src_stmt = select(NoteMetadata).where(NoteMetadata.file_path == path) if uid is not None: src_stmt = src_stmt.where(NoteMetadata.user_id == uid) source = (await session.execute(src_stmt)).scalar_one_or_none() if source is None: return f"Note not found: {path}" TargetMeta = aliased(NoteMetadata) stmt = ( select( NoteLink.kind, NoteLink.link_text, NoteLink.position, NoteLink.target_path, NoteLink.target_note_id, TargetMeta.file_path, TargetMeta.title, ) .outerjoin(TargetMeta, NoteLink.target_note_id == TargetMeta.id) .where(NoteLink.source_note_id == source.id) .order_by(NoteLink.position) ) rows = (await session.execute(stmt)).all() if not rows: return f"`{path}` has no outgoing links" resolved = [r for r in rows if r.target_note_id is not None] dangling = [r for r in rows if r.target_note_id is None] lines = [f"`{path}` — {len(resolved)} resolved, {len(dangling)} dangling:\n"] if resolved: lines.append("**Resolved:**") for r in resolved: lines.append( f"- {r.kind} → **{r.title}** (`{r.file_path}`) — `{r.link_text}`" ) if dangling: lines.append("\n**Dangling:**") for r in dangling: lines.append(f"- {r.kind} → `{r.target_path}` — `{r.link_text}`") return "\n".join(lines) - src/mcp_server/server.py:258-268 (registration)MCP tool registration wrapping get_links_impl. The @mcp.tool() decorator registers this as an MCP tool named 'get_links'. Delegates immediately to get_links_impl.
@mcp.tool() async def get_links(path: str) -> str: """Outgoing links from `path` — both resolved and dangling. Useful for "what does this note depend on?" or finding broken references that need follow-up notes. Args: path: Vault-relative path to the source note. """ return await get_links_impl(path) - src/mcp_server/server.py:12-12 (registration)Import of get_links_impl from tools.py into server.py for registration.
get_links_impl, - src/models/db.py:160-183 (schema)NoteLink SQLAlchemy model defining the note_links table schema. Fields include source_note_id, target_note_id, target_path, link_text, kind, and position. Used by get_links_impl to query outgoing links.
class NoteLink(Base): __tablename__ = "note_links" id: Mapped[int] = mapped_column(Integer, primary_key=True) source_note_id: Mapped[int] = mapped_column( Integer, ForeignKey("notes_metadata.id", ondelete="CASCADE"), nullable=False, ) target_note_id: Mapped[int | None] = mapped_column( Integer, ForeignKey("notes_metadata.id", ondelete="SET NULL"), nullable=True, ) target_path: Mapped[str] = mapped_column(String(1024), nullable=False) link_text: Mapped[str | None] = mapped_column(Text, nullable=True) kind: Mapped[str] = mapped_column(String(16), nullable=False, default="link") position: Mapped[int | None] = mapped_column(Integer, nullable=True) __table_args__ = ( Index("ix_note_links_source", "source_note_id"), Index("ix_note_links_target", "target_note_id"), Index("ix_note_links_target_path", "target_path"), )