-
Notifications
You must be signed in to change notification settings - Fork 0
Add support in binary tool responses #12
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change | ||||||||
|---|---|---|---|---|---|---|---|---|---|---|
| @@ -0,0 +1,76 @@ | ||||||||||
| import base64 | ||||||||||
| import logging | ||||||||||
| import mimetypes | ||||||||||
| from pathlib import Path | ||||||||||
| from uuid import uuid4 | ||||||||||
|
|
||||||||||
| from mcp import types | ||||||||||
|
|
||||||||||
|
|
||||||||||
| def save_binary_data_to_file(config_dir: Path, data: str, mime_type: str, file_prefix: str = "binary") -> str: | ||||||||||
| """ | ||||||||||
| Save binary data (base64-encoded) to a file in the config directory. | ||||||||||
|
|
||||||||||
| Args: | ||||||||||
| config_dir: The .cxk config directory path | ||||||||||
| data: Base64-encoded binary data | ||||||||||
| mime_type: MIME type of the data (e.g., 'image/png', 'audio/wav') | ||||||||||
| file_prefix: Prefix for the generated filename | ||||||||||
|
|
||||||||||
| Returns: | ||||||||||
| Relative path to the saved file from the project root | ||||||||||
|
|
||||||||||
| Raises: | ||||||||||
| Exception: If file save fails (errors are logged but not re-raised) | ||||||||||
| """ | ||||||||||
| try: | ||||||||||
| # Create files directory if it doesn't exist | ||||||||||
| files_dir = config_dir / "files" | ||||||||||
| files_dir.mkdir(exist_ok=True) | ||||||||||
|
|
||||||||||
| # Generate unique filename with appropriate extension | ||||||||||
| extension = mimetypes.guess_extension(mime_type) or "" | ||||||||||
| filename = f"{file_prefix}_{uuid4().hex[:8]}{extension}" | ||||||||||
| file_path = files_dir / filename | ||||||||||
|
|
||||||||||
| # Decode base64 data and write to file | ||||||||||
| binary_data = base64.b64decode(data) | ||||||||||
| with open(file_path, "wb") as f: | ||||||||||
| f.write(binary_data) | ||||||||||
|
|
||||||||||
| # Return relative path from project root | ||||||||||
| relative_path = file_path.relative_to(config_dir.parent) | ||||||||||
| logging.info(f"Saved binary data to {relative_path}") | ||||||||||
| return str(relative_path) | ||||||||||
|
|
||||||||||
| except Exception as e: | ||||||||||
| error_msg = f"Failed to save binary data: {e}" | ||||||||||
| logging.error(error_msg) | ||||||||||
| raise Exception(error_msg) from e | ||||||||||
|
|
||||||||||
|
|
||||||||||
| def handle_binary_content(config_dir: Path, content) -> str: | ||||||||||
| """ | ||||||||||
| Handle binary content from MCP responses, saving to file and returning path. | ||||||||||
|
|
||||||||||
| Args: | ||||||||||
| config_dir: The .cxk config directory path | ||||||||||
| content: MCP content object (ImageContent, AudioContent, or BlobResourceContents) | ||||||||||
|
|
||||||||||
| Returns: | ||||||||||
| Relative path to the saved file or empty string if handling fails | ||||||||||
| """ | ||||||||||
| try: | ||||||||||
| if isinstance(content, types.ImageContent): | ||||||||||
| return save_binary_data_to_file(config_dir, content.data, content.mimeType, "image") | ||||||||||
| elif isinstance(content, types.AudioContent): | ||||||||||
| return save_binary_data_to_file(config_dir, content.data, content.mimeType, "audio") | ||||||||||
| elif isinstance(content, types.BlobResourceContents): | ||||||||||
| # For blob resources, we don't have mime type info, so we'll save as generic file | ||||||||||
| return save_binary_data_to_file(config_dir, content.blob, "application/octet-stream", "blob") | ||||||||||
|
Comment on lines
+69
to
+70
|
||||||||||
| # For blob resources, we don't have mime type info, so we'll save as generic file | |
| return save_binary_data_to_file(config_dir, content.blob, "application/octet-stream", "blob") | |
| # Use the mimeType field from BlobResourceContents if available | |
| return save_binary_data_to_file(config_dir, content.blob, content.mimeType, "blob") |
| Original file line number | Diff line number | Diff line change | ||||
|---|---|---|---|---|---|---|
| @@ -1,8 +1,9 @@ | ||||||
| import logging | ||||||
|
|
||||||
| import questionary | ||||||
| from mcp import types | ||||||
|
|
||||||
| from mcp_client import get_session_manager | ||||||
| from mcp_client import get_session_manager, handle_binary_content | ||||||
| from state import State | ||||||
|
|
||||||
|
|
||||||
|
|
@@ -221,11 +222,20 @@ async def _collect_var_value_from_mcp(self, var_name: str) -> str: | |||||
| # Handle list of content items | ||||||
| content_parts = [] | ||||||
| for item in result.content: | ||||||
| # Try to get text content first (safely) | ||||||
| text_content = getattr(item, "text", None) | ||||||
| if text_content: | ||||||
| content_parts.append(str(text_content)) | ||||||
| # For non-text content, convert to string | ||||||
| # Handle binary content types | ||||||
| if isinstance(item, types.ImageContent | types.AudioContent): | ||||||
|
||||||
| if isinstance(item, types.ImageContent | types.AudioContent): | |
| if isinstance(item, (types.ImageContent, types.AudioContent, types.BlobResourceContents)): |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,7 @@ | ||
| # Task Template | ||
|
|
||
| ## Image links | ||
|
|
||
| {% set image = call_tool('test-mcp', 'get_blob', {}) %} | ||
|
|
||
| {{ image }} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The comment is incorrect. BlobResourceContents has a mimeType field that should be used instead of hardcoding 'application/octet-stream'.