Feature: MCP Tool Adapter As an actor runtime I want an adapter that connects to MCP servers, discovers tools, and invokes them with schema validation So that external MCP tools are usable like any registered tool # ------------------------------------------------------------------- # Adapter Lifecycle # ------------------------------------------------------------------- Scenario: Create adapter from server config Given an MCP server config for "github" with stdio transport When I create an MCP adapter from the config Then the adapter server name should be "github" And the adapter transport should be "stdio" And the adapter should not be connected Scenario: Create adapter from SSE server config Given an MCP server config for "remote-api" with sse transport and url "https://api.example.com/mcp" When I create an MCP adapter from the config Then the adapter server name should be "remote-api" And the adapter transport should be "sse" Scenario: Connect adapter starts handshake Given an MCP adapter with a mock transport When I connect the adapter Then the adapter should be connected And the adapter server capabilities should be set Scenario: Disconnect adapter cleans up Given a connected MCP adapter with a mock transport When I disconnect the adapter Then the adapter should not be connected Scenario: Double connect is idempotent Given a connected MCP adapter with a mock transport When I connect the adapter Then the adapter should be connected Scenario: Disconnect when not connected is safe Given an MCP adapter with a mock transport When I disconnect the adapter Then the adapter should not be connected # ------------------------------------------------------------------- # Tool Discovery # ------------------------------------------------------------------- Scenario: Discover tools from MCP server Given a connected MCP adapter with 3 mock tools When I discover tools from the adapter Then the adapter should have 3 discovered tools And discovered tool 0 should have a name And discovered tool 0 should have an input schema Scenario: Discover tools with include filter Given a connected MCP adapter with 3 mock tools And a tool filter including only "tool_0" When I discover tools from the adapter with filter Then the adapter should have 1 discovered tools Scenario: Discover tools with exclude filter Given a connected MCP adapter with 3 mock tools And a tool filter excluding "tool_0" When I discover tools from the adapter with filter Then the adapter should have 2 discovered tools Scenario: Discover returns empty when server has no tools Given a connected MCP adapter with 0 mock tools When I discover tools from the adapter Then the adapter should have 0 discovered tools Scenario: Discover when not connected raises error Given an MCP adapter with a mock transport When I discover tools expecting an error Then the adapter error should mention "not connected" # ------------------------------------------------------------------- # Tool Invocation # ------------------------------------------------------------------- Scenario: Invoke a discovered tool successfully Given a connected MCP adapter with a callable mock tool "create_issue" When I invoke "create_issue" with arguments {"title": "Bug", "body": "Fix it"} Then the invocation should succeed And the invocation result should contain key "content" Scenario: Invoke with valid input schema passes validation Given a connected MCP adapter with a schema-validated mock tool "create_issue" When I invoke "create_issue" with arguments {"title": "Bug", "body": "Fix it"} Then the invocation should succeed Scenario: Invoke with invalid input fails validation Given a connected MCP adapter with a schema-validated mock tool "create_issue" When I invoke "create_issue" with arguments {"wrong_field": 123} Then the invocation should fail And the invocation error should mention "validation" Scenario: Invoke unknown tool raises error Given a connected MCP adapter with a callable mock tool "create_issue" When I invoke "nonexistent_tool" with arguments {} Then the invocation should fail And the invocation error should mention "not found" Scenario: Invoke when not connected raises error Given an MCP adapter with a mock transport When I invoke MCP tool "create_issue" while disconnected Then the adapter error should mention "not connected" Scenario: Invoke tool that returns error from server Given a connected MCP adapter with a failing mock tool "bad_tool" When I invoke "bad_tool" with arguments {} Then the invocation should fail And the invocation error should mention "server error" # ------------------------------------------------------------------- # Tool Registration in ToolRegistry # ------------------------------------------------------------------- Scenario: Register discovered MCP tools in ToolRegistry Given a connected MCP adapter with 2 mock tools And an empty MCP tool registry When I register MCP tools in the registry with namespace "mcp-github" Then the registry should have 2 tools And registry tool 0 name should start with "mcp-github/" Scenario: Registered MCP tool is callable via registry Given a connected MCP adapter with a callable mock tool "list_repos" And an empty MCP tool registry When I register MCP tools in the registry with namespace "mcp-github" Then calling registry tool "mcp-github/list_repos" should succeed Scenario: Re-registration after tool list changed Given a connected MCP adapter with 2 mock tools And an empty MCP tool registry When I register MCP tools in the registry with namespace "mcp-github" And the MCP server adds a new tool "deploy" And I re-register MCP tools in the registry with namespace "mcp-github" Then the registry should have 3 tools Scenario: Registered tool handler returns error on failed invoke Given a connected MCP adapter with a failing mock tool "bad_tool" And an empty MCP tool registry When I register MCP tools in the registry with namespace "mcp-fail" Then calling registry tool "mcp-fail/bad_tool" should return an error # ------------------------------------------------------------------- # Capability Inference # ------------------------------------------------------------------- Scenario: Infer read_only for tool named list_repos When I infer capabilities for tool name "list_repos" Then the inferred capabilities should have read_only true And the inferred capabilities should have writes false Scenario: Infer writes for tool named create_issue When I infer capabilities for tool name "create_issue" Then the inferred capabilities should have read_only false And the inferred capabilities should have writes true Scenario: Infer writes for tool named delete_branch When I infer capabilities for tool name "delete_branch" Then the inferred capabilities should have read_only false And the inferred capabilities should have writes true Scenario: Infer default for unknown tool name When I infer capabilities for tool name "run_pipeline" Then the inferred capabilities should have read_only false And the inferred capabilities should have writes false Scenario: Infer read_only for tool with get prefix When I infer capabilities for tool name "get-user-details" Then the inferred capabilities should have read_only true And the inferred capabilities should have writes false Scenario: Write overrides read when both keywords present When I infer capabilities for tool name "search_and_update" Then the inferred capabilities should have writes true Scenario: Registered MCP tool has inferred capabilities Given a connected MCP adapter with a callable mock tool "list_repos" And an empty MCP tool registry When I register MCP tools in the registry with namespace "mcp-github" Then registry tool "mcp-github/list_repos" should have read_only capability Scenario: Registered write tool has writes capability Given a connected MCP adapter with a callable mock tool "create_issue" And an empty MCP tool registry When I register MCP tools in the registry with namespace "mcp-github" Then registry tool "mcp-github/create_issue" should have writes capability # ------------------------------------------------------------------- # Edge Cases # ------------------------------------------------------------------- Scenario: Access discovered_tools property after discovery Given a connected MCP adapter with 2 mock tools When I discover tools from the adapter Then the adapter discovered_tools property should have 2 items Scenario: Disconnect handles close errors gracefully Given a connected MCP adapter with a transport that errors on close When I disconnect the adapter Then the adapter should not be connected Scenario: Invoke tool that raises generic exception Given a connected MCP adapter with a transport-error mock tool "crash_tool" When I invoke "crash_tool" with arguments {} Then the invocation should fail And the invocation error should mention "server error" # ------------------------------------------------------------------- # MCP 1.4.0 Content List Format # ------------------------------------------------------------------- Scenario: Invoke tool returns MCP 1.4.0 list-format content normalised to dict Given a connected MCP adapter with a callable mock tool "get_status" When I invoke "get_status" with arguments {} Then the invocation should succeed And the invocation result data should have key "content" And the invocation result content should be a list Scenario: Invoke tool with MCP 1.4.0 content list stores content items Given a connected MCP adapter with a raw list-content mock tool "fetch_data" When I invoke "fetch_data" with arguments {} Then the invocation should succeed And the invocation result data should have key "content" And the invocation result content list should have 1 item # ------------------------------------------------------------------- # Error Classification # ------------------------------------------------------------------- Scenario: Classify connection failure Given an MCP adapter with a transport that fails to connect When I connect the adapter expecting error Then the adapter error should mention "connection" Scenario: Classify timeout error Given a connected MCP adapter with a tool that times out When I invoke "slow_tool" with arguments {} Then the invocation should fail And the invocation error should mention "timeout" # ------------------------------------------------------------------- # Server Config Validation # ------------------------------------------------------------------- Scenario: Stdio transport requires command Given an MCP server config for "bad" with stdio transport but no command When I create an MCP adapter from the config expecting validation error Then the adapter error should mention "command" Scenario: SSE transport requires url Given an MCP server config for "bad" with sse transport but no url When I create an MCP adapter from the config expecting validation error Then the adapter error should mention "url" # ------------------------------------------------------------------- # Reconnect Lifecycle # ------------------------------------------------------------------- Scenario: Reconnect restores connection after disconnect Given a connected MCP adapter with a mock transport When I disconnect the adapter And I reconnect the adapter Then the adapter should be connected Scenario: Reconnect clears tool cache Given a connected MCP adapter with 3 mock tools When I discover tools from the adapter And I reconnect the adapter Then the adapter discovered_tools property should have 0 items Scenario: Reconnect on unavailable server raises connection error Given a connected MCP adapter with a transport that fails to reconnect When I reconnect the adapter expecting error Then the adapter error should mention "connection" Scenario: Connect times out when transport hangs Given an MCP adapter with a transport that hangs on connect When I connect the adapter with timeout 0.05 expecting error Then the adapter error should mention "connection" # ------------------------------------------------------------------- # Source and Checkpointable Metadata # ------------------------------------------------------------------- Scenario: Registered MCP tool has source mcp Given a connected MCP adapter with a callable mock tool "list_repos" And an empty MCP tool registry When I register MCP tools in the registry with namespace "mcp-github" Then registry tool "mcp-github/list_repos" should have source "mcp" Scenario: Registered MCP tool has checkpointable false Given a connected MCP adapter with a callable mock tool "create_issue" And an empty MCP tool registry When I register MCP tools in the registry with namespace "mcp-github" Then registry tool "mcp-github/create_issue" should have checkpointable false