Skip to main content
Glama
ToKiDoO

Advanced Obsidian MCP Server

by ToKiDoO

obsidian_understand_vault

Analyze and visualize the structure of an Obsidian vault by generating a directory tree and a NetworkX graph of note connections. Includes optional settings for attachments and file types to better understand relationships between .md files and associated resources.

Instructions

Get a comprehensive understanding of the vault structure. Returns: 1. directory tree representation and 2. NetworkX graph of note connections used to understand how different notes (.md) and other files (e.g. images, PDFs, referenced/attached) are connected. Combines filesystem directory structure with note relationship graph between notes (.md files).

Input Schema

TableJSON Schema
NameRequiredDescriptionDefault
directory_pathNoOptional path to a subdirectory to analyze, defaults to vault root
include_attachments_in_graphNoWhether to include attachment files (images, PDFs, etc.) in the *NetworkX connections graph*, excluding attachments in Obsidian. Defaults to True
include_other_files_in_treeNoWhether to show only .md files in the *directory tree structure*, excluding other file types. Defaults to True

Implementation Reference

  • The run_tool method implements the core logic of the obsidian_understand_vault tool. It builds a directory tree of the vault (optionally filtered) and generates a NetworkX graph of note connections using obsidiantools, returning both as a combined text response.
    def run_tool(self, args: dict) -> Sequence[TextContent | ImageContent | EmbeddedResource]: vault_path = os.getenv("OBSIDIAN_VAULT_PATH") if not vault_path: raise ValueError("OBSIDIAN_VAULT_PATH environment variable is not set. This tool cannot run without it.") directory_path = args.get('directory_path') include_attachments_in_graph = args.get('include_attachments_in_graph', True) include_other_files_in_tree = args.get('include_other_files_in_tree', True) # Generate directory tree try: tree_structure = self._build_directory_tree(vault_path, directory_path, include_other_files_in_tree) except Exception as e: raise ValueError(f"Error building directory tree: {str(e)}") # Generate note connections graph with proper attachments parameter vault_path_obj = Path(vault_path) vault = otools.Vault(vault_path_obj).connect(attachments=include_attachments_in_graph).gather() graph = vault.graph graph_data = json_graph.node_link_data(graph) # Combine both outputs return [ TextContent( type="text", text=f"# Vault Understanding\n\n## Vault Tree Structure:\n```\n{tree_structure}\n```\n\n## Note Connections:\n```json\n{json.dumps(graph_data, indent=2)}\n```" ) ]
  • The get_tool_description method defines the tool's schema, including input parameters for directory path, attachments in graph, and other files in tree.
    def get_tool_description(self): return Tool( name=self.name, description="Get a comprehensive understanding of the vault structure. Returns: 1. directory tree representation and 2. NetworkX graph of note connections used to understand how different notes (.md) and other files (e.g. images, PDFs, referenced/attached) are connected. Combines filesystem directory structure with note relationship graph between notes (.md files).", inputSchema={ 'type': 'object', 'properties': { 'directory_path': { 'type': 'string', 'description': 'Optional path to a subdirectory to analyze, defaults to vault root' }, 'include_attachments_in_graph': { 'type': 'boolean', 'description': 'Whether to include attachment files (images, PDFs, etc.) in the *NetworkX connections graph*, excluding attachments in Obsidian. Defaults to True', 'default': True }, 'include_other_files_in_tree': { 'type': 'boolean', 'description': 'Whether to show only .md files in the *directory tree structure*, excluding other file types. Defaults to True', 'default': True } } } )
  • TOOL_MAPPING dictionary maps the tool name TOOL_UNDERSTAND_VAULT to its handler class UnderstandVaultToolHandler, which is later used to instantiate and register the tool.
    TOOL_MAPPING = { tools.TOOL_LIST_FILES_IN_DIR: tools.ListFilesInDirToolHandler, tools.TOOL_SIMPLE_SEARCH: tools.SearchToolHandler, tools.TOOL_PATCH_CONTENT: tools.PatchContentToolHandler, tools.TOOL_PUT_CONTENT: tools.PutContentToolHandler, tools.TOOL_APPEND_CONTENT: tools.AppendContentToolHandler, tools.TOOL_DELETE_FILE: tools.DeleteFileToolHandler, tools.TOOL_COMPLEX_SEARCH: tools.ComplexSearchToolHandler, tools.TOOL_BATCH_GET_FILES: tools.BatchGetFilesToolHandler, tools.TOOL_PERIODIC_NOTES: tools.PeriodicNotesToolHandler, tools.TOOL_RECENT_PERIODIC_NOTES: tools.RecentPeriodicNotesToolHandler, tools.TOOL_RECENT_CHANGES: tools.RecentChangesToolHandler, tools.TOOL_UNDERSTAND_VAULT: tools.UnderstandVaultToolHandler, tools.TOOL_GET_ACTIVE_NOTE: tools.GetActiveNoteToolHandler, tools.TOOL_OPEN_FILES: tools.OpenFilesToolHandler, tools.TOOL_LIST_COMMANDS: tools.ListCommandsToolHandler, tools.TOOL_EXECUTE_COMMANDS: tools.ExecuteCommandsToolHandler, }
  • Helper method to build and render a directory tree structure of the vault using anytree, optionally filtering to .md files only.
    def _build_directory_tree(self, vault_path: str, target_dir: str = None, include_other_files: bool = True) -> str: """Build a directory tree structure using anytree.""" vault_path_obj = Path(vault_path) target_path = vault_path_obj / target_dir if target_dir else vault_path_obj if not target_path.exists(): raise ValueError(f"Directory path does not exist: {target_path}") # Create root node with vault name vault_name = vault_path_obj.name root = Node(vault_name) # Dictionary to store nodes by their path for building hierarchy nodes = {str(target_path): root} # Walk through all files and directories for item_path in sorted(target_path.rglob("*")): if item_path == target_path: continue # If include_other_files is False, only show .md files and directories if not include_other_files and item_path.is_file() and item_path.suffix != '.md': continue # Get relative path from vault root rel_path = item_path.relative_to(vault_path_obj) # Find parent node parent_path = str(item_path.parent) parent_node = nodes.get(parent_path, root) # Create display name with relative path for files if item_path.is_file(): display_name = f"{item_path.name} ({rel_path})" else: display_name = f"{item_path.name}/" # Create node node = Node(display_name, parent=parent_node) nodes[str(item_path)] = node # Render tree tree_lines = [] for pre, _, node in RenderTree(root): tree_lines.append(f"{pre}{node.name}") return "\n".join(tree_lines)
  • The register_tools function instantiates handlers from TOOL_MAPPING (including UnderstandVaultToolHandler) and adds them to the server's tool_handlers dict based on INCLUDE_TOOLS env var.
    def register_tools(): """Register the selected tools with the server.""" tools_to_include = parse_include_tools() registered_count = 0 for tool_name in tools_to_include: if tool_name in TOOL_MAPPING: handler_class = TOOL_MAPPING[tool_name] handler_instance = handler_class() add_tool_handler(handler_instance) registered_count += 1 logger.debug(f"Registered tool: {tool_name}") logger.info(f"Successfully registered {registered_count} 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/ToKiDoO/mcp-obsidian-advanced'

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