Skip to main content
Glama
james-livefront

Poetry MCP Server

sync_catalog

Scans markdown files in the catalog directory to build in-memory indices for poetry management. Call this tool before using other catalog functions to ensure your poetry collection is properly indexed.

Instructions

Synchronize catalog from filesystem.

Scans all markdown files in catalog/ directory and builds in-memory indices. This should be called before using other catalog tools.

Args: force_rescan: If True, rescan all files even if already loaded

Returns: SyncResult with statistics about the sync operation

Input Schema

TableJSON Schema
NameRequiredDescriptionDefault
force_rescanNo

Output Schema

TableJSON Schema
NameRequiredDescriptionDefault
warningsNoList of warning messages encountered during sync
new_poemsYesNumber of new poems discovered in this sync
total_poemsYesTotal number of poems in catalog after sync
skipped_poemsNoNumber of poems skipped due to parse errors
updated_poemsYesNumber of existing poems with updated metadata
duration_secondsYesTime taken for sync operation

Implementation Reference

  • The sync_catalog tool handler: decorated with @mcp.tool(), retrieves the catalog instance, calls catalog.sync(), logs progress, and returns SyncResult.
    @mcp.tool()
    async def sync_catalog(force_rescan: bool = False) -> SyncResult:
        """
        Synchronize catalog from filesystem.
    
        Scans all markdown files in catalog/ directory and builds in-memory indices.
        This should be called before using other catalog tools.
    
        Args:
            force_rescan: If True, rescan all files even if already loaded
    
        Returns:
            SyncResult with statistics about the sync operation
        """
        logger.info(f"Syncing catalog (force_rescan={force_rescan})...")
        cat = get_catalog()
        result = cat.sync(force_rescan=force_rescan)
        logger.info(f"Sync complete: {result.total_poems} poems")
        return result
  • Pydantic BaseModel defining the SyncResult returned by the sync_catalog tool, including fields for sync statistics.
    class SyncResult(BaseModel):
        """
        Result from sync_catalog operation.
    
        Reports statistics about catalog synchronization:
        how many poems were discovered, added, updated, or skipped.
        """
    
        total_poems: int = Field(
            ...,
            description="Total number of poems in catalog after sync"
        )
    
        new_poems: int = Field(
            ...,
            description="Number of new poems discovered in this sync"
        )
    
        updated_poems: int = Field(
            ...,
            description="Number of existing poems with updated metadata"
        )
    
        skipped_poems: int = Field(
            default=0,
            description="Number of poems skipped due to parse errors"
        )
    
        warnings: list[str] = Field(
            default_factory=list,
            description="List of warning messages encountered during sync"
        )
    
        duration_seconds: float = Field(
            ...,
            description="Time taken for sync operation"
        )
    
        class Config:
            """Pydantic configuration."""
            json_schema_extra = {
                "example": {
                    "total_poems": 381,
                    "new_poems": 5,
                    "updated_poems": 12,
                    "skipped_poems": 2,
                    "warnings": [
                        "poem_without_frontmatter.md: missing frontmatter, used defaults",
                        "broken_file.md: invalid YAML, skipped"
                    ],
                    "duration_seconds": 2.34
                }
            }
  • Core Catalog.sync() method implementing the filesystem scan, poem parsing, indexing, statistics tracking, and SyncResult creation called by the tool handler.
    def sync(
        self,
        force_rescan: bool = False,
        update_missing_metadata: bool = True
    ) -> SyncResult:
        """
        Sync catalog from filesystem.
    
        Scans catalog/ directory recursively for .md files and builds indices.
    
        Args:
            force_rescan: If True, rescan all files even if already loaded
            update_missing_metadata: Auto-populate missing frontmatter
    
        Returns:
            SyncResult with statistics
        """
        start_time = time.perf_counter()
    
        if force_rescan:
            self.index.clear()
    
        # Track statistics
        total_before = len(self.index.all_poems)
        new_poems = 0
        updated_poems = 0
        skipped_poems = 0
        warnings: list[str] = []
    
        # Scan for markdown files
        logger.info(f"Scanning catalog directory: {self.catalog_dir}")
    
        if not self.catalog_dir.exists():
            raise FileNotFoundError(f"Catalog directory not found: {self.catalog_dir}")
    
        markdown_files = list(self.catalog_dir.rglob("*.md"))
        logger.info(f"Found {len(markdown_files)} markdown files")
    
        # Parse each file
        for md_file in markdown_files:
            try:
                poem = parse_poem_file(md_file, self.vault_root)
    
                # Check if poem already exists
                existing = self.index.get_by_id(poem.id)
                if existing:
                    # Check if updated (don't actually need to track this for now)
                    # Just always add the new version
                    if not force_rescan:
                        updated_poems += 1
                else:
                    new_poems += 1
    
                # Always add the poem (will overwrite if exists)
                self.index.add_poem(poem)
    
            except FrontmatterParseError as e:
                skipped_poems += 1
                warning_msg = f"{md_file.name}: {str(e)}"
                warnings.append(warning_msg)
                logger.warning(warning_msg)
            except Exception as e:
                skipped_poems += 1
                warning_msg = f"{md_file.name}: Unexpected error: {str(e)}"
                warnings.append(warning_msg)
                logger.error(warning_msg)
    
        total_after = len(self.index.all_poems)
        duration = time.perf_counter() - start_time
    
        # Update last sync timestamp
        from datetime import datetime
        self.last_sync = datetime.now().isoformat()
    
        logger.info(
            f"Catalog sync complete: {total_after} poems "
            f"({new_poems} new, {updated_poems} updated, {skipped_poems} skipped) "
            f"in {duration:.2f}s"
        )
    
        return SyncResult(
            total_poems=total_after,
            new_poems=new_poems,
            updated_poems=updated_poems,
            skipped_poems=skipped_poems,
            warnings=warnings,
            duration_seconds=duration
        )
Behavior4/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

With no annotations provided, the description carries the full burden of behavioral disclosure. It effectively describes the tool's action (scanning files, building indices) and prerequisite nature, though it lacks details on error handling, performance implications, or side effects beyond the sync operation. No contradictions exist.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness5/5

Is the description appropriately sized, front-loaded, and free of redundancy?

The description is front-loaded with the core purpose, followed by usage guidelines and parameter/return details in a structured format. Every sentence adds value without redundancy, making it efficient and easy to parse.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness4/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

Given the tool's complexity (prerequisite sync operation), no annotations, and an output schema (implied by 'Returns'), the description is mostly complete. It covers purpose, usage, parameters, and returns, but could benefit from more behavioral context like error scenarios or performance notes.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters4/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

Schema description coverage is 0%, so the description must compensate. It explains the single parameter 'force_rescan' with its effect ('rescan all files even if already loaded'), adding meaningful context beyond the schema's type and default. However, it doesn't cover edge cases or examples.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose5/5

Does the description clearly state what the tool does and how it differs from similar tools?

The description clearly states the specific action ('Synchronize catalog from filesystem') and resource ('catalog'), distinguishing it from sibling tools like 'get_catalog_stats' or 'sync_nexus_tags'. It explicitly mentions scanning markdown files in the catalog/ directory and building in-memory indices, providing a precise operational scope.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines5/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

The description explicitly states 'This should be called before using other catalog tools,' providing clear when-to-use guidance. It distinguishes this tool as a prerequisite for operations like 'find_poems_by_tag' or 'search_poems,' with no misleading exclusions.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

Install Server

Other 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/james-livefront/poetry-mcp'

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