Pass metadata context through tool pipeline to MCP calls (#1323)#1462
Pass metadata context through tool pipeline to MCP calls (#1323)#1462alexheifetz wants to merge 7 commits intomainfrom
Conversation
igordayen
left a comment
There was a problem hiding this comment.
commented on sonare violations
| toolDecorator: ((Tool) -> Tool)?, | ||
| inspectors: List<ToolLoopInspector>, | ||
| transformers: List<ToolLoopTransformer>, | ||
| toolCallContext: ToolCallContext, |
There was a problem hiding this comment.
This function has 8 parameters, which is greater than the 7 authorized.. mark as //NOSONAR or consider addition to decorator
embabel-agent-api/src/main/kotlin/com/embabel/agent/api/tool/ReplanningTools.kt
Show resolved
Hide resolved
|
parameter packing maybe addressed in the different PR |
There was a problem hiding this comment.
Pull request overview
This PR introduces ToolCallContext — an immutable, framework-agnostic key-value bag that carries out-of-band metadata (auth tokens, tenant IDs, correlation IDs) through the tool execution pipeline to MCP calls, resolving issue #1323. The context flows explicitly through Tool.call(input, context) without being exposed to the LLM's JSON schema.
Changes:
- Introduces
ToolCallContextclass with factory methods, merge semantics, and EMPTY singleton; adds a two-argcall(input, context)overload toToolinterface with auto-propagation viaDelegatingTool; injects context into@LlmToolmethods (both Kotlin and Java) while excluding from LLM-facing schema - Updates the tool loop pipeline (
DefaultToolLoop,ParallelToolLoop,ToolLoopFactory) and all decorator tools to propagateToolCallContext; bridges between Embabel and Spring AI contexts inSpringToolCallbackAdapter/SpringToolCallbackWrapper - Adds shell commands (
set-context,show-context,-cflag) for interactive context management,ToolCallContextMcpMetaConverterfor MCP boundary filtering, comprehensive documentation, and extensive test coverage
Reviewed changes
Copilot reviewed 33 out of 33 changed files in this pull request and generated 1 comment.
Show a summary per file
| File | Description |
|---|---|
ToolCallContext.kt |
New immutable key-value context class with factory, merge, and contains operations |
Tool.kt |
Adds two-arg call(input, context) default, ContextAwareFunction interface, and ContextAwareFunctionalTool |
DelegatingTool.kt |
Default context propagation through decorator chains |
MethodTool.kt |
Context injection for @LlmTool methods + schema exclusion for both Kotlin and Java |
ArtifactSinkingTool.kt |
Context-aware call override with inline refactor |
ReplanningTools.kt |
Context-aware call overrides for ReplanningTool and ConditionalReplanningTool |
ToolDecorators.kt |
All 6 decorator tools updated with two-arg call + inline refactor |
DefaultToolLoop.kt |
Uses two-arg tool.call(arguments, toolCallContext) for all tool invocations |
ParallelToolLoop.kt |
Passes toolCallContext through to parent DefaultToolLoop |
ToolLoopFactory.kt |
Adds toolCallContext parameter to factory interface |
ToolLoopLlmOperations.kt |
Resolves effective context from process + interaction levels |
LlmInteraction.kt |
Adds toolCallContext field for interaction-level context |
ProcessOptions.kt |
Adds toolCallContext property with Java-friendly withToolCallContext overloads |
SpringToolCallbackAdapter.kt |
Bridges between Embabel ToolCallContext and Spring AI ToolContext |
ObservabilityToolCallback.kt |
Forwards ToolContext through observation decorator |
OutputTransformingToolCallback.kt |
Forwards ToolContext through output transformation decorator |
ToolCallContextMcpMetaConverter.kt |
New allowlist/denylist filter for MCP metadata boundary (not yet wired) |
ShellCommands.kt |
New set-context/show-context commands and -c flag on execute |
commands.adoc |
Shell commands documentation |
reference/tools/page.adoc |
Comprehensive tool context reference documentation |
reference/agent-process/page.adoc |
ProcessOptions documentation update |
| Test files (8 files) | Comprehensive unit, integration, and Java interop tests |
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
| override fun call(input: String, context: ToolCallContext): Tool.Result = | ||
| delegate.call(input, context) |
There was a problem hiding this comment.
The new DelegatingTool.call(input, context) default forwards directly to delegate.call(input, context), which bypasses the behavior added in call(input) by several DelegatingTool implementations not updated in this PR:
ConditionalAwaitingTool(inAwaitingTools.kt): thedecider.evaluate()check is skipped when context is presentAssetAddingTool(inAssetAddingTool.kt): asset tracking is skipped when context is present
Since DefaultToolLoop.executeToolCall now always calls the two-arg tool.call(arguments, toolCallContext), these decorators will have their behavior silently bypassed at runtime. They need the same treatment as the decorators updated in this PR (override call(input, context) to apply their logic while forwarding context to the delegate).
There was a problem hiding this comment.
Pull request overview
Copilot reviewed 36 out of 36 changed files in this pull request and generated 3 comments.
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
embabel-agent-api/src/main/kotlin/com/embabel/agent/spi/loop/ToolLoopFactory.kt
Show resolved
Hide resolved
...gent-api/src/main/kotlin/com/embabel/agent/spi/support/springai/SpringToolCallbackAdapter.kt
Outdated
Show resolved
Hide resolved
embabel-agent-shell/src/test/kotlin/com/embabel/agent/shell/ShellCommandsContextTest.kt
Outdated
Show resolved
Hide resolved
Introduce ToolCallContext as an immutable, framework-agnostic key-value bag for passing out-of-band metadata (auth tokens, tenant IDs, correlation IDs) through the tool pipeline without polluting JSON input schemas. Core API: - ToolCallContext with merge, contains, and Map conversion - Tool interface two-arg call(input, context) with backward-compatible default - DelegatingTool default propagation through decorator chains - ContextAwareFunction for lambda-based context-aware tools Implementation: - MethodTool (Kotlin + Java): inject ToolCallContext, exclude from schema - ReplanningTool, ArtifactSinkingTool: context-aware overrides - DefaultToolLoop: accept and forward context on every invocation - SpringToolCallbackAdapter/Wrapper: bridge to/from Spring AI ToolContext - ProcessOptions: toolCallContext property with Java-friendly Map overload - ToolCallContextMcpMetaConverter: allowlist/denylist filtering (not yet wired) Tests: - ToolCallContext unit, flow, and Java interop tests - MethodTool context injection and schema exclusion (Kotlin + Java)
|



Summary
Introduces
ToolCallContext— an immutable, framework-agnostic key-value bag that carries out-of-band metadata (auth tokens, tenant IDs, correlation IDs) through the tool execution pipeline to MCP calls, without exposing it to the LLM.Resolves Issue #1323
Context Flow
Major Changes
New:
ToolCallContextImmutable typed key-value bag with merge semantics,
EMPTYsingleton, andtoMap()for Spring AI bridging.New:
Tool.call(input, context)overloadTwo-arg call method on
Toolinterface. Default discards context for full backward compatibility.Canonical
DelegatingToolcall patternDelegatingTool.call(String)now routes throughcall(String, ToolCallContext.EMPTY), making the two-arg method the single canonical entry point for decorator logic. All decorators override one method only —call(String, ToolCallContext). ArchUnit test (DelegatingToolArchitectureTest) runs on everymvn testto enforce this contract.Updated:
MethodToolcontext injection@LlmToolmethods can declare aToolCallContextparameter — framework injects it at call time and excludes it from the LLM-facing JSON schema. Works for both Kotlin and Java methods.Updated: Spring AI bridges
SpringToolCallbackAdapterandSpringToolCallbackWrapperconvert betweenToolCallContextand Spring AIToolContextin both directions.SpringToolCallbackAdapterdeduplicated to a single call path.Updated:
ProcessOptionsNew
toolCallContextproperty withwithToolCallContext(Map)Java-friendly overload.New:
ToolCallContextMcpMetaConverterAllowlist/denylist filter controlling which context entries cross the MCP boundary. Defined but not yet wired — integration pending Spring AI MCP
_metafinalization.Not Yet Included
ToolCallContextMcpMetaConverterwiring intoSpringToolCallbackWrapperPromptRunner-level context enrichment (per-interaction override)