Files
workflows-py/examples/state_management_with_vector_databases.ipynb
Adrian Lyjak d9fd0d3afd docs: update run-llama/workflows-py references to run-llama/llama-agents (#537)
Repo has been renamed from workflows-py to llama-agents. Update remaining
references in README, docs, CI workflows, and example notebooks.

Co-authored-by: Claude <noreply@anthropic.com>
2026-04-14 22:45:47 +00:00

723 lines
28 KiB
Plaintext
Raw Permalink Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
{
"cells": [
{
"cell_type": "markdown",
"metadata": {
"id": "JtU4X05zuYFU"
},
"source": [
"# Vector Databases For Workflow State Management\n",
"\n",
"Workflows are notoriously event-driven code solutions, but it is more and more crucial, for production-grade applications, that they also have write and read access to a global state where they can store and fetch data that are relevant to their run.\n",
"\n",
"[llama-index-workflows](https://github.com/run-llama/llama-agents) offer a perfect solution for customized, asynchronous and lockable [state management](https://docs.llamaindex.ai/en/latest/module_guides/workflow/#adding-typed-state), but the state lacks persistency across different sessions - and this is exactly where databases, and especially vector databases, enter the game.\n",
"\n",
"With a database, you can take snapshots of the workflow state at the end of a run and store them into it, to retrieve them in later runs and inform the behavior of the workflow itself.\n",
"\n",
"This is key for resource management, but also to create a first proof-of-concept of self-learning workflows.\n",
"\n",
"In this examples, we will see how we can combine [Qdrant](https://qdrant.tech) vector database services with [OpenAI](https://openai.com) LLM capabilties (leveraging remote MCP support for searching DeepWiki and structured generation for parsing the ouputs)."
]
},
{
"cell_type": "markdown",
"metadata": {
"id": "VHPUdFb8wZZt"
},
"source": [
"### 1. Install needed dependencies"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"colab": {
"base_uri": "https://localhost:8080/"
},
"id": "JPrURgHgngB7",
"outputId": "0420e854-001b-4a58-cb41-4f9fdc3cc531"
},
"outputs": [],
"source": [
"%pip install -q llama-index-workflows qdrant-client sentence-transformers openai"
]
},
{
"cell_type": "markdown",
"metadata": {
"id": "JV1KuhKOwl6r"
},
"source": [
"### 2. Define a Raw Vector Database Client\n",
"\n",
"To fulfil our state-management requirements, we need to write a raw vector database client that is able to create a database collection, upload data points (not only text, but also metadata - since our state can easily be transformed into a dictionary) and retrieve those data points with similarity search.\n",
"\n",
"We will use dense vector search to keep things plain and simple, and we will employ [all-MiniLM-L6-v2](sentence-transformers/all-MiniLM-L6-v2) as an embedding model, but you can easily change these settings to add layers of complexity (hybrid search, a better embedding model...) to the vector database client."
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"id": "R1pmhM4SoDfT"
},
"outputs": [],
"source": [
"import json\n",
"from typing import Any\n",
"\n",
"from qdrant_client import AsyncQdrantClient, models\n",
"from sentence_transformers import SentenceTransformer\n",
"\n",
"\n",
"class QdrantVectorDatabase:\n",
" def __init__(\n",
" self,\n",
" client: AsyncQdrantClient,\n",
" model: SentenceTransformer,\n",
" collection_name: str,\n",
" ):\n",
" self._has_vectors = False\n",
" self.client = client\n",
" self.model = model\n",
" self.collection_name = collection_name\n",
"\n",
" async def create_collection(self):\n",
" await self.client.create_collection(\n",
" collection_name=self.collection_name,\n",
" vectors_config=models.VectorParams(\n",
" size=self.model.get_sentence_embedding_dimension() or 384,\n",
" distance=models.Distance.COSINE,\n",
" ),\n",
" )\n",
"\n",
" async def upload(\n",
" self, texts: list[str], metadatas: list[dict[str, Any]], ids: list[str]\n",
" ) -> None:\n",
" self._has_vectors = True\n",
" embeddings = self.model.encode(texts).tolist()\n",
" for i, embedding in enumerate(embeddings):\n",
" await self.client.upsert(\n",
" collection_name=self.collection_name,\n",
" points=[\n",
" models.PointStruct(\n",
" id=ids[i],\n",
" vector=embedding,\n",
" payload=metadatas[i],\n",
" )\n",
" ],\n",
" )\n",
"\n",
" async def search(self, query: str, limit: int, threshold: float = 0.75) -> str:\n",
" if not self._has_vectors:\n",
" return \"\"\n",
" embedding = self.model.encode(query).tolist()\n",
" results = await self.client.search(\n",
" self.collection_name, query_vector=embedding, limit=limit\n",
" )\n",
" payloads = [hit.payload for hit in results if hit.score > threshold]\n",
" return json.dumps(payloads, indent=4)"
]
},
{
"cell_type": "markdown",
"metadata": {
"id": "wXHesf5lxc-K"
},
"source": [
"Let's now create the collection and verify that the collection creation was successful."
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"id": "8Q5XrYx-sJl9"
},
"outputs": [],
"source": [
"qdrant_client = AsyncQdrantClient(\":memory:\")\n",
"model = SentenceTransformer(\"all-MiniLM-L6-v2\")\n",
"collection_name = \"workflow_collection\"\n",
"vdb = QdrantVectorDatabase(qdrant_client, model, collection_name)\n",
"await vdb.create_collection()"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"colab": {
"base_uri": "https://localhost:8080/"
},
"id": "VCDpqYBhsjx1",
"outputId": "bc71bcd8-9be1-48cc-f337-4acfe8db5481"
},
"outputs": [
{
"data": {
"text/plain": [
"True"
]
},
"execution_count": 4,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"await qdrant_client.collection_exists(\"workflow_collection\")"
]
},
{
"cell_type": "markdown",
"metadata": {
"id": "608CBS7Vxpyf"
},
"source": [
"### 3. Design the LLM Client\n",
"\n",
"Since we also need customized functions for the LLM client (like remote MCP DeepWiki search and structured output generation), we will also design an LLM client using `AsyncOpenAI` as a starting point.\n",
"\n",
"We will also add a method with which our LLM client can evaluate the relevance of the retrieved context for our workflow runs."
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"id": "CAnqjLgsstHZ"
},
"outputs": [],
"source": [
"from dataclasses import dataclass\n",
"\n",
"from openai import AsyncOpenAI\n",
"from pydantic import BaseModel, Field\n",
"\n",
"\n",
"class ContextRelevance(BaseModel):\n",
" relevance: int = Field(\n",
" description=\"Relevance of the context based on the user message, expressed as a number between 1 and 100\",\n",
" ge=1,\n",
" le=100,\n",
" )\n",
" reasons: str = Field(description=\"Reasons for the evaluation\")\n",
"\n",
"\n",
"class DeepWikiOutput(BaseModel):\n",
" summary: str = Field(description=\"Summary of the research output\")\n",
" focal_points: list[str] = Field(description=\"Focal points of the research output\")\n",
" references: list[str] = Field(\n",
" description=\"References contained in the reseaerch output\", default_factory=list\n",
" )\n",
" similar_topics: list[str] = Field(\n",
" description=\"Topics similar to the one of the research output\"\n",
" )\n",
"\n",
"\n",
"@dataclass\n",
"class OpenAILlm:\n",
" llm: AsyncOpenAI\n",
"\n",
" async def deep_wiki(self, message: str, context: str | None = None) -> str:\n",
" if not context:\n",
" response = await self.llm.responses.create(\n",
" model=\"gpt-4.1\",\n",
" tools=[\n",
" {\n",
" \"type\": \"mcp\",\n",
" \"server_label\": \"deepwiki\",\n",
" \"server_url\": \"https://mcp.deepwiki.com/mcp\",\n",
" \"require_approval\": \"never\",\n",
" },\n",
" ],\n",
" input=message,\n",
" )\n",
" else:\n",
" response = await self.llm.responses.create(\n",
" model=\"gpt-4.1\",\n",
" tools=[\n",
" {\n",
" \"type\": \"mcp\",\n",
" \"server_label\": \"deepwiki\",\n",
" \"server_url\": \"https://mcp.deepwiki.com/mcp\",\n",
" \"require_approval\": \"never\",\n",
" },\n",
" ],\n",
" input=\"<context>\\n\\t\"\n",
" + context\n",
" + \"\\n</context>\\n<user_message>\\n\\t\"\n",
" + message\n",
" + \"\\n</user_message>\\n<instructions>\\n\\tReply to the user message based on the contextual information\\n</instructions>\",\n",
" )\n",
" return await self.format_deep_wiki_output(response.output_text)\n",
"\n",
" async def classify_context_relevance(self, message: str, context: str) -> str:\n",
" response = await self.llm.responses.parse(\n",
" model=\"gpt-4.1\",\n",
" input=\"<context>\\n\\t\"\n",
" + context\n",
" + \"\\n</context>\\n<user_message>\\n\\t\"\n",
" + message\n",
" + \"\\n</user_message>\\n<instructions>\\n\\tEvaluate the relevance of the context in relation to the user message from 1 to 100, and give reasons for this evaluation\\n</instructions>\",\n",
" text_format=ContextRelevance,\n",
" )\n",
" return response.output_parsed\n",
"\n",
" async def format_deep_wiki_output(self, output: str):\n",
" response = await self.llm.responses.parse(\n",
" model=\"gpt-4.1\",\n",
" input=\"<research_output>\\n\\t\"\n",
" + output\n",
" + \"\\n</research_output>\\n<instructions>\\n\\tFormat the output so that you highlight a summary, the focal points, the references contained into it and further topics to explore similar to the one in the ouput\\n</instructions>\",\n",
" text_format=DeepWikiOutput,\n",
" )\n",
" return response.output_parsed"
]
},
{
"cell_type": "markdown",
"metadata": {
"id": "cgKTPQLxyNv8"
},
"source": [
"### 4. Create Resources\n",
"\n",
"[Resources](https://docs.llamaindex.ai/en/latest/module_guides/workflow/#resources) are a way, in workflows, to perform dependency injection: you define functions to get external serices and make them available, step-wise, within the workflow itself."
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"colab": {
"base_uri": "https://localhost:8080/"
},
"id": "icrEAytxxX2v",
"outputId": "cb4e2a79-8ea5-416b-d655-c761b5149a60"
},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"Enter your OpenAI API key: ··········\n"
]
}
],
"source": [
"from getpass import getpass\n",
"\n",
"llm = AsyncOpenAI(api_key=getpass(\"Enter your OpenAI API key: \"))"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"id": "iI5vi2E8zD4r"
},
"outputs": [],
"source": [
"openai_llm = OpenAILlm(llm)\n",
"\n",
"\n",
"def get_llm(**kwargs):\n",
" return openai_llm\n",
"\n",
"\n",
"def get_vdb(**kwargs):\n",
" return vdb"
]
},
{
"cell_type": "markdown",
"metadata": {
"id": "Wg1SispXy9CP"
},
"source": [
"### 5. Define the Workflow\n",
"\n",
"We now need define the workflow: not only the steps themselves, but also the events that will drive the execution."
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"id": "1lJTzuvhyF_I"
},
"outputs": [],
"source": [
"from workflows.events import Event, StartEvent, StopEvent\n",
"\n",
"\n",
"class ResearchQuestionEvent(StartEvent):\n",
" question: str\n",
"\n",
"\n",
"class ResearchEvent(StopEvent, DeepWikiOutput):\n",
" pass\n",
"\n",
"\n",
"class RetrieveContextEvent(Event):\n",
" context: str\n",
"\n",
"\n",
"class ContextRelevanceEvent(Event, ContextRelevance):\n",
" context: str | None"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"id": "VCLsfGrhyssh"
},
"outputs": [],
"source": [
"import uuid\n",
"from typing import Annotated\n",
"\n",
"from workflows import Context, Workflow, step\n",
"from workflows.resource import Resource\n",
"\n",
"\n",
"class WorkflowState(BaseModel):\n",
" question: str = Field(description=\"Question\", default_factory=str)\n",
" summary: str = Field(\n",
" description=\"Summary of the research output\", default_factory=str\n",
" )\n",
" focal_points: list[str] = Field(\n",
" description=\"Focal points of the research output\", default_factory=list\n",
" )\n",
" references: list[str] = Field(\n",
" description=\"References contained in the reseaerch output\", default_factory=list\n",
" )\n",
" similar_topics: list[str] = Field(\n",
" description=\"Topics similar to the one of the research output\",\n",
" default_factory=list,\n",
" )\n",
"\n",
"\n",
"class DeepWikiWorkflow(Workflow):\n",
" @step\n",
" async def research_question(\n",
" self,\n",
" ev: ResearchQuestionEvent,\n",
" ctx: Context[WorkflowState],\n",
" vdb: Annotated[QdrantVectorDatabase, Resource(get_vdb)],\n",
" ) -> ContextRelevanceEvent | RetrieveContextEvent:\n",
" ctx.write_event_to_stream(ev)\n",
" async with ctx.store.edit_state() as state:\n",
" state.question = ev.question\n",
"\n",
" results = await vdb.search(ev.question, 5)\n",
" if not results:\n",
" ctx.write_event_to_stream(\n",
" ContextRelevanceEvent(\n",
" relevance=1, reasons=\"No context found\", context=None\n",
" )\n",
" )\n",
" return ContextRelevanceEvent(\n",
" relevance=1, reasons=\"No context found\", context=None\n",
" )\n",
" ctx.write_event_to_stream(RetrieveContextEvent(context=results))\n",
" return RetrieveContextEvent(context=results)\n",
"\n",
" @step\n",
" async def evaluate_context(\n",
" self,\n",
" ev: RetrieveContextEvent,\n",
" ctx: Context[WorkflowState],\n",
" llm: Annotated[OpenAILlm, Resource(get_llm)],\n",
" ) -> ContextRelevanceEvent:\n",
" state = await ctx.store.get_state()\n",
" relevance = await llm.classify_context_relevance(state.question, ev.context)\n",
" if relevance.relevance >= 75:\n",
" ctx.write_event_to_stream(\n",
" ContextRelevanceEvent(\n",
" relevance=relevance.relevance,\n",
" reasons=relevance.reasons,\n",
" context=ev.context,\n",
" )\n",
" )\n",
" return ContextRelevanceEvent(\n",
" relevance=relevance.relevance,\n",
" reasons=relevance.reasons,\n",
" context=ev.context,\n",
" )\n",
" ctx.write_event_to_stream(\n",
" ContextRelevanceEvent(\n",
" relevance=relevance.relevance, reasons=relevance.reasons, context=None\n",
" )\n",
" )\n",
" return ContextRelevanceEvent(\n",
" relevance=relevance.relevance, reasons=relevance.reasons, context=None\n",
" )\n",
"\n",
" @step\n",
" async def research(\n",
" self,\n",
" ev: ContextRelevanceEvent,\n",
" ctx: Context[WorkflowState],\n",
" llm: Annotated[OpenAILlm, Resource(get_llm)],\n",
" vdb: Annotated[QdrantVectorDatabase, Resource(get_vdb)],\n",
" ) -> ResearchEvent:\n",
" static_state = await ctx.store.get_state()\n",
" result = await llm.deep_wiki(static_state.question, ev.context)\n",
" async with ctx.store.edit_state() as state:\n",
" state.summary = result.summary\n",
" state.focal_points = result.focal_points\n",
" state.references = result.references\n",
" state.similar_topics = result.similar_topics\n",
"\n",
" await vdb.upload([state.question], [state.model_dump()], [str(uuid.uuid4())])\n",
" return ResearchEvent(\n",
" summary=result.summary,\n",
" focal_points=result.focal_points,\n",
" references=result.references,\n",
" similar_topics=result.similar_topics,\n",
" )"
]
},
{
"cell_type": "markdown",
"metadata": {
"id": "P85Zc3hLzHN_"
},
"source": [
"As you can see, the workflow has three key steps:\n",
"\n",
"1. The first one, triggered by a question from the user, retrieves previous workflow states stored in the vector database. As you can see, the context is here retrieved through similarity search on the research question: this is actually the same way [semantic caches](https://qdrant.tech/blog/hitchhikers-guide/#semantic-caching) work - by storing the questions as embedding and the answers and metadata, and finding similar questions to the one the user already asked. If the context is mot there (maybe the workflow is empty, maybe the context is not similar enough), we go directly to step (3), else we perform context evaluation in step (2)\n",
"2. The retrieved context is evaluated for its relevance by the LLM using structured output: the LLM is constrained into producing a score from 1 to 100 and to provide reasons for the scoring\n",
"3. The research step is performed: the user message and the context (if there) are passed to the LLM, which, leveraging remote MCP connection to DeepWiki, performs the research on the user's question. When the response is ready, we \"take a snapshot of the state\" and we upload it, with the associated question, to the vector database."
]
},
{
"cell_type": "markdown",
"metadata": {
"id": "BuclAe9J03xN"
},
"source": [
"### 6. Run the Workflow\n",
"\n",
"We will now perform two runs of the same workflow, with very similar questions, to see how our state-management system works with the vector database!"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"colab": {
"base_uri": "https://localhost:8080/"
},
"id": "5s5iQQgW3ZAc",
"outputId": "6e1549d5-e397-4e29-b4d2-d8c70915a0ca"
},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"Starting working on the question What transport protocols are supported in the 2025-03-26 version of the Model Context Protocol (MCP) spec?\n",
"Context relevance: 1\n"
]
}
],
"source": [
"wf = DeepWikiWorkflow(timeout=600)\n",
"handler = wf.run(\n",
" start_event=ResearchQuestionEvent(\n",
" question=\"What transport protocols are supported in the 2025-03-26 version of the Model Context Protocol (MCP) spec?\"\n",
" )\n",
")\n",
"\n",
"async for event in handler.stream_events():\n",
" if isinstance(event, ResearchQuestionEvent):\n",
" print(\"Starting working on the question\", event.question)\n",
" elif isinstance(event, ContextRelevanceEvent):\n",
" print(f\"Context relevance: {event.relevance}\")\n",
" elif isinstance(event, RetrieveContextEvent):\n",
" print(f\"Context: {event.context}\")\n",
"\n",
"result = await handler"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"colab": {
"base_uri": "https://localhost:8080/"
},
"id": "y9pce24T56Eu",
"outputId": "515d6771-6cd8-4710-dd95-19c8e30022a8"
},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"Summary: The 2025-03-26 version of the Model Context Protocol (MCP) specification outlines four supported transport protocols—HTTP/HTTPS, WebSocket, gRPC, and MQTT—for various messaging and interoperability needs. Raw TCP has been deprecated due to security and interoperability considerations.\n",
"Focal Points:\n",
"- HTTP/HTTPS is the primary MCP messaging transport.\n",
"- WebSocket allows for real-time, bidirectional communication.\n",
"- gRPC provides an efficient binary protocol with strong typing.\n",
"- MQTT, now stable, targets lightweight, IoT, and edge scenarios.\n",
"- Raw TCP transport is deprecated and will be removed in future specifications.\n",
"References:\n",
"- Section 7, Transport Protocols, of the MCP 2025-03-26 spec\n",
"Similar Topics:\n",
"- Comparison of transport protocols in machine learning frameworks\n",
"- Protocol interoperability and security in distributed systems\n",
"- IoT messaging protocols (MQTT, AMQP, CoAP)\n",
"- Transition strategies for protocol deprecation in API standards\n",
"- Streaming and real-time messaging protocols (WebSocket, Server-Sent Events)\n"
]
}
],
"source": [
"print(\"Summary:\", result.summary)\n",
"print(\"Focal Points:\\n- \", \"\\n- \".join(result.focal_points))\n",
"print(\"References:\\n- \", \"\\n- \".join(result.references))\n",
"print(\"Similar Topics:\\n- \", \"\\n- \".join(result.similar_topics))"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"colab": {
"base_uri": "https://localhost:8080/"
},
"id": "7Rss_njN6aWo",
"outputId": "4e99ecf9-53e2-4e95-84e5-3e1509c5988e"
},
"outputs": [
{
"name": "stderr",
"output_type": "stream",
"text": [
"/tmp/ipython-input-2-1548765145.py:42: DeprecationWarning: `search` method is deprecated and will be removed in the future. Use `query_points` instead.\n",
" results = await self.client.search(self.collection_name, query_vector=embedding, limit=limit)\n"
]
},
{
"name": "stdout",
"output_type": "stream",
"text": [
"Starting working on the question Which transport protocols does the Model Context Protocol specification version 2025-03-26 support?\n",
"Context: [\n",
" {\n",
" \"question\": \"What transport protocols are supported in the 2025-03-26 version of the Model Context Protocol (MCP) spec?\",\n",
" \"summary\": \"The 2025-03-26 version of the Model Context Protocol (MCP) specification outlines four supported transport protocols\\u2014HTTP/HTTPS, WebSocket, gRPC, and MQTT\\u2014for various messaging and interoperability needs. Raw TCP has been deprecated due to security and interoperability considerations.\",\n",
" \"focal_points\": [\n",
" \"HTTP/HTTPS is the primary MCP messaging transport.\",\n",
" \"WebSocket allows for real-time, bidirectional communication.\",\n",
" \"gRPC provides an efficient binary protocol with strong typing.\",\n",
" \"MQTT, now stable, targets lightweight, IoT, and edge scenarios.\",\n",
" \"Raw TCP transport is deprecated and will be removed in future specifications.\"\n",
" ],\n",
" \"references\": [\n",
" \"Section 7, \\u2018Transport Protocols,\\u2019 of the MCP 2025-03-26 spec\"\n",
" ],\n",
" \"similar_topics\": [\n",
" \"Comparison of transport protocols in machine learning frameworks\",\n",
" \"Protocol interoperability and security in distributed systems\",\n",
" \"IoT messaging protocols (MQTT, AMQP, CoAP)\",\n",
" \"Transition strategies for protocol deprecation in API standards\",\n",
" \"Streaming and real-time messaging protocols (WebSocket, Server-Sent Events)\"\n",
" ]\n",
" }\n",
"]\n",
"Context relevance: 100\n"
]
}
],
"source": [
"handler = wf.run(\n",
" start_event=ResearchQuestionEvent(\n",
" question=\"Which transport protocols does the Model Context Protocol specification version 2025-03-26 support?\"\n",
" )\n",
")\n",
"\n",
"async for event in handler.stream_events():\n",
" if isinstance(event, ResearchQuestionEvent):\n",
" print(\"Starting working on the question\", event.question)\n",
" elif isinstance(event, ContextRelevanceEvent):\n",
" print(f\"Context relevance: {event.relevance}\")\n",
" elif isinstance(event, RetrieveContextEvent):\n",
" print(f\"Context: {event.context}\")\n",
"\n",
"result = await handler"
]
},
{
"cell_type": "markdown",
"metadata": {
"id": "1z8vm7yN1FbU"
},
"source": [
"As you can see, we have successfully retrieved the state-as-a-context from the vector database, and we successfully rated it as highly relevant and used it to augment the generation of our research report!"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"colab": {
"base_uri": "https://localhost:8080/"
},
"id": "f26Qg9zR61X7",
"outputId": "20bd12ce-bab4-4d0c-c352-6d10be4a4439"
},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"Summary: The Model Context Protocol (MCP) specification version 2025-03-26 enumerates its supported transport protocols, emphasizing modern, secure, and efficient messaging. It supports HTTP/HTTPS as the main transport, with WebSocket, gRPC, and a now-stable MQTT option for lightweight and IoT usage. Raw TCP transport is deprecated and set for future removal for security and interoperability reasons.\n",
"Focal Points:\n",
"- Supported transport protocols: HTTP/HTTPS, WebSocket, gRPC, MQTT\n",
"- MQTT has reached stable status and is aimed at IoT and edge scenarios\n",
"- Raw TCP transport is deprecated due to security and interoperability concerns\n",
"- Anticipated removal of raw TCP transport in upcoming MCP versions\n",
"References:\n",
"- Section 7, Transport Protocols, of the MCP 2025-03-26 spec\n",
"Similar Topics:\n",
"- Protocol deprecation and migration strategies\n",
"- Transport protocol security best practices\n",
"- Comparative analysis of transport protocols for IoT\n",
"- HTTP/2 and HTTP/3 in modern protocol suites\n",
"- Interoperability challenges in distributed systems\n"
]
}
],
"source": [
"print(\"Summary:\", result.summary)\n",
"print(\"Focal Points:\\n- \", \"\\n- \".join(result.focal_points))\n",
"print(\"References:\\n- \", \"\\n- \".join(result.references))\n",
"print(\"Similar Topics:\\n- \", \"\\n- \".join(result.similar_topics))"
]
}
],
"metadata": {
"colab": {
"provenance": [],
"toc_visible": true
},
"kernelspec": {
"display_name": "Python 3",
"name": "python3"
},
"language_info": {
"name": "python"
}
},
"nbformat": 4,
"nbformat_minor": 0
}