chore: import upstream snapshot with attribution

This commit is contained in:
wehub-resource-sync
2026-07-13 13:31:35 +08:00
commit c275ba2868
13613 changed files with 2980806 additions and 0 deletions
@@ -0,0 +1,97 @@
# Study Plan Generator with Chainlit & Microsoft Learn Docs MCP
## Prerequisites
- Python 3.8 or higher
- pip (Python package manager)
- Internet access to connect to the Microsoft Learn Docs MCP server
## Installation
1. Clone this repository or download the project files.
2. Install the required dependencies:
```bash
pip install -r requirements.txt
```
## Usage
### Scenario 1: Simple Query to Docs MCP
A command-line client that connects to the Docs MCP server, sends a query, and prints the result.
1. Run the script:
```bash
python scenario1.py
```
2. Enter your documentation question at the prompt.
### Scenario 2: Study Plan Generator (Chainlit Web App)
A web-based interface (using Chainlit) that allows users to generate a personalized, week-by-week study plan for any technical topic.
1. Start the Chainlit app:
```bash
chainlit run scenario2.py
```
2. Open the local URL provided in your terminal (e.g., http://localhost:8000) in your browser.
3. In the chat window, enter your study topic and the number of weeks you want to study (e.g., "AI-900 certification, 8 weeks").
4. The app will respond with a week-by-week study plan, including links to relevant Microsoft Learn documentation.
**Environment Variables Required:**
To use Scenario 2 (the Chainlit web app with Azure OpenAI), you must set the following environment variables in a `.env` file in the `python` directory:
```
AZURE_OPENAI_CHAT_DEPLOYMENT_NAME=
AZURE_OPENAI_API_KEY=
AZURE_OPENAI_ENDPOINT=
AZURE_OPENAI_API_VERSION=
```
Fill in these values with your Azure OpenAI resource details before running the app.
> [!TIP]
> You can easily deploy your own models using [Microsoft Foundry](https://ai.azure.com/).
### Scenario 3: In-Editor Docs with MCP Server in VS Code
Instead of switching browser tabs to search documentation, you can bring Microsoft Learn Docs directly into your VS Code using the MCP server. This enables you to:
- Search and read docs inside VS Code without leaving your coding environment.
- Reference documentation and insert links directly into your README or course files.
- Use GitHub Copilot and MCP together for a seamless, AI-powered documentation workflow.
**Example Use Cases:**
- Quickly add reference links to a README while writing a course or project documentation.
- Use Copilot to generate code and MCP to instantly find and cite relevant docs.
- Stay focused in your editor and boost productivity.
> [!IMPORTANT]
> Ensure you have a valid [`mcp.json`](../scenario3/mcp.json) configuration in your workspace (location is `.vscode/mcp.json`).
## Why Chainlit for Scenario 2?
Chainlit is a modern open-source framework for building conversational web applications. It makes it easy to create chat-based user interfaces that connect to backend services like the Microsoft Learn Docs MCP server. This project uses Chainlit to provide a simple, interactive way to generate personalized study plans in real time. By leveraging Chainlit, you can quickly build and deploy chat-based tools that enhance productivity and learning.
## What This Does
This app allows users to create a personalized study plan by simply entering a topic and a duration. The app parses your input, queries the Microsoft Learn Docs MCP server for relevant content, and organizes the results into a structured, week-by-week plan. Each weeks recommendations are displayed in the chat, making it easy to follow and track your progress. The integration ensures you always get the latest, most relevant learning resources.
## Sample Queries
Try these queries in the chat window to see how the app responds:
- `AI-900 certification, 8 weeks`
- `Learn Azure Functions, 4 weeks`
- `Azure DevOps, 6 weeks`
- `Data engineering on Azure, 10 weeks`
- `Microsoft security fundamentals, 5 weeks`
- `Power Platform, 7 weeks`
- `Azure AI services, 12 weeks`
- `Cloud architecture, 9 weeks`
These examples demonstrate the flexibility of the app for different learning goals and timeframes.
## References
- [Chainlit Documentation](https://docs.chainlit.io/)
- [MCP Documentation](https://github.com/MicrosoftDocs/mcp)
@@ -0,0 +1,8 @@
chainlit
mcp
semantic-kernel
# Security pin: force the patched Werkzeug (a transitive dependency) to resolve
# the safe_join Windows device-name DoS advisories
# CVE-2025-66221 / CVE-2026-21860 / CVE-2026-27199 (fixed in 3.1.6)
werkzeug>=3.1.6
@@ -0,0 +1,88 @@
# Scenario 1: Simple query to Docs MCP
# This script demonstrates how to connect to the Microsoft Learn Docs MCP server,
# send a query, and print the result.
import asyncio
import logging
import sys
from mcp.client.streamable_http import streamablehttp_client
from mcp import ClientSession
import json
# Microsoft Docs MCP Server Endpoint
MCP_SERVER_URL = "https://learn.microsoft.com/api/mcp"
# Configure logging
logging.basicConfig(
level=logging.INFO,
format='%(asctime)s - %(name)s - %(levelname)s - %(message)s',
datefmt='%Y-%m-%d %H:%M:%S'
)
logger = logging.getLogger('mcp_client')
def prompt_user():
"""Prompt user for a search query."""
print("Type your Microsoft Docs search query (or 'exit' to quit):")
try:
return input("> ").strip()
except (KeyboardInterrupt, EOFError):
print("\nDetected exit signal.")
return "exit"
async def main():
logger.info("Connecting to Microsoft Docs MCP Server at: %s", MCP_SERVER_URL)
try:
async with streamablehttp_client(MCP_SERVER_URL) as (read_stream, write_stream, _):
logger.info("Connection established. Initializing MCP session.")
async with ClientSession(read_stream, write_stream) as session:
await session.initialize()
logger.info("Session initialized successfully.")
print("\n=== Microsoft Docs MCP Client ===")
print("Tool: microsoft_docs_search")
print("Enter documentation queries to search Microsoft Learn docs.")
print("Type 'exit' or 'quit' to end the session.\n")
while True:
user_query = prompt_user()
if not user_query:
print("Query cannot be empty. Please try again.")
continue
if user_query.lower() in ("exit", "quit"):
print("Exiting client. Goodbye!")
break
try:
logger.info("Executing query: %s", user_query)
result = await session.call_tool("microsoft_docs_search", {"question": user_query})
# print("RESULT:", result)
print("\n--- Search Result ---")
if hasattr(result, 'content'):
# print(result.content)
for item in result.content:
my_list = json.loads(item.text)
for doc in my_list:
print(f"[Title]: {doc.get('title', 'No title')}")
print(f"[Content]: {doc.get('content', 'No content')}")
print("---")
else:
print("No content returned from the search.")
print("---------------------\n")
except Exception as e:
logger.error("Query failed: %s", e)
print(f"Error: {e}. Please try a different query or check your connection.\n")
except Exception as e:
logger.error("Connection error: %s", e)
print(f"Failed to connect to Microsoft Docs MCP Server: {e}")
print("Please check your internet connection and try again.")
sys.exit(1)
if __name__ == "__main__":
print("Starting Microsoft Docs MCP Client...")
try:
asyncio.run(main())
except KeyboardInterrupt:
print("\nApplication terminated by user.")
sys.exit(0)
@@ -0,0 +1,115 @@
# Scenario 2: Integrate Docs MCP into a web development project
# This script demonstrates how to use Chainlit to build a conversational web app
# that queries the Microsoft Learn Docs MCP server.
import chainlit as cl
import logging
import json
from mcp.client.streamable_http import streamablehttp_client
from mcp import ClientSession
from semantic_kernel.kernel import Kernel
from azure.core.credentials import AzureKeyCredential
from semantic_kernel.connectors.ai.open_ai import AzureChatCompletion
from semantic_kernel.functions import kernel_function
from semantic_kernel.agents import ChatCompletionAgent
MCP_SERVER_URL = "https://learn.microsoft.com/api/mcp"
logging.basicConfig(level=logging.INFO)
logger = logging.getLogger('mcp_client')
# MCP Docs Plugin as a Semantic Kernel plugin
class MCPDocsPlugin:
def __init__(self, mcp_server_url):
self.mcp_server_url = mcp_server_url
@kernel_function(name="search_docs", description="Search Microsoft Docs using MCP")
async def search_docs(self, question: str) -> str:
async with streamablehttp_client(self.mcp_server_url) as (read_stream, write_stream, _):
async with ClientSession(read_stream, write_stream) as session:
await session.initialize()
result = await session.call_tool("microsoft_docs_search", {"question": question})
output = []
if hasattr(result, 'content'):
for item in result.content:
try:
my_list = json.loads(item.text)
for doc in my_list:
title = doc.get('title', 'No title')
content = doc.get('content', 'No content')
output.append(f"**{title}**\n{content}")
except Exception:
output.append(item.text)
return "\n".join(output)
else:
return "No content returned from the search."
# Register the MCP Docs search as a function
async def mcp_docs_search(question: str):
async with streamablehttp_client(MCP_SERVER_URL) as (read_stream, write_stream, _):
async with ClientSession(read_stream, write_stream) as session:
await session.initialize()
result = await session.call_tool("microsoft_docs_search", {"question": question})
output = []
if hasattr(result, 'content'):
for item in result.content:
try:
my_list = json.loads(item.text)
for doc in my_list:
title = doc.get('title', 'No title')
content = doc.get('content', 'No content')
output.append(f"**{title}**\n{content}")
except Exception:
output.append(item.text)
return "\n".join(output)
else:
return "No content returned from the search."
@cl.on_chat_start
async def start():
await cl.Message(content="Welcome! Enter your Microsoft Docs search query below.").send()
kernel = Kernel()
service_id = "agent"
kernel.add_service(AzureChatCompletion(service_id=service_id))
from semantic_kernel.connectors.ai import FunctionChoiceBehavior
settings = kernel.get_prompt_execution_settings_from_service_id(service_id=service_id)
settings.function_choice_behavior = FunctionChoiceBehavior.Auto()
# Register the MCPDocsPlugin
mcp_plugin = MCPDocsPlugin(MCP_SERVER_URL)
kernel.add_plugin(mcp_plugin, plugin_name="MCPDocs")
# Create the agent
agent = ChatCompletionAgent(
service=AzureChatCompletion(),
name="DocsAgent",
instructions="You are a helpful assistant that uses the MCPDocs plugin to answer Microsoft Docs questions. Format your answers clearly.",
plugins=[mcp_plugin]
)
cl.user_session.set("kernel", kernel)
cl.user_session.set("agent", agent)
cl.user_session.set("settings", settings)
@cl.on_message
async def handle_message(message: cl.Message):
agent = cl.user_session.get("agent")
user_query = message.content.strip()
if not user_query:
await cl.Message(content="Query cannot be empty. Please try again.").send()
return
answer = cl.Message(content="Processing your request...")
await answer.send()
try:
response_printed = False
async for content in agent.invoke(user_query):
msg = content.content
if hasattr(msg, "content"):
msg = msg.content
if msg:
await answer.stream_token(str(msg))
response_printed = True
if not response_printed:
await answer.stream_token("No response generated by the agent.\n")
await answer.update()
except Exception as e:
await answer.stream_token(f"\n\n❌ Error: {str(e)}\n\n")
await answer.update()