Skip to main content
Glama
james-livefront

Poetry MCP Server

get_poem

Retrieve poems by ID or title from a poetry catalog, with options to include full text content for literary analysis and reference.

Instructions

Get a poem by ID or title.

Args: identifier: Poem ID or exact title include_content: Whether to include full poem text

Returns: Poem object or None if not found

Input Schema

TableJSON Schema
NameRequiredDescriptionDefault
identifierYes
include_contentNo

Output Schema

TableJSON Schema
NameRequiredDescriptionDefault
resultYes

Implementation Reference

  • The handler function for the 'get_poem' MCP tool, decorated with @mcp.tool() for automatic registration and schema inference from signature/docstring. Retrieves poem by ID or title from catalog index.
    @mcp.tool()
    async def get_poem(
        identifier: str,
        include_content: bool = True
    ) -> Optional[Poem]:
        """
        Get a poem by ID or title.
    
        Args:
            identifier: Poem ID or exact title
            include_content: Whether to include full poem text
    
        Returns:
            Poem object or None if not found
        """
        cat = get_catalog()
    
        # Try by ID first
        poem = cat.index.get_by_id(identifier.lower())
    
        # Try by title if not found
        if not poem:
            poem = cat.index.get_by_title(identifier)
    
        if poem and not include_content:
            # Return copy without content
            poem_dict = poem.model_dump()
            poem_dict['content'] = None
            poem = Poem(**poem_dict)
    
        return poem
  • Pydantic BaseModel defining the structure and validation for the Poem object returned by the get_poem tool.
    class Poem(BaseModel):
        """
        Poem model representing a single poem with metadata from frontmatter.
    
        Required frontmatter properties:
        - state: Production state (completed, fledgeling, etc.)
        - form: Structural pattern (free_verse, prose_poem, etc.)
    
        Optional frontmatter properties:
        - tags: Thematic tags for nexus connections
        - keywords: Legacy comma-separated tags
    
        Computed properties:
        - id: Generated from filename
        - word_count, line_count, stanza_count: Computed from content
        - created_at, updated_at: From filesystem timestamps
        """
    
        # Core identity
        id: str = Field(..., description="Unique identifier (filename without .md)")
        title: str = Field(..., description="Poem title from first # heading or filename")
        file_path: str = Field(..., description="Relative path from vault root")
    
        # Frontmatter: Required properties
        state: Literal[
            "completed",
            "fledgeling",
            "still_cooking",
            "needs_research",
            "risk"
        ] = Field(..., description="Production state of the poem")
    
        form: Literal[
            "free_verse",
            "prose_poem",
            "american_sentence",
            "catalog_poem"
        ] = Field(..., description="Structural/formal pattern")
    
        # Frontmatter: Optional properties
        tags: list[str] = Field(
            default_factory=list,
            description="Thematic tags for nexus connections"
        )
        keywords: Optional[str] = Field(
            default=None,
            description="Legacy comma-separated keywords (prefer tags)"
        )
        notes: Optional[str] = Field(
            default=None,
            description="Editorial notes about the poem"
        )
    
        # Computed metrics
        word_count: int = Field(..., description="Total word count")
        line_count: int = Field(..., description="Total line count")
        stanza_count: Optional[int] = Field(
            default=None,
            description="Number of stanzas (blank-line separated)"
        )
    
        # Filesystem metadata
        created_at: datetime = Field(..., description="File creation timestamp")
        updated_at: datetime = Field(..., description="File modification timestamp")
    
        # Content (optional, for search/display)
        content: Optional[str] = Field(
            default=None,
            description="Full poem text (only included if requested)"
        )
    
        @field_validator('state')
        @classmethod
        def validate_state(cls, v: str) -> str:
            """Validate state enum value."""
            valid_states = {
                "completed", "fledgeling", "still_cooking",
                "needs_research", "risk"
            }
            if v not in valid_states:
                raise ValueError(
                    f"Invalid state '{v}'. Must be one of: {', '.join(valid_states)}"
                )
            return v
    
        @field_validator('form')
        @classmethod
        def validate_form(cls, v: str) -> str:
            """Validate form enum value."""
            valid_forms = {
                "free_verse", "prose_poem",
                "american_sentence", "catalog_poem"
            }
            if v not in valid_forms:
                raise ValueError(
                    f"Invalid form '{v}'. Must be one of: {', '.join(valid_forms)}"
                )
            return v
    
        @field_validator('tags')
        @classmethod
        def normalize_tags(cls, v: list[str]) -> list[str]:
            """Normalize tags: lowercase, strip whitespace, remove duplicates."""
            if not v:
                return []
            normalized = [tag.lower().strip() for tag in v if tag.strip()]
            return list(dict.fromkeys(normalized))  # Preserve order, remove dupes
    
        class Config:
            """Pydantic configuration."""
            json_schema_extra = {
                "example": {
                    "id": "second-bridge-out-old-route-12",
                    "title": "Second Bridge Out Old Route 12",
                    "file_path": "catalog/Completed/second-bridge-out-old-route-12.md",
                    "state": "completed",
                    "form": "free_verse",
                    "tags": ["water", "body", "memory", "Vermont"],
                    "word_count": 358,
                    "line_count": 42,
                    "stanza_count": 7,
                    "created_at": "2024-01-15T10:30:00Z",
                    "updated_at": "2024-06-20T14:22:00Z"
                }
            }
Behavior2/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 mentions that the tool returns 'Poem object or None if not found', which adds some context on error handling. However, it lacks details on permissions, rate limits, side effects, or what the 'Poem object' entails (e.g., structure, fields). For a read operation with zero annotation coverage, this is minimal but not sufficient.

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

Conciseness4/5

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

The description is appropriately sized and front-loaded: the first sentence states the core purpose, followed by structured sections for args and returns. Each sentence adds value, with no redundant information. It could be slightly more concise by integrating the sections, but overall it's efficient and well-organized.

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

Completeness3/5

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

Given the tool's moderate complexity (2 parameters, no annotations, but has an output schema), the description is partially complete. The output schema likely covers return values, so the description doesn't need to detail the 'Poem object'. However, it lacks usage guidelines and full behavioral context, making it adequate but with clear gaps for effective tool selection.

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

Parameters3/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 that 'identifier' can be 'Poem ID or exact title', adding meaning beyond the schema's string type. For 'include_content', it clarifies 'Whether to include full poem text', which is useful. However, it doesn't cover nuances like case-sensitivity for titles or default behavior, leaving some gaps given the low coverage.

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

Purpose4/5

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

The description clearly states the tool's purpose: 'Get a poem by ID or title.' It specifies the verb ('Get') and resource ('poem'), and distinguishes it from siblings like 'search_poems' or 'list_poems_by_state' by focusing on retrieval via specific identifier. However, it doesn't explicitly differentiate from 'find_poems_by_tag' or 'get_poems_for_enrichment', which might also retrieve poems, so it's not fully sibling-distinctive.

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

Usage Guidelines2/5

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

The description provides no guidance on when to use this tool versus alternatives. It doesn't mention scenarios like preferring 'search_poems' for fuzzy matching, 'list_poems_by_state' for filtered lists, or 'find_poems_by_tag' for tag-based retrieval. There's no context on prerequisites or exclusions, leaving the agent to infer usage from the purpose alone.

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