From a26b03b26a8613dc1db88b7c1b3c627c076cb2d8 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Mon, 23 Feb 2026 14:27:22 +0000 Subject: [PATCH 1/6] Initial plan From 7688c0348bedb5405e9b2781cc7b22d8aad295e6 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Mon, 23 Feb 2026 14:32:02 +0000 Subject: [PATCH 2/6] Add integration test reproducing MCP tool descriptions issue Co-authored-by: g3force <779094+g3force@users.noreply.github.com> --- adk/tests/test_mcp_tool_descriptions.py | 221 ++++++++++++++++++++++++ 1 file changed, 221 insertions(+) create mode 100644 adk/tests/test_mcp_tool_descriptions.py diff --git a/adk/tests/test_mcp_tool_descriptions.py b/adk/tests/test_mcp_tool_descriptions.py new file mode 100644 index 0000000..55d18c9 --- /dev/null +++ b/adk/tests/test_mcp_tool_descriptions.py @@ -0,0 +1,221 @@ +"""Integration test to verify MCP tool descriptions are included in agent instructions. + +This test reproduces the issue described in: +https://github.com/agentic-layer/sdk-python/issues/XX + +The problem: When MCP tools are added to an agent, their descriptions should be +included in the agent's instructions so the LLM knows what each tool does. However, +currently the tool descriptions are not being added to the instructions, unlike +sub-agents which do have their descriptions added. + +Expected behavior: +- Agent instructions should contain tool names and descriptions +- Format should be similar to sub-agent descriptions + +Actual behavior: +- Agent instructions do not contain MCP tool descriptions +- Tools are available but LLM doesn't know what they do without explicit prompts +""" + +from typing import Any + +import pytest +import respx +from agenticlayer.config import McpTool +from asgi_lifespan import LifespanManager +from fastmcp import FastMCP +from pydantic import AnyHttpUrl + +from tests.utils.helpers import create_asgi_request_handler + + +class TestMcpToolDescriptions: + """Tests for MCP tool descriptions in agent instructions.""" + + @pytest.mark.asyncio + async def test_mcp_tool_descriptions_missing_from_agent_instructions( + self, + app_factory: Any, + agent_factory: Any, + respx_mock: respx.MockRouter, + ) -> None: + """Test that reproduces the issue: MCP tool descriptions are not in agent instructions. + + This test demonstrates that when MCP tools are added to an agent, their + descriptions are NOT included in the agent's instructions, making it harder + for the LLM to know what tools are available and how to use them. + + This is the ACTUAL behavior (the bug we're documenting). + """ + + # Given: MCP server with tools that have detailed descriptions + mcp = FastMCP("CustomerService") + + @mcp.tool() + def get_customer_crm_data(customer_id: str) -> dict: + """Retrieve customer CRM data including contact info and purchase history.""" + return {"customer_id": customer_id, "name": "John Doe"} + + @mcp.tool() + def get_all_customer_data() -> list: + """Get a list of all customers in the system.""" + return [{"id": "1", "name": "Customer 1"}] + + @mcp.tool() + def send_message(customer_id: str, subject: str, body: str) -> str: + """Send a personalized message to a customer via email.""" + return f"Message sent to {customer_id}" + + @mcp.tool() + def get_insurance_products() -> list: + """Get all available insurance products.""" + return [{"id": "prod1", "name": "Health Insurance"}] + + @mcp.tool() + def get_product_details(product_id: str) -> dict: + """Get detailed information about a specific insurance product.""" + return {"id": product_id, "name": "Product Details"} + + @mcp.tool() + def get_products_by_segment(segment: str) -> list: + """Get insurance products filtered by customer segment.""" + return [{"id": "prod1", "segment": segment}] + + # Start MCP server + mcp_server_url = "http://test-crm-mcp.local" + mcp_app = mcp.http_app(path="/mcp") + + async with LifespanManager(mcp_app) as mcp_manager: + # Route MCP requests through ASGI transport + handler = create_asgi_request_handler(mcp_manager.app, mcp_server_url) + respx_mock.route(host="test-crm-mcp.local").mock(side_effect=handler) + + # When: Create agent with MCP tools + test_agent = agent_factory("customer_service_agent") + # Set a simple instruction + test_agent.instruction = "You are a customer service agent." + + tools = [McpTool(name="crm_tools", url=AnyHttpUrl(f"{mcp_server_url}/mcp"), timeout=30)] + + # Create the app which loads the MCP tools + async with app_factory(test_agent, tools=tools): + # Access the agent to check its instructions + # The agent is modified during app startup in agent_factory.load_agent() + # We need to get the configured agent instance + + # ACTUAL BEHAVIOR (the bug): + # The agent instructions do NOT contain the MCP tool descriptions + agent_instructions = test_agent.instruction + + print("\n" + "=" * 80) + print("AGENT INSTRUCTIONS:") + print("=" * 80) + print(agent_instructions) + print("=" * 80) + + # These assertions document the CURRENT (buggy) behavior: + # The tool descriptions are NOT present in the instructions + + # Check that the basic instruction is still there + assert "customer service agent" in agent_instructions.lower() + + # DOCUMENT THE BUG: Tool descriptions are missing + # If this were working correctly, we would expect to see something like: + # "Following tools are available: + # - 'get_customer_crm_data': Retrieve customer CRM data... + # - 'send_message': Send a personalized message..." + # But these are NOT present currently. + + assert "get_customer_crm_data" not in agent_instructions, ( + "Tool names should NOT be in instructions yet (this documents the bug). " + "If this assertion fails, the issue might be fixed!" + ) + assert "Retrieve customer CRM data" not in agent_instructions, ( + "Tool descriptions should NOT be in instructions yet (this documents the bug). " + "If this assertion fails, the issue might be fixed!" + ) + assert "send_message" not in agent_instructions, ( + "Tool names should NOT be in instructions yet (this documents the bug)" + ) + + # When the issue is fixed, the agent instructions should include + # tool descriptions similar to how sub-agent descriptions are added + # in agent.py lines 74-80 + + @pytest.mark.asyncio + async def test_mcp_tool_descriptions_expected_behavior( + self, + app_factory: Any, + agent_factory: Any, + respx_mock: respx.MockRouter, + ) -> None: + """Test that documents the EXPECTED behavior: MCP tool descriptions should be in instructions. + + This test is currently EXPECTED TO FAIL. It documents what the correct + behavior should be once the issue is fixed. + + When the bug is fixed, this test should pass, and the agent instructions + should contain the MCP tool descriptions, similar to how sub-agent + descriptions are currently handled. + """ + + # Given: MCP server with tools + mcp = FastMCP("Calculator") + + @mcp.tool() + def add(a: int, b: int) -> int: + """Add two numbers together.""" + return a + b + + @mcp.tool() + def multiply(x: float, y: float) -> float: + """Multiply two numbers.""" + return x * y + + # Start MCP server + mcp_server_url = "http://test-calc-mcp.local" + mcp_app = mcp.http_app(path="/mcp") + + async with LifespanManager(mcp_app) as mcp_manager: + # Route MCP requests through ASGI transport + handler = create_asgi_request_handler(mcp_manager.app, mcp_server_url) + respx_mock.route(host="test-calc-mcp.local").mock(side_effect=handler) + + # When: Create agent with MCP tools + test_agent = agent_factory("calculator_agent") + test_agent.instruction = "You are a calculator assistant." + + tools = [McpTool(name="calculator", url=AnyHttpUrl(f"{mcp_server_url}/mcp"), timeout=30)] + + async with app_factory(test_agent, tools=tools): + agent_instructions = test_agent.instruction + + print("\n" + "=" * 80) + print("EXPECTED AGENT INSTRUCTIONS (when bug is fixed):") + print("=" * 80) + print(agent_instructions) + print("=" * 80) + + # EXPECTED BEHAVIOR (will fail until bug is fixed): + # Tool names and descriptions should be in the instructions + + # Mark this test as expected to fail + pytest.skip( + "This test documents expected behavior and will fail until the issue is fixed. " + "When MCP tool descriptions are properly added to agent instructions, " + "remove the pytest.skip() and this test should pass." + ) + + # These assertions define the expected behavior: + assert "add" in agent_instructions, "Tool name 'add' should be in instructions" + assert "multiply" in agent_instructions, "Tool name 'multiply' should be in instructions" + + # The descriptions should also be present + assert "Add two numbers" in agent_instructions, "Tool description should be in instructions" + assert "Multiply two numbers" in agent_instructions, "Tool description should be in instructions" + + # The format should be similar to sub-agent descriptions + # (see agent.py lines 74-80 for reference) + assert ( + "tools are available" in agent_instructions.lower() or "functions" in agent_instructions.lower() + ), "Instructions should mention available tools/functions" From 0b9a44088b6dde08535476268af31e34c104bc02 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Mon, 23 Feb 2026 14:34:12 +0000 Subject: [PATCH 3/6] Fix type hints in MCP tool test functions Co-authored-by: g3force <779094+g3force@users.noreply.github.com> --- adk/tests/test_mcp_tool_descriptions.py | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/adk/tests/test_mcp_tool_descriptions.py b/adk/tests/test_mcp_tool_descriptions.py index 55d18c9..f7bdb83 100644 --- a/adk/tests/test_mcp_tool_descriptions.py +++ b/adk/tests/test_mcp_tool_descriptions.py @@ -52,12 +52,12 @@ async def test_mcp_tool_descriptions_missing_from_agent_instructions( mcp = FastMCP("CustomerService") @mcp.tool() - def get_customer_crm_data(customer_id: str) -> dict: + def get_customer_crm_data(customer_id: str) -> dict[str, Any]: """Retrieve customer CRM data including contact info and purchase history.""" return {"customer_id": customer_id, "name": "John Doe"} @mcp.tool() - def get_all_customer_data() -> list: + def get_all_customer_data() -> list[dict[str, str]]: """Get a list of all customers in the system.""" return [{"id": "1", "name": "Customer 1"}] @@ -67,17 +67,17 @@ def send_message(customer_id: str, subject: str, body: str) -> str: return f"Message sent to {customer_id}" @mcp.tool() - def get_insurance_products() -> list: + def get_insurance_products() -> list[dict[str, str]]: """Get all available insurance products.""" return [{"id": "prod1", "name": "Health Insurance"}] @mcp.tool() - def get_product_details(product_id: str) -> dict: + def get_product_details(product_id: str) -> dict[str, str]: """Get detailed information about a specific insurance product.""" return {"id": product_id, "name": "Product Details"} @mcp.tool() - def get_products_by_segment(segment: str) -> list: + def get_products_by_segment(segment: str) -> list[dict[str, str]]: """Get insurance products filtered by customer segment.""" return [{"id": "prod1", "segment": segment}] From 593f0ce55fe37eef211211293220a4400123c27d Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Mon, 23 Feb 2026 14:36:03 +0000 Subject: [PATCH 4/6] Address code review feedback on MCP tool descriptions test Co-authored-by: g3force <779094+g3force@users.noreply.github.com> --- adk/tests/test_mcp_tool_descriptions.py | 12 +++++++----- 1 file changed, 7 insertions(+), 5 deletions(-) diff --git a/adk/tests/test_mcp_tool_descriptions.py b/adk/tests/test_mcp_tool_descriptions.py index f7bdb83..664a57e 100644 --- a/adk/tests/test_mcp_tool_descriptions.py +++ b/adk/tests/test_mcp_tool_descriptions.py @@ -1,7 +1,7 @@ """Integration test to verify MCP tool descriptions are included in agent instructions. -This test reproduces the issue described in: -https://github.com/agentic-layer/sdk-python/issues/XX +This test reproduces the issue described in the GitHub issue about MCP tool descriptions +not being contained in agent instructions. The problem: When MCP tools are added to an agent, their descriptions should be included in the agent's instructions so the LLM knows what each tool does. However, @@ -210,9 +210,11 @@ def multiply(x: float, y: float) -> float: assert "add" in agent_instructions, "Tool name 'add' should be in instructions" assert "multiply" in agent_instructions, "Tool name 'multiply' should be in instructions" - # The descriptions should also be present - assert "Add two numbers" in agent_instructions, "Tool description should be in instructions" - assert "Multiply two numbers" in agent_instructions, "Tool description should be in instructions" + # The full descriptions should be present + assert "Add two numbers together" in agent_instructions, ( + "Full tool description should be in instructions" + ) + assert "Multiply two numbers" in agent_instructions, "Full tool description should be in instructions" # The format should be similar to sub-agent descriptions # (see agent.py lines 74-80 for reference) From 84f2a77cde77659c35b23d5772bac64be1cc26e4 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Mon, 23 Feb 2026 14:37:26 +0000 Subject: [PATCH 5/6] Move pytest.skip to beginning of test for proper skipping Co-authored-by: g3force <779094+g3force@users.noreply.github.com> --- adk/tests/test_mcp_tool_descriptions.py | 19 ++++++++----------- 1 file changed, 8 insertions(+), 11 deletions(-) diff --git a/adk/tests/test_mcp_tool_descriptions.py b/adk/tests/test_mcp_tool_descriptions.py index 664a57e..7d2a3dd 100644 --- a/adk/tests/test_mcp_tool_descriptions.py +++ b/adk/tests/test_mcp_tool_descriptions.py @@ -151,7 +151,7 @@ async def test_mcp_tool_descriptions_expected_behavior( ) -> None: """Test that documents the EXPECTED behavior: MCP tool descriptions should be in instructions. - This test is currently EXPECTED TO FAIL. It documents what the correct + This test is currently SKIPPED. It documents what the correct behavior should be once the issue is fixed. When the bug is fixed, this test should pass, and the agent instructions @@ -159,6 +159,13 @@ async def test_mcp_tool_descriptions_expected_behavior( descriptions are currently handled. """ + # Mark this test as expected to fail - remove this when the issue is fixed + pytest.skip( + "This test documents expected behavior and will fail until the issue is fixed. " + "When MCP tool descriptions are properly added to agent instructions, " + "remove the pytest.skip() and this test should pass." + ) + # Given: MCP server with tools mcp = FastMCP("Calculator") @@ -196,16 +203,6 @@ def multiply(x: float, y: float) -> float: print(agent_instructions) print("=" * 80) - # EXPECTED BEHAVIOR (will fail until bug is fixed): - # Tool names and descriptions should be in the instructions - - # Mark this test as expected to fail - pytest.skip( - "This test documents expected behavior and will fail until the issue is fixed. " - "When MCP tool descriptions are properly added to agent instructions, " - "remove the pytest.skip() and this test should pass." - ) - # These assertions define the expected behavior: assert "add" in agent_instructions, "Tool name 'add' should be in instructions" assert "multiply" in agent_instructions, "Tool name 'multiply' should be in instructions" From c4f7e0f20f4fefb9a3513f8a6ecca8573c555386 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Tue, 24 Feb 2026 08:22:17 +0000 Subject: [PATCH 6/6] Update test to reproduce exact bug: MCP tool descriptions missing from function logs Co-authored-by: g3force <779094+g3force@users.noreply.github.com> --- adk/tests/test_mcp_tool_descriptions.py | 127 ++++++++++++++---------- 1 file changed, 77 insertions(+), 50 deletions(-) diff --git a/adk/tests/test_mcp_tool_descriptions.py b/adk/tests/test_mcp_tool_descriptions.py index 7d2a3dd..aba29a0 100644 --- a/adk/tests/test_mcp_tool_descriptions.py +++ b/adk/tests/test_mcp_tool_descriptions.py @@ -17,6 +17,7 @@ - Tools are available but LLM doesn't know what they do without explicit prompts """ +import logging from typing import Any import pytest @@ -25,8 +26,10 @@ from asgi_lifespan import LifespanManager from fastmcp import FastMCP from pydantic import AnyHttpUrl +from starlette.testclient import TestClient -from tests.utils.helpers import create_asgi_request_handler +from tests.fixtures.mock_llm import LLMMockController +from tests.utils.helpers import create_asgi_request_handler, create_send_message_request class TestMcpToolDescriptions: @@ -37,17 +40,30 @@ async def test_mcp_tool_descriptions_missing_from_agent_instructions( self, app_factory: Any, agent_factory: Any, + llm_controller: LLMMockController, respx_mock: respx.MockRouter, + caplog: pytest.LogCaptureFixture, ) -> None: - """Test that reproduces the issue: MCP tool descriptions are not in agent instructions. + """Test that reproduces the issue: MCP tool descriptions are not in the logged functions. This test demonstrates that when MCP tools are added to an agent, their - descriptions are NOT included in the agent's instructions, making it harder - for the LLM to know what tools are available and how to use them. + descriptions are NOT included in the function logs that the ADK generates. - This is the ACTUAL behavior (the bug we're documenting). + The ADK logs functions in this format: + Functions: + get_customer_crm_data: {'customer_id': {'title': 'Customer Id', 'type': }} -> None + + Notice that the description ("Retrieve customer CRM data...") is MISSING. + This is the bug reproduced from the GitHub issue. """ + # Enable DEBUG logging to capture the function logs + # Need to set it at the root level to capture all ADK logs + caplog.set_level(logging.DEBUG) + + # Configure LLM to respond with a simple message + llm_controller.respond_with_message("", "I can help you with customer service tasks.") + # Given: MCP server with tools that have detailed descriptions mcp = FastMCP("CustomerService") @@ -92,55 +108,66 @@ def get_products_by_segment(segment: str) -> list[dict[str, str]]: # When: Create agent with MCP tools test_agent = agent_factory("customer_service_agent") - # Set a simple instruction test_agent.instruction = "You are a customer service agent." tools = [McpTool(name="crm_tools", url=AnyHttpUrl(f"{mcp_server_url}/mcp"), timeout=30)] - # Create the app which loads the MCP tools - async with app_factory(test_agent, tools=tools): - # Access the agent to check its instructions - # The agent is modified during app startup in agent_factory.load_agent() - # We need to get the configured agent instance - - # ACTUAL BEHAVIOR (the bug): - # The agent instructions do NOT contain the MCP tool descriptions - agent_instructions = test_agent.instruction - - print("\n" + "=" * 80) - print("AGENT INSTRUCTIONS:") - print("=" * 80) - print(agent_instructions) - print("=" * 80) - - # These assertions document the CURRENT (buggy) behavior: - # The tool descriptions are NOT present in the instructions - - # Check that the basic instruction is still there - assert "customer service agent" in agent_instructions.lower() - - # DOCUMENT THE BUG: Tool descriptions are missing - # If this were working correctly, we would expect to see something like: - # "Following tools are available: - # - 'get_customer_crm_data': Retrieve customer CRM data... - # - 'send_message': Send a personalized message..." - # But these are NOT present currently. - - assert "get_customer_crm_data" not in agent_instructions, ( - "Tool names should NOT be in instructions yet (this documents the bug). " - "If this assertion fails, the issue might be fixed!" - ) - assert "Retrieve customer CRM data" not in agent_instructions, ( - "Tool descriptions should NOT be in instructions yet (this documents the bug). " - "If this assertion fails, the issue might be fixed!" - ) - assert "send_message" not in agent_instructions, ( - "Tool names should NOT be in instructions yet (this documents the bug)" - ) - - # When the issue is fixed, the agent instructions should include - # tool descriptions similar to how sub-agent descriptions are added - # in agent.py lines 74-80 + # Create the app and send a message to trigger LLM call with logging + async with app_factory(test_agent, tools=tools) as app: + client = TestClient(app) + user_message = "What can you help me with?" + response = client.post("", json=create_send_message_request(user_message)) + + # Then: Verify we got a successful response + assert response.status_code == 200 + + # Find the "Functions:" section in the logs + functions_log = None + for record in caplog.records: + if "Functions:" in record.message: + functions_log = record.message + break + + assert functions_log is not None, "Should have logged functions" + + print("\n" + "=" * 80) + print("LOGGED FUNCTIONS (from ADK debug logs):") + print("=" * 80) + print(functions_log) + print("=" * 80) + + # DOCUMENT THE BUG: The logged functions contain the exact format from the issue + # Functions should be logged like: + # get_customer_crm_data: {'customer_id': {'title': 'Customer Id', 'type': }} -> None + + # Verify the bug - function names are present + assert "get_customer_crm_data" in functions_log, "Function name should be in log" + assert "send_message" in functions_log, "Function name should be in log" + assert "get_insurance_products" in functions_log, "Function name should be in log" + + # BUG: The descriptions are MISSING from the log + # The log shows parameter types but not the human-readable descriptions + assert "Retrieve customer CRM data including contact info and purchase history" not in functions_log, ( + "Tool description should NOT be in log (this documents the bug). " + "If this assertion fails, the issue might be fixed!" + ) + assert "Get a list of all customers in the system" not in functions_log, ( + "Tool description should NOT be in log (this documents the bug)" + ) + assert "Send a personalized message to a customer via email" not in functions_log, ( + "Tool description should NOT be in log (this documents the bug)" + ) + + # The log shows parameter information (like 'customer_id') but not descriptions + assert "customer_id" in functions_log, "Parameter names should be in log" + + print("\n" + "=" * 80) + print("BUG REPRODUCED: Functions logged without their descriptions!") + print("The log shows function signatures like:") + print(" get_customer_crm_data: {'customer_id': ...} -> None") + print("But missing the description:") + print(" 'Retrieve customer CRM data including contact info and purchase history.'") + print("=" * 80) @pytest.mark.asyncio async def test_mcp_tool_descriptions_expected_behavior(