Skip to main content
Glama
ToKiDoO

Advanced Obsidian MCP Server

by ToKiDoO

obsidian_periodic_notes

Retrieve current periodic notes (daily, weekly, monthly, quarterly, yearly) from Obsidian vaults with comprehensive metadata and content for structured journaling and planning.

Instructions

Get current periodic note for the specified period. Returns both comprehensive metadata (tags, links, titles, etc.) and note content using the enhanced API approach.

Input Schema

TableJSON Schema
NameRequiredDescriptionDefault
periodYesThe period type (daily, weekly, monthly, quarterly, yearly)

Implementation Reference

  • PeriodicNotesToolHandler class implements the tool 'obsidian_periodic_notes'. The run_tool method fetches the current periodic note for the given period (daily/weekly/etc.), retrieves metadata and content using Obsidian API, enhances with note info (tags, links, frontmatter), and returns formatted TextContent.
    class PeriodicNotesToolHandler(ToolHandler): def __init__(self): super().__init__(TOOL_PERIODIC_NOTES) def get_tool_description(self): return Tool( name=self.name, description="Get current periodic note for the specified period. Returns both comprehensive metadata (tags, links, titles, etc.) and note content using the enhanced API approach.", inputSchema={ "type": "object", "properties": { "period": { "type": "string", "description": "The period type (daily, weekly, monthly, quarterly, yearly)", "enum": ["daily", "weekly", "monthly", "quarterly", "yearly"] } }, "required": ["period"] } ) def run_tool(self, args: dict) -> Sequence[TextContent | ImageContent | EmbeddedResource]: if "period" not in args: raise RuntimeError("period argument missing in arguments") period = args["period"] valid_periods = ["daily", "weekly", "monthly", "quarterly", "yearly"] if period not in valid_periods: raise RuntimeError(f"Invalid period: {period}. Must be one of: {', '.join(valid_periods)}") try: # Get the periodic note metadata to extract the file path metadata_response = api.get_periodic_note(period, "metadata") # Parse the JSON response to extract the file path import json try: metadata_json = json.loads(metadata_response) filepath = metadata_json.get('path', '') except (json.JSONDecodeError, AttributeError): # Fallback: try to get content directly if metadata parsing fails content = api.get_periodic_note(period, "content") return [ TextContent( type="text", text=f"## Periodic Note ({period})\n\n### Content Below:\n\n{content}" ) ] if not filepath: return [ TextContent( type="text", text=f"No {period} periodic note found." ) ] # Use the enhanced API approach to get comprehensive metadata and content # Get content using the existing method content = api.get_file_contents(filepath) # Get enhanced metadata using REST API url = f"{api.get_base_url()}/vault/{filepath}" headers = api._get_headers() | {'Accept': 'application/vnd.olrapi.note+json'} def call_fn(): response = requests.get(url, headers=headers, verify=api.verify_ssl, timeout=api.timeout) response.raise_for_status() return response.json() file_data = api._safe_call(call_fn) # Extract data from the API response api_frontmatter = file_data.get('frontmatter', {}) api_stat = file_data.get('stat', {}) api_tags = file_data.get('tags', []) # Get additional note info using obsidiantools for connections/links try: note_info = api.get_note_info(filepath) # Replace the tags from get_note_info with the more accurate API tags note_info['metadata']['tags'] = api_tags # Also update frontmatter with API data for accuracy note_info['metadata']['front_matter'] = api_frontmatter # Update file info with API stat data note_info['metadata']['file_info'].update({ 'ctime': api_stat.get('ctime'), 'mtime': api_stat.get('mtime'), 'size': api_stat.get('size') }) except Exception as note_info_error: # Fallback: create basic note info from API data note_info = { 'metadata': { 'tags': api_tags, 'front_matter': api_frontmatter, 'file_info': { 'rel_filepath': filepath, 'ctime': api_stat.get('ctime'), 'mtime': api_stat.get('mtime'), 'size': api_stat.get('size') }, 'counts': { 'n_backlinks': 0, 'n_wikilinks': 0, 'n_embedded_files': 0, 'n_tags': len(api_tags) } }, 'connections': { 'direct_links': [], 'backlinks': [], 'non_existent_links': [] } } # Create metadata JSON following BatchGetFilesToolHandler pattern metadata_json = { "filepath": filepath, "note_info": note_info } return [ TextContent( type="text", text=f"## Periodic Note ({period}): {filepath}\n\n### Metadata & Info\n```json\n{json.dumps(metadata_json, indent=2)}\n```" ), TextContent( type="text", text=f"### Content Below:\n\n{content}" ) ] except Exception as e: return [ TextContent( type="text", text=f"Error getting {period} periodic note: {str(e)}" ) ]
  • Input schema definition for the 'obsidian_periodic_notes' tool, specifying the required 'period' parameter with valid enum values.
    def get_tool_description(self): return Tool( name=self.name, description="Get current periodic note for the specified period. Returns both comprehensive metadata (tags, links, titles, etc.) and note content using the enhanced API approach.", inputSchema={ "type": "object", "properties": { "period": { "type": "string", "description": "The period type (daily, weekly, monthly, quarterly, yearly)", "enum": ["daily", "weekly", "monthly", "quarterly", "yearly"] } }, "required": ["period"] } )
  • TOOL_MAPPING dictionary maps the tool name 'obsidian_periodic_notes' (TOOL_PERIODIC_NOTES) to its handler class PeriodicNotesToolHandler, used for registration.
    # Tool mapping between tool constants and their handler classes 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, }
  • register_tools function instantiates handler classes from TOOL_MAPPING (including PeriodicNotesToolHandler) and adds them to tool_handlers dictionary for MCP server registration.
    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