From 51be352dc6aa2f376fc8f9a8f8bb220ed0df0e0e Mon Sep 17 00:00:00 2001 From: Dean Schmigelski Date: Mon, 19 May 2025 00:13:44 -0400 Subject: [PATCH 01/61] ci: add workflows verifying compatibility with tools, docs, and agent builder --- .../verify-agent-builder-compatibility.yml | 47 +++++++++++++++++ .../workflows/verify-docs-compatibility.yml | 42 +++++++++++++++ .../workflows/verify-tools-compatibility.yml | 52 +++++++++++++++++++ 3 files changed, 141 insertions(+) create mode 100644 .github/workflows/verify-agent-builder-compatibility.yml create mode 100644 .github/workflows/verify-docs-compatibility.yml create mode 100644 .github/workflows/verify-tools-compatibility.yml diff --git a/.github/workflows/verify-agent-builder-compatibility.yml b/.github/workflows/verify-agent-builder-compatibility.yml new file mode 100644 index 000000000..588dfb334 --- /dev/null +++ b/.github/workflows/verify-agent-builder-compatibility.yml @@ -0,0 +1,47 @@ +name: Verify Agent Builder Compatibility + +on: + pull_request: + branches: [ main ] + push: + branches: [ main ] + +jobs: + test-dependency: + runs-on: ubuntu-latest + strategy: + matrix: + python-version: ["3.10", "3.11", "3.12", "3.13"] + + steps: + - name: Checkout sdk-python + uses: actions/checkout@v4 + with: + path: sdk-python + - name: Checkout Agent Builder Repository + uses: actions/checkout@v4 + with: + repository: strands-agents/agent-builder + path: agent-builder + - name: Set up Python ${{ matrix.python-version }} + uses: actions/setup-python@v4 + with: + python-version: ${{ matrix.python-version }} + - name: Install dependencies + run: | + pip install --no-cache-dir hatch + - name: Patch agent-builder dependency on tools and test + run: | + cd agent-builder + + sed -i "s|.*strands-agents\[ollama\].*|\"strands-agents[ollama] @ file://${GITHUB_WORKSPACE}/sdk-python\",|" pyproject.toml + count=$(grep -c "strands-agents\[ollama\] @ file://${GITHUB_WORKSPACE}/sdk-python" pyproject.toml) + + if [ "$count" -eq 2 ]; then + echo "Dependency found exactly twice in pyproject.toml" + else + echo "Dependency found $count times, expected 2" + exit 1 + fi + + hatch run test diff --git a/.github/workflows/verify-docs-compatibility.yml b/.github/workflows/verify-docs-compatibility.yml new file mode 100644 index 000000000..cdce2a456 --- /dev/null +++ b/.github/workflows/verify-docs-compatibility.yml @@ -0,0 +1,42 @@ +name: Verify Docs Compatibility + +on: + pull_request: + branches: [ main ] + push: + branches: [ main ] + +jobs: + test-dependency: + runs-on: ubuntu-latest + strategy: + matrix: + python-version: ["3.10", "3.11", "3.12", "3.13"] + + steps: + - name: Checkout sdk-python + uses: actions/checkout@v4 + with: + path: sdk-python + - name: Checkout Tools Repository + uses: actions/checkout@v4 + with: + repository: strands-agents/docs + path: docs + - name: Set up Python ${{ matrix.python-version }} + uses: actions/setup-python@v4 + with: + python-version: ${{ matrix.python-version }} + - name: Patch tools dependency sdk-python and test + run: | + cd docs + sed -i "s|.*strands-agents.*|strands-agents @ file://${GITHUB_WORKSPACE}/sdk-python|" requirements.txt + count=$(grep -c "strands-agents @ file://${GITHUB_WORKSPACE}/sdk-python" requirements.txt) + if [ "$count" -eq 1 ]; then + echo "Dependency found exactly once in requirements.txt" + else + echo "Dependency found $count times, expected 1" + exit 1 + fi + pip install -r requirements.txt + mkdocs build --strict diff --git a/.github/workflows/verify-tools-compatibility.yml b/.github/workflows/verify-tools-compatibility.yml new file mode 100644 index 000000000..5390ad220 --- /dev/null +++ b/.github/workflows/verify-tools-compatibility.yml @@ -0,0 +1,52 @@ +name: Verify Tools Compatibility + +on: + pull_request: + branches: [ main ] + push: + branches: [ main ] + +jobs: + test-dependency: + runs-on: ubuntu-latest + strategy: + matrix: + python-version: ["3.10", "3.11", "3.12", "3.13"] + + steps: + - name: Checkout sdk-python + uses: actions/checkout@v4 + with: + path: sdk-python + - name: Checkout Tools Repository + uses: actions/checkout@v4 + with: + repository: strands-agents/tools + path: tools + - name: Checkout Agent Builder Repository + uses: actions/checkout@v4 + with: + repository: strands-agents/agent-builder + path: agent-builder + - name: Set up Python ${{ matrix.python-version }} + uses: actions/setup-python@v4 + with: + python-version: ${{ matrix.python-version }} + - name: Install dependencies + run: | + pip install --no-cache-dir hatch + - name: Patch tools dependency on sdk-python and test + run: | + cd tools + + sed -i "s|.*strands-agents>.*|\"strands-agents @ file://${GITHUB_WORKSPACE}/sdk-python/\",|" pyproject.toml + + count=$(grep -c "strands-agents @ file://${GITHUB_WORKSPACE}/sdk-python" pyproject.toml) + if [ "$count" -eq 2 ]; then + echo "Dependency found exactly twice in pyproject.toml" + else + echo "Dependency found $count times, expected 2" + exit 1 + fi + + hatch run test From d4eea134a03281b4acdebe9979609b3605a009be Mon Sep 17 00:00:00 2001 From: Dean Schmigelski Date: Mon, 19 May 2025 16:37:26 -0400 Subject: [PATCH 02/61] Update verify-agent-builder-compatibility.yml to only run against 3.10 --- .github/workflows/verify-agent-builder-compatibility.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/verify-agent-builder-compatibility.yml b/.github/workflows/verify-agent-builder-compatibility.yml index 588dfb334..22d515905 100644 --- a/.github/workflows/verify-agent-builder-compatibility.yml +++ b/.github/workflows/verify-agent-builder-compatibility.yml @@ -11,7 +11,7 @@ jobs: runs-on: ubuntu-latest strategy: matrix: - python-version: ["3.10", "3.11", "3.12", "3.13"] + python-version: ["3.10"] steps: - name: Checkout sdk-python From 3d2d5ffebdffa6636d5fbdf4fc66e03e8c1b4c1f Mon Sep 17 00:00:00 2001 From: Dean Schmigelski Date: Mon, 19 May 2025 16:37:37 -0400 Subject: [PATCH 03/61] Update verify-docs-compatibility.yml to only run against 3.10 --- .github/workflows/verify-docs-compatibility.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/verify-docs-compatibility.yml b/.github/workflows/verify-docs-compatibility.yml index cdce2a456..9475ddedb 100644 --- a/.github/workflows/verify-docs-compatibility.yml +++ b/.github/workflows/verify-docs-compatibility.yml @@ -11,7 +11,7 @@ jobs: runs-on: ubuntu-latest strategy: matrix: - python-version: ["3.10", "3.11", "3.12", "3.13"] + python-version: ["3.10"] steps: - name: Checkout sdk-python From d1e3a7b85ad170406cc7a4b2e19670f7b7b2aaa4 Mon Sep 17 00:00:00 2001 From: Dean Schmigelski Date: Mon, 19 May 2025 16:37:46 -0400 Subject: [PATCH 04/61] Update verify-tools-compatibility.yml to only run against 3.10 --- .github/workflows/verify-tools-compatibility.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/verify-tools-compatibility.yml b/.github/workflows/verify-tools-compatibility.yml index 5390ad220..4f8c7627c 100644 --- a/.github/workflows/verify-tools-compatibility.yml +++ b/.github/workflows/verify-tools-compatibility.yml @@ -11,7 +11,7 @@ jobs: runs-on: ubuntu-latest strategy: matrix: - python-version: ["3.10", "3.11", "3.12", "3.13"] + python-version: ["3.10"] steps: - name: Checkout sdk-python From 048965647d678b11ef51aac40c181496807ca747 Mon Sep 17 00:00:00 2001 From: Dean Schmigelski Date: Thu, 5 Jun 2025 12:58:09 +0300 Subject: [PATCH 05/61] Delete .github/workflows/verify-docs-compatibility.yml --- .../workflows/verify-docs-compatibility.yml | 42 ------------------- 1 file changed, 42 deletions(-) delete mode 100644 .github/workflows/verify-docs-compatibility.yml diff --git a/.github/workflows/verify-docs-compatibility.yml b/.github/workflows/verify-docs-compatibility.yml deleted file mode 100644 index 9475ddedb..000000000 --- a/.github/workflows/verify-docs-compatibility.yml +++ /dev/null @@ -1,42 +0,0 @@ -name: Verify Docs Compatibility - -on: - pull_request: - branches: [ main ] - push: - branches: [ main ] - -jobs: - test-dependency: - runs-on: ubuntu-latest - strategy: - matrix: - python-version: ["3.10"] - - steps: - - name: Checkout sdk-python - uses: actions/checkout@v4 - with: - path: sdk-python - - name: Checkout Tools Repository - uses: actions/checkout@v4 - with: - repository: strands-agents/docs - path: docs - - name: Set up Python ${{ matrix.python-version }} - uses: actions/setup-python@v4 - with: - python-version: ${{ matrix.python-version }} - - name: Patch tools dependency sdk-python and test - run: | - cd docs - sed -i "s|.*strands-agents.*|strands-agents @ file://${GITHUB_WORKSPACE}/sdk-python|" requirements.txt - count=$(grep -c "strands-agents @ file://${GITHUB_WORKSPACE}/sdk-python" requirements.txt) - if [ "$count" -eq 1 ]; then - echo "Dependency found exactly once in requirements.txt" - else - echo "Dependency found $count times, expected 1" - exit 1 - fi - pip install -r requirements.txt - mkdocs build --strict From dfdc2ffe0f0eff2144c7e29a3284d8dd4b66e35c Mon Sep 17 00:00:00 2001 From: Dean Schmigelski Date: Thu, 5 Jun 2025 12:58:15 +0300 Subject: [PATCH 06/61] Delete .github/workflows/verify-agent-builder-compatibility.yml --- .../verify-agent-builder-compatibility.yml | 47 ------------------- 1 file changed, 47 deletions(-) delete mode 100644 .github/workflows/verify-agent-builder-compatibility.yml diff --git a/.github/workflows/verify-agent-builder-compatibility.yml b/.github/workflows/verify-agent-builder-compatibility.yml deleted file mode 100644 index 22d515905..000000000 --- a/.github/workflows/verify-agent-builder-compatibility.yml +++ /dev/null @@ -1,47 +0,0 @@ -name: Verify Agent Builder Compatibility - -on: - pull_request: - branches: [ main ] - push: - branches: [ main ] - -jobs: - test-dependency: - runs-on: ubuntu-latest - strategy: - matrix: - python-version: ["3.10"] - - steps: - - name: Checkout sdk-python - uses: actions/checkout@v4 - with: - path: sdk-python - - name: Checkout Agent Builder Repository - uses: actions/checkout@v4 - with: - repository: strands-agents/agent-builder - path: agent-builder - - name: Set up Python ${{ matrix.python-version }} - uses: actions/setup-python@v4 - with: - python-version: ${{ matrix.python-version }} - - name: Install dependencies - run: | - pip install --no-cache-dir hatch - - name: Patch agent-builder dependency on tools and test - run: | - cd agent-builder - - sed -i "s|.*strands-agents\[ollama\].*|\"strands-agents[ollama] @ file://${GITHUB_WORKSPACE}/sdk-python\",|" pyproject.toml - count=$(grep -c "strands-agents\[ollama\] @ file://${GITHUB_WORKSPACE}/sdk-python" pyproject.toml) - - if [ "$count" -eq 2 ]; then - echo "Dependency found exactly twice in pyproject.toml" - else - echo "Dependency found $count times, expected 2" - exit 1 - fi - - hatch run test From d7c9c65acefcb3187ad6bb8076b68cbd96f7877c Mon Sep 17 00:00:00 2001 From: Dean Schmigelski Date: Thu, 5 Jun 2025 12:58:22 +0300 Subject: [PATCH 07/61] Delete .github/workflows/verify-tools-compatibility.yml --- .../workflows/verify-tools-compatibility.yml | 52 ------------------- 1 file changed, 52 deletions(-) delete mode 100644 .github/workflows/verify-tools-compatibility.yml diff --git a/.github/workflows/verify-tools-compatibility.yml b/.github/workflows/verify-tools-compatibility.yml deleted file mode 100644 index 4f8c7627c..000000000 --- a/.github/workflows/verify-tools-compatibility.yml +++ /dev/null @@ -1,52 +0,0 @@ -name: Verify Tools Compatibility - -on: - pull_request: - branches: [ main ] - push: - branches: [ main ] - -jobs: - test-dependency: - runs-on: ubuntu-latest - strategy: - matrix: - python-version: ["3.10"] - - steps: - - name: Checkout sdk-python - uses: actions/checkout@v4 - with: - path: sdk-python - - name: Checkout Tools Repository - uses: actions/checkout@v4 - with: - repository: strands-agents/tools - path: tools - - name: Checkout Agent Builder Repository - uses: actions/checkout@v4 - with: - repository: strands-agents/agent-builder - path: agent-builder - - name: Set up Python ${{ matrix.python-version }} - uses: actions/setup-python@v4 - with: - python-version: ${{ matrix.python-version }} - - name: Install dependencies - run: | - pip install --no-cache-dir hatch - - name: Patch tools dependency on sdk-python and test - run: | - cd tools - - sed -i "s|.*strands-agents>.*|\"strands-agents @ file://${GITHUB_WORKSPACE}/sdk-python/\",|" pyproject.toml - - count=$(grep -c "strands-agents @ file://${GITHUB_WORKSPACE}/sdk-python" pyproject.toml) - if [ "$count" -eq 2 ]; then - echo "Dependency found exactly twice in pyproject.toml" - else - echo "Dependency found $count times, expected 2" - exit 1 - fi - - hatch run test From 1d219690182b6074cd552e9243c6e8613d0df6b7 Mon Sep 17 00:00:00 2001 From: Dean Schmigelski Date: Thu, 5 Jun 2025 13:01:31 +0300 Subject: [PATCH 08/61] Update pypi-publish-on-release.yml --- .github/workflows/pypi-publish-on-release.yml | 1 + 1 file changed, 1 insertion(+) diff --git a/.github/workflows/pypi-publish-on-release.yml b/.github/workflows/pypi-publish-on-release.yml index 0e26a1dbd..5854e77c0 100644 --- a/.github/workflows/pypi-publish-on-release.yml +++ b/.github/workflows/pypi-publish-on-release.yml @@ -15,6 +15,7 @@ jobs: name: Build distribution 📦 permissions: contents: read + id-token: write needs: - call-test-lint runs-on: ubuntu-latest From 16c66b5b975a54785d31efd16e3815d50b9bdbfd Mon Sep 17 00:00:00 2001 From: Dean Schmigelski Date: Thu, 5 Jun 2025 13:01:43 +0300 Subject: [PATCH 09/61] Update pr-and-push.yml --- .github/workflows/pr-and-push.yml | 1 + 1 file changed, 1 insertion(+) diff --git a/.github/workflows/pr-and-push.yml b/.github/workflows/pr-and-push.yml index 2b2d026f4..d19851a8f 100644 --- a/.github/workflows/pr-and-push.yml +++ b/.github/workflows/pr-and-push.yml @@ -15,5 +15,6 @@ jobs: uses: ./.github/workflows/test-lint.yml permissions: contents: read + id-token: write with: ref: ${{ github.event.pull_request.head.sha }} From fb6734d5c27aabd6939a1f718b948bb587572818 Mon Sep 17 00:00:00 2001 From: Dean Schmigelski Date: Thu, 5 Jun 2025 13:06:27 +0300 Subject: [PATCH 10/61] Update test-lint.yml --- .github/workflows/test-lint.yml | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/.github/workflows/test-lint.yml b/.github/workflows/test-lint.yml index 35e0f5841..706943aad 100644 --- a/.github/workflows/test-lint.yml +++ b/.github/workflows/test-lint.yml @@ -59,6 +59,11 @@ jobs: uses: actions/setup-python@v5 with: python-version: ${{ matrix.python-version }} + - name: Configure Credentials + uses: aws-actions/configure-aws-credentials@v4 + with: + role-to-assume: arn:aws:iam::224477382724:role/StrandsGitHubWorkflowBedrockInvokeRole + aws-region: us-east-1 - name: Install dependencies run: | pip install --no-cache-dir hatch From 501c6ce968632a8831984b3e1994cd13992ea8ca Mon Sep 17 00:00:00 2001 From: Dean Schmigelski Date: Thu, 5 Jun 2025 13:09:31 +0300 Subject: [PATCH 11/61] Update pr-and-push.yml --- .github/workflows/pr-and-push.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/pr-and-push.yml b/.github/workflows/pr-and-push.yml index d19851a8f..979454282 100644 --- a/.github/workflows/pr-and-push.yml +++ b/.github/workflows/pr-and-push.yml @@ -5,7 +5,7 @@ on: branches: [ main ] types: [opened, synchronize, reopened, ready_for_review, review_requested, review_request_removed] push: - branches: [ main ] # Also run on direct pushes to main + branches: [ main, dea/integ-test ] # Also run on direct pushes to main concurrency: group: ${{ github.workflow }}-${{ github.event.pull_request.number || github.ref }} cancel-in-progress: true From 14ca4001448ab2cbf33df26ebd45b7915a26eddb Mon Sep 17 00:00:00 2001 From: Dean Schmigelski Date: Thu, 5 Jun 2025 13:10:57 +0300 Subject: [PATCH 12/61] Update test-lint.yml --- .github/workflows/test-lint.yml | 1 + 1 file changed, 1 insertion(+) diff --git a/.github/workflows/test-lint.yml b/.github/workflows/test-lint.yml index 706943aad..67e09bba4 100644 --- a/.github/workflows/test-lint.yml +++ b/.github/workflows/test-lint.yml @@ -12,6 +12,7 @@ jobs: name: Unit Tests - Python ${{ matrix.python-version }} - ${{ matrix.os-name }} permissions: contents: read + id-token: write strategy: matrix: include: From ecdfec815e6b59e836a26eadc709e15a1672d7c5 Mon Sep 17 00:00:00 2001 From: Dean Schmigelski Date: Thu, 5 Jun 2025 13:53:52 +0300 Subject: [PATCH 13/61] Update test-lint.yml --- .github/workflows/test-lint.yml | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/.github/workflows/test-lint.yml b/.github/workflows/test-lint.yml index 67e09bba4..5f0682aa6 100644 --- a/.github/workflows/test-lint.yml +++ b/.github/workflows/test-lint.yml @@ -65,8 +65,18 @@ jobs: with: role-to-assume: arn:aws:iam::224477382724:role/StrandsGitHubWorkflowBedrockInvokeRole aws-region: us-east-1 + - name: Set LLM Provider Env Vars + uses: aws-actions/aws-secretsmanager-get-secrets@v2 + with: + secret-ids: | + LLAMA_API_KEY, arn:aws:secretsmanager:us-east-1:224477382724:secret:llamaapi-testing-key + OPENAI_API_KEY, arn:aws:secretsmanager:us-east-1:224477382724:secret:openai-testing-key + ANTHROPIC_API_KEY, arn:aws:secretsmanager:us-east-1:224477382724:secret:anthropic-testing-key - name: Install dependencies run: | + echo $LLAMA_API_KEY + echo $OPENAI_API_KEY + echo $ANTHROPIC_API_KEY pip install --no-cache-dir hatch - name: Run Unit tests id: tests From 8ba756c538a2111f146398da78bdd22a14da702c Mon Sep 17 00:00:00 2001 From: Dean Schmigelski Date: Thu, 5 Jun 2025 14:03:49 +0300 Subject: [PATCH 14/61] Update test-lint.yml --- .github/workflows/test-lint.yml | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/.github/workflows/test-lint.yml b/.github/workflows/test-lint.yml index 5f0682aa6..cc0cdd8ef 100644 --- a/.github/workflows/test-lint.yml +++ b/.github/workflows/test-lint.yml @@ -69,9 +69,9 @@ jobs: uses: aws-actions/aws-secretsmanager-get-secrets@v2 with: secret-ids: | - LLAMA_API_KEY, arn:aws:secretsmanager:us-east-1:224477382724:secret:llamaapi-testing-key - OPENAI_API_KEY, arn:aws:secretsmanager:us-east-1:224477382724:secret:openai-testing-key - ANTHROPIC_API_KEY, arn:aws:secretsmanager:us-east-1:224477382724:secret:anthropic-testing-key + LLAMA_API_KEY, arn:aws:secretsmanager:us-east-1:224477382724:secret:llamaapi-testing-key-TaDL5A + OPENAI_API_KEY, arn:aws:secretsmanager:us-east-1:224477382724:secret:openai-testing-key-9zoeWL + ANTHROPIC_API_KEY, arn:aws:secretsmanager:us-east-1:224477382724:secret:anthropic-testing-key-ICk4sH - name: Install dependencies run: | echo $LLAMA_API_KEY From 27ac257201b59f9c21b427303fe8d9944fb0c122 Mon Sep 17 00:00:00 2001 From: Dean Schmigelski Date: Thu, 5 Jun 2025 16:15:16 +0300 Subject: [PATCH 15/61] testing integ on mcp --- .github/workflows/test-lint.yml | 2 ++ pyproject.toml | 3 ++ tests-integ/test_mcp_stdio.py | 58 +++++++++++++++++++++++++++++++++ 3 files changed, 63 insertions(+) create mode 100644 tests-integ/test_mcp_stdio.py diff --git a/.github/workflows/test-lint.yml b/.github/workflows/test-lint.yml index cc0cdd8ef..063b36329 100644 --- a/.github/workflows/test-lint.yml +++ b/.github/workflows/test-lint.yml @@ -82,6 +82,8 @@ jobs: id: tests run: hatch test tests --cover continue-on-error: false + - name: Run MCP Integ + run: hatch run test-integ-mcp lint: name: Lint runs-on: ubuntu-latest diff --git a/pyproject.toml b/pyproject.toml index bd3097327..20f84738b 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -165,6 +165,9 @@ test = [ test-integ = [ "hatch test tests-integ {args}" ] +test-integ-mcp = [ + "hatch test tests-integ/test_mcp_stdio.py" +] [tool.mypy] diff --git a/tests-integ/test_mcp_stdio.py b/tests-integ/test_mcp_stdio.py new file mode 100644 index 000000000..1dbfa0e99 --- /dev/null +++ b/tests-integ/test_mcp_stdio.py @@ -0,0 +1,58 @@ +import threading +from typing import List, Literal + +from mcp import StdioServerParameters, stdio_client + +from strands import Agent +from strands.tools.mcp.mcp_client import MCPClient +from strands.tools.mcp.mcp_types import MCPTransport +from strands.types.content import Message +from strands.types.tools import ToolUse + + +def start_calculator_server(transport: Literal["sse", "streamable-http"], port=int): + """ + Initialize and start an MCP calculator server for integration testing. + + This function creates a FastMCP server instance that provides a simple + calculator tool for performing addition operations. The server uses + Server-Sent Events (SSE) transport for communication, making it accessible + over HTTP. + """ + from mcp.server import FastMCP + + mcp = FastMCP("Calculator Server", port=port) + + @mcp.tool(description="Calculator tool which performs calculations") + def calculator(x: int, y: int) -> int: + return x + y + + @mcp.tool(description="Generates a custom image") + def generate_custom_image() -> MCPImageContent: + try: + with open("tests-integ/test_image.png", "rb") as image_file: + encoded_image = base64.b64encode(image_file.read()) + return MCPImageContent(type="image", data=encoded_image, mimeType="image/png") + except Exception as e: + print("Error while generating custom image: {}".format(e)) + + mcp.run(transport=transport) + + +def test_mcp_client(): + """ + Test should yield output similar to the following + {'role': 'user', 'content': [{'text': 'add 1 and 2, then echo the result back to me'}]} + {'role': 'assistant', 'content': [{'text': "I'll help you add 1 and 2 and then echo the result back to you.\n\nFirst, I'll calculate 1 + 2:"}, {'toolUse': {'toolUseId': 'tooluse_17ptaKUxQB20ySZxwgiI_w', 'name': 'calculator', 'input': {'x': 1, 'y': 2}}}]} + {'role': 'user', 'content': [{'toolResult': {'status': 'success', 'toolUseId': 'tooluse_17ptaKUxQB20ySZxwgiI_w', 'content': [{'text': '3'}]}}]} + {'role': 'assistant', 'content': [{'text': "\n\nNow I'll echo the result back to you:"}, {'toolUse': {'toolUseId': 'tooluse_GlOc5SN8TE6ti8jVZJMBOg', 'name': 'echo', 'input': {'to_echo': '3'}}}]} + {'role': 'user', 'content': [{'toolResult': {'status': 'success', 'toolUseId': 'tooluse_GlOc5SN8TE6ti8jVZJMBOg', 'content': [{'text': '3'}]}}]} + {'role': 'assistant', 'content': [{'text': '\n\nThe result of adding 1 and 2 is 3.'}]} + """ # noqa: E501 + + stdio_mcp_client = MCPClient( + lambda: stdio_client(StdioServerParameters(command="python", args=["tests-integ/echo_server.py"])) + ) + with stdio_mcp_client: + agent = Agent(tools=stdio_mcp_client.list_tools_sync()) + print("DONE") From 77d08953e85cc50d9642ba0f5f793820f2d17147 Mon Sep 17 00:00:00 2001 From: Dean Schmigelski Date: Thu, 5 Jun 2025 16:18:40 +0300 Subject: [PATCH 16/61] windows only --- .github/workflows/test-lint.yml | 67 --------------------------------- tests-integ/test_mcp_stdio.py | 1 + 2 files changed, 1 insertion(+), 67 deletions(-) diff --git a/.github/workflows/test-lint.yml b/.github/workflows/test-lint.yml index 063b36329..13bfc0204 100644 --- a/.github/workflows/test-lint.yml +++ b/.github/workflows/test-lint.yml @@ -16,29 +16,10 @@ jobs: strategy: matrix: include: - # Linux - - os: ubuntu-latest - os-name: 'linux' - python-version: "3.10" - - os: ubuntu-latest - os-name: 'linux' - python-version: "3.11" - - os: ubuntu-latest - os-name: 'linux' - python-version: "3.12" - os: ubuntu-latest os-name: 'linux' python-version: "3.13" # Windows - - os: windows-latest - os-name: 'windows' - python-version: "3.10" - - os: windows-latest - os-name: 'windows' - python-version: "3.11" - - os: windows-latest - os-name: 'windows' - python-version: "3.12" - os: windows-latest os-name: 'windows' python-version: "3.13" @@ -60,53 +41,5 @@ jobs: uses: actions/setup-python@v5 with: python-version: ${{ matrix.python-version }} - - name: Configure Credentials - uses: aws-actions/configure-aws-credentials@v4 - with: - role-to-assume: arn:aws:iam::224477382724:role/StrandsGitHubWorkflowBedrockInvokeRole - aws-region: us-east-1 - - name: Set LLM Provider Env Vars - uses: aws-actions/aws-secretsmanager-get-secrets@v2 - with: - secret-ids: | - LLAMA_API_KEY, arn:aws:secretsmanager:us-east-1:224477382724:secret:llamaapi-testing-key-TaDL5A - OPENAI_API_KEY, arn:aws:secretsmanager:us-east-1:224477382724:secret:openai-testing-key-9zoeWL - ANTHROPIC_API_KEY, arn:aws:secretsmanager:us-east-1:224477382724:secret:anthropic-testing-key-ICk4sH - - name: Install dependencies - run: | - echo $LLAMA_API_KEY - echo $OPENAI_API_KEY - echo $ANTHROPIC_API_KEY - pip install --no-cache-dir hatch - - name: Run Unit tests - id: tests - run: hatch test tests --cover - continue-on-error: false - name: Run MCP Integ run: hatch run test-integ-mcp - lint: - name: Lint - runs-on: ubuntu-latest - permissions: - contents: read - steps: - - name: Checkout code - uses: actions/checkout@v4 - with: - ref: ${{ inputs.ref }} - persist-credentials: false - - - name: Set up Python - uses: actions/setup-python@v5 - with: - python-version: '3.10' - cache: 'pip' - - - name: Install dependencies - run: | - pip install --no-cache-dir hatch - - - name: Run lint - id: lint - run: hatch run test-lint - continue-on-error: false diff --git a/tests-integ/test_mcp_stdio.py b/tests-integ/test_mcp_stdio.py index 1dbfa0e99..bc250e8a9 100644 --- a/tests-integ/test_mcp_stdio.py +++ b/tests-integ/test_mcp_stdio.py @@ -50,6 +50,7 @@ def test_mcp_client(): {'role': 'assistant', 'content': [{'text': '\n\nThe result of adding 1 and 2 is 3.'}]} """ # noqa: E501 + print("STARTING STDIO") stdio_mcp_client = MCPClient( lambda: stdio_client(StdioServerParameters(command="python", args=["tests-integ/echo_server.py"])) ) From 0e41ef766a785f056d5f717cc02be033a1104701 Mon Sep 17 00:00:00 2001 From: Dean Schmigelski Date: Thu, 5 Jun 2025 16:37:51 +0300 Subject: [PATCH 17/61] add hatch --- .github/workflows/test-lint.yml | 3 +++ 1 file changed, 3 insertions(+) diff --git a/.github/workflows/test-lint.yml b/.github/workflows/test-lint.yml index 13bfc0204..398b37936 100644 --- a/.github/workflows/test-lint.yml +++ b/.github/workflows/test-lint.yml @@ -41,5 +41,8 @@ jobs: uses: actions/setup-python@v5 with: python-version: ${{ matrix.python-version }} + - name: Install dependencies + run: | + pip install --no-cache-dir hatch - name: Run MCP Integ run: hatch run test-integ-mcp From 66938f142326a9d06370a1ebf08786d93b05077b Mon Sep 17 00:00:00 2001 From: Dean Schmigelski Date: Thu, 5 Jun 2025 17:58:43 +0300 Subject: [PATCH 18/61] switch to uvx --- tests-integ/test_mcp_stdio.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests-integ/test_mcp_stdio.py b/tests-integ/test_mcp_stdio.py index bc250e8a9..47ee824c9 100644 --- a/tests-integ/test_mcp_stdio.py +++ b/tests-integ/test_mcp_stdio.py @@ -52,7 +52,7 @@ def test_mcp_client(): print("STARTING STDIO") stdio_mcp_client = MCPClient( - lambda: stdio_client(StdioServerParameters(command="python", args=["tests-integ/echo_server.py"])) + lambda: stdio_client(StdioServerParameters(command="uvx", args=["awslabs.aws-documentation-mcp-server@latest"])) ) with stdio_mcp_client: agent = Agent(tools=stdio_mcp_client.list_tools_sync()) From a2a46813e87526054732e0eb102c21a0e1c5164a Mon Sep 17 00:00:00 2001 From: Dean Schmigelski Date: Thu, 5 Jun 2025 18:04:44 +0300 Subject: [PATCH 19/61] windows mode --- tests-integ/test_mcp_stdio.py | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) diff --git a/tests-integ/test_mcp_stdio.py b/tests-integ/test_mcp_stdio.py index 47ee824c9..4a26823fb 100644 --- a/tests-integ/test_mcp_stdio.py +++ b/tests-integ/test_mcp_stdio.py @@ -52,7 +52,16 @@ def test_mcp_client(): print("STARTING STDIO") stdio_mcp_client = MCPClient( - lambda: stdio_client(StdioServerParameters(command="uvx", args=["awslabs.aws-documentation-mcp-server@latest"])) + lambda: stdio_client( + StdioServerParameters( + command="uvx", + args=[ + "--from", + "awslabs.aws-documentation-mcp-server@latest", + "awslabs.aws-documentation-mcp-server.exe", + ], + ) + ) ) with stdio_mcp_client: agent = Agent(tools=stdio_mcp_client.list_tools_sync()) From 4076cff87f5a47cb80f1be276998908d552295a3 Mon Sep 17 00:00:00 2001 From: Dean Schmigelski Date: Thu, 5 Jun 2025 18:16:07 +0300 Subject: [PATCH 20/61] why not showing --- .github/workflows/test-lint.yml | 2 ++ 1 file changed, 2 insertions(+) diff --git a/.github/workflows/test-lint.yml b/.github/workflows/test-lint.yml index 398b37936..93a5bf01c 100644 --- a/.github/workflows/test-lint.yml +++ b/.github/workflows/test-lint.yml @@ -44,5 +44,7 @@ jobs: - name: Install dependencies run: | pip install --no-cache-dir hatch + - name: Install uv + uses: astral-sh/setup-uv@v5 - name: Run MCP Integ run: hatch run test-integ-mcp From 3bc7451bbd28de299c0a6c08f5c5e6fd25c9196e Mon Sep 17 00:00:00 2001 From: Dean Schmigelski Date: Thu, 5 Jun 2025 19:25:52 +0300 Subject: [PATCH 21/61] why not showing --- .github/workflows/test-lint.yml | 2 +- tests-integ/test_mcp_stdio.py | 4 ++++ 2 files changed, 5 insertions(+), 1 deletion(-) diff --git a/.github/workflows/test-lint.yml b/.github/workflows/test-lint.yml index 93a5bf01c..4e51cf199 100644 --- a/.github/workflows/test-lint.yml +++ b/.github/workflows/test-lint.yml @@ -27,7 +27,7 @@ jobs: - os: macos-latest os-name: 'macOS' python-version: "3.13" - fail-fast: true + fail-fast: false runs-on: ${{ matrix.os }} env: LOG_LEVEL: DEBUG diff --git a/tests-integ/test_mcp_stdio.py b/tests-integ/test_mcp_stdio.py index 4a26823fb..96ddda5c9 100644 --- a/tests-integ/test_mcp_stdio.py +++ b/tests-integ/test_mcp_stdio.py @@ -1,3 +1,4 @@ +import logging import threading from typing import List, Literal @@ -10,6 +11,9 @@ from strands.types.tools import ToolUse +logging.getLogger("strands").setLevel(logging.DEBUG) + + def start_calculator_server(transport: Literal["sse", "streamable-http"], port=int): """ Initialize and start an MCP calculator server for integration testing. From de40b2b245f0356f74ee7bcb98c522becc832c95 Mon Sep 17 00:00:00 2001 From: Dean Schmigelski Date: Thu, 5 Jun 2025 19:35:17 +0300 Subject: [PATCH 22/61] integ test --- tests-integ/test_mcp_stdio.py | 13 ++++++++----- 1 file changed, 8 insertions(+), 5 deletions(-) diff --git a/tests-integ/test_mcp_stdio.py b/tests-integ/test_mcp_stdio.py index 96ddda5c9..9983de42f 100644 --- a/tests-integ/test_mcp_stdio.py +++ b/tests-integ/test_mcp_stdio.py @@ -42,6 +42,12 @@ def generate_custom_image() -> MCPImageContent: mcp.run(transport=transport) +def get_platform_args(base_args): + """Convert base uvx args to platform-specific format""" + if platform.system() == "Windows": + package_name = base_args[0].split("@")[0] + return ["--from"] + base_args + [f"{package_name}.exe"] + return base_args def test_mcp_client(): """ @@ -54,16 +60,13 @@ def test_mcp_client(): {'role': 'assistant', 'content': [{'text': '\n\nThe result of adding 1 and 2 is 3.'}]} """ # noqa: E501 + print("STARTING STDIO") stdio_mcp_client = MCPClient( lambda: stdio_client( StdioServerParameters( command="uvx", - args=[ - "--from", - "awslabs.aws-documentation-mcp-server@latest", - "awslabs.aws-documentation-mcp-server.exe", - ], + args=get_platform_args(["awslabs.aws-documentation-mcp-server@latest"]) ) ) ) From e24eabb76d0b8196fc490e3e38216d2c24db330a Mon Sep 17 00:00:00 2001 From: Dean Schmigelski Date: Thu, 5 Jun 2025 19:36:54 +0300 Subject: [PATCH 23/61] add platform --- tests-integ/test_mcp_stdio.py | 1 + 1 file changed, 1 insertion(+) diff --git a/tests-integ/test_mcp_stdio.py b/tests-integ/test_mcp_stdio.py index 9983de42f..c44e7d8b1 100644 --- a/tests-integ/test_mcp_stdio.py +++ b/tests-integ/test_mcp_stdio.py @@ -1,6 +1,7 @@ import logging import threading from typing import List, Literal +import platform from mcp import StdioServerParameters, stdio_client From 79bed99321105ac8734c1cb0d8ff276bf118df46 Mon Sep 17 00:00:00 2001 From: Dean Schmigelski Date: Thu, 5 Jun 2025 19:45:08 +0300 Subject: [PATCH 24/61] another try --- tests-integ/test_mcp_stdio.py | 3 +++ 1 file changed, 3 insertions(+) diff --git a/tests-integ/test_mcp_stdio.py b/tests-integ/test_mcp_stdio.py index c44e7d8b1..64c42c0e1 100644 --- a/tests-integ/test_mcp_stdio.py +++ b/tests-integ/test_mcp_stdio.py @@ -13,6 +13,7 @@ logging.getLogger("strands").setLevel(logging.DEBUG) +logger = logging.getLogger(__name__) def start_calculator_server(transport: Literal["sse", "streamable-http"], port=int): @@ -63,6 +64,7 @@ def test_mcp_client(): print("STARTING STDIO") + logger.info("STARTING STDIO_STDIO") stdio_mcp_client = MCPClient( lambda: stdio_client( StdioServerParameters( @@ -73,4 +75,5 @@ def test_mcp_client(): ) with stdio_mcp_client: agent = Agent(tools=stdio_mcp_client.list_tools_sync()) + logger.debug(f"Tools {agent.tool_names}") print("DONE") From 82481b38d640e3249d3529b83c4515e3bc4dab6f Mon Sep 17 00:00:00 2001 From: Dean Schmigelski Date: Thu, 5 Jun 2025 20:03:01 +0300 Subject: [PATCH 25/61] always fail test --- tests-integ/test_mcp_stdio.py | 1 + 1 file changed, 1 insertion(+) diff --git a/tests-integ/test_mcp_stdio.py b/tests-integ/test_mcp_stdio.py index 64c42c0e1..7990d04f8 100644 --- a/tests-integ/test_mcp_stdio.py +++ b/tests-integ/test_mcp_stdio.py @@ -77,3 +77,4 @@ def test_mcp_client(): agent = Agent(tools=stdio_mcp_client.list_tools_sync()) logger.debug(f"Tools {agent.tool_names}") print("DONE") + assert 1 == 2 From 20ad17dea5d99cf1ba8b559ce53f3a6968a245ca Mon Sep 17 00:00:00 2001 From: Dean Schmigelski Date: Thu, 5 Jun 2025 20:07:51 +0300 Subject: [PATCH 26/61] temp switch back --- tests-integ/test_mcp_stdio.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/tests-integ/test_mcp_stdio.py b/tests-integ/test_mcp_stdio.py index 7990d04f8..8a6dd703c 100644 --- a/tests-integ/test_mcp_stdio.py +++ b/tests-integ/test_mcp_stdio.py @@ -46,7 +46,7 @@ def generate_custom_image() -> MCPImageContent: def get_platform_args(base_args): """Convert base uvx args to platform-specific format""" - if platform.system() == "Windows": + if False and platform.system() == "Windows": package_name = base_args[0].split("@")[0] return ["--from"] + base_args + [f"{package_name}.exe"] return base_args @@ -76,5 +76,6 @@ def test_mcp_client(): with stdio_mcp_client: agent = Agent(tools=stdio_mcp_client.list_tools_sync()) logger.debug(f"Tools {agent.tool_names}") + print(f"Tools {agent.tool_names}") print("DONE") assert 1 == 2 From d3873b185c31d026b98b37705bf294ec176fc7b1 Mon Sep 17 00:00:00 2001 From: Dean Schmigelski Date: Thu, 5 Jun 2025 22:01:16 +0300 Subject: [PATCH 27/61] Update pyproject.toml --- pyproject.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pyproject.toml b/pyproject.toml index 20f84738b..f593eceb9 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -29,7 +29,7 @@ dependencies = [ "boto3>=1.26.0,<2.0.0", "botocore>=1.29.0,<2.0.0", "docstring_parser>=0.15,<0.16.0", - "mcp>=1.8.0,<2.0.0", + "mcp>=1.9.3,<2.0.0", "pydantic>=2.0.0,<3.0.0", "typing-extensions>=4.13.2,<5.0.0", "watchdog>=6.0.0,<7.0.0", From 7cd45401003aad3d5602e1a3ecaa75e635bfe980 Mon Sep 17 00:00:00 2001 From: Dean Schmigelski Date: Thu, 5 Jun 2025 22:05:55 +0300 Subject: [PATCH 28/61] Update test_mcp_stdio.py --- tests-integ/test_mcp_stdio.py | 3 --- 1 file changed, 3 deletions(-) diff --git a/tests-integ/test_mcp_stdio.py b/tests-integ/test_mcp_stdio.py index 8a6dd703c..b05ae154f 100644 --- a/tests-integ/test_mcp_stdio.py +++ b/tests-integ/test_mcp_stdio.py @@ -46,9 +46,6 @@ def generate_custom_image() -> MCPImageContent: def get_platform_args(base_args): """Convert base uvx args to platform-specific format""" - if False and platform.system() == "Windows": - package_name = base_args[0].split("@")[0] - return ["--from"] + base_args + [f"{package_name}.exe"] return base_args def test_mcp_client(): From 266cb409b67b7025ae0c16aa8c44f82491f004db Mon Sep 17 00:00:00 2001 From: Dean Schmigelski Date: Thu, 5 Jun 2025 22:11:51 +0300 Subject: [PATCH 29/61] logs --- tests-integ/test_mcp_stdio.py | 32 ++++++++++++++++++++++++++++++++ 1 file changed, 32 insertions(+) diff --git a/tests-integ/test_mcp_stdio.py b/tests-integ/test_mcp_stdio.py index b05ae154f..029cbf73d 100644 --- a/tests-integ/test_mcp_stdio.py +++ b/tests-integ/test_mcp_stdio.py @@ -48,6 +48,37 @@ def get_platform_args(base_args): """Convert base uvx args to platform-specific format""" return base_args +def get_windows_executable_command(command: str) -> str: + """ + Get the correct executable command normalized for Windows. + + On Windows, commands might exist with specific extensions (.exe, .cmd, etc.) + that need to be located for proper execution. + + Args: + command: Base command (e.g., 'uvx', 'npx') + + Returns: + str: Windows-appropriate command path + """ + try: + # First check if command exists in PATH as-is + if command_path := shutil.which(command): + return command_path + + # Check for Windows-specific extensions + for ext in [".cmd", ".bat", ".exe", ".ps1"]: + ext_version = f"{command}{ext}" + if ext_path := shutil.which(ext_version): + return ext_path + + # For regular commands or if we couldn't find special versions + return command + except OSError: + # Handle file system errors during path resolution + # (permissions, broken symlinks, etc.) + return command + def test_mcp_client(): """ Test should yield output similar to the following @@ -61,6 +92,7 @@ def test_mcp_client(): print("STARTING STDIO") + print(f"WINDOWS {get_windows_executable_command("uvx")}) logger.info("STARTING STDIO_STDIO") stdio_mcp_client = MCPClient( lambda: stdio_client( From 1a597aaafadd6e56bb70b30c0a6aba2982209d54 Mon Sep 17 00:00:00 2001 From: Dean Schmigelski Date: Fri, 6 Jun 2025 16:37:32 +0300 Subject: [PATCH 30/61] Delete .github/workflows/test-lint.yml --- .github/workflows/test-lint.yml | 50 --------------------------------- 1 file changed, 50 deletions(-) delete mode 100644 .github/workflows/test-lint.yml diff --git a/.github/workflows/test-lint.yml b/.github/workflows/test-lint.yml deleted file mode 100644 index 4e51cf199..000000000 --- a/.github/workflows/test-lint.yml +++ /dev/null @@ -1,50 +0,0 @@ -name: Test and Lint - -on: - workflow_call: - inputs: - ref: - required: true - type: string - -jobs: - unit-test: - name: Unit Tests - Python ${{ matrix.python-version }} - ${{ matrix.os-name }} - permissions: - contents: read - id-token: write - strategy: - matrix: - include: - - os: ubuntu-latest - os-name: 'linux' - python-version: "3.13" - # Windows - - os: windows-latest - os-name: 'windows' - python-version: "3.13" - # MacOS - latest only; not enough runners for macOS - - os: macos-latest - os-name: 'macOS' - python-version: "3.13" - fail-fast: false - runs-on: ${{ matrix.os }} - env: - LOG_LEVEL: DEBUG - steps: - - name: Checkout code - uses: actions/checkout@v4 - with: - ref: ${{ inputs.ref }} # Explicitly define which commit to check out - persist-credentials: false # Don't persist credentials for subsequent actions - - name: Set up Python - uses: actions/setup-python@v5 - with: - python-version: ${{ matrix.python-version }} - - name: Install dependencies - run: | - pip install --no-cache-dir hatch - - name: Install uv - uses: astral-sh/setup-uv@v5 - - name: Run MCP Integ - run: hatch run test-integ-mcp From 9bf04514aeff26ec65597e3f3c7ded503a354d51 Mon Sep 17 00:00:00 2001 From: Dean Schmigelski Date: Fri, 6 Jun 2025 17:05:17 +0300 Subject: [PATCH 31/61] Create integration-test.yml --- .github/workflows/integration-test.yml | 37 ++++++++++++++++++++++++++ 1 file changed, 37 insertions(+) create mode 100644 .github/workflows/integration-test.yml diff --git a/.github/workflows/integration-test.yml b/.github/workflows/integration-test.yml new file mode 100644 index 000000000..528f3030b --- /dev/null +++ b/.github/workflows/integration-test.yml @@ -0,0 +1,37 @@ +name: Secure Integration test + +on: + pull_request_target: + types: [opened, synchronize, labeled, unlabled, reopened] +jobs: + check-access-and-checkout: + runs-on: ubuntu-latest + permissions: + id-token: write + pull-requests: read + contents: read + steps: + - name: Check PR labels and author + id: check + uses: actions/github-script@v7 + with: + script: | + if (!(hasLabel || isOwner)) { + - name: Configure Credentials + uses: aws-actions/configure-aws-credentials@v4 + with: + role-to-assume: ${{ secrets.STRANDS_INTEG_TEST_ROLE }} + aws-region: us-east-1 + - name: Set LLM Provider Env VarsMore actions + uses: aws-actions/aws-secretsmanager-get-secrets@v2 + with: + secret-ids: | + LLAMA_API_KEY, ${{ secrets.STRANDS_LLAMAAPI_API_KEY_SECRET }} + OPENAI_API_KEY, ${{ secrets.STRANDS_OPENAI_API_KEY_SECRET }} + ANTHROPIC_API_KEY, ${{ secrets.STRANDS_ANTHROPIC_API_KEY_SECRET }} + - name: Checkout base branch + uses: actions/checkout@v4 + with: + ref: ${{ github.event.pull_request.base.ref }} + + From fbd6ef6f34366206f831c5168c7d14134a9e648d Mon Sep 17 00:00:00 2001 From: Dean Schmigelski Date: Fri, 6 Jun 2025 17:09:10 +0300 Subject: [PATCH 32/61] Update integration-test.yml --- .github/workflows/integration-test.yml | 3 +++ 1 file changed, 3 insertions(+) diff --git a/.github/workflows/integration-test.yml b/.github/workflows/integration-test.yml index 528f3030b..7e40edd94 100644 --- a/.github/workflows/integration-test.yml +++ b/.github/workflows/integration-test.yml @@ -3,6 +3,9 @@ name: Secure Integration test on: pull_request_target: types: [opened, synchronize, labeled, unlabled, reopened] + push: + branches: + - dea/integ-test jobs: check-access-and-checkout: runs-on: ubuntu-latest From 323288aab7ad7f7a7ee2e97ce3d04b9ce7f0676d Mon Sep 17 00:00:00 2001 From: Dean Schmigelski Date: Fri, 6 Jun 2025 17:13:04 +0300 Subject: [PATCH 33/61] Update integration-test.yml --- .github/workflows/integration-test.yml | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/.github/workflows/integration-test.yml b/.github/workflows/integration-test.yml index 7e40edd94..85af0b10c 100644 --- a/.github/workflows/integration-test.yml +++ b/.github/workflows/integration-test.yml @@ -19,13 +19,19 @@ jobs: uses: actions/github-script@v7 with: script: | + const pr = context.payload.pull_request; + const isOwner = pr.user.type === 'User' && pr.user.login === context.repo.owner; + const labels = pr.labels.map(label => label.name); + const hasLabel = labels.includes('approved-for-integ-test') if (!(hasLabel || isOwner)) { + core.setFailed('Pull Request must either have label approved-for-integ-test or be created by an owner') + } - name: Configure Credentials uses: aws-actions/configure-aws-credentials@v4 with: role-to-assume: ${{ secrets.STRANDS_INTEG_TEST_ROLE }} aws-region: us-east-1 - - name: Set LLM Provider Env VarsMore actions + - name: Set LLM Provider Env Vars uses: aws-actions/aws-secretsmanager-get-secrets@v2 with: secret-ids: | From edbcae35cbd52a73680c8f4b90f312b7f2b76cca Mon Sep 17 00:00:00 2001 From: Dean Schmigelski Date: Fri, 6 Jun 2025 17:13:44 +0300 Subject: [PATCH 34/61] Update integration-test.yml --- .github/workflows/integration-test.yml | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/.github/workflows/integration-test.yml b/.github/workflows/integration-test.yml index 85af0b10c..68ff7f7a0 100644 --- a/.github/workflows/integration-test.yml +++ b/.github/workflows/integration-test.yml @@ -3,9 +3,7 @@ name: Secure Integration test on: pull_request_target: types: [opened, synchronize, labeled, unlabled, reopened] - push: - branches: - - dea/integ-test + jobs: check-access-and-checkout: runs-on: ubuntu-latest From 1e4427b0673fbba9cd3f260eb4334bbcf99758a8 Mon Sep 17 00:00:00 2001 From: Dean Schmigelski Date: Fri, 6 Jun 2025 17:14:47 +0300 Subject: [PATCH 35/61] Update README.md --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index ed98d0012..84a45673c 100644 --- a/README.md +++ b/README.md @@ -6,7 +6,7 @@

