Skip to content

Commit 8d1b3fd

Browse files
Python: fixes for new MCP types and small openapi fix (#12486)
### Motivation and Context <!-- Thank you for your contribution to the semantic-kernel repo! Please help reviewers and future users, providing the following information: 1. Why is this change required? 2. What problem does it solve? 3. What scenario does it contribute to? 4. If it fixes an open issue, please link to the issue here. --> Fixes to include AudioContent for MCP Small typing improvement in OpenAPI. ### Description <!-- Describe your changes, the overall approach, the underlying design. These notes will help understanding how your code works. Thanks! --> ### Contribution Checklist <!-- Before submitting this PR, please make sure: --> - [x] The code builds clean without any errors or warnings - [x] The PR follows the [SK Contribution Guidelines](https://github.com/microsoft/semantic-kernel/blob/main/CONTRIBUTING.md) and the [pre-submission formatting script](https://github.com/microsoft/semantic-kernel/blob/main/CONTRIBUTING.md#development-scripts) raises no violations - [x] All unit tests pass, and I have added new tests where possible - [x] I didn't break anyone 😄
1 parent ad797d1 commit 8d1b3fd

File tree

3 files changed

+3415
-3432
lines changed

3 files changed

+3415
-3432
lines changed

python/semantic_kernel/connectors/mcp.py

Lines changed: 22 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,7 @@
2525

2626
from semantic_kernel import Kernel
2727
from semantic_kernel.connectors.ai.chat_completion_client_base import ChatCompletionClientBase
28+
from semantic_kernel.contents.audio_content import AudioContent
2829
from semantic_kernel.contents.binary_content import BinaryContent
2930
from semantic_kernel.contents.chat_history import ChatHistory
3031
from semantic_kernel.contents.chat_message_content import ChatMessageContent
@@ -81,20 +82,22 @@ def _mcp_prompt_message_to_kernel_content(
8182
@experimental
8283
def _mcp_call_tool_result_to_kernel_contents(
8384
mcp_type: types.CallToolResult,
84-
) -> list[TextContent | ImageContent | BinaryContent]:
85+
) -> list[TextContent | ImageContent | BinaryContent | AudioContent]:
8586
"""Convert a MCP container type to a Semantic Kernel type."""
8687
return [_mcp_content_types_to_kernel_content(item) for item in mcp_type.content]
8788

8889

8990
@experimental
9091
def _mcp_content_types_to_kernel_content(
91-
mcp_type: types.ImageContent | types.TextContent | types.EmbeddedResource,
92-
) -> TextContent | ImageContent | BinaryContent:
92+
mcp_type: types.ImageContent | types.TextContent | types.AudioContent | types.EmbeddedResource,
93+
) -> TextContent | ImageContent | BinaryContent | AudioContent:
9394
"""Convert a MCP type to a Semantic Kernel type."""
9495
if isinstance(mcp_type, types.TextContent):
9596
return TextContent(text=mcp_type.text, inner_content=mcp_type)
9697
if isinstance(mcp_type, types.ImageContent):
9798
return ImageContent(data=mcp_type.data, mime_type=mcp_type.mimeType, inner_content=mcp_type)
99+
if isinstance(mcp_type, types.AudioContent):
100+
return AudioContent(data=mcp_type.data, mime_type=mcp_type.mimeType, inner_content=mcp_type)
98101
# subtypes of EmbeddedResource
99102
if isinstance(mcp_type.resource, types.TextResourceContents):
100103
return TextContent(
@@ -111,13 +114,15 @@ def _mcp_content_types_to_kernel_content(
111114

112115
@experimental
113116
def _kernel_content_to_mcp_content_types(
114-
content: TextContent | ImageContent | BinaryContent | ChatMessageContent,
115-
) -> Sequence[types.TextContent | types.ImageContent | types.EmbeddedResource]:
117+
content: TextContent | ImageContent | BinaryContent | AudioContent | ChatMessageContent,
118+
) -> Sequence[types.TextContent | types.ImageContent | types.AudioContent | types.EmbeddedResource]:
116119
"""Convert a kernel content type to a MCP type."""
117120
if isinstance(content, TextContent):
118121
return [types.TextContent(type="text", text=content.text)]
119122
if isinstance(content, ImageContent):
120123
return [types.ImageContent(type="image", data=content.data_string, mimeType=content.mime_type)]
124+
if isinstance(content, AudioContent):
125+
return [types.AudioContent(type="audio", data=content.data_string, mimeType=content.mime_type)]
121126
if isinstance(content, BinaryContent):
122127
return [
123128
types.EmbeddedResource(
@@ -128,9 +133,9 @@ def _kernel_content_to_mcp_content_types(
128133
)
129134
]
130135
if isinstance(content, ChatMessageContent):
131-
messages: list[types.TextContent | types.ImageContent | types.EmbeddedResource] = []
136+
messages: list[types.TextContent | types.ImageContent | types.AudioContent | types.EmbeddedResource] = []
132137
for item in content.items:
133-
if isinstance(item, (TextContent, ImageContent, BinaryContent)):
138+
if isinstance(item, (TextContent, ImageContent, BinaryContent, AudioContent)):
134139
messages.extend(_kernel_content_to_mcp_content_types(item))
135140
else:
136141
logger.debug("Unsupported content type: %s", type(item))
@@ -891,24 +896,30 @@ async def _list_tools() -> list[types.Tool]:
891896
return tools
892897

893898
@server.call_tool()
894-
async def _call_tool(*args: Any) -> Sequence[types.TextContent | types.ImageContent | types.EmbeddedResource]:
899+
async def _call_tool(
900+
*args: Any,
901+
) -> Sequence[types.TextContent | types.ImageContent | types.AudioContent | types.EmbeddedResource]:
895902
"""Call a tool in the kernel."""
896903
await _log(level="debug", data=f"Calling tool with args: {args}")
897904
function_name, arguments = args[0], args[1]
898905
result = await _call_kernel_function(function_name, arguments)
899906
if result:
900907
value = result.value
901-
messages: list[types.TextContent | types.ImageContent | types.EmbeddedResource] = []
908+
messages: list[
909+
types.TextContent | types.ImageContent | types.AudioContent | types.EmbeddedResource
910+
] = []
902911
if isinstance(value, list):
903912
for item in value:
904-
if isinstance(value, (TextContent, ImageContent, BinaryContent, ChatMessageContent)):
913+
if isinstance(
914+
value, (TextContent, ImageContent, BinaryContent, AudioContent, ChatMessageContent)
915+
):
905916
messages.extend(_kernel_content_to_mcp_content_types(item))
906917
else:
907918
messages.append(
908919
types.TextContent(type="text", text=str(item)),
909920
)
910921
else:
911-
if isinstance(value, (TextContent, ImageContent, BinaryContent, ChatMessageContent)):
922+
if isinstance(value, (TextContent, ImageContent, BinaryContent, AudioContent, ChatMessageContent)):
912923
messages.extend(_kernel_content_to_mcp_content_types(value))
913924
else:
914925
messages.append(

python/semantic_kernel/connectors/openapi_plugin/openapi_parser.py

Lines changed: 4 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -7,18 +7,12 @@
77

88
from prance import ResolvingParser
99

10-
from semantic_kernel.connectors.openapi_plugin.models.rest_api_expected_response import (
11-
RestApiExpectedResponse,
12-
)
10+
from semantic_kernel.connectors.openapi_plugin.models.rest_api_expected_response import RestApiExpectedResponse
1311
from semantic_kernel.connectors.openapi_plugin.models.rest_api_operation import RestApiOperation
1412
from semantic_kernel.connectors.openapi_plugin.models.rest_api_parameter import RestApiParameter
15-
from semantic_kernel.connectors.openapi_plugin.models.rest_api_parameter_location import (
16-
RestApiParameterLocation,
17-
)
13+
from semantic_kernel.connectors.openapi_plugin.models.rest_api_parameter_location import RestApiParameterLocation
1814
from semantic_kernel.connectors.openapi_plugin.models.rest_api_payload import RestApiPayload
19-
from semantic_kernel.connectors.openapi_plugin.models.rest_api_payload_property import (
20-
RestApiPayloadProperty,
21-
)
15+
from semantic_kernel.connectors.openapi_plugin.models.rest_api_payload_property import RestApiPayloadProperty
2216
from semantic_kernel.connectors.openapi_plugin.models.rest_api_security_requirement import RestApiSecurityRequirement
2317
from semantic_kernel.connectors.openapi_plugin.models.rest_api_security_scheme import RestApiSecurityScheme
2418
from semantic_kernel.exceptions.function_exceptions import PluginInitializationError
@@ -66,7 +60,7 @@ def _parse_parameters(self, parameters: list[dict[str, Any]]):
6660
# The schema and content fields are mutually exclusive.
6761
raise PluginInitializationError(f"Parameter {name} cannot have a 'content' field. Expected: schema.")
6862
location = RestApiParameterLocation(param["in"])
69-
description: str = param.get("description", None)
63+
description: str | None = param.get("description", None)
7064
is_required: bool = param.get("required", False)
7165
default_value = param.get("default", None)
7266
schema: dict[str, Any] | None = param.get("schema", None)

0 commit comments

Comments
 (0)