Coverage for src/qdrant_loader_mcp_server/fastmcp_tools/expand.py: 57%
21 statements
« prev ^ index » next coverage.py v7.15.0, created at 2026-07-20 10:15 +0000
« prev ^ index » next coverage.py v7.15.0, created at 2026-07-20 10:15 +0000
1"""FastMCP expansion tools (lazy-loading).
3Delegate to existing handlers — SearchHandler for document/chunk expansion,
4IntelligenceHandler for cluster expansion — and unwrap the structured payload.
5"""
7from __future__ import annotations
9from typing import Annotated, Any
11from fastmcp import Context, FastMCP
12from pydantic import Field
14from ._common import REQUEST_ID, unwrap
17def register_expand_tools(mcp: FastMCP) -> None:
18 @mcp.tool(annotations={"readOnlyHint": True})
19 async def expand_document(
20 ctx: Context,
21 document_id: Annotated[
22 str,
23 Field(
24 description="The ID of the document to expand and retrieve full content",
25 min_length=1,
26 ),
27 ],
28 include_metadata: Annotated[
29 bool, Field(description="Include detailed metadata (optional)")
30 ] = True,
31 include_hierarchy: Annotated[
32 bool,
33 Field(description="Include hierarchy information for Confluence documents"),
34 ] = True,
35 include_attachments: Annotated[
36 bool, Field(description="Include attachment information if available")
37 ] = True,
38 ) -> dict[str, Any]:
39 """Retrieve full document content by document ID for lazy loading."""
40 handler = ctx.lifespan_context["search_handler"]
41 params = {
42 "document_id": document_id,
43 "include_metadata": include_metadata,
44 "include_hierarchy": include_hierarchy,
45 "include_attachments": include_attachments,
46 }
47 return unwrap(await handler.handle_expand_document(REQUEST_ID, params))
49 @mcp.tool(annotations={"readOnlyHint": True})
50 async def expand_chunk_context(
51 ctx: Context,
52 document_id: Annotated[
53 str, Field(description="Unique identifier of the document.", min_length=1)
54 ],
55 chunk_index: Annotated[
56 int,
57 Field(description="Index of the target chunk within the document.", ge=0),
58 ],
59 window_size: Annotated[
60 int,
61 Field(
62 description="Number of chunks to include before and after the target chunk.",
63 ge=0,
64 ),
65 ] = 2,
66 ) -> dict[str, Any]:
67 """Retrieve neighboring chunks within the same document based on chunk_index."""
68 handler = ctx.lifespan_context["search_handler"]
69 params = {
70 "document_id": document_id,
71 "chunk_index": chunk_index,
72 "window_size": window_size,
73 }
74 return unwrap(await handler.handle_expand_chunk_context(REQUEST_ID, params))
76 @mcp.tool(annotations={"readOnlyHint": True})
77 async def expand_cluster(
78 ctx: Context,
79 cluster_id: Annotated[
80 str,
81 Field(
82 description="The ID of the cluster to expand and retrieve all documents",
83 min_length=1,
84 ),
85 ],
86 cluster_session_id: Annotated[
87 str,
88 Field(description="UUID representing a clustering session", min_length=1),
89 ],
90 limit: Annotated[
91 int,
92 Field(
93 description="Maximum number of documents to return from cluster", ge=1
94 ),
95 ] = 20,
96 offset: Annotated[
97 int, Field(description="Number of documents to skip for pagination", ge=0)
98 ] = 0,
99 include_metadata: Annotated[
100 bool, Field(description="Include detailed metadata for each document")
101 ] = True,
102 ) -> dict[str, Any]:
103 """Retrieve all documents from a specific cluster for lazy loading."""
104 handler = ctx.lifespan_context["intelligence_handler"]
105 params = {
106 "cluster_id": cluster_id,
107 "cluster_session_id": cluster_session_id,
108 "limit": limit,
109 "offset": offset,
110 "include_metadata": include_metadata,
111 }
112 return unwrap(await handler.handle_expand_cluster(REQUEST_ID, params))