Skip to main content
Glama

answer_question

Retrieve relevant documentation chunks as RAG context with citations to answer questions about Open Finance Brasil.

Instructions

Retrieve the most relevant chunks formatted as RAG context.

The MCP itself does NOT call an LLM — it returns the raw context plus citations so the calling assistant can answer using its own context window (saving tokens vs. running a second model here).

Input Schema

TableJSON Schema
NameRequiredDescriptionDefault
questionYes
max_chunksNo

Output Schema

TableJSON Schema
NameRequiredDescriptionDefault
resultYes

Implementation Reference

  • Handler function for the answer_question MCP tool. Performs BM25 search via search.search_chunks, formats results with full chunk text via search.format_hits_for_rag, and prepends instructions for the calling LLM to synthesize the answer.
    @mcp.tool()
    def answer_question(question: str, max_chunks: int = 6) -> str:
        """Retrieve the most relevant chunks formatted as RAG context.
    
        The MCP itself does NOT call an LLM — it returns the raw context plus
        citations so the calling assistant can answer using its own context window
        (saving tokens vs. running a second model here).
        """
        max_chunks = max(1, min(int(max_chunks), 12))
        with closing(_conn()) as conn:
            hits = search.search_chunks(conn, question, limit=max_chunks)
        if not hits:
            return (
                f"No relevant docs for the question. Index status: {_index_status()}.\n"
                "If the index is empty, run the crawler first."
            )
        body = search.format_hits_for_rag(hits)
        instructions = (
            "Use the context below to answer the question. Cite sources with "
            "the [n] markers. If the answer is not in the context, say so.\n\n"
            f"Question: {question}\n\nContext:\n"
        )
        return instructions + body
  • Tool registration via FastMCP @mcp.tool() decorator in src/of_mcp/server.py
    @mcp.tool()
    def answer_question(question: str, max_chunks: int = 6) -> str:
  • BM25 search function called by answer_question. Executes FTS5 MATCH query against the SQLite chunks_fts virtual table and returns SearchHit objects.
    def search_chunks(conn: sqlite3.Connection, query: str, limit: int = 8) -> list[SearchHit]:
        fts_query = sanitize_query(query)
        if not fts_query:
            return []
        sql = """
        SELECT
            c.id          AS chunk_id,
            c.page_id     AS page_id,
            p.title       AS page_title,
            p.url         AS page_url,
            c.heading_path AS heading_path,
            snippet(chunks_fts, 1, '<<', '>>', ' … ', 18) AS snippet,
            c.body_md     AS body_md,
            c.token_estimate AS token_estimate,
            bm25(chunks_fts) AS rank
        FROM chunks_fts
        JOIN chunks c ON c.id = chunks_fts.rowid
        JOIN pages  p ON p.id = c.page_id
        WHERE chunks_fts MATCH ?
        ORDER BY rank
        LIMIT ?
        """
        rows = conn.execute(sql, (fts_query, limit)).fetchall()
        return [
            SearchHit(
                chunk_id=r["chunk_id"],
                page_id=r["page_id"],
                page_title=r["page_title"],
                page_url=r["page_url"],
                heading_path=r["heading_path"],
                snippet=r["snippet"],
                body_md=r["body_md"],
                token_estimate=r["token_estimate"],
                rank=float(r["rank"]),
            )
            for r in rows
        ]
  • RAG formatting helper that converts search hits into verbose context blocks with full chunk text, heading path, and source citation, used exclusively by answer_question.
    def format_hits_for_rag(hits: list[SearchHit]) -> str:
        """Verbose formatting (full chunk text) for the answer_question tool."""
        if not hits:
            return "No results."
        blocks = []
        for i, h in enumerate(hits, 1):
            blocks.append(
                f"### [{i}] {h.heading_path}\n"
                f"Source: {h.page_title} — {h.page_url}\n\n"
                f"{h.body_md}"
            )
        return "\n\n---\n\n".join(blocks)
  • Input schema: question (str, required) and max_chunks (int, default 6, clamped to 1-12). Output: str (formatted RAG context with instructions for the LLM).
    @mcp.tool()
    def answer_question(question: str, max_chunks: int = 6) -> str:
Behavior4/5

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

Clearly discloses it does NOT call an LLM and returns raw context plus citations, which is beyond the basic read operation. With no annotations, the description effectively communicates behavioral traits.

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?

Two concise sentences with no redundancy. The key behavioral distinction is front-loaded, and every word adds value.

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?

Provides a clear overview but lacks parameter details, especially for max_chunks. While output schema exists and siblings are given, the description could elaborate on how chunks are selected or the format of citations.

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

Parameters2/5

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

Schema coverage is 0%, and the description does not explain the parameters (question, max_chunks) beyond the implicit context. The default value of max_chunks is not mentioned, nor is the relationship between parameters and output.

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 retrieves relevant chunks formatted as RAG context, distinguishing it from siblings like get_page, list_sections, and search_docs. It specifies it does not call an LLM, clarifying its role in the pipeline.

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

Usage Guidelines4/5

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

Explicitly explains the tool's purpose as providing raw context for the calling assistant, saving tokens by avoiding a second model call. However, it does not explicitly state when to avoid using it or mention alternatives.

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/ThiTheGoat/of-mcp'

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