qtype 0.1.10__py3-none-any.whl → 0.1.12__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (216) hide show
  1. docs/Concepts/mental-model-and-philosophy.md +363 -0
  2. docs/Contributing/index.md +276 -0
  3. docs/Contributing/roadmap.md +81 -0
  4. docs/Decisions/ADR-001-Chat-vs-Completion-Endpoint-Features.md +56 -0
  5. docs/Gallery/dataflow_pipelines.md +80 -0
  6. docs/Gallery/dataflow_pipelines.mermaid +45 -0
  7. docs/Gallery/research_assistant.md +98 -0
  8. docs/Gallery/research_assistant.mermaid +42 -0
  9. docs/Gallery/simple_chatbot.md +36 -0
  10. docs/Gallery/simple_chatbot.mermaid +35 -0
  11. docs/How To/Authentication/configure_aws_authentication.md +60 -0
  12. docs/How To/Authentication/use_api_key_authentication.md +40 -0
  13. docs/How To/Command Line Usage/load_multiple_inputs_from_files.md +62 -0
  14. docs/How To/Command Line Usage/pass_inputs_on_the_cli.md +52 -0
  15. docs/How To/Command Line Usage/serve_with_auto_reload.md +26 -0
  16. docs/How To/Data Processing/adjust_concurrency.md +41 -0
  17. docs/How To/Data Processing/cache_step_results.md +71 -0
  18. docs/How To/Data Processing/decode_json_xml.md +24 -0
  19. docs/How To/Data Processing/explode_collections.md +40 -0
  20. docs/How To/Data Processing/gather_results.md +68 -0
  21. docs/How To/Data Processing/read_data_from_files.md +35 -0
  22. docs/How To/Data Processing/read_sql_databases.md +47 -0
  23. docs/How To/Data Processing/write_data_to_file.md +40 -0
  24. docs/How To/Invoke Models/call_large_language_models.md +51 -0
  25. docs/How To/Invoke Models/create_embeddings.md +49 -0
  26. docs/How To/Invoke Models/reuse_prompts_with_templates.md +39 -0
  27. docs/How To/Language Features/include_qtype_yaml.md +45 -0
  28. docs/How To/Language Features/include_raw_text_from_other_files.md +47 -0
  29. docs/How To/Language Features/reference_entities_by_id.md +51 -0
  30. docs/How To/Language Features/use_environment_variables.md +47 -0
  31. docs/How To/Language Features/use_qtype_mcp.md +59 -0
  32. docs/How To/Observability & Debugging/trace_calls_with_open_telemetry.md +49 -0
  33. docs/How To/Observability & Debugging/validate_qtype_yaml.md +35 -0
  34. docs/How To/Observability & Debugging/visualize_application_architecture.md +61 -0
  35. docs/How To/Observability & Debugging/visualize_example.mermaid +35 -0
  36. docs/How To/Qtype Server/flow_as_ui.png +0 -0
  37. docs/How To/Qtype Server/serve_flows_as_apis.md +40 -0
  38. docs/How To/Qtype Server/serve_flows_as_ui.md +42 -0
  39. docs/How To/Qtype Server/use_conversational_interfaces.md +59 -0
  40. docs/How To/Qtype Server/use_variables_with_ui_hints.md +47 -0
  41. docs/How To/Tools & Integration/bind_tool_inputs_and_outputs.md +48 -0
  42. docs/How To/Tools & Integration/create_tools_from_openapi_specifications.md +89 -0
  43. docs/How To/Tools & Integration/create_tools_from_python_modules.md +90 -0
  44. docs/Reference/cli.md +338 -0
  45. docs/Reference/plugins.md +95 -0
  46. docs/Reference/semantic-validation-rules.md +179 -0
  47. docs/Tutorials/01-first-qtype-application.md +248 -0
  48. docs/Tutorials/02-conversational-chatbot.md +327 -0
  49. docs/Tutorials/03-structured-data.md +481 -0
  50. docs/Tutorials/04-tools-and-function-calling.md +483 -0
  51. docs/Tutorials/example_chat.png +0 -0
  52. docs/Tutorials/index.md +92 -0
  53. docs/components/APIKeyAuthProvider.md +7 -0
  54. docs/components/APITool.md +10 -0
  55. docs/components/AWSAuthProvider.md +13 -0
  56. docs/components/AWSSecretManager.md +5 -0
  57. docs/components/Agent.md +6 -0
  58. docs/components/Aggregate.md +8 -0
  59. docs/components/AggregateStats.md +7 -0
  60. docs/components/Application.md +22 -0
  61. docs/components/AuthorizationProvider.md +6 -0
  62. docs/components/AuthorizationProviderList.md +5 -0
  63. docs/components/BearerTokenAuthProvider.md +6 -0
  64. docs/components/BedrockReranker.md +8 -0
  65. docs/components/ChatContent.md +7 -0
  66. docs/components/ChatMessage.md +6 -0
  67. docs/components/ConstantPath.md +5 -0
  68. docs/components/CustomType.md +7 -0
  69. docs/components/Decoder.md +8 -0
  70. docs/components/DecoderFormat.md +8 -0
  71. docs/components/DocToTextConverter.md +7 -0
  72. docs/components/Document.md +7 -0
  73. docs/components/DocumentEmbedder.md +7 -0
  74. docs/components/DocumentIndex.md +7 -0
  75. docs/components/DocumentSearch.md +7 -0
  76. docs/components/DocumentSource.md +12 -0
  77. docs/components/DocumentSplitter.md +10 -0
  78. docs/components/Echo.md +8 -0
  79. docs/components/Embedding.md +7 -0
  80. docs/components/EmbeddingModel.md +6 -0
  81. docs/components/FieldExtractor.md +20 -0
  82. docs/components/FileSource.md +6 -0
  83. docs/components/FileWriter.md +7 -0
  84. docs/components/Flow.md +14 -0
  85. docs/components/FlowInterface.md +7 -0
  86. docs/components/Index.md +8 -0
  87. docs/components/IndexUpsert.md +6 -0
  88. docs/components/InvokeEmbedding.md +7 -0
  89. docs/components/InvokeFlow.md +8 -0
  90. docs/components/InvokeTool.md +8 -0
  91. docs/components/LLMInference.md +9 -0
  92. docs/components/ListType.md +5 -0
  93. docs/components/Memory.md +8 -0
  94. docs/components/MessageRole.md +14 -0
  95. docs/components/Model.md +10 -0
  96. docs/components/ModelList.md +5 -0
  97. docs/components/OAuth2AuthProvider.md +9 -0
  98. docs/components/PrimitiveTypeEnum.md +21 -0
  99. docs/components/PromptTemplate.md +7 -0
  100. docs/components/PythonFunctionTool.md +7 -0
  101. docs/components/RAGChunk.md +7 -0
  102. docs/components/RAGDocument.md +10 -0
  103. docs/components/RAGSearchResult.md +8 -0
  104. docs/components/Reranker.md +5 -0
  105. docs/components/SQLSource.md +8 -0
  106. docs/components/Search.md +7 -0
  107. docs/components/SearchResult.md +7 -0
  108. docs/components/SecretManager.md +7 -0
  109. docs/components/SecretReference.md +7 -0
  110. docs/components/Source.md +6 -0
  111. docs/components/Step.md +9 -0
  112. docs/components/TelemetrySink.md +9 -0
  113. docs/components/Tool.md +9 -0
  114. docs/components/ToolList.md +5 -0
  115. docs/components/ToolParameter.md +6 -0
  116. docs/components/TypeList.md +5 -0
  117. docs/components/Variable.md +6 -0
  118. docs/components/VariableList.md +5 -0
  119. docs/components/VectorIndex.md +7 -0
  120. docs/components/VectorSearch.md +6 -0
  121. docs/components/VertexAuthProvider.md +9 -0
  122. docs/components/Writer.md +5 -0
  123. docs/example_ui.png +0 -0
  124. docs/index.md +81 -0
  125. docs/legacy_how_tos/Configuration/modular-yaml.md +366 -0
  126. docs/legacy_how_tos/Configuration/phoenix_projects.png +0 -0
  127. docs/legacy_how_tos/Configuration/phoenix_traces.png +0 -0
  128. docs/legacy_how_tos/Configuration/reference-by-id.md +251 -0
  129. docs/legacy_how_tos/Configuration/telemetry-setup.md +259 -0
  130. docs/legacy_how_tos/Data Types/custom-types.md +52 -0
  131. docs/legacy_how_tos/Data Types/domain-types.md +113 -0
  132. docs/legacy_how_tos/Debugging/visualize-apps.md +147 -0
  133. docs/legacy_how_tos/Tools/api-tools.md +29 -0
  134. docs/legacy_how_tos/Tools/python-tools.md +299 -0
  135. examples/authentication/aws_authentication.qtype.yaml +63 -0
  136. examples/conversational_ai/hello_world_chat.qtype.yaml +43 -0
  137. examples/conversational_ai/simple_chatbot.qtype.yaml +40 -0
  138. examples/data_processing/batch_processing.qtype.yaml +54 -0
  139. examples/data_processing/cache_step_results.qtype.yaml +78 -0
  140. examples/data_processing/collect_results.qtype.yaml +55 -0
  141. examples/data_processing/dataflow_pipelines.qtype.yaml +108 -0
  142. examples/data_processing/decode_json.qtype.yaml +23 -0
  143. examples/data_processing/explode_items.qtype.yaml +25 -0
  144. examples/data_processing/read_file.qtype.yaml +60 -0
  145. examples/invoke_models/create_embeddings.qtype.yaml +28 -0
  146. examples/invoke_models/simple_llm_call.qtype.yaml +32 -0
  147. examples/language_features/include_raw.qtype.yaml +27 -0
  148. examples/language_features/ui_hints.qtype.yaml +52 -0
  149. examples/legacy/bedrock/data_analysis_with_telemetry.qtype.yaml +169 -0
  150. examples/legacy/bedrock/hello_world.qtype.yaml +39 -0
  151. examples/legacy/bedrock/hello_world_chat.qtype.yaml +37 -0
  152. examples/legacy/bedrock/hello_world_chat_with_telemetry.qtype.yaml +40 -0
  153. examples/legacy/bedrock/hello_world_chat_with_thinking.qtype.yaml +40 -0
  154. examples/legacy/bedrock/hello_world_completion.qtype.yaml +41 -0
  155. examples/legacy/bedrock/hello_world_completion_with_auth.qtype.yaml +44 -0
  156. examples/legacy/bedrock/simple_agent_chat.qtype.yaml +46 -0
  157. examples/legacy/chat_with_langfuse.qtype.yaml +50 -0
  158. examples/legacy/data_processor.qtype.yaml +48 -0
  159. examples/legacy/echo/debug_example.qtype.yaml +59 -0
  160. examples/legacy/echo/prompt.qtype.yaml +22 -0
  161. examples/legacy/echo/test.qtype.yaml +26 -0
  162. examples/legacy/echo/video.qtype.yaml +20 -0
  163. examples/legacy/field_extractor_example.qtype.yaml +137 -0
  164. examples/legacy/multi_flow_example.qtype.yaml +125 -0
  165. examples/legacy/openai/hello_world_chat.qtype.yaml +43 -0
  166. examples/legacy/openai/hello_world_chat_with_telemetry.qtype.yaml +46 -0
  167. examples/legacy/rag.qtype.yaml +207 -0
  168. examples/legacy/time_utilities.qtype.yaml +64 -0
  169. examples/legacy/vertex/hello_world_chat.qtype.yaml +36 -0
  170. examples/legacy/vertex/hello_world_completion.qtype.yaml +40 -0
  171. examples/legacy/vertex/hello_world_completion_with_auth.qtype.yaml +45 -0
  172. examples/observability_debugging/trace_with_opentelemetry.qtype.yaml +40 -0
  173. examples/research_assistant/research_assistant.qtype.yaml +94 -0
  174. examples/research_assistant/tavily.oas.yaml +722 -0
  175. examples/research_assistant/tavily.qtype.yaml +289 -0
  176. examples/tutorials/01_hello_world.qtype.yaml +48 -0
  177. examples/tutorials/02_conversational_chat.qtype.yaml +37 -0
  178. examples/tutorials/03_structured_data.qtype.yaml +130 -0
  179. examples/tutorials/04_tools_and_function_calling.qtype.yaml +89 -0
  180. qtype/application/converters/tools_from_api.py +39 -35
  181. qtype/base/types.py +6 -1
  182. qtype/commands/convert.py +3 -6
  183. qtype/commands/generate.py +7 -3
  184. qtype/commands/mcp.py +68 -0
  185. qtype/commands/validate.py +4 -4
  186. qtype/dsl/custom_types.py +2 -1
  187. qtype/dsl/linker.py +15 -7
  188. qtype/dsl/loader.py +3 -3
  189. qtype/dsl/model.py +24 -3
  190. qtype/interpreter/api.py +4 -1
  191. qtype/interpreter/base/base_step_executor.py +3 -1
  192. qtype/interpreter/conversions.py +7 -3
  193. qtype/interpreter/executors/construct_executor.py +1 -1
  194. qtype/interpreter/executors/document_splitter_executor.py +4 -1
  195. qtype/interpreter/executors/file_source_executor.py +3 -3
  196. qtype/interpreter/executors/file_writer_executor.py +4 -4
  197. qtype/interpreter/executors/index_upsert_executor.py +1 -1
  198. qtype/interpreter/executors/sql_source_executor.py +1 -1
  199. qtype/interpreter/resource_cache.py +3 -1
  200. qtype/interpreter/rich_progress.py +6 -3
  201. qtype/interpreter/stream/chat/converter.py +25 -17
  202. qtype/interpreter/stream/chat/ui_request_to_domain_type.py +2 -2
  203. qtype/interpreter/typing.py +5 -7
  204. qtype/mcp/__init__.py +0 -0
  205. qtype/mcp/server.py +467 -0
  206. qtype/semantic/checker.py +1 -1
  207. qtype/semantic/generate.py +3 -3
  208. qtype/semantic/visualize.py +38 -51
  209. {qtype-0.1.10.dist-info → qtype-0.1.12.dist-info}/METADATA +21 -1
  210. qtype-0.1.12.dist-info/RECORD +325 -0
  211. {qtype-0.1.10.dist-info → qtype-0.1.12.dist-info}/WHEEL +1 -1
  212. schema/qtype.schema.json +4018 -0
  213. qtype-0.1.10.dist-info/RECORD +0 -142
  214. {qtype-0.1.10.dist-info → qtype-0.1.12.dist-info}/entry_points.txt +0 -0
  215. {qtype-0.1.10.dist-info → qtype-0.1.12.dist-info}/licenses/LICENSE +0 -0
  216. {qtype-0.1.10.dist-info → qtype-0.1.12.dist-info}/top_level.txt +0 -0