- Strands Agents + Strands Agents---

From 80d7504eac7945febdd91d583bf13eb3aa77b4f1 Mon Sep 17 00:00:00 2001 From: Dean Schmigelski Date: Fri, 6 Jun 2025 17:20:04 +0300 Subject: [PATCH 36/61] Update README.md --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 84a45673c..b700d40c2 100644 --- a/README.md +++ b/README.md @@ -6,7 +6,7 @@

- Strands Agents--- + Strands Agents----

From 444ffa1de871b3f6b271a1a50b4ec55897b5c289 Mon Sep 17 00:00:00 2001 From: Dean Schmigelski Date: Fri, 6 Jun 2025 17:22:39 +0300 Subject: [PATCH 37/61] Update README.md --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index b700d40c2..e71e50599 100644 --- a/README.md +++ b/README.md @@ -6,7 +6,7 @@

- Strands Agents---- + Strands Agents-----

From 482980f7f13ed9dd51828aef869e895af1d80f7b Mon Sep 17 00:00:00 2001 From: Dean Schmigelski Date: Fri, 6 Jun 2025 17:30:07 +0300 Subject: [PATCH 38/61] Update README.md --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index e71e50599..7a6db7a67 100644 --- a/README.md +++ b/README.md @@ -6,7 +6,7 @@

