81c2878ec8
CI / benchmark-publish (pull_request) Has been skipped
CI / build (pull_request) Successful in 17s
CI / helm (pull_request) Successful in 22s
CI / quality (pull_request) Successful in 34s
CI / lint (pull_request) Successful in 3m19s
CI / typecheck (pull_request) Successful in 4m6s
CI / security (pull_request) Successful in 4m7s
CI / unit_tests (pull_request) Successful in 7m4s
CI / integration_tests (pull_request) Successful in 7m11s
CI / docker (pull_request) Successful in 1m35s
CI / coverage (pull_request) Failing after 8m51s
CI / e2e_tests (pull_request) Failing after 17m45s
CI / status-check (pull_request) Failing after 1s
CI / benchmark-regression (pull_request) Successful in 54m58s
Add lifecycle management and sandbox support for MCP tools: - McpClient: lazy start (server starts on first call_tool()), configurable idle timeout with auto-stop, health monitoring with automatic restart on server crash - McpRegistry: namespace-isolated tracking of multiple MCP servers with independent lifecycles - SandboxPathRewriter: bi-directional file path rewriting between host and sandbox workspaces using PathMapper - MCPCapabilityMetadata: structured exposure of full MCP server capabilities (tools, resources, prompts) - MCPToolDescriptor: extended with annotations field - MCPToolAdapter: capability_metadata property, enhanced source_metadata with server capabilities and tool annotations BDD scenarios: - 16 lifecycle scenarios (lazy start, auto-stop, health check, registry) - 10 sandbox path rewriting scenarios (arguments, responses, roundtrip) - All 42 existing MCP adapter scenarios continue to pass ISSUES CLOSED: #938
161 lines
7.0 KiB
Gherkin
161 lines
7.0 KiB
Gherkin
Feature: MCP Server Lifecycle Management
|
|
As an actor runtime
|
|
I want MCP servers to start lazily and stop when idle
|
|
So that resources are used efficiently and server management is automatic
|
|
|
|
# -------------------------------------------------------------------
|
|
# Lazy Start
|
|
# -------------------------------------------------------------------
|
|
|
|
Scenario: MCP server starts on first tool call (lazy start)
|
|
Given an MCP client config for "github" with lazy start enabled
|
|
And a mock MCP transport with tool "list_repos"
|
|
When I create an MCP client
|
|
Then the MCP client state should be "idle"
|
|
And the MCP client should not be connected
|
|
When I call MCP tool "list_repos" with arguments {}
|
|
Then the MCP client should be connected
|
|
And the MCP client state should be "running"
|
|
|
|
Scenario: MCP server does not start without tool call when lazy start enabled
|
|
Given an MCP client config for "github" with lazy start enabled
|
|
And a mock MCP transport with tool "list_repos"
|
|
When I create an MCP client
|
|
Then the MCP client should not be connected
|
|
|
|
Scenario: Explicit start works with lazy start enabled
|
|
Given an MCP client config for "github" with lazy start enabled
|
|
And a mock MCP transport with tool "list_repos"
|
|
When I create an MCP client
|
|
And I explicitly start the MCP client
|
|
Then the MCP client should be connected
|
|
And the MCP client state should be "running"
|
|
|
|
Scenario: Tool call fails when lazy start disabled and not started
|
|
Given an MCP client config for "github" with lazy start disabled
|
|
And a mock MCP transport with tool "list_repos"
|
|
When I create an MCP client
|
|
And I call MCP tool "list_repos" expecting a runtime error
|
|
Then the MCP client error should mention "not started"
|
|
|
|
Scenario: Explicit start is idempotent
|
|
Given an MCP client config for "github" with lazy start enabled
|
|
And a mock MCP transport with tool "list_repos"
|
|
When I create an MCP client
|
|
And I explicitly start the MCP client
|
|
And I explicitly start the MCP client
|
|
Then the MCP client should be connected
|
|
|
|
# -------------------------------------------------------------------
|
|
# Auto-Stop
|
|
# -------------------------------------------------------------------
|
|
|
|
Scenario: MCP server auto-stops after idle timeout
|
|
Given an MCP client config for "github" with idle timeout 0.15 seconds
|
|
And a mock MCP transport with tool "list_repos"
|
|
When I create an MCP client
|
|
And I call MCP tool "list_repos" with arguments {}
|
|
And I wait 0.5 seconds
|
|
Then the MCP client state should be "stopped"
|
|
And the MCP client should not be connected
|
|
|
|
Scenario: Activity resets idle timer
|
|
Given an MCP client config for "github" with idle timeout 0.5 seconds
|
|
And a mock MCP transport with tool "list_repos"
|
|
When I create an MCP client
|
|
And I call MCP tool "list_repos" with arguments {}
|
|
And I wait 0.25 seconds
|
|
And I call MCP tool "list_repos" with arguments {}
|
|
And I wait 0.25 seconds
|
|
Then the MCP client should be connected
|
|
|
|
Scenario: Auto-stop disabled when timeout is zero
|
|
Given an MCP client config for "github" with idle timeout 0.0 seconds
|
|
And a mock MCP transport with tool "list_repos"
|
|
When I create an MCP client
|
|
And I call MCP tool "list_repos" with arguments {}
|
|
And I wait 0.15 seconds
|
|
Then the MCP client should be connected
|
|
|
|
# -------------------------------------------------------------------
|
|
# Shutdown
|
|
# -------------------------------------------------------------------
|
|
|
|
Scenario: Explicit shutdown stops the server
|
|
Given an MCP client config for "github" with lazy start enabled
|
|
And a mock MCP transport with tool "list_repos"
|
|
When I create an MCP client
|
|
And I call MCP tool "list_repos" with arguments {}
|
|
And I shutdown the MCP client
|
|
Then the MCP client state should be "stopped"
|
|
And the MCP client should not be connected
|
|
|
|
Scenario: Double shutdown is safe
|
|
Given an MCP client config for "github" with lazy start enabled
|
|
And a mock MCP transport with tool "list_repos"
|
|
When I create an MCP client
|
|
And I call MCP tool "list_repos" with arguments {}
|
|
And I shutdown the MCP client
|
|
And I shutdown the MCP client
|
|
Then the MCP client state should be "stopped"
|
|
|
|
# -------------------------------------------------------------------
|
|
# Health Monitoring
|
|
# -------------------------------------------------------------------
|
|
|
|
Scenario: Health check detects crash and auto-restarts
|
|
Given an MCP client config for "github" with health check interval 0.15 seconds
|
|
And a mock MCP transport with tool "list_repos" that crashes after 1 call
|
|
When I create an MCP client
|
|
And I call MCP tool "list_repos" with arguments {}
|
|
And I wait 1.0 seconds
|
|
Then the MCP client restart count should be greater than 0
|
|
|
|
Scenario: Health check disabled when interval is zero
|
|
Given an MCP client config for "github" with health check interval 0.0 seconds
|
|
And a mock MCP transport with tool "list_repos"
|
|
When I create an MCP client
|
|
And I call MCP tool "list_repos" with arguments {}
|
|
Then the MCP client health check failures should be 0
|
|
|
|
# -------------------------------------------------------------------
|
|
# Registry (Multiple Servers)
|
|
# -------------------------------------------------------------------
|
|
|
|
Scenario: Multiple MCP servers with independent lifecycles
|
|
Given an MCP registry
|
|
And an MCP client config for "github" with lazy start enabled
|
|
And a mock MCP transport with tool "list_repos"
|
|
When I register the MCP client in namespace "gh"
|
|
And I register another MCP client config for "jira" in namespace "jira"
|
|
Then the MCP registry should have 2 namespaces
|
|
And MCP namespace "gh" should not be connected
|
|
And MCP namespace "jira" should not be connected
|
|
|
|
Scenario: Registry call_tool starts specific server lazily
|
|
Given an MCP registry
|
|
And an MCP client config for "github" with lazy start enabled
|
|
And a mock MCP transport with tool "list_repos"
|
|
When I register the MCP client in namespace "gh"
|
|
And I call tool "list_repos" on MCP namespace "gh" with arguments {}
|
|
Then MCP namespace "gh" should be connected
|
|
|
|
Scenario: Registry shutdown_all stops all servers
|
|
Given an MCP registry with 2 running servers
|
|
When I shutdown all MCP servers
|
|
Then the MCP registry should have 2 namespaces
|
|
And all MCP servers should be stopped
|
|
|
|
# -------------------------------------------------------------------
|
|
# Capability Metadata
|
|
# -------------------------------------------------------------------
|
|
|
|
Scenario: Full capability metadata exposed after connect
|
|
Given an MCP client config for "github" with lazy start enabled
|
|
And a mock MCP transport with full capabilities
|
|
When I create an MCP client
|
|
And I explicitly start the MCP client
|
|
Then the MCP adapter capability metadata should have tools true
|
|
And the MCP adapter capability metadata should have resources true
|
|
And the MCP adapter capability metadata should have prompts true
|