qtype/mcp/server.py ADDED
@@ -0,0 +1,467 @@
1
+ from __future__ import annotations
2
+
3
+ import json
4
+ import re
5
+ from functools import lru_cache
6
+ from importlib.resources import files
7
+ from pathlib import Path
8
+ from typing import Any
9
+
10
+ from mcp.server.fastmcp import FastMCP
11
+ from pydantic import BaseModel
12
+
13
+ from qtype.commands.convert import convert_to_yaml
14
+
15
+ # Initialize FastMCP server
16
+ mcp = FastMCP("qtype", host="0.0.0.0")
17
+
18
+ # Regex for pymdownx snippets: --8<-- "path/to/file"
19
+ SNIPPET_REGEX = re.compile(r'--8<--\s+"([^"]+)"')
20
+
21
+
22
+ # ============================================================================
23
+ # Helper Functions
24
+ # ============================================================================
25
+
26
+
27
+ def _get_docs_path() -> Path:
28
+ """Get the path to the documentation directory.
29
+
30
+ Returns:
31
+ Path to the docs directory, trying installed package first,
32
+ then falling back to development path.
33
+ """
34
+ try:
35
+ # Try to get from installed package
36
+ docs_root = files("qtype") / "docs"
37
+ # Check if it exists by trying to iterate
38
+ list(docs_root.iterdir())
39
+ return Path(str(docs_root))
40
+ except (FileNotFoundError, AttributeError, TypeError):
41
+ # Fall back to development path
42
+ return Path(__file__).parent.parent.parent / "docs"
43
+
44
+
45
+ @lru_cache(maxsize=1)
46
+ def _load_schema() -> dict[str, Any]:
47
+ """Load the QType schema JSON file once and cache it.
48
+
49
+ Returns:
50
+ The complete schema as a dictionary.
51
+
52
+ Raises:
53
+ FileNotFoundError: If schema file doesn't exist.
54
+ json.JSONDecodeError: If schema file is invalid JSON.
55
+ """
56
+ # Try to load from installed package data first
57
+ try:
58
+ schema_file = files("qtype") / "qtype.schema.json"
59
+ schema_text = schema_file.read_text(encoding="utf-8")
60
+ return json.loads(schema_text)
61
+ except (FileNotFoundError, AttributeError):
62
+ # Fall back to development path
63
+ schema_path = (
64
+ Path(__file__).parent.parent.parent / "schema/qtype.schema.json"
65
+ )
66
+ with open(schema_path, encoding="utf-8") as f:
67
+ return json.load(f)
68
+
69
+
70
+ def resolve_snippets(content: str, base_path: Path) -> str:
71
+ """
72
+ Recursively finds and replaces MkDocs snippets in markdown content.
73
+ Mimics the behavior of pymdownx.snippets.
74
+
75
+ Args:
76
+ content: The markdown content to process
77
+ base_path: Path to the file being processed (used to resolve relative paths)
78
+ """
79
+ docs_root = _get_docs_path()
80
+ project_root = docs_root.parent
81
+
82
+ def replace_match(match):
83
+ snippet_path = match.group(1)
84
+
85
+ # pymdownx logic: try relative to current file, then relative to docs, then project root
86
+ candidates = [
87
+ base_path.parent / snippet_path, # Relative to the doc file
88
+ docs_root / snippet_path, # Relative to docs root
89
+ project_root / snippet_path, # Relative to project root
90
+ ]
91
+
92
+ for candidate in candidates:
93
+ if candidate.exists() and candidate.is_file():
94
+ # Recursively resolve snippets inside the included file
95
+ return resolve_snippets(
96
+ candidate.read_text(encoding="utf-8"), candidate
97
+ )
98
+
99
+ return f"> [!WARNING] Could not resolve snippet: {snippet_path}"
100
+
101
+ return SNIPPET_REGEX.sub(replace_match, content)
102
+
103
+
104
+ # ============================================================================
105
+ # Tool Functions
106
+ # ============================================================================
107
+
108
+
109
+ class MermaidDiagramPreviewInput(BaseModel):
110
+ """Arguments for VS Code's `mermaid-diagram-preview` tool."""
111
+
112
+ code: str
113
+
114
+
115
+ class MermaidVisualizationResult(BaseModel):
116
+ """Structured output for Mermaid visualization."""
117
+
118
+ mermaid_code: str
119
+ mermaid_markdown: str
120
+ suggested_next_tool: str
121
+ mermaid_diagram_preview_input: MermaidDiagramPreviewInput
122
+ preview_instructions: str
123
+
124
+
125
+ @mcp.tool(
126
+ title="Convert API Specification to QType Tools",
127
+ description=(
128
+ "Converts an OpenAPI specification (URL or file path) to QType tool definitions. "
129
+ "Returns YAML code containing the generated tools, custom types, and authentication "
130
+ "providers that can be used in QType applications."
131
+ ),
132
+ )
133
+ async def convert_api_to_tools(api_spec: str) -> str:
134
+ """Convert API specification to QType YAML format.
135
+
136
+ Args:
137
+ api_spec: URL or file path to an OpenAPI/Swagger specification.
138
+ Examples: "https://api.example.com/openapi.json",
139
+ "/path/to/openapi.yaml"
140
+
141
+ Returns:
142
+ YAML string containing the generated QType tools, types, and
143
+ authentication providers.
144
+
145
+ Raises:
146
+ Exception: If conversion fails or no tools are found.
147
+ """
148
+ from qtype.application.converters.tools_from_api import tools_from_api
149
+ from qtype.dsl.model import Application, ToolList
150
+
151
+ try:
152
+ api_name, auths, tools, types = tools_from_api(api_spec)
153
+ if not tools:
154
+ raise ValueError(
155
+ f"No tools found from the API specification: {api_spec}"
156
+ )
157
+
158
+ # Create document with or without Application wrapper
159
+ if not auths and not types:
160
+ doc = ToolList(root=list(tools))
161
+ else:
162
+ doc = Application(
163
+ id=api_name,
164
+ description=(
165
+ f"Tools created from API specification {api_spec}"
166
+ ),
167
+ tools=list(tools),
168
+ types=types,
169
+ auths=auths,
170
+ )
171
+
172
+ return convert_to_yaml(doc)
173
+
174
+ except Exception as e:
175
+ raise Exception(f"API conversion failed: {str(e)}")
176
+
177
+
178
+ @mcp.tool(
179
+ title="Convert Python Module to QType Tools",
180
+ description=(
181
+ "Converts Python functions from a module to QType tool definitions. "
182
+ "Analyzes function signatures, docstrings, and type hints to generate "
183
+ "YAML tool definitions that can be used in QType applications."
184
+ ),
185
+ )
186
+ async def convert_python_to_tools(module_path: str) -> str:
187
+ """Convert Python module to QType YAML format.
188
+
189
+ Args:
190
+ module_path: Path to the Python module to convert.
191
+ Example: "my_package.my_module" or "/path/to/module.py"
192
+
193
+ Returns:
194
+ YAML string containing the generated QType tools and custom types.
195
+
196
+ Raises:
197
+ Exception: If conversion fails or no tools are found.
198
+ """
199
+ from qtype.application.converters.tools_from_module import (
200
+ tools_from_module,
201
+ )
202
+ from qtype.dsl.model import Application, ToolList
203
+
204
+ try:
205
+ tools, types = tools_from_module(module_path)
206
+ if not tools:
207
+ raise ValueError(f"No tools found in the module: {module_path}")
208
+
209
+ # Create document with or without Application wrapper
210
+ if types:
211
+ doc = Application(
212
+ id=module_path,
213
+ description=(
214
+ f"Tools created from Python module {module_path}"
215
+ ),
216
+ tools=list(tools),
217
+ types=types,
218
+ )
219
+ else:
220
+ doc = ToolList(root=list(tools))
221
+
222
+ return convert_to_yaml(doc)
223
+
224
+ except Exception as e:
225
+ raise Exception(f"Python module conversion failed: {str(e)}")
226
+
227
+
228
+ @mcp.tool(
229
+ title="Get QType Component Schema",
230
+ description=(
231
+ "Returns the JSON Schema definition for a specific QType component. "
232
+ "Use this to understand the structure, required fields, and allowed values "
233
+ "when building QType YAML specifications. "
234
+ "Common components include: Flow, Agent, LLMInference, DocumentSource, "
235
+ "Application, Model, Variable, CustomType. "
236
+ "Component names are case-sensitive and must match exactly."
237
+ ),
238
+ structured_output=True,
239
+ )
240
+ def get_component_schema(component_name: str) -> dict[str, Any]:
241
+ """Get the JSON Schema definition for a QType component.
242
+
243
+ Args:
244
+ component_name: The exact name of the QType component (case-sensitive).
245
+ Examples: "DocumentSource", "Flow", "Agent", "LLMInference",
246
+ "Application", "Model", "Variable", "CustomType".
247
+
248
+ Returns:
249
+ JSON Schema definition for the component including its properties,
250
+ required fields, types, and descriptions.
251
+
252
+ Raises:
253
+ ValueError: If component_name is not found. The error message will
254
+ include a list of all available component names.
255
+ """
256
+ schema = _load_schema()
257
+
258
+ # Look up the component in $defs
259
+ if "$defs" not in schema:
260
+ raise ValueError("Schema file does not contain $defs section")
261
+
262
+ if component_name not in schema["$defs"]:
263
+ available = sorted(schema["$defs"].keys())
264
+ raise ValueError(
265
+ f"Component '{component_name}' not found in schema. "
266
+ f"Available components: {', '.join(available)}"
267
+ )
268
+
269
+ return schema["$defs"][component_name]
270
+
271
+
272
+ @mcp.tool(
273
+ title="Get QType Documentation",
274
+ description=(
275
+ "Returns the content of a specific documentation file. "
276
+ "Use list_documentation first to see available files. "
277
+ "Provide the relative path (e.g., 'components/Flow.md', 'index.md', "
278
+ "'Tutorials/getting_started.md')."
279
+ ),
280
+ )
281
+ def get_documentation(file_path: str) -> str:
282
+ """Get the content of a specific documentation file.
283
+
284
+ Args:
285
+ file_path: Relative path to the documentation file from the docs root.
286
+ Example: "components/Flow.md", "index.md", "Tutorials/getting_started.md".
287
+ Use list_documentation to see all available files.
288
+
289
+ Returns:
290
+ The full markdown content of the documentation file.
291
+
292
+ Raises:
293
+ FileNotFoundError: If the specified file doesn't exist.
294
+ ValueError: If the path tries to access files outside the docs directory.
295
+ """
296
+ docs_path = _get_docs_path()
297
+
298
+ # Resolve the requested file path
299
+ requested_file = (docs_path / file_path).resolve()
300
+
301
+ # Security check: ensure the resolved path is within docs directory
302
+ try:
303
+ requested_file.relative_to(docs_path.resolve())
304
+ except ValueError:
305
+ raise ValueError(
306
+ f"Invalid path: '{file_path}' is outside documentation directory"
307
+ )
308
+
309
+ if not requested_file.exists():
310
+ raise FileNotFoundError(
311
+ f"Documentation file not found: '{file_path}'. "
312
+ "Use list_documentation to see available files."
313
+ )
314
+
315
+ if not requested_file.is_file():
316
+ raise ValueError(f"Path is not a file: '{file_path}'")
317
+
318
+ content = requested_file.read_text(encoding="utf-8")
319
+ return resolve_snippets(content, requested_file)
320
+
321
+
322
+ @mcp.tool(
323
+ title="List QType Components",
324
+ description=(
325
+ "Returns a list of all available QType component types that can be used "
326
+ "in YAML specifications. Use this to discover what components exist before "
327
+ "requesting their detailed schemas with get_component_schema."
328
+ ),
329
+ structured_output=True,
330
+ )
331
+ def list_components() -> list[str]:
332
+ """List all available QType component types.
333
+
334
+ Returns:
335
+ Sorted list of all component names available in the QType schema.
336
+ Each name can be used with get_component_schema to retrieve its
337
+ full JSON Schema definition.
338
+ """
339
+ schema = _load_schema()
340
+
341
+ if "$defs" not in schema:
342
+ raise ValueError("Schema file does not contain $defs section")
343
+
344
+ return sorted(schema["$defs"].keys())
345
+
346
+
347
+ @mcp.tool(
348
+ title="List QType Documentation",
349
+ description=(
350
+ "Returns a list of all available documentation files. "
351
+ "Use this to discover what documentation exists, then retrieve "
352
+ "specific files with get_documentation. Files are organized by category: "
353
+ "components/ (component reference), Concepts/ (conceptual guides), "
354
+ "Tutorials/ (step-by-step tutorials), How To/ (task guides), etc."
355
+ ),
356
+ structured_output=True,
357
+ )
358
+ def list_documentation() -> list[str]:
359
+ """List all available documentation markdown files.
360
+
361
+ Returns:
362
+ Sorted list of relative paths to all .md documentation files.
363
+ Paths are relative to the docs root (e.g., "components/Flow.md",
364
+ "Tutorials/getting_started.md").
365
+ """
366
+ docs_path = _get_docs_path()
367
+
368
+ if not docs_path.exists():
369
+ raise FileNotFoundError(
370
+ f"Documentation directory not found: {docs_path}"
371
+ )
372
+
373
+ # Find all markdown files
374
+ md_files = []
375
+ for md_file in docs_path.rglob("*.md"):
376
+ # Get relative path from docs root
377
+ rel_path = md_file.relative_to(docs_path)
378
+ md_files.append(str(rel_path))
379
+
380
+ return sorted(md_files)
381
+
382
+
383
+ @mcp.tool(
384
+ title="Validate QType YAML",
385
+ description=(
386
+ "Validates QType YAML for syntax and semantic correctness. "
387
+ "Returns a human-readable status string: either a success message or "
388
+ "a validation error with details."
389
+ ),
390
+ )
391
+ async def validate_qtype_yaml(yaml_content: str) -> str:
392
+ """Validate QType YAML for syntax and semantic errors.
393
+
394
+ Args:
395
+ yaml_content: The QType YAML content to validate.
396
+
397
+ Returns:
398
+ A human-readable status string.
399
+ """
400
+ from qtype.semantic.loader import load_from_string
401
+
402
+ try:
403
+ document, _ = load_from_string(yaml_content)
404
+ return "✅ Valid QType Code"
405
+
406
+ except Exception as e:
407
+ # Return the error message so the LLM can fix it
408
+ return f"❌ Validation Error: {str(e)}"
409
+
410
+
411
+ @mcp.tool(
412
+ title="Visualize QType Architecture",
413
+ description=(
414
+ "Generates a Mermaid flowchart diagram from QType YAML code. "
415
+ "Returns a structured result containing raw Mermaid code plus preview guidance. "
416
+ "After calling this tool, call the mermaid-diagram-preview tool using the "
417
+ "returned mermaid_diagram_preview_input."
418
+ ),
419
+ structured_output=True,
420
+ )
421
+ async def visualize_qtype_architecture(
422
+ yaml_content: str,
423
+ ) -> MermaidVisualizationResult:
424
+ """Generate Mermaid diagram from QType YAML.
425
+
426
+ Args:
427
+ yaml_content: The complete QType YAML specification to visualize.
428
+ Must be a valid Application definition.
429
+
430
+ Returns:
431
+ A structured result with:
432
+ - mermaid_code: Raw Mermaid diagram code (no backticks/fences)
433
+ - suggested_next_tool: "mermaid-diagram-preview"
434
+ - preview_instructions: How to preview in VS Code
435
+
436
+ Raises:
437
+ Exception: If YAML is invalid or visualization fails.
438
+ """
439
+ from qtype.semantic.loader import load_from_string
440
+ from qtype.semantic.model import Application
441
+ from qtype.semantic.visualize import visualize_application
442
+
443
+ try:
444
+ document, _ = load_from_string(yaml_content)
445
+ if not isinstance(document, Application):
446
+ raise ValueError(
447
+ "YAML must contain an Application to visualize. "
448
+ f"Got {type(document).__name__} instead."
449
+ )
450
+ mermaid_content = visualize_application(document)
451
+
452
+ return MermaidVisualizationResult(
453
+ mermaid_code=mermaid_content,
454
+ mermaid_markdown=f"```mermaid\n{mermaid_content}\n```\n",
455
+ suggested_next_tool="mermaid-diagram-preview",
456
+ mermaid_diagram_preview_input=MermaidDiagramPreviewInput(
457
+ code=mermaid_content
458
+ ),
459
+ preview_instructions=(
460
+ "Call mermaid-diagram-preview with mermaid_diagram_preview_input. "
461
+ "Alternatively, save mermaid_code in a .md file fenced with "
462
+ "```mermaid ...``` and open the Markdown preview."
463
+ ),
464
+ )
465
+
466
+ except Exception as e:
467
+ raise RuntimeError(f"Visualization failed: {e}") from e
qtype/semantic/checker.py CHANGED
@@ -704,7 +704,7 @@ def check(model: BaseModel) -> None:
704
704
  # Check if this model type has a validator