- Strands Agents----- + Strands Agents------

From 853e4934ff2e29d060c76ecf67d9865107a6e0a3 Mon Sep 17 00:00:00 2001 From: Dean Schmigelski Date: Fri, 6 Jun 2025 17:54:50 +0300 Subject: [PATCH 39/61] Update README.md --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 7a6db7a67..5c3c28e9c 100644 --- a/README.md +++ b/README.md @@ -6,7 +6,7 @@

- Strands Agents------ + Strands Agents-------

From d708bb7c49233ed3a89b60402dc21ca163af3535 Mon Sep 17 00:00:00 2001 From: Dean Schmigelski Date: Fri, 6 Jun 2025 17:56:45 +0300 Subject: [PATCH 40/61] Update README.md --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 5c3c28e9c..25254a50d 100644 --- a/README.md +++ b/README.md @@ -6,7 +6,7 @@

- Strands Agents------- + Strands Agents--------

From 860b4996263378c3cc48a1c248ba48dd12ee928a Mon Sep 17 00:00:00 2001 From: Dean Schmigelski Date: Fri, 6 Jun 2025 18:29:02 +0300 Subject: [PATCH 41/61] Update test_bedrock_guardrails.py --- tests-integ/test_bedrock_guardrails.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests-integ/test_bedrock_guardrails.py b/tests-integ/test_bedrock_guardrails.py index 9ffd1bdf0..ea16559c7 100644 --- a/tests-integ/test_bedrock_guardrails.py +++ b/tests-integ/test_bedrock_guardrails.py @@ -12,7 +12,7 @@ @pytest.fixture(scope="module") def boto_session(): - return boto3.Session(region_name="us-west-2") + return boto3.Session(region_name="us-east-1") @pytest.fixture(scope="module") From 7f770f0768e46047942030484665e55603ee6895 Mon Sep 17 00:00:00 2001 From: Dean Schmigelski Date: Fri, 6 Jun 2025 18:44:58 +0300 Subject: [PATCH 42/61] update region --- tests-integ/test_bedrock_guardrails.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests-integ/test_bedrock_guardrails.py b/tests-integ/test_bedrock_guardrails.py index ea16559c7..bf0be7068 100644 --- a/tests-integ/test_bedrock_guardrails.py +++ b/tests-integ/test_bedrock_guardrails.py @@ -142,7 +142,7 @@ def test_guardrail_output_intervention_redact_output(bedrock_guardrail, processi guardrail_stream_processing_mode=processing_mode, guardrail_redact_output=True, guardrail_redact_output_message=REDACT_MESSAGE, - region_name="us-west-2", + region_name="us-east-1", ) agent = Agent( From 2d3bc7fbe3c0d6a755bd9f07a1cfb0574bc78401 Mon Sep 17 00:00:00 2001 From: Dean Schmigelski Date: Fri, 6 Jun 2025 18:49:30 +0300 Subject: [PATCH 43/61] Update integration-test.yml --- .github/workflows/integration-test.yml | 32 +++++++++++++++++++++++--- 1 file changed, 29 insertions(+), 3 deletions(-) diff --git a/.github/workflows/integration-test.yml b/.github/workflows/integration-test.yml index 68ff7f7a0..ed040a30c 100644 --- a/.github/workflows/integration-test.yml +++ b/.github/workflows/integration-test.yml @@ -4,6 +4,9 @@ on: pull_request_target: types: [opened, synchronize, labeled, unlabled, reopened] +env: + AWS_REGION: us-east-1 + jobs: check-access-and-checkout: runs-on: ubuntu-latest @@ -18,17 +21,28 @@ jobs: with: script: | const pr = context.payload.pull_request; - const isOwner = pr.user.type === 'User' && pr.user.login === context.repo.owner; + const labels = pr.labels.map(label => label.name); const hasLabel = labels.includes('approved-for-integ-test') - if (!(hasLabel || isOwner)) { - core.setFailed('Pull Request must either have label approved-for-integ-test or be created by an owner') + if (hasLabel) { + core.info('PR contains label approved-for-integ-test') + return + } + + const isOwner = pr.user.type === 'User' && pr.user.login === context.repo.owner; + if (isOwner) { + core.info('PR auther is an OWNER') + return } + + core.setFailed('Pull Request must either have label approved-for-integ-test or be created by an owner') + - name: Configure Credentials uses: aws-actions/configure-aws-credentials@v4 with: role-to-assume: ${{ secrets.STRANDS_INTEG_TEST_ROLE }} aws-region: us-east-1 + mask-aws-account-id: true - name: Set LLM Provider Env Vars uses: aws-actions/aws-secretsmanager-get-secrets@v2 with: @@ -40,5 +54,17 @@ jobs: uses: actions/checkout@v4 with: ref: ${{ github.event.pull_request.base.ref }} + persist-credentials: false # Don't persist credentials for subsequent actions + - name: Set up Python + uses: actions/setup-python@v5 + with: + python-version: '3.10' + - name: Install dependencies + run: | + pip install --no-cache-dir hatch + - name: Run integration tests + id: tests + run: | + hatch test tests-integ From 023f86ee8b271b7b9b4693a6f5e658887f5f1d72 Mon Sep 17 00:00:00 2001 From: Dean Schmigelski Date: Fri, 6 Jun 2025 18:58:04 +0300 Subject: [PATCH 44/61] Update README.md --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 25254a50d..725f6e7be 100644 --- a/README.md +++ b/README.md @@ -6,7 +6,7 @@

- Strands Agents-------- + Strands Agents---------

From bf05d3e4449eac98bc7c2eb95fa51049fb903169 Mon Sep 17 00:00:00 2001 From: Dean Schmigelski Date: Fri, 6 Jun 2025 19:40:50 +0300 Subject: [PATCH 45/61] update workflow --- .github/workflows/integration-test.yml | 2 -- tests-integ/test_model_litellm.py | 2 +- 2 files changed, 1 insertion(+), 3 deletions(-) diff --git a/.github/workflows/integration-test.yml b/.github/workflows/integration-test.yml index ed040a30c..1275007f3 100644 --- a/.github/workflows/integration-test.yml +++ b/.github/workflows/integration-test.yml @@ -47,9 +47,7 @@ jobs: uses: aws-actions/aws-secretsmanager-get-secrets@v2 with: secret-ids: | - LLAMA_API_KEY, ${{ secrets.STRANDS_LLAMAAPI_API_KEY_SECRET }} OPENAI_API_KEY, ${{ secrets.STRANDS_OPENAI_API_KEY_SECRET }} - ANTHROPIC_API_KEY, ${{ secrets.STRANDS_ANTHROPIC_API_KEY_SECRET }} - name: Checkout base branch uses: actions/checkout@v4 with: diff --git a/tests-integ/test_model_litellm.py b/tests-integ/test_model_litellm.py index f1afb61fa..86f6b42f1 100644 --- a/tests-integ/test_model_litellm.py +++ b/tests-integ/test_model_litellm.py @@ -7,7 +7,7 @@ @pytest.fixture def model(): - return LiteLLMModel(model_id="us.anthropic.claude-3-7-sonnet-20250219-v1:0") + return LiteLLMModel(model_id="bedrock/us.anthropic.claude-3-7-sonnet-20250219-v1:0") @pytest.fixture From 0c1dfeb5550d212453c56ab260e41394585572ba Mon Sep 17 00:00:00 2001 From: Dean Schmigelski Date: Fri, 6 Jun 2025 20:03:34 +0300 Subject: [PATCH 46/61] Update README.md --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 725f6e7be..297dbf1fc 100644 --- a/README.md +++ b/README.md @@ -6,7 +6,7 @@

- Strands Agents--------- + Strands Agents----------

From 06425ec244446ecf27ca48d39fb51988e60a8262 Mon Sep 17 00:00:00 2001 From: Dean Schmigelski Date: Fri, 6 Jun 2025 20:09:42 +0300 Subject: [PATCH 47/61] Update README.md --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 297dbf1fc..42d9d5866 100644 --- a/README.md +++ b/README.md @@ -6,7 +6,7 @@

- Strands Agents---------- + Strands Agents-----------

From 5441b0f37455c10b5a2c09a161302e40beb7363f Mon Sep 17 00:00:00 2001 From: Dean Schmigelski Date: Fri, 6 Jun 2025 20:19:15 +0300 Subject: [PATCH 48/61] Update integration-test.yml --- .github/workflows/integration-test.yml | 5 ----- 1 file changed, 5 deletions(-) diff --git a/.github/workflows/integration-test.yml b/.github/workflows/integration-test.yml index 1275007f3..cc814a699 100644 --- a/.github/workflows/integration-test.yml +++ b/.github/workflows/integration-test.yml @@ -43,11 +43,6 @@ jobs: role-to-assume: ${{ secrets.STRANDS_INTEG_TEST_ROLE }} aws-region: us-east-1 mask-aws-account-id: true - - name: Set LLM Provider Env Vars - uses: aws-actions/aws-secretsmanager-get-secrets@v2 - with: - secret-ids: | - OPENAI_API_KEY, ${{ secrets.STRANDS_OPENAI_API_KEY_SECRET }} - name: Checkout base branch uses: actions/checkout@v4 with: From de41a3ac502af1e648649faa0a82a76f6a95a4ff Mon Sep 17 00:00:00 2001 From: Dean Schmigelski Date: Fri, 6 Jun 2025 20:24:56 +0300 Subject: [PATCH 49/61] Delete tests-integ/test_mcp_stdio.py --- tests-integ/test_mcp_stdio.py | 110 ---------------------------------- 1 file changed, 110 deletions(-) delete mode 100644 tests-integ/test_mcp_stdio.py diff --git a/tests-integ/test_mcp_stdio.py b/tests-integ/test_mcp_stdio.py deleted file mode 100644 index 029cbf73d..000000000 --- a/tests-integ/test_mcp_stdio.py +++ /dev/null @@ -1,110 +0,0 @@ -import logging -import threading -from typing import List, Literal -import platform - -from mcp import StdioServerParameters, stdio_client - -from strands import Agent -from strands.tools.mcp.mcp_client import MCPClient -from strands.tools.mcp.mcp_types import MCPTransport -from strands.types.content import Message -from strands.types.tools import ToolUse - - -logging.getLogger("strands").setLevel(logging.DEBUG) -logger = logging.getLogger(__name__) - - -def start_calculator_server(transport: Literal["sse", "streamable-http"], port=int): - """ - Initialize and start an MCP calculator server for integration testing. - - This function creates a FastMCP server instance that provides a simple - calculator tool for performing addition operations. The server uses - Server-Sent Events (SSE) transport for communication, making it accessible - over HTTP. - """ - from mcp.server import FastMCP - - mcp = FastMCP("Calculator Server", port=port) - - @mcp.tool(description="Calculator tool which performs calculations") - def calculator(x: int, y: int) -> int: - return x + y - - @mcp.tool(description="Generates a custom image") - def generate_custom_image() -> MCPImageContent: - try: - with open("tests-integ/test_image.png", "rb") as image_file: - encoded_image = base64.b64encode(image_file.read()) - return MCPImageContent(type="image", data=encoded_image, mimeType="image/png") - except Exception as e: - print("Error while generating custom image: {}".format(e)) - - mcp.run(transport=transport) - -def get_platform_args(base_args): - """Convert base uvx args to platform-specific format""" - return base_args - -def get_windows_executable_command(command: str) -> str: - """ - Get the correct executable command normalized for Windows. - - On Windows, commands might exist with specific extensions (.exe, .cmd, etc.) - that need to be located for proper execution. - - Args: - command: Base command (e.g., 'uvx', 'npx') - - Returns: - str: Windows-appropriate command path - """ - try: - # First check if command exists in PATH as-is - if command_path := shutil.which(command): - return command_path - - # Check for Windows-specific extensions - for ext in [".cmd", ".bat", ".exe", ".ps1"]: - ext_version = f"{command}{ext}" - if ext_path := shutil.which(ext_version): - return ext_path - - # For regular commands or if we couldn't find special versions - return command - except OSError: - # Handle file system errors during path resolution - # (permissions, broken symlinks, etc.) - return command - -def test_mcp_client(): - """ - Test should yield output similar to the following - {'role': 'user', 'content': [{'text': 'add 1 and 2, then echo the result back to me'}]} - {'role': 'assistant', 'content': [{'text': "I'll help you add 1 and 2 and then echo the result back to you.\n\nFirst, I'll calculate 1 + 2:"}, {'toolUse': {'toolUseId': 'tooluse_17ptaKUxQB20ySZxwgiI_w', 'name': 'calculator', 'input': {'x': 1, 'y': 2}}}]} - {'role': 'user', 'content': [{'toolResult': {'status': 'success', 'toolUseId': 'tooluse_17ptaKUxQB20ySZxwgiI_w', 'content': [{'text': '3'}]}}]} - {'role': 'assistant', 'content': [{'text': "\n\nNow I'll echo the result back to you:"}, {'toolUse': {'toolUseId': 'tooluse_GlOc5SN8TE6ti8jVZJMBOg', 'name': 'echo', 'input': {'to_echo': '3'}}}]} - {'role': 'user', 'content': [{'toolResult': {'status': 'success', 'toolUseId': 'tooluse_GlOc5SN8TE6ti8jVZJMBOg', 'content': [{'text': '3'}]}}]} - {'role': 'assistant', 'content': [{'text': '\n\nThe result of adding 1 and 2 is 3.'}]} - """ # noqa: E501 - - - print("STARTING STDIO") - print(f"WINDOWS {get_windows_executable_command("uvx")}) - logger.info("STARTING STDIO_STDIO") - stdio_mcp_client = MCPClient( - lambda: stdio_client( - StdioServerParameters( - command="uvx", - args=get_platform_args(["awslabs.aws-documentation-mcp-server@latest"]) - ) - ) - ) - with stdio_mcp_client: - agent = Agent(tools=stdio_mcp_client.list_tools_sync()) - logger.debug(f"Tools {agent.tool_names}") - print(f"Tools {agent.tool_names}") - print("DONE") - assert 1 == 2 From f2a8453c2311f2640188253a2572ed08a57bc8bb Mon Sep 17 00:00:00 2001 From: Dean Schmigelski Date: Fri, 6 Jun 2025 20:32:55 +0300 Subject: [PATCH 50/61] Update README.md --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 42d9d5866..c01389601 100644 --- a/README.md +++ b/README.md @@ -6,7 +6,7 @@

- Strands Agents----------- + Strands Agents------------

From 8042fe31fff07c4acc512c2c2a0daa190cccb9e1 Mon Sep 17 00:00:00 2001 From: Dean Schmigelski Date: Fri, 6 Jun 2025 20:40:35 +0300 Subject: [PATCH 51/61] Update test_model_litellm.py --- tests-integ/test_model_litellm.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests-integ/test_model_litellm.py b/tests-integ/test_model_litellm.py index 86f6b42f1..d6a83b503 100644 --- a/tests-integ/test_model_litellm.py +++ b/tests-integ/test_model_litellm.py @@ -7,7 +7,7 @@ @pytest.fixture def model(): - return LiteLLMModel(model_id="bedrock/us.anthropic.claude-3-7-sonnet-20250219-v1:0") + return LiteLLMModel(model_id="bedrock/anthropic.claude-3-7-sonnet-20250219-v1:0") @pytest.fixture From b225c329beadc06c62cdc90c7b90743e705fcf4e Mon Sep 17 00:00:00 2001 From: Dean Schmigelski Date: Fri, 6 Jun 2025 20:42:49 +0300 Subject: [PATCH 52/61] Update README.md --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index c01389601..ef3a0e9b8 100644 --- a/README.md +++ b/README.md @@ -6,7 +6,7 @@

- Strands Agents------------ + Strands Agents-------------

From f7215c6decda9818e5a75fc6a813fe59023e8cdd Mon Sep 17 00:00:00 2001 From: Dean Schmigelski Date: Fri, 6 Jun 2025 21:12:50 +0300 Subject: [PATCH 53/61] Update README.md --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index ef3a0e9b8..179979138 100644 --- a/README.md +++ b/README.md @@ -6,7 +6,7 @@

- Strands Agents------------- + Strands Agents--------------

From ff4b229b179ad00a20060358566acf2b5c7ac983 Mon Sep 17 00:00:00 2001 From: Dean Schmigelski Date: Fri, 6 Jun 2025 21:23:10 +0300 Subject: [PATCH 54/61] Update test_mcp_client.py --- tests-integ/test_mcp_client.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests-integ/test_mcp_client.py b/tests-integ/test_mcp_client.py index 59ae2a14e..8dace8f61 100644 --- a/tests-integ/test_mcp_client.py +++ b/tests-integ/test_mcp_client.py @@ -106,7 +106,7 @@ def test_streamable_http_mcp_client(): target=start_calculator_server, kwargs={"transport": "streamable-http", "port": 8001}, daemon=True ) server_thread.start() - time.sleep(2) # wait for server to startup completely + time.sleep(8) # wait for server to startup completely def transport_callback() -> MCPTransport: return streamablehttp_client(url="http://127.0.0.1:8001/mcp") From 96ee084956c27d0b9e3d94c26c245637ef8b498b Mon Sep 17 00:00:00 2001 From: Dean Schmigelski Date: Fri, 6 Jun 2025 22:15:28 +0300 Subject: [PATCH 55/61] Update test_mcp_client.py --- tests-integ/test_mcp_client.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/tests-integ/test_mcp_client.py b/tests-integ/test_mcp_client.py index 8dace8f61..68330da63 100644 --- a/tests-integ/test_mcp_client.py +++ b/tests-integ/test_mcp_client.py @@ -103,13 +103,13 @@ def test_can_reuse_mcp_client(): def test_streamable_http_mcp_client(): server_thread = threading.Thread( - target=start_calculator_server, kwargs={"transport": "streamable-http", "port": 8001}, daemon=True + target=start_calculator_server, kwargs={"transport": "streamable-http", "port": 8004}, daemon=True ) server_thread.start() time.sleep(8) # wait for server to startup completely def transport_callback() -> MCPTransport: - return streamablehttp_client(url="http://127.0.0.1:8001/mcp") + return streamablehttp_client(url="http://127.0.0.1:8004/mcp") streamable_http_client = MCPClient(transport_callback) with streamable_http_client: From fec2edf7c6161b1ae8a0ac6f49583037699da545 Mon Sep 17 00:00:00 2001 From: Dean Schmigelski Date: Fri, 6 Jun 2025 22:42:27 +0300 Subject: [PATCH 56/61] Update pyproject.toml --- pyproject.toml | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/pyproject.toml b/pyproject.toml index f593eceb9..d65d7f711 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -29,7 +29,7 @@ dependencies = [ "boto3>=1.26.0,<2.0.0", "botocore>=1.29.0,<2.0.0", "docstring_parser>=0.15,<0.16.0", - "mcp>=1.9.3,<2.0.0", + "mcp>=1.8.3,<1.9.0", "pydantic>=2.0.0,<3.0.0", "typing-extensions>=4.13.2,<5.0.0", "watchdog>=6.0.0,<7.0.0", @@ -165,9 +165,6 @@ test = [ test-integ = [ "hatch test tests-integ {args}" ] -test-integ-mcp = [ - "hatch test tests-integ/test_mcp_stdio.py" -] [tool.mypy] From 281446dffde88d43addea189b31a32f2f04e6b94 Mon Sep 17 00:00:00 2001 From: Dean Schmigelski Date: Fri, 6 Jun 2025 22:44:56 +0300 Subject: [PATCH 57/61] Update pyproject.toml --- pyproject.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pyproject.toml b/pyproject.toml index d65d7f711..bd3097327 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -29,7 +29,7 @@ dependencies = [ "boto3>=1.26.0,<2.0.0", "botocore>=1.29.0,<2.0.0", "docstring_parser>=0.15,<0.16.0", - "mcp>=1.8.3,<1.9.0", + "mcp>=1.8.0,<2.0.0", "pydantic>=2.0.0,<3.0.0", "typing-extensions>=4.13.2,<5.0.0", "watchdog>=6.0.0,<7.0.0", From a1ede2e452c0cf0e06a1821d7d91fa8909bf7e1b Mon Sep 17 00:00:00 2001 From: Dean Schmigelski Date: Fri, 6 Jun 2025 22:52:50 +0300 Subject: [PATCH 58/61] Update test_model_litellm.py --- tests-integ/test_model_litellm.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests-integ/test_model_litellm.py b/tests-integ/test_model_litellm.py index d6a83b503..8c7413e00 100644 --- a/tests-integ/test_model_litellm.py +++ b/tests-integ/test_model_litellm.py @@ -7,7 +7,7 @@ @pytest.fixture def model(): - return LiteLLMModel(model_id="bedrock/anthropic.claude-3-7-sonnet-20250219-v1:0") + return LiteLLMModel(model_id="bedrock/anthropic.claude-3-sonnet-20240229-v1:0") @pytest.fixture From 3decfebb51f3a2c4036986d06e8b9ad2244856a1 Mon Sep 17 00:00:00 2001 From: Dean Schmigelski Date: Tue, 10 Jun 2025 17:20:25 +0300 Subject: [PATCH 59/61] Update test_mcp_client.py --- tests-integ/test_mcp_client.py | 57 ---------------------------------- 1 file changed, 57 deletions(-) diff --git a/tests-integ/test_mcp_client.py b/tests-integ/test_mcp_client.py index 68330da63..bbcbc8cac 100644 --- a/tests-integ/test_mcp_client.py +++ b/tests-integ/test_mcp_client.py @@ -44,63 +44,6 @@ def generate_custom_image() -> MCPImageContent: mcp.run(transport=transport) -def test_mcp_client(): - """ - Test should yield output similar to the following - {'role': 'user', 'content': [{'text': 'add 1 and 2, then echo the result back to me'}]} - {'role': 'assistant', 'content': [{'text': "I'll help you add 1 and 2 and then echo the result back to you.\n\nFirst, I'll calculate 1 + 2:"}, {'toolUse': {'toolUseId': 'tooluse_17ptaKUxQB20ySZxwgiI_w', 'name': 'calculator', 'input': {'x': 1, 'y': 2}}}]} - {'role': 'user', 'content': [{'toolResult': {'status': 'success', 'toolUseId': 'tooluse_17ptaKUxQB20ySZxwgiI_w', 'content': [{'text': '3'}]}}]} - {'role': 'assistant', 'content': [{'text': "\n\nNow I'll echo the result back to you:"}, {'toolUse': {'toolUseId': 'tooluse_GlOc5SN8TE6ti8jVZJMBOg', 'name': 'echo', 'input': {'to_echo': '3'}}}]} - {'role': 'user', 'content': [{'toolResult': {'status': 'success', 'toolUseId': 'tooluse_GlOc5SN8TE6ti8jVZJMBOg', 'content': [{'text': '3'}]}}]} - {'role': 'assistant', 'content': [{'text': '\n\nThe result of adding 1 and 2 is 3.'}]} - """ # noqa: E501 - - server_thread = threading.Thread( - target=start_calculator_server, kwargs={"transport": "sse", "port": 8000}, daemon=True - ) - server_thread.start() - time.sleep(2) # wait for server to startup completely - - sse_mcp_client = MCPClient(lambda: sse_client("http://127.0.0.1:8000/sse")) - stdio_mcp_client = MCPClient( - lambda: stdio_client(StdioServerParameters(command="python", args=["tests-integ/echo_server.py"])) - ) - with sse_mcp_client, stdio_mcp_client: - agent = Agent(tools=sse_mcp_client.list_tools_sync() + stdio_mcp_client.list_tools_sync()) - agent("add 1 and 2, then echo the result back to me") - - tool_use_content_blocks = _messages_to_content_blocks(agent.messages) - assert any([block["name"] == "echo" for block in tool_use_content_blocks]) - assert any([block["name"] == "calculator" for block in tool_use_content_blocks]) - - image_prompt = """ - Generate a custom image, then tell me if the image is red, blue, yellow, pink, orange, or green. - RESPOND ONLY WITH THE COLOR - """ - assert any( - [ - "yellow".casefold() in block["text"].casefold() - for block in agent(image_prompt).message["content"] - if "text" in block - ] - ) - - -def test_can_reuse_mcp_client(): - stdio_mcp_client = MCPClient( - lambda: stdio_client(StdioServerParameters(command="python", args=["tests-integ/echo_server.py"])) - ) - with stdio_mcp_client: - stdio_mcp_client.list_tools_sync() - pass - with stdio_mcp_client: - agent = Agent(tools=stdio_mcp_client.list_tools_sync()) - agent("echo the following to me DOG") - - tool_use_content_blocks = _messages_to_content_blocks(agent.messages) - assert any([block["name"] == "echo" for block in tool_use_content_blocks]) - - def test_streamable_http_mcp_client(): server_thread = threading.Thread( target=start_calculator_server, kwargs={"transport": "streamable-http", "port": 8004}, daemon=True From 5834346037143d816ab444cc5efbecced32e1e37 Mon Sep 17 00:00:00 2001 From: Dean Schmigelski Date: Tue, 10 Jun 2025 17:29:51 +0300 Subject: [PATCH 60/61] Update test_mcp_client.py --- tests-integ/test_mcp_client.py | 64 ++++++++++++++++++++++++++++++++-- 1 file changed, 61 insertions(+), 3 deletions(-) diff --git a/tests-integ/test_mcp_client.py b/tests-integ/test_mcp_client.py index bbcbc8cac..a8995e355 100644 --- a/tests-integ/test_mcp_client.py +++ b/tests-integ/test_mcp_client.py @@ -1,4 +1,5 @@ import base64 +import pytest import threading import time from typing import List, Literal @@ -44,15 +45,72 @@ def generate_custom_image() -> MCPImageContent: mcp.run(transport=transport) +def test_mcp_client(): + """ + Test should yield output similar to the following + {'role': 'user', 'content': [{'text': 'add 1 and 2, then echo the result back to me'}]} + {'role': 'assistant', 'content': [{'text': "I'll help you add 1 and 2 and then echo the result back to you.\n\nFirst, I'll calculate 1 + 2:"}, {'toolUse': {'toolUseId': 'tooluse_17ptaKUxQB20ySZxwgiI_w', 'name': 'calculator', 'input': {'x': 1, 'y': 2}}}]} + {'role': 'user', 'content': [{'toolResult': {'status': 'success', 'toolUseId': 'tooluse_17ptaKUxQB20ySZxwgiI_w', 'content': [{'text': '3'}]}}]} + {'role': 'assistant', 'content': [{'text': "\n\nNow I'll echo the result back to you:"}, {'toolUse': {'toolUseId': 'tooluse_GlOc5SN8TE6ti8jVZJMBOg', 'name': 'echo', 'input': {'to_echo': '3'}}}]} + {'role': 'user', 'content': [{'toolResult': {'status': 'success', 'toolUseId': 'tooluse_GlOc5SN8TE6ti8jVZJMBOg', 'content': [{'text': '3'}]}}]} + {'role': 'assistant', 'content': [{'text': '\n\nThe result of adding 1 and 2 is 3.'}]} + """ # noqa: E501 + + server_thread = threading.Thread( + target=start_calculator_server, kwargs={"transport": "sse", "port": 8000}, daemon=True + ) + server_thread.start() + time.sleep(2) # wait for server to startup completely + + sse_mcp_client = MCPClient(lambda: sse_client("http://127.0.0.1:8000/sse")) + stdio_mcp_client = MCPClient( + lambda: stdio_client(StdioServerParameters(command="python", args=["tests-integ/echo_server.py"])) + ) + with sse_mcp_client, stdio_mcp_client: + agent = Agent(tools=sse_mcp_client.list_tools_sync() + stdio_mcp_client.list_tools_sync()) + agent("add 1 and 2, then echo the result back to me") + + tool_use_content_blocks = _messages_to_content_blocks(agent.messages) + assert any([block["name"] == "echo" for block in tool_use_content_blocks]) + assert any([block["name"] == "calculator" for block in tool_use_content_blocks]) + + image_prompt = """ + Generate a custom image, then tell me if the image is red, blue, yellow, pink, orange, or green. + RESPOND ONLY WITH THE COLOR + """ + assert any( + [ + "yellow".casefold() in block["text"].casefold() + for block in agent(image_prompt).message["content"] + if "text" in block + ] + ) + + +def test_can_reuse_mcp_client(): + stdio_mcp_client = MCPClient( + lambda: stdio_client(StdioServerParameters(command="python", args=["tests-integ/echo_server.py"])) + ) + with stdio_mcp_client: + stdio_mcp_client.list_tools_sync() + pass + with stdio_mcp_client: + agent = Agent(tools=stdio_mcp_client.list_tools_sync()) + agent("echo the following to me DOG") + + tool_use_content_blocks = _messages_to_content_blocks(agent.messages) + assert any([block["name"] == "echo" for block in tool_use_content_blocks]) + +@pytest.mark.skip(reason="streamable transport is failing in GitHub actions, debugging if linux compatibility issue") def test_streamable_http_mcp_client(): server_thread = threading.Thread( - target=start_calculator_server, kwargs={"transport": "streamable-http", "port": 8004}, daemon=True + target=start_calculator_server, kwargs={"transport": "streamable-http", "port": 8001}, daemon=True ) server_thread.start() - time.sleep(8) # wait for server to startup completely + time.sleep(2) # wait for server to startup completely def transport_callback() -> MCPTransport: - return streamablehttp_client(url="http://127.0.0.1:8004/mcp") + return streamablehttp_client(url="http://127.0.0.1:8001/mcp") streamable_http_client = MCPClient(transport_callback) with streamable_http_client: From fa43c10261c9e7afe4b2cc90cd62d45595028dd2 Mon Sep 17 00:00:00 2001 From: Dean Schmigelski Date: Tue, 10 Jun 2025 17:45:18 +0300 Subject: [PATCH 61/61] Create conftest.py --- tests-integ/conftest.py | 6 ++++++ 1 file changed, 6 insertions(+) create mode 100644 tests-integ/conftest.py diff --git a/tests-integ/conftest.py b/tests-integ/conftest.py new file mode 100644 index 000000000..5b66acadf --- /dev/null +++ b/tests-integ/conftest.py @@ -0,0 +1,6 @@ +import pytest +import time + +@pytest.fixture(autouse=True) +def sleep_to_avoid_throttling(): + time.sleep(5)