Skip to main content
Glama
ZoezoeCookie

mcp-luopan

by ZoezoeCookie

luopan_chat

Ask follow-up questions about a Bazi chart reading. Provide a session_id from luopan_analyze to continue, with up to 5 questions per session and a 2-hour expiry.

Instructions

Ask a follow-up question against an existing chart-reading session.

Session_id comes from a prior luopan_analyze call. The backend enforces a 2-hour TTL and a 5-question cap; when either is hit, call luopan_analyze again to open a new session.

Returns (normalized): answer: the AI reply text followup_remaining: questions you still have left after this one followup_count: questions used so far (incl. this one) max_followups: hard cap (5) session_id: echoed back

When followup_remaining == 0 or this call returns session_expired, the next turn must call luopan_analyze to open a fresh session. When followup_remaining == 1, warn the user before they spend it.

Args: session_id: The session_id returned by luopan_analyze question: The user's follow-up question (specific events / years / topics yield better answers than vague "is my fate good")

Input Schema

TableJSON Schema
NameRequiredDescriptionDefault
session_idYes
questionYes

Output Schema

TableJSON Schema
NameRequiredDescriptionDefault
resultYes

Implementation Reference

  • Main handler for the 'luopan_chat' tool. Validates session_id and question, delegates async HTTP POST via LuopanClient.chat(), normalizes the response with followup_remaining/count/max_followups/session_id, and handles errors (session_expired, service_unreachable, internal).
    @mcp.tool()
    async def luopan_chat(session_id: str, question: str) -> str:
        """Ask a follow-up question against an existing chart-reading session.
    
        Session_id comes from a prior luopan_analyze call. The backend enforces
        a 2-hour TTL and a 5-question cap; when either is hit, call luopan_analyze
        again to open a new session.
    
        Returns (normalized):
          answer:              the AI reply text
          followup_remaining:  questions you still have left after this one
          followup_count:      questions used so far (incl. this one)
          max_followups:       hard cap (5)
          session_id:          echoed back
    
        When `followup_remaining == 0` or this call returns `session_expired`,
        the next turn must call luopan_analyze to open a fresh session.
        When `followup_remaining == 1`, warn the user before they spend it.
    
        Args:
            session_id: The session_id returned by luopan_analyze
            question: The user's follow-up question (specific events / years / topics
                      yield better answers than vague "is my fate good")
        """
        if not session_id or len(session_id) > 64:
            return _err("bad_input", "session_id 无效")
        if not question.strip():
            return _err("bad_input", "问题不能为空")
    
        try:
            data = await _client.chat(session_id, question.strip())
        except LuopanServiceError as e:
            if e.kind == "session_expired":
                return _err("session_expired", "此盘气已散(session 过期或追问已尽),需重新起盘。")
            if e.kind == "service_unreachable":
                return _err("service_unreachable", f"罗盘后端未就绪:{_config.api_base}。请先启动 uvicorn。")
            return _err(e.kind, e.detail)
        except Exception as e:  # noqa: BLE001
            logger.exception("luopan_chat unexpected error")
            return _err("internal", str(e))
    
        count = data.get("followup_count", 0)
        cap = data.get("max_followups", 5)
        normalized = {
            "answer": data.get("reply", ""),
            "followup_remaining": max(cap - count, 0),
            "followup_count": count,
            "max_followups": cap,
            "session_id": data.get("session_id", session_id),
        }
        return _dump(normalized)
  • The tool is registered via FastMCP's @mcp.tool() decorator on the luopan_chat function. No separate registration table; decorator-based registration on line 100.
    @mcp.tool()
    async def luopan_chat(session_id: str, question: str) -> str:
  • Schema/contract for the tool: parameters (session_id: str, question: str) and return structure (answer, followup_remaining, followup_count, max_followups, session_id). Defined via docstring and the normalized dict in the response.
    """Ask a follow-up question against an existing chart-reading session.
    
    Session_id comes from a prior luopan_analyze call. The backend enforces
    a 2-hour TTL and a 5-question cap; when either is hit, call luopan_analyze
    again to open a new session.
    
    Returns (normalized):
      answer:              the AI reply text
      followup_remaining:  questions you still have left after this one
      followup_count:      questions used so far (incl. this one)
      max_followups:       hard cap (5)
      session_id:          echoed back
    
    When `followup_remaining == 0` or this call returns `session_expired`,
    the next turn must call luopan_analyze to open a fresh session.
    When `followup_remaining == 1`, warn the user before they spend it.
    
    Args:
        session_id: The session_id returned by luopan_analyze
        question: The user's follow-up question (specific events / years / topics
                  yield better answers than vague "is my fate good")
    """
  • Helper HTTP client method 'chat' on LuopanClient that calls the backend POST /api/chat with session_id and question. This is the underlying network call supporting luopan_chat.
    async def chat(self, session_id: str, question: str) -> dict[str, Any]:
        return await self._post(
            "/api/chat",
            {"session_id": session_id, "question": question},
        )
  • Helper functions _err (error response) and _dump (JSON formatting) used by the luopan_chat handler.
    def _err(kind: str, hint: str) -> str:
        return json.dumps({"error": kind, "hint": hint}, ensure_ascii=False)
    
    
    def _dump(payload: dict) -> str:
        return json.dumps(payload, ensure_ascii=False, indent=2)
Behavior5/5

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

With no annotations, the description fully discloses behavior: backend-enforced limits, return fields with meanings, and lifecycle management. It clearly states what happens when limits are hit, meeting the full burden for behavioral transparency.

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 well-structured: purpose statement, runtime constraints, structured return fields, and actionable usage notes. Each sentence earns its place; no redundancy.

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

Completeness5/5

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

Given the output schema not provided as structured input, the description enumerates return fields and their meanings. It fully explains the session lifecycle, restrictions, and expected behavior, providing complete context for an AI to use the tool correctly within the sibling ecosystem.

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

Parameters5/5

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

Schema coverage is 0%, so description must add meaning. It explains session_id comes from prior luopan_analyze, and question provides usage tips ('specific events/years/topics yield better answers'). This adds significant value beyond the bare schema.

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: 'Ask a follow-up question against an existing chart-reading session.' It specifies the resource (session) and verb (ask), and distinguishes from sibling tool luopan_analyze, which starts new sessions.

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?

Explicitly guides when to use (follow-up questions) and when not to (session expired or followup_remaining==0, then call luopan_analyze). It also details constraints (2-hour TTL, 5-question cap) and gives actionable advice (warn user when remaining==1).

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/ZoezoeCookie/mcp-luopan'

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