705
705
  model_type = type(model)
706
706
  if model_type in _VALIDATORS:
707
- _VALIDATORS[model_type](model)
707
+ _VALIDATORS[model_type](model) # type: ignore[arg-type]
708
708
 
709
709
  # Recursively validate all fields
710
710
  for field_name, field_value in model:
@@ -73,7 +73,7 @@ def sort_classes_by_inheritance(
73
73
  ):
74
74
  graph.add_edge(base.__name__, class_name)
75
75
 
76
- sorted_names = list(nx.topological_sort(graph))
76
+ sorted_names = list(nx.topological_sort(graph)) # type: ignore[arg-type]
77
77
 
78
78
  # sorted_names = sorted(graph.nodes, key=lambda node: depths[node])
79
79
  return [(name, class_dict[name]) for name in sorted_names]
@@ -490,10 +490,10 @@ def generate_semantic_class(class_name: str, cls: type) -> str:
490
490
  # Only process fields that are actually defined on this class
491
491
  for field_name in cls.__annotations__:
492
492
  if (
493
- field_name in cls.model_fields
493
+ field_name in cls.model_fields # type: ignore[operator]
494
494
  and f"{class_name}.{field_name}" not in FIELDS_TO_IGNORE
495
495
  ):
496
- field_info = cls.model_fields[field_name]
496
+ field_info = cls.model_fields[field_name] # type: ignore[index]
497
497
  field_type = field_info.annotation
498
498
  field_default = field_info.default
499
499
  field_default_factory = field_info.default_factory