From 592207e41d1dec13f632fb01395d25f711f1c01d Mon Sep 17 00:00:00 2001 From: nigel brown Date: Thu, 23 Oct 2025 14:05:28 +0100 Subject: [PATCH 1/3] Better logging for validataion errors --- src/mcp_optimizer/mcp_client.py | 52 +++++++++++++++++++++++++++++++-- 1 file changed, 49 insertions(+), 3 deletions(-) diff --git a/src/mcp_optimizer/mcp_client.py b/src/mcp_optimizer/mcp_client.py index 300d23e..80bdf82 100644 --- a/src/mcp_optimizer/mcp_client.py +++ b/src/mcp_optimizer/mcp_client.py @@ -125,7 +125,7 @@ async def _execute_with_session(self, operation: Callable[[ClientSession], Await proxy_mode = self._determine_proxy_mode() logger.info( - f"Using {proxy_mode} client for workload", + f"Using {proxy_mode} client for workload '{self.workload.name}'", workload=self.workload.name, proxy_mode_field=self.workload.proxy_mode, url=self.workload.url, @@ -173,16 +173,42 @@ async def _execute_streamable_session( self, operation: Callable[[ClientSession], Awaitable] ) -> Any: """Execute operation with streamable HTTP session.""" + logger.debug( + f"Establishing streamable HTTP session for workload '{self.workload.name}'", + workload=self.workload.name, + url=self.workload.url, + ) async with streamablehttp_client(self.workload.url) as (read_stream, write_stream, _): async with ClientSession(read_stream, write_stream) as session: + logger.info( + f"Initializing MCP session for workload '{self.workload.name}'", + workload=self.workload.name, + ) await session.initialize() + logger.debug( + f"MCP session initialized successfully for workload '{self.workload.name}'", + workload=self.workload.name, + ) return await operation(session) async def _execute_sse_session(self, operation: Callable[[ClientSession], Awaitable]) -> Any: """Execute operation with SSE session.""" + logger.debug( + f"Establishing SSE session for workload '{self.workload.name}'", + workload=self.workload.name, + url=self.workload.url, + ) async with sse_client(self.workload.url) as (read_stream, write_stream): async with ClientSession(read_stream, write_stream) as session: + logger.info( + f"Initializing MCP session for workload '{self.workload.name}'", + workload=self.workload.name, + ) await session.initialize() + logger.debug( + f"MCP session initialized successfully for workload '{self.workload.name}'", + workload=self.workload.name, + ) return await operation(session) async def list_tools(self) -> ListToolsResult: @@ -192,7 +218,16 @@ async def list_tools(self) -> ListToolsResult: Returns: ListToolsResult: Available tools from the MCP server """ - return await self._execute_with_session(lambda session: session.list_tools()) + logger.debug( + f"Listing tools for workload '{self.workload.name}'", workload=self.workload.name + ) + result = await self._execute_with_session(lambda session: session.list_tools()) + logger.debug( + f"Retrieved {len(result.tools)} tools from workload '{self.workload.name}'", + workload=self.workload.name, + tool_count=len(result.tools), + ) + return result async def call_tool(self, tool_name: str, arguments: dict[str, Any]) -> CallToolResult: """ @@ -205,6 +240,17 @@ async def call_tool(self, tool_name: str, arguments: dict[str, Any]) -> CallTool Returns: CallToolResult: Result of the tool execution """ - return await self._execute_with_session( + logger.debug( + f"Calling tool '{tool_name}' on workload '{self.workload.name}'", + workload=self.workload.name, + tool_name=tool_name, + ) + result = await self._execute_with_session( lambda session: session.call_tool(tool_name, arguments) ) + logger.debug( + f"Tool '{tool_name}' call completed on workload '{self.workload.name}'", + workload=self.workload.name, + tool_name=tool_name, + ) + return result From 1aa77fae2a0c56f9c0654748ee586e59d8825bec Mon Sep 17 00:00:00 2001 From: nigel brown Date: Thu, 23 Oct 2025 14:05:43 +0100 Subject: [PATCH 2/3] Build multi arch locally --- Taskfile.yml | 20 ++++++++++++++++---- 1 file changed, 16 insertions(+), 4 deletions(-) diff --git a/Taskfile.yml b/Taskfile.yml index da8ee1a..9485f7b 100644 --- a/Taskfile.yml +++ b/Taskfile.yml @@ -74,12 +74,24 @@ tasks: deps: - install - run-container: - desc: Run the application in a container + build: + desc: Build multi-architecture container image cmds: - - docker build -t mcp-optimizer . + - docker buildx create --name mcp-optimizer-builder --use --bootstrap || docker buildx use mcp-optimizer-builder + - docker buildx build --platform linux/amd64,linux/arm64 -t mcp-optimizer:latest --load . + - docker rm -f mcp-optimizer-container || true + + build-local: + desc: Build container image for local architecture only (faster for development) + cmds: + - docker build -t mcp-optimizer:latest . - docker rm -f mcp-optimizer-container || true - - docker run --network host --name mcp-optimizer-container mcp-optimizer + + run-container: + desc: Run the application in a container (builds for local arch only) + cmds: + - task: build-local + - docker run --network host --name mcp-optimizer-container mcp-optimizer:latest install-hooks: desc: Install git hooks for the project From 9d2241b84d97594030c4e72cd81cb58899c10778 Mon Sep 17 00:00:00 2001 From: nigel brown Date: Thu, 23 Oct 2025 14:06:14 +0100 Subject: [PATCH 3/3] Add labels and provenance to builds --- .github/workflows/release.yml | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index 4dd9d6c..bd9b6f9 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -48,6 +48,14 @@ jobs: type=ref,event=tag type=raw,value=latest,enable={{is_default_branch}} type=raw,value=${{ steps.tag.outputs.VERSION }} + labels: | + org.opencontainers.image.title=mcp-optimizer + org.opencontainers.image.description=MCP Optimizer - Intelligent MCP server orchestration + org.opencontainers.image.vendor=Stacklok + org.opencontainers.image.source=https://github.com/${{ github.repository }} + org.opencontainers.image.version=${{ steps.tag.outputs.VERSION }} + org.opencontainers.image.revision=${{ github.sha }} + org.opencontainers.image.created=${{ github.event.head_commit.timestamp }} - name: Build and push container uses: docker/build-push-action@263435318d21b8e681c14492fe198d362a7d2c83 # v6.18.0 @@ -59,6 +67,8 @@ jobs: labels: ${{ steps.meta.outputs.labels }} cache-from: type=gha cache-to: type=gha,mode=max + provenance: true + sbom: true - name: Install Cosign uses: sigstore/cosign-installer@faadad0cce49287aee09b3a48701e75088a2c6ad # v4.0.0