sangkyoonnam opened a new pull request, #1373: URL: https://github.com/apache/flink-agents/pull/1373
Linked issue: #606 ### Purpose of change Agent plans can be built and serialized without a reachable MCP server. Discovery runs when the operator starts, so the deployed task uses the server's current tools and prompts. This continues the Java implementation from #639 by @yanand0909 and adds the Python path. #### Runtime flow Plan construction records server descriptors. Java operator initialization and Python runner-context initialization discover resources into their resource caches; tool calls resolve them there. Internal sub-agent caches initialize both language paths before the first action, including children that declare MCP servers without AGENT resources. Python MCP tools/prompts are also registered as Java-side wrappers for Java actions. Caches retain servers even when discovery returns no tools or prompts, and close them during shutdown. #### Key decisions Discovery remains synchronous and fails startup on errors. Server-specific timeout and Java retry settings bound requests. Dynamic refresh and graceful startup without a declared server are outside this change. ### Behavioral Semantics #### Interactions | Declaration / result | Behavior | | --- | --- | | Java or Python MCP declaration; plan construction | Preserve the server descriptor without connecting | | Python YAML alias at shared or agent scope | Preserve the declaration and discover through the same runtime path | | Successful discovery | Cache tools and prompts; attach server identity to tools | | No tools and no prompts | Retain and close the server itself | | Duplicate tool/prompt, including an existing Java resource seen through the Python bridge | Reject startup without overwriting the existing resource | | Tool name starts with `_subagent_` | Reject the reserved name | | Server does not answer | Fail discovery after its configured request timeout/retries | #### Contracts and failures Compilation makes no discovery calls. Discovered resources become available from the corresponding cache. Duplicate names are checked within each resource namespace, so a tool and prompt may share a name. A failed Python runner or child-cache discovery closes resources created by that attempt and preserves the discovery error; a Java child-cache failure also closes its partial cache. Normal operator shutdown closes servers that advertised nothing. No discovery error silently degrades into a partial tool set. Endpoint/authentication errors remain errors; there is no new fallback. Server resources are rediscovered on restart, rather than frozen in the serialized plan. ### Tests | Contract | Test | | --- | --- | | No compile-time network | `AgentPlanMCPDeferredDiscoveryTest`; `test_mcp_server_is_registered_without_contacting_it` | | Runtime tools/prompts and server identity | `JavaMCPResourceDiscoveryTest`; `test_startup_discovers_and_registers_tools_and_prompts` | | Empty-server client lifetime | `JavaMCPStartupIntegrationTest.emptyDiscoveryClosesTheRealClientSession`; `test_server_is_closed_with_the_cache_even_when_nothing_is_discovered` | | Operator startup/close wiring | `ActionExecutionOperatorTest.testOpenDiscoversJavaMCPServerAndCloseReleasesIt` | | Actual HTTP request timeout | Java `startupTimesOutWhenTheServerAcceptsButNeverAnswersInitialize`; Python `test_real_startup_timeout_without_a_json_rpc_response` | | Shared/local YAML declarations | `test_yaml_shared_and_local_servers_are_discovered_only_at_startup` | | Duplicate and reserved names | `JavaMCPResourceDiscoveryTest`, `PythonMCPResourceDiscoveryTest`, `test_mcp_resource_discovery.py` | | Java child-cache discovery and close | `childScopeDiscoversOnceAndReleasesItsEmptyServer` | | Python MCP-only child startup and Java access | `mcpOnlyChildInitializesPythonAndExposesToolsToJavaBeforeActions`; `test_child_mcp_is_discovered_before_the_first_action` | | Python construction failure cleanup | `test_runner_context_creation_fails_when_the_server_is_unreachable`; `test_failed_child_scope_discovery_closes_the_new_cache` | On current main, `test_mcp_resource_discovery.py`, `test_agent_plan.py`, `integrations/mcp/tests/test_mcp.py` and `api/yaml/tests/test_loader.py` pass in three runs, as does the full Python unit suite. The Java tests in the table plus `ActionExecutionOperatorTest`, `ResourceCacheTest` and the internal sub-agent tests pass on JDK17 and JDK21, and `tools/lint.sh -c` passes on JDK11. Loopback HTTP tests require no external MCP service. Not verified: full cluster end-to-end deployment, TLS/OAuth server integration, or real Pemja transport for the mixed-language child test (the bridge contract is mocked, and Python scope behavior is tested directly). Python actions calling Java-owned MCP tools were not supported by the existing resource-provider bridge and are not added here. <details> <summary>Regression evidence</summary> Before the rebase onto current main, the controls ran against upstream main 64e9e0f9: the Python compile-time discovery test fails behaviorally there in three runs, then passes with this change. Removing only the server-cache insertion reproduces an unclosed real empty MCP session in three runs. Omitting the child Python initialization hook also fails the MCP-only child regression. These controls test network invocation, client shutdown, and startup wiring. Java API/plan/runtime modules were rebuilt from source for JDK17 and JDK21 tests. </details> ### API MCP declaration syntax is unchanged. Python already rejected duplicate and reserved names at plan compilation; those checks now run at startup. Java already rejected reserved `_subagent_` names, but registered duplicate tool or prompt names last-wins; a duplicate now fails startup instead of silently replacing a resource. Plan JSON no longer embeds remotely discovered tool/prompt providers. Python's configured `timeout` also bounds client-session requests, including discovery. Existing server authentication and Java retry settings remain in effect. ### Documentation - [ ] `doc-needed` - [ ] `doc-not-needed` - [x] `doc-included` ### Was this patch authored or co-authored using generative AI tooling? - [x] Yes - [ ] No Generated-by: Claude Code 2.1.319 (Claude Opus 5.5) Generated-by: Codex CLI 0.166.0 (gpt-6-astra) The first commit is @yanand0909's change from #639 with its original author and date; only the conflict resolution and the `provide(ResourceContext)` test adaptation were changed, as its message and its own `Generated-by` line say. The fix for the #639 review comments and everything else are in the second commit. -- This is an automated message from the Apache Git Service. To respond to the message, please log on to GitHub and use the URL above to go to the specific comment. To unsubscribe, e-mail: [email protected] For queries about this service, please contact Infrastructure at: [email protected]
