Skip to main content
Glama

parse_time

Convert natural language time expressions like 'tomorrow' or 'in 2 hours' into structured time data, with optional timezone support.

Instructions

Parse a natural language time string.

Args: text: Time to parse (e.g., "tomorrow", "next friday", "in 2 hours") timezone: Optional timezone (e.g., "America/New_York")

Returns: Parsed time in various formats

Input Schema

TableJSON Schema
NameRequiredDescriptionDefault
textYes
timezoneNo

Output Schema

TableJSON Schema
NameRequiredDescriptionDefault

No arguments

Implementation Reference

  • The 'parse_time' tool handler function. Decorated with @mcp.tool() inside register_utility_tools(). It takes a natural language time string (text) and optional timezone, calls the RTM API's rtm.time.parse method, and returns the parsed time, precision, and original input.
    @mcp.tool()
    async def parse_time(
        ctx: Context,
        text: str,
        timezone: str | None = None,
    ) -> dict[str, Any]:
        """Parse a natural language time string.
    
        Args:
            text: Time to parse (e.g., "tomorrow", "next friday", "in 2 hours")
            timezone: Optional timezone (e.g., "America/New_York")
    
        Returns:
            Parsed time in various formats
        """
        from ..client import RTMClient
    
        client: RTMClient = await get_client()
    
        params: dict[str, Any] = {"text": text}
        if timezone:
            params["timezone"] = timezone
    
        result = await client.call("rtm.time.parse", **params)
    
        time_data = result.get("time", {})
    
        return build_response(
            data={
                "input": text,
                "parsed": time_data.get("$t"),
                "precision": time_data.get("precision"),
            },
        )
  • The register_utility_tools() function which is the registration context. Inside this function, @mcp.tool() decorators register each tool (including parse_time) with the MCP server.
    def register_utility_tools(mcp: Any, get_client: Any) -> None:
        """Register utility and diagnostic tools."""
    
        @mcp.tool()
        async def test_connection(ctx: Context) -> dict[str, Any]:
            """Test connection to RTM API.
    
            Returns:
                Connection status and response time
            """
            import time
    
            from ..client import RTMClient
    
            client: RTMClient = await get_client()
    
            start = time.monotonic()
            try:
                result = await client.test_echo()
                elapsed = time.monotonic() - start
    
                return build_response(
                    data={
                        "status": "connected",
                        "response_time_ms": round(elapsed * 1000, 2),
                        "api_response": result,
                    },
                )
            except Exception as e:
                elapsed = time.monotonic() - start
                return build_response(
                    data={
                        "status": "error",
                        "error": str(e),
                        "response_time_ms": round(elapsed * 1000, 2),
                    },
                )
    
        @mcp.tool()
        async def check_auth(ctx: Context) -> dict[str, Any]:
            """Check if authentication token is valid.
    
            Returns:
                Auth status and user info
            """
            from ..client import RTMClient
    
            client: RTMClient = await get_client()
    
            try:
                result = await client.check_token()
                auth = result.get("auth", {})
                user = auth.get("user", {})
    
                return build_response(
                    data={
                        "status": "authenticated",
                        "user": {
                            "id": user.get("id"),
                            "username": user.get("username"),
                            "fullname": user.get("fullname"),
                        },
                        "permissions": auth.get("perms"),
                    },
                )
            except Exception as e:
                return build_response(
                    data={
                        "status": "not_authenticated",
                        "error": str(e),
                    },
                )
    
        @mcp.tool()
        async def get_tags(ctx: Context) -> dict[str, Any]:
            """Get all tags in use.
    
            Returns:
                List of tags with usage counts
            """
            from ..client import RTMClient
    
            client: RTMClient = await get_client()
    
            result = await client.call("rtm.tags.getList")
    
            tags_data = result.get("tags", {}).get("tag", [])
            if isinstance(tags_data, dict):
                tags_data = [tags_data]
            if isinstance(tags_data, str):
                tags_data = [{"name": tags_data}]
    
            tags = []
            for tag in tags_data:
                if isinstance(tag, str):
                    tags.append({"name": tag})
                else:
                    tags.append(
                        {
                            "name": tag.get("name", tag.get("$t", "")),
                        }
                    )
    
            return build_response(
                data={
                    "tags": sorted(tags, key=lambda x: x["name"]),
                    "count": len(tags),
                },
            )
    
        @mcp.tool()
        async def get_locations(ctx: Context) -> dict[str, Any]:
            """Get all saved locations.
    
            Returns:
                List of locations
            """
            from ..client import RTMClient
    
            client: RTMClient = await get_client()
    
            result = await client.call("rtm.locations.getList")
    
            locations_data = result.get("locations", {}).get("location", [])
            if isinstance(locations_data, dict):
                locations_data = [locations_data]
    
            locations = []
            for loc in locations_data:
                locations.append(
                    {
                        "id": loc.get("id"),
                        "name": loc.get("name"),
                        "latitude": float(loc.get("latitude", 0)),
                        "longitude": float(loc.get("longitude", 0)),
                        "zoom": int(loc.get("zoom", 0)) if loc.get("zoom") else None,
                        "address": loc.get("address"),
                    }
                )
    
            return build_response(
                data={
                    "locations": locations,
                    "count": len(locations),
                },
            )
    
        @mcp.tool()
        async def get_settings(ctx: Context) -> dict[str, Any]:
            """Get user settings.
    
            Returns:
                User preferences and settings
            """
            from ..client import RTMClient
    
            client: RTMClient = await get_client()
    
            result = await client.call("rtm.settings.getList")
    
            settings = result.get("settings", {})
    
            # Format settings nicely
            date_format = (
                "European (DD/MM/YY)" if settings.get("dateformat") == "0" else "American (MM/DD/YY)"
            )
            time_format = "12-hour" if settings.get("timeformat") == "0" else "24-hour"
    
            return build_response(
                data={
                    "timezone": settings.get("timezone"),
                    "date_format": date_format,
                    "time_format": time_format,
                    "default_list_id": settings.get("defaultlist"),
                    "language": settings.get("language"),
                    "raw": settings,
                },
            )
    
        @mcp.tool()
        async def parse_time(
            ctx: Context,
            text: str,
            timezone: str | None = None,
        ) -> dict[str, Any]:
            """Parse a natural language time string.
    
            Args:
                text: Time to parse (e.g., "tomorrow", "next friday", "in 2 hours")
                timezone: Optional timezone (e.g., "America/New_York")
    
            Returns:
                Parsed time in various formats
            """
            from ..client import RTMClient
    
            client: RTMClient = await get_client()
    
            params: dict[str, Any] = {"text": text}
            if timezone:
                params["timezone"] = timezone
    
            result = await client.call("rtm.time.parse", **params)
    
            time_data = result.get("time", {})
    
            return build_response(
                data={
                    "input": text,
                    "parsed": time_data.get("$t"),
                    "precision": time_data.get("precision"),
                },
            )
    
        @mcp.tool()
        async def undo(
            ctx: Context,
            transaction_id: str,
        ) -> dict[str, Any]:
            """Undo a previous operation.
    
            Use the transaction_id returned from write operations.
    
            Args:
                transaction_id: Transaction ID from previous operation
    
            Returns:
                Undo confirmation
            """
            from ..client import RTMClient
    
            client: RTMClient = await get_client()
    
            try:
                await client.call(
                    "rtm.transactions.undo",
                    require_timeline=True,
                    transaction_id=transaction_id,
                )
    
                return build_response(
                    data={
                        "status": "success",
                        "message": "Operation undone",
                        "transaction_id": transaction_id,
                    },
                )
            except Exception as e:
                return build_response(
                    data={
                        "status": "error",
                        "error": str(e),
                        "transaction_id": transaction_id,
                    },
                )
    
        @mcp.tool()
        async def get_contacts(ctx: Context) -> dict[str, Any]:
            """Get contacts for task sharing.
    
            Returns:
                List of contacts
            """
            from ..client import RTMClient
    
            client: RTMClient = await get_client()
    
            result = await client.call("rtm.contacts.getList")
    
            contacts_data = result.get("contacts", {}).get("contact", [])
            if isinstance(contacts_data, dict):
                contacts_data = [contacts_data]
    
            contacts = []
            for contact in contacts_data:
                contacts.append(
                    {
                        "id": contact.get("id"),
                        "fullname": contact.get("fullname"),
                        "username": contact.get("username"),
                    }
                )
    
            return build_response(
                data={
                    "contacts": contacts,
                    "count": len(contacts),
                },
            )
    
        @mcp.tool()
        async def get_groups(ctx: Context) -> dict[str, Any]:
            """Get contact groups.
    
            Returns:
                List of groups with member counts
            """
            from ..client import RTMClient
    
            client: RTMClient = await get_client()
    
            result = await client.call("rtm.groups.getList")
    
            groups_data = result.get("groups", {}).get("group", [])
            if isinstance(groups_data, dict):
                groups_data = [groups_data]
    
            groups = []
            for group in groups_data:
                contacts = group.get("contacts", {}).get("contact", [])
                if isinstance(contacts, dict):
                    contacts = [contacts]
    
                groups.append(
                    {
                        "id": group.get("id"),
                        "name": group.get("name"),
                        "member_count": len(contacts),
                    }
                )
    
            return build_response(
                data={
                    "groups": groups,
                    "count": len(groups),
                },
            )
  • Where register_utility_tools (which contains parse_time) is called in the main server setup.
    # Register all tools
    register_task_tools(mcp, get_client)
    register_list_tools(mcp, get_client)
    register_note_tools(mcp, get_client)
    register_utility_tools(mcp, get_client)
  • Import and re-export of register_utility_tools from the tools package.
    from .utilities import register_utility_tools
    
    __all__ = [
        "register_list_tools",
        "register_note_tools",
        "register_task_tools",
        "register_utility_tools",
  • The parse_time function uses build_response (imported from ..response_builder) as a helper to format the output and uses RTMClient.call as a helper to invoke the RTM API.
    ) -> dict[str, Any]:
        """Parse a natural language time string.
    
        Args:
            text: Time to parse (e.g., "tomorrow", "next friday", "in 2 hours")
            timezone: Optional timezone (e.g., "America/New_York")
    
        Returns:
            Parsed time in various formats
        """
        from ..client import RTMClient
    
        client: RTMClient = await get_client()
    
        params: dict[str, Any] = {"text": text}
        if timezone:
            params["timezone"] = timezone
    
        result = await client.call("rtm.time.parse", **params)
    
        time_data = result.get("time", {})
    
        return build_response(
            data={
                "input": text,
                "parsed": time_data.get("$t"),
                "precision": time_data.get("precision"),
            },
        )
Behavior3/5

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

With no annotations, the description carries the full burden. It discloses that it parses natural language time strings and returns various formats, but does not detail side effects, rate limits, or specific output formats beyond vague 'various formats.'

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 concise with no extraneous words. It uses a structured Args/Returns format that is easy to scan, making it efficient for an AI agent.

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 simplicity (2 parameters, no nested objects) and the existence of an output schema, the description covers the essential functionality. It could mention edge cases or failure modes, but it is mostly complete.

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 coverage is 0%, so the description compensates by explaining the 'text' parameter with examples like 'tomorrow' and the 'timezone' parameter with an example timezone. This adds significant meaning beyond the bare schema types.

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 tool's purpose: parsing natural language time strings. It uses a specific verb ('Parse') and resource ('time string'), and it distinguishes well from sibling tools like task operations.

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?

No guidance is provided on when to use this tool versus alternatives. It does not mention any prerequisites, when not to use it, or related tools that might be more appropriate.

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/ljadach/rtm-mcp'

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