chore: import upstream snapshot with attribution
This commit is contained in:
@@ -0,0 +1,41 @@
|
||||
# Model Context Protocol
|
||||
|
||||
The model context protocol is a standard created by Anthropic to allow models to share context with each other. See the [official documentation](https://modelcontextprotocol.io/introduction) for more information.
|
||||
|
||||
It consists of clients and servers, and servers can be hosted locally, or they can be exposed as a online API.
|
||||
|
||||
Our goal is that Semantic Kernel can act as both a client and a server.
|
||||
|
||||
In this folder the client side of things is demonstrated. It takes the definition of a server and uses that to create a Semantic Kernel plugin, this plugin exposes the tools and prompts of the server as functions in the kernel.
|
||||
|
||||
Those can then be used with function calling in a chat or agent.
|
||||
|
||||
## Server types
|
||||
|
||||
There are two types of servers, Stdio and Sse based. The sample shows how to use the Stdio based server, which get's run locally, in this case by using [npx](https://docs.npmjs.com/cli/v8/commands/npx).
|
||||
|
||||
Some other common runners are [uvx](https://docs.astral.sh/uv/guides/tools/), for python servers and [docker](https://www.docker.com/), for containerized servers.
|
||||
|
||||
The code shown works the same for a Sse server, only then a MCPSsePlugin needs to be used instead of the MCPStdioPlugin. For Streamable HTTP server, MCPStreamableHttpPlugin can be used.
|
||||
|
||||
The reverse, using Semantic Kernel as a server, can be found in the [demos/mcp_server](../../demos/mcp_server/) folder.
|
||||
|
||||
## Running the samples
|
||||
|
||||
1. Depending on the sample you want to run:
|
||||
1. [Docker](https://www.docker.com/products/docker-desktop/) installed, for the samples that use the Github MCP server.
|
||||
1. [uv](https://docs.astral.sh/uv/getting-started/installation/) installed, for the samples that use the local MCP server.
|
||||
2. The Github MCP Server uses a Github Personal Access Token (PAT) to authenticate, see [the documentation](https://github.com/modelcontextprotocol/servers/tree/main/src/github) on how to create one.
|
||||
1. Check the comment at the start of the sample you want to run, for the appropriate environment variables to set.
|
||||
1. Install Semantic Kernel with the mcp extra:
|
||||
|
||||
```bash
|
||||
pip install semantic-kernel[mcp]
|
||||
```
|
||||
|
||||
4. Run any of the samples:
|
||||
|
||||
```bash
|
||||
cd python/samples/concepts/mcp
|
||||
python <name>.py
|
||||
```
|
||||
@@ -0,0 +1,138 @@
|
||||
# Copyright (c) Microsoft. All rights reserved.
|
||||
|
||||
import asyncio
|
||||
|
||||
from azure.identity import AzureCliCredential
|
||||
|
||||
from semantic_kernel.agents import ChatCompletionAgent, ChatHistoryAgentThread
|
||||
from semantic_kernel.connectors.ai.open_ai import AzureChatCompletion
|
||||
from semantic_kernel.connectors.mcp import MCPStreamableHttpPlugin
|
||||
|
||||
"""
|
||||
The following sample demonstrates how to create a chat completion agent that
|
||||
answers questions about Github using a Semantic Kernel Plugin from a MCP server.
|
||||
|
||||
It uses the Azure OpenAI service to create a agent, so make sure to
|
||||
set the required environment variables for the Azure AI Foundry service:
|
||||
- AZURE_OPENAI_CHAT_DEPLOYMENT_NAME
|
||||
- Optionally: AZURE_OPENAI_API_KEY
|
||||
If this is not set, it's also possible to pass AsyncTokenCredential to the service, e.g. AzureCliCredential.
|
||||
"""
|
||||
|
||||
|
||||
# Simulate a conversation with the agent
|
||||
USER_INPUTS = [
|
||||
"How do I make a Python chat completion request in Semantic Kernel using Azure OpenAI?",
|
||||
]
|
||||
|
||||
|
||||
async def main():
|
||||
# 1. Create the agent
|
||||
async with MCPStreamableHttpPlugin(
|
||||
name="LearnSite",
|
||||
description="Learn Docs Plugin",
|
||||
url="https://learn.microsoft.com/api/mcp",
|
||||
) as learn_plugin:
|
||||
agent = ChatCompletionAgent(
|
||||
service=AzureChatCompletion(credential=AzureCliCredential()),
|
||||
name="DocsAgent",
|
||||
instructions="Answer questions about the Microsoft's Semantic Kernel SDK.",
|
||||
plugins=[learn_plugin],
|
||||
)
|
||||
|
||||
for user_input in USER_INPUTS:
|
||||
# 2. Create a thread to hold the conversation
|
||||
# If no thread is provided, a new thread will be
|
||||
# created and returned with the initial response
|
||||
thread: ChatHistoryAgentThread | None = None
|
||||
|
||||
print(f"# User: {user_input}")
|
||||
# 3. Invoke the agent for a response
|
||||
response = await agent.get_response(messages=user_input, thread=thread)
|
||||
print(f"# {response.name}: {response} ")
|
||||
thread = response.thread
|
||||
|
||||
# 4. Cleanup: Clear the thread
|
||||
await thread.delete() if thread else None
|
||||
|
||||
|
||||
"""
|
||||
Sample output:
|
||||
|
||||
# User: How do I make a Python chat completion request in Semantic Kernel using Azure OpenAI?
|
||||
# DocsAgent: To make a **Python chat completion request in Semantic Kernel using Azure OpenAI**, follow these steps:
|
||||
|
||||
---
|
||||
|
||||
### 1. Install Semantic Kernel
|
||||
|
||||
```bash
|
||||
pip install semantic-kernel
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
### 2. Import Necessary Libraries
|
||||
|
||||
```python
|
||||
import semantic_kernel as sk
|
||||
from semantic_kernel.connectors.ai.open_ai import AzureChatCompletion
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
### 3. Initialize the Kernel and Add Azure OpenAI Service
|
||||
|
||||
```python
|
||||
# Initialize the kernel
|
||||
kernel = sk.Kernel()
|
||||
|
||||
# Set your Azure OpenAI details
|
||||
deployment_name = "your-chat-deployment"
|
||||
endpoint = "https://your-resource-name.openai.azure.com/"
|
||||
api_key = "your-azure-openai-api-key"
|
||||
|
||||
# Add Azure Chat Completion service
|
||||
kernel.add_chat_service(
|
||||
"azure_chat",
|
||||
AzureChatCompletion(
|
||||
deployment_name=deployment_name,
|
||||
endpoint=endpoint,
|
||||
api_key=api_key,
|
||||
),
|
||||
)
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
### 4. Create a Chat History and Send a Request
|
||||
|
||||
```python
|
||||
# Create an initial chat history
|
||||
history = [
|
||||
{"role": "system", "content": "You are a helpful assistant."},
|
||||
{"role": "user", "content": "What can you do?"},
|
||||
]
|
||||
|
||||
# Get chat completion
|
||||
result = kernel.chat.complete(
|
||||
chat_history=history,
|
||||
max_tokens=100,
|
||||
temperature=0.7,
|
||||
top_p=0.95,
|
||||
)
|
||||
|
||||
print(result)
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Example Summary
|
||||
|
||||
This makes a chat completion request to Azure OpenAI through Semantic Kernel in Python. You can add more user/assistant
|
||||
turns to `history`.
|
||||
"""
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
asyncio.run(main())
|
||||
@@ -0,0 +1,119 @@
|
||||
# Copyright (c) Microsoft. All rights reserved.
|
||||
|
||||
import asyncio
|
||||
import os
|
||||
from pathlib import Path
|
||||
|
||||
from azure.identity import AzureCliCredential
|
||||
|
||||
from semantic_kernel.agents import ChatCompletionAgent, ChatHistoryAgentThread
|
||||
from semantic_kernel.connectors.ai.open_ai import AzureChatCompletion
|
||||
from semantic_kernel.connectors.mcp import MCPStdioPlugin
|
||||
from semantic_kernel.core_plugins.time_plugin import TimePlugin
|
||||
|
||||
"""
|
||||
The following sample demonstrates how to create a chat completion agent that
|
||||
answers questions about Github using a Semantic Kernel Plugin from a MCP server.
|
||||
|
||||
It uses the Azure OpenAI service to create a agent, so make sure to
|
||||
set the required environment variables for the Azure AI Foundry service:
|
||||
- AZURE_OPENAI_CHAT_DEPLOYMENT_NAME
|
||||
- Optionally: AZURE_OPENAI_API_KEY
|
||||
If this is not set, it's also possible to pass AsyncTokenCredential to the service, e.g. AzureCliCredential.
|
||||
"""
|
||||
|
||||
|
||||
async def main():
|
||||
# 1. Create the agent
|
||||
async with (
|
||||
MCPStdioPlugin(
|
||||
name="Menu",
|
||||
description="Menu plugin, for details about the menu, call this plugin.",
|
||||
command="uv",
|
||||
args=[
|
||||
f"--directory={str(Path(os.path.dirname(__file__)).joinpath('servers'))}",
|
||||
"run",
|
||||
"menu_agent_server.py",
|
||||
],
|
||||
env={
|
||||
"AZURE_OPENAI_CHAT_DEPLOYMENT_NAME": os.getenv("AZURE_OPENAI_CHAT_DEPLOYMENT_NAME"),
|
||||
"AZURE_OPENAI_ENDPOINT": os.getenv("AZURE_OPENAI_ENDPOINT"),
|
||||
},
|
||||
) as restaurant_agent,
|
||||
MCPStdioPlugin(
|
||||
name="Booking",
|
||||
description="Restaurant Booking Plugin",
|
||||
command="uv",
|
||||
args=[
|
||||
f"--directory={str(Path(os.path.dirname(__file__)).joinpath('servers'))}",
|
||||
"run",
|
||||
"restaurant_booking_agent_server.py",
|
||||
],
|
||||
env={
|
||||
"AZURE_OPENAI_CHAT_DEPLOYMENT_NAME": os.getenv("AZURE_OPENAI_CHAT_DEPLOYMENT_NAME"),
|
||||
"AZURE_OPENAI_ENDPOINT": os.getenv("AZURE_OPENAI_ENDPOINT"),
|
||||
},
|
||||
) as booking_agent,
|
||||
):
|
||||
agent = ChatCompletionAgent(
|
||||
service=AzureChatCompletion(credential=AzureCliCredential()),
|
||||
name="PersonalAssistant",
|
||||
instructions="Help the user with restaurant bookings.",
|
||||
plugins=[restaurant_agent, booking_agent, TimePlugin()],
|
||||
)
|
||||
|
||||
# 2. Create a thread to hold the conversation
|
||||
# If no thread is provided, a new thread will be
|
||||
# created and returned with the initial response
|
||||
thread: ChatHistoryAgentThread | None = None
|
||||
while True:
|
||||
user_input = input("User: ")
|
||||
if user_input.lower() == "exit":
|
||||
break
|
||||
# 3. Invoke the agent for a response
|
||||
response = await agent.get_response(messages=user_input, thread=thread)
|
||||
print(f"# {response.name}: {response} ")
|
||||
thread = response.thread
|
||||
|
||||
# 4. Cleanup: Clear the thread
|
||||
await thread.delete() if thread else None
|
||||
|
||||
|
||||
"""
|
||||
User: what restaurants can I choose from?
|
||||
# PersonalAssistant: Here are the available restaurants you can choose from:
|
||||
|
||||
1. **The Farm**: A classic steakhouse with a rustic atmosphere.
|
||||
2. **The Harbor**: A seafood restaurant with a view of the ocean.
|
||||
3. **The Joint**: A casual eatery with a diverse menu.
|
||||
|
||||
Let me know if you would like to make a booking or need more information about any specific restaurant!
|
||||
User: the farm sounds nice, what are the specials there?
|
||||
# PersonalAssistant: The specials at The Farm are:
|
||||
|
||||
- **Special Entree:** T-bone steak
|
||||
- **Special Salad:** Caesar Salad
|
||||
- **Special Drink:** Old Fashioned
|
||||
|
||||
Let me know if you'd like to make a booking or if you need any more information!
|
||||
User: That entree sounds great, how much does it cost?
|
||||
# PersonalAssistant: The cost of the T-bone steak at The Farm is $9.99. Would you like to proceed with a booking?
|
||||
User: yes, for 2 people tomorrow
|
||||
# PersonalAssistant: I can confirm a booking for 2 people at The Farm for tomorrow, April 17, 2025. What time would you
|
||||
like the reservation?
|
||||
User: at 2000
|
||||
# PersonalAssistant: I apologize, but the booking at The Farm for tomorrow at 20:00 has been denied. However,
|
||||
I was able to confirm bookings at the following restaurants:
|
||||
|
||||
- **The Harbor**: Booking confirmed.
|
||||
- **The Joint**: Booking confirmed.
|
||||
|
||||
If you'd like to book at one of these restaurants or try a different time or restaurant, just let me know!
|
||||
User: try 21.00
|
||||
# PersonalAssistant: Your table for 2 people at The Farm has been successfully booked for tomorrow, April 17, 2025,
|
||||
at 21:00. Enjoy your meal! If you need anything else, feel free to ask.
|
||||
User: exit
|
||||
"""
|
||||
|
||||
if __name__ == "__main__":
|
||||
asyncio.run(main())
|
||||
@@ -0,0 +1,128 @@
|
||||
# Copyright (c) Microsoft. All rights reserved.
|
||||
|
||||
import asyncio
|
||||
import os
|
||||
|
||||
from azure.identity import AzureCliCredential
|
||||
|
||||
from semantic_kernel.agents import ChatCompletionAgent, ChatHistoryAgentThread
|
||||
from semantic_kernel.connectors.ai.open_ai import AzureChatCompletion
|
||||
from semantic_kernel.connectors.mcp import MCPStdioPlugin
|
||||
|
||||
"""
|
||||
The following sample demonstrates how to create a chat completion agent that
|
||||
answers questions about Github using a Semantic Kernel Plugin from a MCP server.
|
||||
|
||||
It uses the Azure OpenAI service to create a agent, so make sure to
|
||||
set the required environment variables for the Azure AI Foundry service:
|
||||
- AZURE_OPENAI_CHAT_DEPLOYMENT_NAME
|
||||
- Optionally: AZURE_OPENAI_API_KEY
|
||||
If this is not set, it's also possible to pass AsyncTokenCredential to the service, e.g. AzureCliCredential.
|
||||
|
||||
"""
|
||||
|
||||
|
||||
# Simulate a conversation with the agent
|
||||
USER_INPUTS = [
|
||||
"What are the latest 5 python issues in Microsoft/semantic-kernel?",
|
||||
"Are there any untriaged python issues?",
|
||||
"What is the status of issue #10785?",
|
||||
]
|
||||
|
||||
|
||||
async def main():
|
||||
# 1. Create the agent
|
||||
async with MCPStdioPlugin(
|
||||
name="Github",
|
||||
description="Github Plugin",
|
||||
command="docker",
|
||||
args=["run", "-i", "--rm", "-e", "GITHUB_PERSONAL_ACCESS_TOKEN", "ghcr.io/github/github-mcp-server"],
|
||||
env={"GITHUB_PERSONAL_ACCESS_TOKEN": os.getenv("GITHUB_PERSONAL_ACCESS_TOKEN")},
|
||||
) as github_plugin:
|
||||
agent = ChatCompletionAgent(
|
||||
service=AzureChatCompletion(credential=AzureCliCredential()),
|
||||
name="IssueAgent",
|
||||
instructions="Answer questions about the Microsoft semantic-kernel github project.",
|
||||
plugins=[github_plugin],
|
||||
)
|
||||
|
||||
for user_input in USER_INPUTS:
|
||||
# 2. Create a thread to hold the conversation
|
||||
# If no thread is provided, a new thread will be
|
||||
# created and returned with the initial response
|
||||
thread: ChatHistoryAgentThread | None = None
|
||||
|
||||
print(f"# User: {user_input}")
|
||||
# 3. Invoke the agent for a response
|
||||
response = await agent.get_response(messages=user_input, thread=thread)
|
||||
print(f"# {response.name}: {response} ")
|
||||
thread = response.thread
|
||||
|
||||
# 4. Cleanup: Clear the thread
|
||||
await thread.delete() if thread else None
|
||||
|
||||
"""
|
||||
Sample output:
|
||||
GitHub MCP Server running on stdio
|
||||
# User: What are the latest 5 python issues in Microsoft/semantic-kernel?
|
||||
# IssueAgent: Here are the latest 5 Python issues in the
|
||||
[Microsoft/semantic-kernel](https://github.com/microsoft/semantic-kernel) repository:
|
||||
|
||||
1. **[Issue #11358](https://github.com/microsoft/semantic-kernel/pull/11358)**
|
||||
**Title:** Python: Bump Python version to 1.27.0 for a release.
|
||||
**Created by:** [moonbox3](https://github.com/moonbox3)
|
||||
**Created at:** April 3, 2025
|
||||
**State:** Open
|
||||
**Comments:** 1
|
||||
**Description:** Bump Python version to 1.27.0 for a release.
|
||||
|
||||
2. **[Issue #11357](https://github.com/microsoft/semantic-kernel/pull/11357)**
|
||||
**Title:** .Net: Version 1.45.0
|
||||
**Created by:** [markwallace-microsoft](https://github.com/markwallace-microsoft)
|
||||
**Created at:** April 3, 2025
|
||||
**State:** Open
|
||||
**Comments:** 0
|
||||
**Description:** Version bump for release 1.45.0.
|
||||
|
||||
3. **[Issue #11356](https://github.com/microsoft/semantic-kernel/pull/11356)**
|
||||
**Title:** .Net: Fix bug in sqlite filter logic
|
||||
**Created by:** [westey-m](https://github.com/westey-m)
|
||||
**Created at:** April 3, 2025
|
||||
**State:** Open
|
||||
**Comments:** 0
|
||||
**Description:** Fix bug in sqlite filter logic.
|
||||
|
||||
4. **[Issue #11355](https://github.com/microsoft/semantic-kernel/issues/11355)**
|
||||
**Title:** .Net: [MEVD] Validate that the collection generic key parameter corresponds to the model
|
||||
**Created by:** [roji](https://github.com/roji)
|
||||
**Created at:** April 3, 2025
|
||||
**State:** Open
|
||||
**Comments:** 0
|
||||
**Description:** We currently have validation for the TKey generic type parameter passed to the collection type,
|
||||
and we have validation for the key property type on the model.
|
||||
|
||||
5. **[Issue #11354](https://github.com/microsoft/semantic-kernel/issues/11354)**
|
||||
**Title:** .Net: How to add custom JsonSerializer on a builder level
|
||||
**Created by:** [PawelStadnicki](https://github.com/PawelStadnicki)
|
||||
**Created at:** April 3, 2025
|
||||
**State:** Open
|
||||
**Comments:** 0
|
||||
**Description:** Inquiry about adding a custom JsonSerializer for handling F# types within the SDK.
|
||||
|
||||
If you need more details about a specific issue, let me know!
|
||||
# User: Are there any untriaged python issues?
|
||||
# IssueAgent: There are no untriaged Python issues in the Microsoft semantic-kernel repository.
|
||||
# User: What is the status of issue #10785?
|
||||
# IssueAgent: The status of issue #10785 in the Microsoft Semantic Kernel repository is **open**.
|
||||
|
||||
- **Title**: Port dotnet feature: Create MCP Sample
|
||||
- **Created at**: March 4, 2025
|
||||
- **Comments**: 0
|
||||
- **Labels**: python
|
||||
|
||||
You can view the issue [here](https://github.com/microsoft/semantic-kernel/issues/10785).
|
||||
"""
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
asyncio.run(main())
|
||||
@@ -0,0 +1,116 @@
|
||||
# Copyright (c) Microsoft. All rights reserved.
|
||||
|
||||
import asyncio
|
||||
import logging
|
||||
import os
|
||||
from pathlib import Path
|
||||
|
||||
from semantic_kernel.agents import ChatCompletionAgent
|
||||
from semantic_kernel.connectors.ai.open_ai import OpenAIChatCompletion
|
||||
from semantic_kernel.connectors.mcp import MCPStdioPlugin
|
||||
|
||||
# set this lower or higher depending on your needs
|
||||
logging.basicConfig(level=logging.INFO)
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
"""
|
||||
The following sample demonstrates how to use a MCP Server that requires sampling
|
||||
to generate release notes from a list of issues.
|
||||
|
||||
It uses the OpenAI service to create a agent, so make sure to
|
||||
set the required environment variables for the Azure AI Foundry service:
|
||||
- OPENAI_API_KEY
|
||||
- OPENAI_CHAT_MODEL_ID
|
||||
"""
|
||||
|
||||
PR_MESSAGES = """* Python: Add ChatCompletionAgent integration tests by @moonbox3 in https://github.com/microsoft/semantic-kernel/pull/11430
|
||||
* Python: Update Doc Gen demo based on latest agent invocation api pattern by @moonbox3 in https://github.com/microsoft/semantic-kernel/pull/11426
|
||||
* Python: Update Python min version in README by @moonbox3 in https://github.com/microsoft/semantic-kernel/pull/11428
|
||||
* Python: Fix `TypeError` when required is missing in MCP tool’s inputSchema by @KanchiShimono in https://github.com/microsoft/semantic-kernel/pull/11458
|
||||
* Python: Update chromadb requirement from <0.7,>=0.5 to >=0.5,<1.1 in /python by @dependabot in https://github.com/microsoft/semantic-kernel/pull/11420
|
||||
* Python: Bump google-cloud-aiplatform from 1.86.0 to 1.87.0 in /python by @dependabot in https://github.com/microsoft/semantic-kernel/pull/11423
|
||||
* Python: Support Auto Function Invocation Filter for AzureAIAgent and OpenAIAssistantAgent by @moonbox3 in https://github.com/microsoft/semantic-kernel/pull/11460
|
||||
* Python: Improve agent integration tests by @moonbox3 in https://github.com/microsoft/semantic-kernel/pull/11475
|
||||
* Python: Allow Kernel Functions from Prompt for image and audio content by @eavanvalkenburg in https://github.com/microsoft/semantic-kernel/pull/11403
|
||||
* Python: Introducing SK as a MCP Server by @eavanvalkenburg in https://github.com/microsoft/semantic-kernel/pull/11362
|
||||
* Python: sample using GitHub MCP Server and Azure AI Agent by @eavanvalkenburg in https://github.com/microsoft/semantic-kernel/pull/11465
|
||||
* Python: allow settings to be created directly by @eavanvalkenburg in https://github.com/microsoft/semantic-kernel/pull/11468
|
||||
* Python: Bug fix for azure ai agent truncate strategy. Add sample. by @moonbox3 in https://github.com/microsoft/semantic-kernel/pull/11503
|
||||
* Python: small code improvements in code of call automation sample by @eavanvalkenburg in https://github.com/microsoft/semantic-kernel/pull/11477
|
||||
* Added missing import asyncio to agent with plugin python by @sphenry in https://github.com/microsoft/semantic-kernel/pull/11472
|
||||
* Python: version updated to 1.28.0 by @eavanvalkenburg in https://github.com/microsoft/semantic-kernel/pull/11504"""
|
||||
|
||||
|
||||
async def main():
|
||||
# 1. Create the agent
|
||||
async with MCPStdioPlugin(
|
||||
name="ReleaseNotes",
|
||||
description="SK Release Notes Plugin",
|
||||
command="uv",
|
||||
args=[
|
||||
f"--directory={str(Path(os.path.dirname(__file__)).parent.parent.joinpath('demos', 'mcp_server'))}",
|
||||
"run",
|
||||
"mcp_server_with_sampling.py",
|
||||
],
|
||||
sampling_auto_approve=True,
|
||||
) as plugin:
|
||||
agent = ChatCompletionAgent(
|
||||
service=OpenAIChatCompletion(),
|
||||
name="IssueAgent",
|
||||
instructions="For the messages supplied, call the release_notes_prompt function to get the broader "
|
||||
"prompt, then call the run_prompt function to get the final output, return that without any other text."
|
||||
"Do not add any other text to the output, or rewrite the output from run_prompt.",
|
||||
plugins=[plugin],
|
||||
)
|
||||
|
||||
print(f"# Task: {PR_MESSAGES}")
|
||||
# 3. Invoke the agent for a response
|
||||
response = await agent.get_response(messages=PR_MESSAGES)
|
||||
print(str(response))
|
||||
|
||||
# 4. Cleanup: Clear the thread
|
||||
await response.thread.delete()
|
||||
|
||||
"""
|
||||
# Task: * Python: Add ChatCompletionAgent integration tests by @moonbox3 in https://github.com/microsoft/semantic-kernel/pull/11430
|
||||
* Python: Update Doc Gen demo based on latest agent invocation api pattern by @moonbox3 in https://github.com/microsoft/semantic-kernel/pull/11426
|
||||
* Python: Update Python min version in README by @moonbox3 in https://github.com/microsoft/semantic-kernel/pull/11428
|
||||
* Python: Fix `TypeError` when required is missing in MCP tool’s inputSchema by @KanchiShimono in https://github.com/microsoft/semantic-kernel/pull/11458
|
||||
* Python: Update chromadb requirement from <0.7,>=0.5 to >=0.5,<1.1 in /python by @dependabot in https://github.com/microsoft/semantic-kernel/pull/11420
|
||||
* Python: Bump google-cloud-aiplatform from 1.86.0 to 1.87.0 in /python by @dependabot in https://github.com/microsoft/semantic-kernel/pull/11423
|
||||
* Python: Support Auto Function Invocation Filter for AzureAIAgent and OpenAIAssistantAgent by @moonbox3 in https://github.com/microsoft/semantic-kernel/pull/11460
|
||||
* Python: Improve agent integration tests by @moonbox3 in https://github.com/microsoft/semantic-kernel/pull/11475
|
||||
* Python: Allow Kernel Functions from Prompt for image and audio content by @eavanvalkenburg in https://github.com/microsoft/semantic-kernel/pull/11403
|
||||
* Python: Introducing SK as a MCP Server by @eavanvalkenburg in https://github.com/microsoft/semantic-kernel/pull/11362
|
||||
* Python: sample using GitHub MCP Server and Azure AI Agent by @eavanvalkenburg in https://github.com/microsoft/semantic-kernel/pull/11465
|
||||
* Python: allow settings to be created directly by @eavanvalkenburg in https://github.com/microsoft/semantic-kernel/pull/11468
|
||||
* Python: Bug fix for azure ai agent truncate strategy. Add sample. by @moonbox3 in https://github.com/microsoft/semantic-kernel/pull/11503
|
||||
* Python: small code improvements in code of call automation sample by @eavanvalkenburg in https://github.com/microsoft/semantic-kernel/pull/11477
|
||||
* Added missing import asyncio to agent with plugin python by @sphenry in https://github.com/microsoft/semantic-kernel/pull/11472
|
||||
* Python: version updated to 1.28.0 by @eavanvalkenburg in https://github.com/microsoft/semantic-kernel/pull/11504
|
||||
|
||||
Here’s a summary of the recent changes and contributions made to the Microsoft Semantic Kernel repository:
|
||||
|
||||
1. **Integration Tests**:
|
||||
- Added integration tests for `ChatCompletionAgent` by @moonbox3 ([PR #11430](https://github.com/microsoft/semantic-kernel/pull/11430)).
|
||||
- Improved agent integration tests by @moonbox3 ([PR #11475](https://github.com/microsoft/semantic-kernel/pull/11475)).
|
||||
|
||||
2. **Documentation and Demos**:
|
||||
- Updated the Doc Gen demo to align with the latest agent invocation API pattern by @moonbox3 ([PR #11426](https://github.com/microsoft/semantic-kernel/pull/11426)).
|
||||
- Small code improvements made in the code of the call automation sample by @eavanvalkenburg ([PR #11477](https://github.com/microsoft/semantic-kernel/pull/11477)).
|
||||
|
||||
3. **Version Updates**:
|
||||
- Updated the minimum Python version in the README by @moonbox3 ([PR #11428](https://github.com/microsoft/semantic-kernel/pull/11428)).
|
||||
- Updated `chromadb` requirement to allow versions >=0.5 and <1.1 by @dependabot ([PR #11420](https://github.com/microsoft/semantic-kernel/pull/11420)).
|
||||
- Bumped `google-cloud-aiplatform` from 1.86.0 to 1.87.0 by @dependabot ([PR #11423](https://github.com/microsoft/semantic-kernel/pull/11423)).
|
||||
- Version updated to 1.28.0 by @eavanvalkenburg ([PR #11504](https://github.com/microsoft/semantic-kernel/pull/11504)).
|
||||
|
||||
4. **Bug Fixes**:
|
||||
- Fixed a `TypeError` in the MCP tool’s input schema when the required field is missing by @KanchiShimono ([PR #11458](https://github.com/microsoft/semantic-kernel/pull/11458)).
|
||||
- Bug fix for Azure AI agent truncate strategy with an added sample by @moonbox3 ([PR #11503](https://github.com/microsoft/semantic-kernel/pull/11503)).
|
||||
- Added a missing import for `asyncio` in the agent with plugin Python by @sphenry ([PR #11472](https://github.com/microsoft/semantic-kernel/pull/11472)).
|
||||
"""
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
asyncio.run(main())
|
||||
@@ -0,0 +1,108 @@
|
||||
# Copyright (c) Microsoft. All rights reserved.
|
||||
|
||||
import asyncio
|
||||
import os
|
||||
from pathlib import Path
|
||||
|
||||
from azure.identity.aio import AzureCliCredential
|
||||
|
||||
from semantic_kernel.agents import AzureAIAgent, AzureAIAgentSettings, AzureAIAgentThread
|
||||
from semantic_kernel.connectors.mcp import MCPStdioPlugin
|
||||
from semantic_kernel.functions import KernelArguments
|
||||
|
||||
"""
|
||||
The following sample demonstrates how to create a chat completion agent that
|
||||
answers questions about Github using a Local Agent with two local MCP Servers.
|
||||
|
||||
It uses the Azure AI Foundry Agent service to create a agent, so make sure to
|
||||
set the required environment variables for the Azure AI Foundry service:
|
||||
- AZURE_AI_AGENT_PROJECT_CONNECTION_STRING
|
||||
- AZURE_AI_AGENT_MODEL_DEPLOYMENT_NAME
|
||||
"""
|
||||
|
||||
USER_INPUTS = [
|
||||
"list the latest 10 issues that have the label: triage and python and are open",
|
||||
"""generate release notes with this list:
|
||||
* Python: Add ChatCompletionAgent integration tests by @moonbox3 in https://github.com/microsoft/semantic-kernel/pull/11430
|
||||
* Python: Update Doc Gen demo based on latest agent invocation api pattern by @moonbox3 in https://github.com/microsoft/semantic-kernel/pull/11426
|
||||
* Python: Update Python min version in README by @moonbox3 in https://github.com/microsoft/semantic-kernel/pull/11428
|
||||
* Python: Fix `TypeError` when required is missing in MCP tool’s inputSchema by @KanchiShimono in https://github.com/microsoft/semantic-kernel/pull/11458
|
||||
* Python: Update chromadb requirement from <0.7,>=0.5 to >=0.5,<1.1 in /python by @dependabot in https://github.com/microsoft/semantic-kernel/pull/11420
|
||||
* Python: Bump google-cloud-aiplatform from 1.86.0 to 1.87.0 in /python by @dependabot in https://github.com/microsoft/semantic-kernel/pull/11423
|
||||
* Python: Support Auto Function Invocation Filter for AzureAIAgent and OpenAIAssistantAgent by @moonbox3 in https://github.com/microsoft/semantic-kernel/pull/11460
|
||||
* Python: Improve agent integration tests by @moonbox3 in https://github.com/microsoft/semantic-kernel/pull/11475
|
||||
* Python: Allow Kernel Functions from Prompt for image and audio content by @eavanvalkenburg in https://github.com/microsoft/semantic-kernel/pull/11403
|
||||
* Python: Introducing SK as a MCP Server by @eavanvalkenburg in https://github.com/microsoft/semantic-kernel/pull/11362
|
||||
* Python: sample using GitHub MCP Server and Azure AI Agent by @eavanvalkenburg in https://github.com/microsoft/semantic-kernel/pull/11465
|
||||
* Python: allow settings to be created directly by @eavanvalkenburg in https://github.com/microsoft/semantic-kernel/pull/11468
|
||||
* Python: Bug fix for azure ai agent truncate strategy. Add sample. by @moonbox3 in https://github.com/microsoft/semantic-kernel/pull/11503
|
||||
* Python: small code improvements in code of call automation sample by @eavanvalkenburg in https://github.com/microsoft/semantic-kernel/pull/11477
|
||||
* Added missing import asyncio to agent with plugin python by @sphenry in https://github.com/microsoft/semantic-kernel/pull/11472
|
||||
* Python: version updated to 1.28.0 by @eavanvalkenburg in https://github.com/microsoft/semantic-kernel/pull/11504""",
|
||||
]
|
||||
|
||||
|
||||
async def main():
|
||||
# Load the MCP Servers as Plugins
|
||||
async with (
|
||||
# 1. Login to Azure and create a Azure AI Project Client
|
||||
AzureCliCredential() as creds,
|
||||
AzureAIAgent.create_client(credential=creds) as client,
|
||||
MCPStdioPlugin(
|
||||
name="Github",
|
||||
description="Github Plugin",
|
||||
command="docker",
|
||||
args=["run", "-i", "--rm", "-e", "GITHUB_PERSONAL_ACCESS_TOKEN", "ghcr.io/github/github-mcp-server"],
|
||||
env={"GITHUB_PERSONAL_ACCESS_TOKEN": os.getenv("GITHUB_PERSONAL_ACCESS_TOKEN")},
|
||||
) as github_plugin,
|
||||
MCPStdioPlugin(
|
||||
name="ReleaseNotes",
|
||||
description="SK Release Notes Plugin",
|
||||
command="uv",
|
||||
args=[
|
||||
f"--directory={str(Path(os.path.dirname(__file__)).parent.parent.joinpath('demos', 'mcp_server'))}",
|
||||
"run",
|
||||
"mcp_server_with_prompts.py",
|
||||
],
|
||||
) as release_notes_plugin,
|
||||
):
|
||||
# 3. Create the agent, with the MCP plugin and the thread
|
||||
agent = AzureAIAgent(
|
||||
client=client,
|
||||
definition=await client.agents.create_agent(
|
||||
model=AzureAIAgentSettings().model_deployment_name,
|
||||
name="GithubAgent",
|
||||
instructions="You interact with the user to help them with the Microsoft semantic-kernel github "
|
||||
"project. You have dedicated tools for this, including one to write release notes, "
|
||||
"make sure to use that when needed. The repo is always semantic-kernel (aka SK) with owner Microsoft. "
|
||||
"and when doing lists, always return 5 items and sort descending by created or updated"
|
||||
"You are specialized in Python, so always include label, python, in addition to the other labels.",
|
||||
),
|
||||
plugins=[github_plugin, release_notes_plugin], # add the sample plugin to the agent
|
||||
)
|
||||
|
||||
# Create a thread to hold the conversation
|
||||
# If no thread is provided, a new thread will be
|
||||
# created and returned with the initial response
|
||||
thread: AzureAIAgentThread | None = None
|
||||
for user_input in USER_INPUTS:
|
||||
print(f"# User: {user_input}", end="\n\n")
|
||||
first_chunk = True
|
||||
async for response in agent.invoke_stream(
|
||||
messages=user_input,
|
||||
thread=thread,
|
||||
arguments=KernelArguments(owner="microsoft", repo="semantic-kernel"),
|
||||
):
|
||||
if first_chunk:
|
||||
print(f"# {response.name}: ", end="", flush=True)
|
||||
first_chunk = False
|
||||
print(response.content, end="", flush=True)
|
||||
thread = response.thread
|
||||
print()
|
||||
|
||||
# Cleanup: Clear the thread
|
||||
await thread.delete() if thread else None
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
asyncio.run(main())
|
||||
@@ -0,0 +1,100 @@
|
||||
# Copyright (c) Microsoft. All rights reserved.
|
||||
|
||||
import asyncio
|
||||
import os
|
||||
|
||||
from azure.identity.aio import AzureCliCredential
|
||||
|
||||
from semantic_kernel.agents import AzureAIAgent, AzureAIAgentSettings, AzureAIAgentThread
|
||||
from semantic_kernel.connectors.mcp import MCPStdioPlugin
|
||||
|
||||
"""
|
||||
The following sample demonstrates how to create a AzureAIAgent that
|
||||
answers questions about Github using a Semantic Kernel Plugin from a MCP server.
|
||||
|
||||
It uses the Azure AI Foundry Agent service to create a agent, so make sure to
|
||||
set the required environment variables for the Azure AI Foundry service:
|
||||
- AZURE_AI_AGENT_PROJECT_CONNECTION_STRING
|
||||
- AZURE_AI_AGENT_MODEL_DEPLOYMENT_NAME
|
||||
"""
|
||||
|
||||
|
||||
async def main():
|
||||
async with (
|
||||
# 1. Login to Azure and create a Azure AI Project Client
|
||||
AzureCliCredential() as creds,
|
||||
AzureAIAgent.create_client(credential=creds) as client,
|
||||
# 2. Create the MCP plugin
|
||||
MCPStdioPlugin(
|
||||
name="github",
|
||||
description="Github Plugin",
|
||||
command="docker",
|
||||
args=["run", "-i", "--rm", "-e", "GITHUB_PERSONAL_ACCESS_TOKEN", "ghcr.io/github/github-mcp-server"],
|
||||
env={"GITHUB_PERSONAL_ACCESS_TOKEN": os.getenv("GITHUB_PERSONAL_ACCESS_TOKEN")},
|
||||
) as github_plugin,
|
||||
):
|
||||
# 3. Create the agent, with the MCP plugin and the thread
|
||||
agent = AzureAIAgent(
|
||||
client=client,
|
||||
definition=await client.agents.create_agent(
|
||||
model=AzureAIAgentSettings.create().model_deployment_name,
|
||||
name="GithubAgent",
|
||||
instructions="You are a microsoft/semantic-kernel Issue Triage Agent. "
|
||||
"You look at all issues that have the tag: 'triage' and 'python'."
|
||||
"When you find one that is untriaged, you will suggest a new assignee "
|
||||
"based on the issue description, look at recent closed PR's for issues in the same area. "
|
||||
"You will also suggest additional context if needed, like related issues or a bug fix. ",
|
||||
),
|
||||
plugins=[github_plugin], # add the sample plugin to the agent
|
||||
)
|
||||
thread: AzureAIAgentThread | None = None
|
||||
# 4. Print instructions and set the initial user input
|
||||
print("Starting Azure AI Agent with MCP Plugin sample...")
|
||||
print("Once the first prompt is answered, you can further ask questions, use `exit` to exit.")
|
||||
user_input = "Find the latest untriaged, unassigned issues and suggest new assignees."
|
||||
print(f"# User: {user_input}")
|
||||
try:
|
||||
while user_input.lower() != "exit":
|
||||
# 5. Invoke the agent for a response
|
||||
response = await agent.get_response(messages=user_input, thread=thread)
|
||||
print(f"# {response.name}: {response} ")
|
||||
thread = response.thread
|
||||
# 6. Get a new user input
|
||||
user_input = input("# User: ")
|
||||
finally:
|
||||
# 7. Cleanup: Clear the thread
|
||||
await thread.delete() if thread else None
|
||||
await client.agents.delete_agent(agent.definition.id)
|
||||
|
||||
"""
|
||||
Sample output:
|
||||
GitHub MCP Server running on stdio
|
||||
Starting Azure AI Agent with MCP Plugin sample...
|
||||
Once the first prompt is answered, you can further ask questions, use `exit` to exit.
|
||||
# User: Find the latest untriaged, unassigned issues and suggest new assignees.
|
||||
# GithubAgent: Here are the latest untriaged and unassigned issues that are tagged with Python:
|
||||
|
||||
1. **[Issue #11459](https://github.com/microsoft/semantic-kernel/issues/11459)**
|
||||
- **Title:** Python: Bug: The provided example is incorrect
|
||||
- **Description:** There are apparent mistakes in the provided Python examples concerning shared and
|
||||
non-shared stateful configurations.
|
||||
- **Assignee Suggestion:** Assign to **eavanvalkenburg** based on prior involvement with Python-related code and
|
||||
recent PRs focusing on bug fixes.
|
||||
|
||||
2. **[Issue #11465](https://github.com/microsoft/semantic-kernel/issues/11465)**
|
||||
- **Title:** Python: sample using GitHub MCP Server and Azure AI Agent
|
||||
- **Description:** This adds a sample demonstrating how to use MCP tools with the Azure AI Agent.
|
||||
- **Assignee Suggestion:** Assign to **eavanvalkenburg** who is associated with the issue.
|
||||
|
||||
### Summary of Suggested Assignees:
|
||||
- **Issue #11459**: **eavanvalkenburg**
|
||||
- **Issue #11465**: **eavanvalkenburg**
|
||||
|
||||
It seems that I cannot update the assignees directly due to authentication issues. You can use this information
|
||||
as you see fit to assign these issues. If you need further assistance or specific context for each issue,
|
||||
please let me know!
|
||||
"""
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
asyncio.run(main())
|
||||
@@ -0,0 +1,112 @@
|
||||
# Copyright (c) Microsoft. All rights reserved.
|
||||
|
||||
import asyncio
|
||||
import os
|
||||
from pathlib import Path
|
||||
|
||||
from semantic_kernel.agents import ChatCompletionAgent, ChatHistoryAgentThread
|
||||
from semantic_kernel.connectors.ai import FunctionChoiceBehavior
|
||||
from semantic_kernel.connectors.ai.ollama import OllamaChatCompletion
|
||||
from semantic_kernel.connectors.mcp import MCPStdioPlugin
|
||||
from semantic_kernel.functions import KernelArguments
|
||||
|
||||
"""
|
||||
The following sample demonstrates how to create a chat completion agent that
|
||||
answers questions about Github using a Local Agent with two local MCP Servers.
|
||||
|
||||
It uses a Ollama Chat Completion to create a agent, so make sure to
|
||||
set the required environment variables for the Azure AI Foundry service:
|
||||
- OLLAMA_CHAT_MODEL_ID
|
||||
"""
|
||||
|
||||
USER_INPUTS = [
|
||||
"list the latest 10 issues that have the label: triage and python and are open",
|
||||
"""generate release notes with this list:
|
||||
* Python: Add ChatCompletionAgent integration tests by @moonbox3 in https://github.com/microsoft/semantic-kernel/pull/11430
|
||||
* Python: Update Doc Gen demo based on latest agent invocation api pattern by @moonbox3 in https://github.com/microsoft/semantic-kernel/pull/11426
|
||||
* Python: Update Python min version in README by @moonbox3 in https://github.com/microsoft/semantic-kernel/pull/11428
|
||||
* Python: Fix `TypeError` when required is missing in MCP tool’s inputSchema by @KanchiShimono in https://github.com/microsoft/semantic-kernel/pull/11458
|
||||
* Python: Update chromadb requirement from <0.7,>=0.5 to >=0.5,<1.1 in /python by @dependabot in https://github.com/microsoft/semantic-kernel/pull/11420
|
||||
* Python: Bump google-cloud-aiplatform from 1.86.0 to 1.87.0 in /python by @dependabot in https://github.com/microsoft/semantic-kernel/pull/11423
|
||||
* Python: Support Auto Function Invocation Filter for AzureAIAgent and OpenAIAssistantAgent by @moonbox3 in https://github.com/microsoft/semantic-kernel/pull/11460
|
||||
* Python: Improve agent integration tests by @moonbox3 in https://github.com/microsoft/semantic-kernel/pull/11475
|
||||
* Python: Allow Kernel Functions from Prompt for image and audio content by @eavanvalkenburg in https://github.com/microsoft/semantic-kernel/pull/11403
|
||||
* Python: Introducing SK as a MCP Server by @eavanvalkenburg in https://github.com/microsoft/semantic-kernel/pull/11362
|
||||
* Python: sample using GitHub MCP Server and Azure AI Agent by @eavanvalkenburg in https://github.com/microsoft/semantic-kernel/pull/11465
|
||||
* Python: allow settings to be created directly by @eavanvalkenburg in https://github.com/microsoft/semantic-kernel/pull/11468
|
||||
* Python: Bug fix for azure ai agent truncate strategy. Add sample. by @moonbox3 in https://github.com/microsoft/semantic-kernel/pull/11503
|
||||
* Python: small code improvements in code of call automation sample by @eavanvalkenburg in https://github.com/microsoft/semantic-kernel/pull/11477
|
||||
* Added missing import asyncio to agent with plugin python by @sphenry in https://github.com/microsoft/semantic-kernel/pull/11472
|
||||
* Python: version updated to 1.28.0 by @eavanvalkenburg in https://github.com/microsoft/semantic-kernel/pull/11504""",
|
||||
]
|
||||
|
||||
|
||||
async def main():
|
||||
# Load the MCP Servers as Plugins
|
||||
async with (
|
||||
MCPStdioPlugin(
|
||||
name="Github",
|
||||
description="Github Plugin",
|
||||
command="docker",
|
||||
args=["run", "-i", "--rm", "-e", "GITHUB_PERSONAL_ACCESS_TOKEN", "ghcr.io/github/github-mcp-server"],
|
||||
env={"GITHUB_PERSONAL_ACCESS_TOKEN": os.getenv("GITHUB_PERSONAL_ACCESS_TOKEN")},
|
||||
) as github_plugin,
|
||||
MCPStdioPlugin(
|
||||
name="ReleaseNotes",
|
||||
description="SK Release Notes Plugin",
|
||||
command="uv",
|
||||
args=[
|
||||
f"--directory={str(Path(os.path.dirname(__file__)).parent.parent.joinpath('demos', 'mcp_server'))}",
|
||||
"run",
|
||||
"mcp_server_with_prompts.py",
|
||||
],
|
||||
) as release_notes_plugin,
|
||||
):
|
||||
# Create the agent
|
||||
agent = ChatCompletionAgent(
|
||||
# Using the OllamaChatCompletion service
|
||||
service=OllamaChatCompletion(),
|
||||
name="GithubAgent",
|
||||
instructions="You interact with the user to help them with the Microsoft semantic-kernel github project. "
|
||||
"You have dedicated tools for this, including one to write release notes, "
|
||||
"make sure to use that when needed. The repo is always semantic-kernel (aka SK) with owner Microsoft. "
|
||||
"and when doing lists, always return 5 items and sort descending by created or updated"
|
||||
"You are specialized in Python, so always include label, python, in addition to the other labels.",
|
||||
plugins=[github_plugin, release_notes_plugin],
|
||||
function_choice_behavior=FunctionChoiceBehavior.Auto(
|
||||
filters={
|
||||
# exclude a bunch of functions because the local models have trouble with too many functions
|
||||
"included_functions": [
|
||||
"Github-list_issues",
|
||||
"ReleaseNotes-release_notes_prompt",
|
||||
]
|
||||
}
|
||||
),
|
||||
)
|
||||
print(f"Agent uses Ollama with the {agent.service.ai_model_id} model")
|
||||
|
||||
# Create a thread to hold the conversation
|
||||
# If no thread is provided, a new thread will be
|
||||
# created and returned with the initial response
|
||||
thread: ChatHistoryAgentThread | None = None
|
||||
for user_input in USER_INPUTS:
|
||||
print(f"# User: {user_input}", end="\n\n")
|
||||
first_chunk = True
|
||||
async for response in agent.invoke_stream(
|
||||
messages=user_input,
|
||||
thread=thread,
|
||||
arguments=KernelArguments(owner="microsoft", repo="semantic-kernel"),
|
||||
):
|
||||
if first_chunk:
|
||||
print(f"# {response.name}: ", end="", flush=True)
|
||||
first_chunk = False
|
||||
print(response.content, end="", flush=True)
|
||||
thread = response.thread
|
||||
print()
|
||||
|
||||
# Cleanup: Clear the thread
|
||||
await thread.delete() if thread else None
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
asyncio.run(main())
|
||||
@@ -0,0 +1,122 @@
|
||||
# Copyright (c) Microsoft. All rights reserved.
|
||||
|
||||
import asyncio
|
||||
import logging
|
||||
import os
|
||||
|
||||
from samples.concepts.setup.chat_completion_services import Services, get_chat_completion_service_and_request_settings
|
||||
from semantic_kernel import Kernel
|
||||
from semantic_kernel.connectors.ai import FunctionChoiceBehavior
|
||||
from semantic_kernel.connectors.mcp import MCPStdioPlugin
|
||||
from semantic_kernel.contents import ChatHistory
|
||||
from semantic_kernel.utils.logging import setup_logging
|
||||
|
||||
"""
|
||||
This sample demonstrates how to build a conversational chatbot
|
||||
using Semantic Kernel,
|
||||
it creates a Plugin from a MCP server config and adds it to the kernel.
|
||||
The chatbot is designed to interact with the user, call MCP tools
|
||||
as needed, and return responses.
|
||||
|
||||
To run this sample, make sure to run:
|
||||
`pip install semantic-kernel[mcp]`
|
||||
|
||||
or install the mcp package manually.
|
||||
|
||||
In addition, different MCP Stdio servers need different commands to run.
|
||||
For example, the Github plugin requires `npx`, others use `uvx` or `docker`.
|
||||
|
||||
Make sure those are available in your PATH.
|
||||
"""
|
||||
|
||||
# System message defining the behavior and persona of the chat bot.
|
||||
system_message = """
|
||||
You are a chat bot. And you help users interact with Github.
|
||||
You are especially good at answering questions about the Microsoft semantic-kernel project.
|
||||
You can call functions to get the information you need.
|
||||
"""
|
||||
|
||||
setup_logging()
|
||||
logging.getLogger("semantic_kernel.connectors.mcp").setLevel(logging.DEBUG)
|
||||
|
||||
# Create and configure the kernel.
|
||||
kernel = Kernel()
|
||||
|
||||
# You can select from the following chat completion services that support function calling:
|
||||
# - Services.OPENAI
|
||||
# - Services.AZURE_OPENAI
|
||||
# - Services.AZURE_AI_INFERENCE
|
||||
# - Services.ANTHROPIC
|
||||
# - Services.BEDROCK
|
||||
# - Services.GOOGLE_AI
|
||||
# - Services.MISTRAL_AI
|
||||
# - Services.OLLAMA
|
||||
# - Services.ONNX
|
||||
# - Services.VERTEX_AI
|
||||
# - Services.DEEPSEEK
|
||||
# Please make sure you have configured your environment correctly for the selected chat completion service.
|
||||
chat_service, settings = get_chat_completion_service_and_request_settings(Services.OPENAI)
|
||||
|
||||
# Configure the function choice behavior. Here, we set it to Auto, where auto_invoke=True by default.
|
||||
# With `auto_invoke=True`, the model will automatically choose and call functions as needed.
|
||||
settings.function_choice_behavior = FunctionChoiceBehavior.Auto()
|
||||
|
||||
kernel.add_service(chat_service)
|
||||
|
||||
# Create a chat history to store the system message, initial messages, and the conversation.
|
||||
history = ChatHistory()
|
||||
history.add_system_message(system_message)
|
||||
|
||||
|
||||
async def chat() -> bool:
|
||||
"""
|
||||
Continuously prompt the user for input and show the assistant's response.
|
||||
Type 'exit' to exit.
|
||||
"""
|
||||
try:
|
||||
user_input = input("User:> ")
|
||||
except (KeyboardInterrupt, EOFError):
|
||||
print("\n\nExiting chat...")
|
||||
return False
|
||||
if user_input.lower().strip() == "exit":
|
||||
print("\n\nExiting chat...")
|
||||
return False
|
||||
|
||||
history.add_user_message(user_input)
|
||||
result = await chat_service.get_chat_message_content(history, settings, kernel=kernel)
|
||||
if result:
|
||||
print(f"Mosscap:> {result}")
|
||||
history.add_message(result)
|
||||
|
||||
return True
|
||||
|
||||
|
||||
async def main() -> None:
|
||||
# Create a plugin from the MCP server config and add it to the kernel.
|
||||
# The MCP server plugin is defined using the MCPStdioPlugin class.
|
||||
# The command and args are specific to the MCP server you want to run.
|
||||
# For example, the Github MCP Server uses `npx` to run the server.
|
||||
# There are also MCPSsePlugin and MCPStreamableHttpPlugin, which take a URL.
|
||||
async with MCPStdioPlugin(
|
||||
name="Github",
|
||||
description="Github Plugin",
|
||||
command="docker",
|
||||
args=["run", "-i", "--rm", "-e", "GITHUB_PERSONAL_ACCESS_TOKEN", "ghcr.io/github/github-mcp-server"],
|
||||
env={"GITHUB_PERSONAL_ACCESS_TOKEN": os.getenv("GITHUB_PERSONAL_ACCESS_TOKEN")},
|
||||
) as github_plugin:
|
||||
# instead of using this async context manager, you can also use:
|
||||
# await github_plugin.connect()
|
||||
# and then await github_plugin.close() at the end of the program.
|
||||
|
||||
# Add the plugin to the kernel.
|
||||
kernel.add_plugin(github_plugin)
|
||||
|
||||
# Start the chat loop.
|
||||
print("Welcome to the chat bot!\n Type 'exit' to exit.\n")
|
||||
chatting = True
|
||||
while chatting:
|
||||
chatting = await chat()
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
asyncio.run(main())
|
||||
@@ -0,0 +1,176 @@
|
||||
# /// script # noqa: CPY001
|
||||
# dependencies = [
|
||||
# "semantic-kernel[mcp]",
|
||||
# ]
|
||||
# ///
|
||||
# Copyright (c) Microsoft. All rights reserved.
|
||||
import argparse
|
||||
import logging
|
||||
from typing import Annotated, Any, Literal
|
||||
|
||||
import anyio
|
||||
from azure.identity import AzureCliCredential
|
||||
|
||||
from semantic_kernel.agents import ChatCompletionAgent
|
||||
from semantic_kernel.connectors.ai.open_ai import AzureChatCompletion
|
||||
from semantic_kernel.functions import kernel_function
|
||||
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
"""
|
||||
This sample demonstrates how to expose an Agent as a MCP server.
|
||||
|
||||
To run this sample, set up your MCP host (like Claude Desktop or VSCode Github Copilot Agents)
|
||||
with the following configuration:
|
||||
```json
|
||||
{
|
||||
"mcpServers": {
|
||||
"sk": {
|
||||
"command": "uv",
|
||||
"args": [
|
||||
"--directory=<path to sk project>/semantic-kernel/python/samples/demos/mcp_server",
|
||||
"run",
|
||||
"agent_mcp_server.py"
|
||||
],
|
||||
"env": {
|
||||
"AZURE_AI_AGENT_PROJECT_CONNECTION_STRING": "<your azure connection string>",
|
||||
"AZURE_AI_AGENT_MODEL_DEPLOYMENT_NAME": "<your azure model deployment name>",
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
Alternatively, you can run this as a SSE server, by setting the same environment variables as above,
|
||||
and running the following command:
|
||||
```bash
|
||||
uv --directory=<path to sk project>/semantic-kernel/python/samples/demos/mcp_server \
|
||||
run agent_mcp_server.py --transport sse --port 8000
|
||||
```
|
||||
This will start a server that listens for incoming requests on port 8000.
|
||||
|
||||
In both cases, uv will make sure to install semantic-kernel with the mcp extra for you in a temporary venv.
|
||||
"""
|
||||
|
||||
|
||||
def parse_arguments():
|
||||
parser = argparse.ArgumentParser(description="Run the Semantic Kernel MCP server.")
|
||||
parser.add_argument(
|
||||
"--transport",
|
||||
type=str,
|
||||
choices=["sse", "stdio"],
|
||||
default="stdio",
|
||||
help="Transport method to use (default: stdio).",
|
||||
)
|
||||
parser.add_argument(
|
||||
"--port",
|
||||
type=int,
|
||||
default=None,
|
||||
help="Port to use for SSE transport (required if transport is 'sse').",
|
||||
)
|
||||
return parser.parse_args()
|
||||
|
||||
|
||||
# Define a simple plugin for the sample
|
||||
class RestaurantPlugin:
|
||||
"""A sample Menu Plugin used for the sample."""
|
||||
|
||||
@kernel_function(description="List the available restaurants.")
|
||||
def list_restaurants(self) -> Annotated[str, "Returns a list of available restaurants."]:
|
||||
return """
|
||||
1. The Farm: a classic steakhouse with a rustic atmosphere.
|
||||
2. The Harbor: a seafood restaurant with a view of the ocean.
|
||||
3. The Joint: a casual eatery with a diverse menu.
|
||||
"""
|
||||
|
||||
@kernel_function(description="Provides a list of specials from the menu.")
|
||||
def get_specials(
|
||||
self, restaurant: Literal["The Farm, The Harbor, The Joint"]
|
||||
) -> Annotated[str, "Returns the specials from the menu."]:
|
||||
match restaurant:
|
||||
case "The Farm":
|
||||
return """
|
||||
Special Entree: T-bone steak
|
||||
Special Salad: Caesar Salad
|
||||
Special Drink: Old Fashioned
|
||||
"""
|
||||
case "The Harbor":
|
||||
return """
|
||||
Special Soup: Lobster Bisque
|
||||
Special Salad: Cobb Salad
|
||||
Special Drink: Mai Tai
|
||||
"""
|
||||
case "The Joint":
|
||||
return """
|
||||
Special Burger: Avocado and Jalapeno Burger
|
||||
Special Salad: Greek Salad
|
||||
Special Drink: Milkshake Strawberry
|
||||
"""
|
||||
case _:
|
||||
return "No specials available for this restaurant."
|
||||
|
||||
@kernel_function(description="Provides the price of the requested menu item.")
|
||||
def get_item_price(
|
||||
self,
|
||||
restaurant: Literal["The Farm, The Harbor, The Joint"],
|
||||
menu_item: Annotated[str, "The name of the menu item."],
|
||||
) -> Annotated[str, "Returns the price of the menu item."]:
|
||||
match restaurant:
|
||||
case "The Farm":
|
||||
return "$9.99"
|
||||
case "The Harbor":
|
||||
return "$12.99"
|
||||
case "The Joint":
|
||||
return "$8.99"
|
||||
case _:
|
||||
return "No price available for this restaurant."
|
||||
|
||||
|
||||
async def run(transport: Literal["sse", "stdio"] = "stdio", port: int | None = None) -> None:
|
||||
agent = ChatCompletionAgent(
|
||||
service=AzureChatCompletion(credential=AzureCliCredential()),
|
||||
name="Host",
|
||||
instructions="Answer questions about the menu for different restaurants, use the list_restaurants function "
|
||||
"to get the list of restaurants.",
|
||||
plugins=[RestaurantPlugin()], # add the sample plugin to the agent
|
||||
)
|
||||
|
||||
server = agent.as_mcp_server()
|
||||
|
||||
if transport == "sse" and port is not None:
|
||||
import nest_asyncio
|
||||
import uvicorn
|
||||
from mcp.server.sse import SseServerTransport
|
||||
from starlette.applications import Starlette
|
||||
from starlette.routing import Mount, Route
|
||||
|
||||
sse = SseServerTransport("/messages/")
|
||||
|
||||
async def handle_sse(request):
|
||||
async with sse.connect_sse(request.scope, request.receive, request._send) as (
|
||||
read_stream,
|
||||
write_stream,
|
||||
):
|
||||
await server.run(read_stream, write_stream, server.create_initialization_options())
|
||||
|
||||
starlette_app = Starlette(
|
||||
debug=True,
|
||||
routes=[
|
||||
Route("/sse", endpoint=handle_sse),
|
||||
Mount("/messages/", app=sse.handle_post_message),
|
||||
],
|
||||
)
|
||||
nest_asyncio.apply()
|
||||
uvicorn.run(starlette_app, host="0.0.0.0", port=port) # nosec
|
||||
elif transport == "stdio":
|
||||
from mcp.server.stdio import stdio_server
|
||||
|
||||
async def handle_stdin(stdin: Any | None = None, stdout: Any | None = None) -> None:
|
||||
async with stdio_server() as (read_stream, write_stream):
|
||||
await server.run(read_stream, write_stream, server.create_initialization_options())
|
||||
|
||||
await handle_stdin()
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
args = parse_arguments()
|
||||
anyio.run(run, args.transport, args.port)
|
||||
@@ -0,0 +1,150 @@
|
||||
# /// script # noqa: CPY001
|
||||
# dependencies = [
|
||||
# "semantic-kernel[mcp]",
|
||||
# ]
|
||||
# ///
|
||||
# Copyright (c) Microsoft. All rights reserved.
|
||||
import argparse
|
||||
import logging
|
||||
from random import random
|
||||
from typing import Annotated, Any, Literal
|
||||
|
||||
import anyio
|
||||
from azure.identity import AzureCliCredential
|
||||
|
||||
from semantic_kernel.agents import ChatCompletionAgent
|
||||
from semantic_kernel.connectors.ai.open_ai import AzureChatCompletion
|
||||
from semantic_kernel.functions import kernel_function
|
||||
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
"""
|
||||
This sample demonstrates how to expose an Agent as a MCP server.
|
||||
|
||||
To run this sample, set up your MCP host (like Claude Desktop or VSCode Github Copilot Agents)
|
||||
with the following configuration:
|
||||
```json
|
||||
{
|
||||
"mcpServers": {
|
||||
"sk": {
|
||||
"command": "uv",
|
||||
"args": [
|
||||
"--directory=<path to sk project>/semantic-kernel/python/samples/demos/mcp_server",
|
||||
"run",
|
||||
"agent_mcp_server.py"
|
||||
],
|
||||
"env": {
|
||||
"AZURE_AI_AGENT_PROJECT_CONNECTION_STRING": "<your azure connection string>",
|
||||
"AZURE_AI_AGENT_MODEL_DEPLOYMENT_NAME": "<your azure model deployment name>",
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
Alternatively, you can run this as a SSE server, by setting the same environment variables as above,
|
||||
and running the following command:
|
||||
```bash
|
||||
uv --directory=<path to sk project>/semantic-kernel/python/samples/demos/mcp_server \
|
||||
run agent_mcp_server.py --transport sse --port 8000
|
||||
```
|
||||
This will start a server that listens for incoming requests on port 8000.
|
||||
|
||||
In both cases, uv will make sure to install semantic-kernel with the mcp extra for you in a temporary venv.
|
||||
"""
|
||||
|
||||
|
||||
def parse_arguments():
|
||||
parser = argparse.ArgumentParser(description="Run the Semantic Kernel MCP server.")
|
||||
parser.add_argument(
|
||||
"--transport",
|
||||
type=str,
|
||||
choices=["sse", "stdio"],
|
||||
default="stdio",
|
||||
help="Transport method to use (default: stdio).",
|
||||
)
|
||||
parser.add_argument(
|
||||
"--port",
|
||||
type=int,
|
||||
default=None,
|
||||
help="Port to use for SSE transport (required if transport is 'sse').",
|
||||
)
|
||||
return parser.parse_args()
|
||||
|
||||
|
||||
# Define a simple plugin for the sample
|
||||
class BookingPlugin:
|
||||
"""A sample Booking Plugin used for the sample."""
|
||||
|
||||
@kernel_function(description="Asks for a booking, will return 'confirmed' or 'denied'.")
|
||||
def book_a_table(
|
||||
self,
|
||||
restaurant: Annotated[Literal["The Farm, The Harbor, The Joint"], "The name of the restaurant."],
|
||||
day: Annotated[str, "Day of the week"],
|
||||
time: Annotated[int, "The hour of the booking (whole hours only)"],
|
||||
number_of_guests: Annotated[int, "The number of guests."],
|
||||
) -> Annotated[str, "Confirmed or denied."]:
|
||||
if time < 12 or time > 23:
|
||||
return "denied"
|
||||
odds = 0.5 if number_of_guests > 4 else 0.9
|
||||
if time < 12 or time > 21:
|
||||
odds = min(1.0, odds * 1.5)
|
||||
if day in ["Friday", "Saturday"]:
|
||||
odds = max(0.0, min(1.0, odds * 0.8))
|
||||
match restaurant:
|
||||
case "The Farm":
|
||||
odds = max(0.0, odds * 0.5)
|
||||
case "The Harbor":
|
||||
odds = max(0.0, odds * 0.7)
|
||||
case "The Joint":
|
||||
odds = min(1.0, odds * 1.2)
|
||||
return "confirmed" if random() < odds else "denied" # nosec
|
||||
|
||||
|
||||
async def run(transport: Literal["sse", "stdio"] = "stdio", port: int | None = None) -> None:
|
||||
agent = ChatCompletionAgent(
|
||||
service=AzureChatCompletion(credential=AzureCliCredential()),
|
||||
name="Booker",
|
||||
instructions="Create a booking for the user, this is for the following restaurants: "
|
||||
"The Farm, The Harbor, The Joint. ",
|
||||
plugins=[BookingPlugin()], # add the sample plugin to the agent
|
||||
)
|
||||
server = agent.as_mcp_server()
|
||||
|
||||
if transport == "sse" and port is not None:
|
||||
import nest_asyncio
|
||||
import uvicorn
|
||||
from mcp.server.sse import SseServerTransport
|
||||
from starlette.applications import Starlette
|
||||
from starlette.routing import Mount, Route
|
||||
|
||||
sse = SseServerTransport("/messages/")
|
||||
|
||||
async def handle_sse(request):
|
||||
async with sse.connect_sse(request.scope, request.receive, request._send) as (
|
||||
read_stream,
|
||||
write_stream,
|
||||
):
|
||||
await server.run(read_stream, write_stream, server.create_initialization_options())
|
||||
|
||||
starlette_app = Starlette(
|
||||
debug=True,
|
||||
routes=[
|
||||
Route("/sse", endpoint=handle_sse),
|
||||
Mount("/messages/", app=sse.handle_post_message),
|
||||
],
|
||||
)
|
||||
nest_asyncio.apply()
|
||||
uvicorn.run(starlette_app, host="0.0.0.0", port=port) # nosec
|
||||
elif transport == "stdio":
|
||||
from mcp.server.stdio import stdio_server
|
||||
|
||||
async def handle_stdin(stdin: Any | None = None, stdout: Any | None = None) -> None:
|
||||
async with stdio_server() as (read_stream, write_stream):
|
||||
await server.run(read_stream, write_stream, server.create_initialization_options())
|
||||
|
||||
await handle_stdin()
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
args = parse_arguments()
|
||||
anyio.run(run, args.transport, args.port)
|
||||
Reference in New Issue
Block a user