Skip to content

Conversation

@oujezdsky
Copy link

Description

This pull request introduces a set of 7 new tools to support the OpenSearch Agentic Memory API (released in 3.3). This allows agents using the MCP server to create, manage, and interact with agentic memories.

Key changes include:

  • New Tools: Adds CreateAgenticMemoryContainerTool, CreateAgenticMemorySessionTool, AddAgenticMemoriesTool, GetAgenticMemoryTool, UpdateAgenticMemoryArgsTool, DeleteAgenticMemoryByIDTool, DeleteAgenticMemoryByQueryTool, and SearchAgenticMemoryTool.
  • Pydantic Models: Implements Pydantic V2 models for all new tool arguments.
  • Async Implementation: The core logic is implemented as async helper functions in src/opensearch/helper.py.
  • Error Handling: Introduces a new HelperOperationError to provide better, contextualized error logging.
  • Testing: Adds a set of unit tests for the new tools, using pytest.mark.parametrize for all happy paths and pytest.raises for Pydantic validation.

Issues Resolved

Closes #113

By submitting this pull request, I confirm that my contribution is made under the terms of the Apache 2.0 license.
For more information on following Developer Certificate of Origin and signing off your commits, please check here.

Signed-off-by: Jiri Oujezdsky <oujezdsky2@gmail.com>
Signed-off-by: Jiri Oujezdsky <oujezdsky2@gmail.com>
Signed-off-by: Jiri Oujezdsky <oujezdsky2@gmail.com>
Signed-off-by: Jiri Oujezdsky <oujezdsky2@gmail.com>
Signed-off-by: Jiri Oujezdsky <oujezdsky2@gmail.com>
Signed-off-by: Jiri Oujezdsky <oujezdsky2@gmail.com>
Signed-off-by: Jiri Oujezdsky <oujezdsky2@gmail.com>
Signed-off-by: Jiri Oujezdsky <oujezdsky2@gmail.com>
Signed-off-by: Jiri Oujezdsky <oujezdsky2@gmail.com>
…uster_name param

Signed-off-by: Jiri Oujezdsky <oujezdsky2@gmail.com>
Signed-off-by: Jiri Oujezdsky <oujezdsky2@gmail.com>
Signed-off-by: Jiri Oujezdsky <oujezdsky2@gmail.com>
Signed-off-by: Jiri Oujezdsky <oujezdsky2@gmail.com>
Signed-off-by: Jiri Oujezdsky <oujezdsky2@gmail.com>
@oujezdsky oujezdsky marked this pull request as draft November 18, 2025 14:43
Signed-off-by: Jiri Oujezdsky <oujezdsky2@gmail.com>
Signed-off-by: Jiri Oujezdsky <oujezdsky2@gmail.com>
…Tool

Signed-off-by: Jiri Oujezdsky <oujezdsky2@gmail.com>
Signed-off-by: Jiri Oujezdsky <oujezdsky2@gmail.com>
…moryTool

Signed-off-by: Jiri Oujezdsky <oujezdsky2@gmail.com>
@oujezdsky oujezdsky marked this pull request as ready for review November 18, 2025 19:05
@oujezdsky
Copy link
Author

Hello,

This PR is ready for review again.

5 new commits that address issues:

  • Fixed packaging by moving exceptions.py.
  • Added compatibility checks to all Agentic Memory tools.
  • Corrected naming for UpdateAgenticMemoryTool (in code and CHANGELOG).
  • Fixed CreateAgenticMemoryContainerTool validation by changing the strategy field from invalid strategy_type to the correct type.

Thank you for the review and apologies for the inconvenience.

@rithin-pullela-aws
Copy link
Collaborator

Hi @oujezdsky thanks for the PR!

Few high level thoughts before I review the PR:

  • Can we fix the failing tests?
  • Can we add the tools in Readme and Userguide?
  • Looks like the tool_params.py and tool.py have a lot of lines of code added. Can we create separate files for agentic_memory related tools and import the tools into tools.py ? I believe this would make the code more readable

@oujezdsky
Copy link
Author

oujezdsky commented Nov 18, 2025

Hello @rithin-pullela-aws,
Yes, I will look at the failed tests (seemed OK in my dev env.) and at the separation of agentic_memory tools.

Regarding the Readme and Userguide—no problem, I’ll add the new tools there as well.
I originally thought it was outside the scope of this issue, and I had a similar assumption about adding the new AM tools to src/tools/tool_filter.py, specifically inside process_tool_filter() function and its core_tools. Without that, opensearch-mcp-server-py won’t detect them. Should I add them there as well?

And if so, would you prefer that I include them directly in core_tools, or should I create a separate group like agentic_memory_tools and follow the same pattern used for core_tools?

thanks

@oujezdsky oujezdsky marked this pull request as draft November 18, 2025 20:10
…Tool

Signed-off-by: Jiri Oujezdsky <oujezdsky2@gmail.com>
Signed-off-by: Jiri Oujezdsky <oujezdsky2@gmail.com>
Signed-off-by: Jiri Oujezdsky <oujezdsky2@gmail.com>
Signed-off-by: Jiri Oujezdsky <oujezdsky2@gmail.com>
@oujezdsky
Copy link
Author

This PR has been updated to address all comments and is now ready for re-review.

  1. Refactoring and Readability

    • Solution: All Agentic Memory implementation logic (functions, Pydantic models, constants) has been extracted from the large files (tools.py and tool_params.py) into a new, dedicated Python package: src/tools/agentic_memory/.

    • This package now segregates logic into actions.py and data models into params.py.

  2. Fixing Failing Tests (Version Compatibility)

    • Problem: The new tools required OpenSearch 3.3.0+, but the existing test class (TestTools) was mocked to version 2.19.0 in its setup_method. The check_tool_compatibility function correctly raised an incompatibility error, causing all Agentic Memory tests to fail.

    • Solution: To fix this without affecting the current test environment, I have isolated all Agentic Memory tests into a new file: tests/tools/test_agentic_memory_tools.py. The test class within this file now defines its own isolated setup_method, mocking the OpenSearch version as 3.3.0. This ensures the new feature is tested against the correct version while preserving the existing test baseline.

  3. Documentation Updates (README & User Guide)

    • README.md: Updated the "Available Tools" section, adding the full list of Agentic Memory tools and their parameter definitions.

    • USER_GUIDE.md: Added a new chapter "Agentic Memory Usage" with a detailed 5-step workflow (Create, Session, Add, Search, Update/Delete) using the "Vacation Planner" example.

@oujezdsky oujezdsky marked this pull request as ready for review November 19, 2025 12:36
Copy link
Collaborator

@nathaliellenaa nathaliellenaa left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks for raising this PR @oujezdsky! Added some comments

CHANGELOG.md Outdated

### Fixed
- Fix AWS auth issues for cat based tools, pin OpenSearchPy to 2.18.0 ([#135](https://github.com/opensearch-project/opensearch-mcp-server-py/pull/135))
- Add new toolset for the OpenSearch Agentic Memory API: `CreateAgenticMemoryContainerTool`, `CreateAgenticMemorySessionTool`, `AddAgenticMemoriesTool`, `GetAgenticMemoryTool`, `UpdateAgenticMemoryTool`, `DeleteAgenticMemoryByIDTool`, `DeleteAgenticMemoryByQueryTool`, and `SearchAgenticMemoryTool`. ([#113](https://github.com/opensearch-project/opensearch-mcp-server-py/pull/138))
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
- Add new toolset for the OpenSearch Agentic Memory API: `CreateAgenticMemoryContainerTool`, `CreateAgenticMemorySessionTool`, `AddAgenticMemoriesTool`, `GetAgenticMemoryTool`, `UpdateAgenticMemoryTool`, `DeleteAgenticMemoryByIDTool`, `DeleteAgenticMemoryByQueryTool`, and `SearchAgenticMemoryTool`. ([#113](https://github.com/opensearch-project/opensearch-mcp-server-py/pull/138))
- Add new toolset for the OpenSearch Agentic Memory API: `CreateAgenticMemoryContainerTool`, `CreateAgenticMemorySessionTool`, `AddAgenticMemoriesTool`, `GetAgenticMemoryTool`, `UpdateAgenticMemoryTool`, `DeleteAgenticMemoryByIDTool`, `DeleteAgenticMemoryByQueryTool`, and `SearchAgenticMemoryTool`. ([#138](https://github.com/opensearch-project/opensearch-mcp-server-py/pull/138))

README.md Outdated
- `messages` (conditional): A list of messages. Required when `payload_type` is `conversational`. *(Body Parameter)*
- `structured_data` (conditional): Structured data content. Required when `payload_type` is `data`. *(Body Parameter)*
- `binary_data` (optional): Binary data content encoded as a Base64 string for binary payloads. *(Body Parameter)*
- `payload_type` (required): The type of payload. Valid values are `conversational` or `data`. See [See Payload types](https://docs.opensearch.org/latest/ml-commons-plugin/agentic-memory/#payload-types). *(Body Parameter)*
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
- `payload_type` (required): The type of payload. Valid values are `conversational` or `data`. See [See Payload types](https://docs.opensearch.org/latest/ml-commons-plugin/agentic-memory/#payload-types). *(Body Parameter)*
- `payload_type` (required): The type of payload. Valid values are `conversational` or `data`. See [Payload types](https://docs.opensearch.org/latest/ml-commons-plugin/agentic-memory/#payload-types). *(Body Parameter)*

README.md Outdated
- `namespace` (optional): The [namespace](https://docs.opensearch.org/latest/ml-commons-plugin/agentic-memory/#namespaces) context for organizing memories (for example, `user_id`, `session_id`, or `agent_id`). If `session_id` is not specified in the namespace field and `disable_session`: `false` (default is `true`), a new session with a new session ID is created. *(Body Parameter)*
- `metadata` (optional): Additional metadata for the memory (for example, `status`, `branch`, or custom fields). *(Body Parameter)*
- `tags` (optional): Tags for categorizing memories. *(Body Parameter)*
- `infer` (optional): Whether to use an LLM to extract key information (default: `false`). When `true`, the LLM extracts key information from the original text and stores it as a memory. [See Inference mode](https://docs.opensearch.org/latest/ml-commons-plugin/agentic-memory/#inference-mode). *(Body Parameter)*
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
- `infer` (optional): Whether to use an LLM to extract key information (default: `false`). When `true`, the LLM extracts key information from the original text and stores it as a memory. [See Inference mode](https://docs.opensearch.org/latest/ml-commons-plugin/agentic-memory/#inference-mode). *(Body Parameter)*
- `infer` (optional): Whether to use an LLM to extract key information (default: `false`). When `true`, the LLM extracts key information from the original text and stores it as a memory. See [Inference mode](https://docs.opensearch.org/latest/ml-commons-plugin/agentic-memory/#inference-mode). *(Body Parameter)*

"""Create a new agentic memory session in the specified memory container.
Args:
args: CreateSessionArgs containing memory_container_id and optional session_id, summary, metadata, namespace
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Nit:

Suggested change
args: CreateSessionArgs containing memory_container_id and optional session_id, summary, metadata, namespace
args: CreateAgenticMemorySessionArgs containing memory_container_id and optional session_id, summary, metadata, namespace

return [{'type': 'text', 'text': f'Error updating memory: {str(error_to_report)}'}]


async def delete_agentic_memoryby_ID_tool(
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Function name be should be delete_agentic_memory_by_id_tool to make it consistent with other function names

Comment on lines 43 to 48
if container_id:
message = f'Successfully created memory container. ID: {container_id}. Response: {json.dumps(result)}'
else:
message = (
f'Memory container created, but no ID was returned. Response: {json.dumps(result)}'
)
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Should we keep a consistent message formatting? We can follow the format in create_agentic_memory_session_tool, for example

message = (
            f'Successfully created memory container. ID: {container_id}. Response: {json.dumps(result)}'
            if container_id
            else f'Memory container created, but no ID was returned. Response: {json.dumps(result)}'
)

@model_validator(mode='after')
def validate_embedding_configuration(self) -> 'AgenticMemoryConfigurationArgs':
"""Validate embedding model configuration."""
if self.embedding_model_type == 'TEXT_EMBEDDING' and self.embedding_dimension is None:
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can we do if self.embedding_model_type == EmbeddingModelType.text_embedding?

'function': create_agentic_memory_session_tool,
'args_model': CreateAgenticMemorySessionArgs,
'min_version': '3.3.0', # Agentic memory APIs requires OpenSearch 3.3+
'http_methods': 'UPDATE',
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The http_methods should be the actual REST API method being called, so in this case it should be POST. The same should be applied for the other agentic memory tools

Signed-off-by: Jiri Oujezdsky <oujezdsky2@gmail.com>
Signed-off-by: Jiri Oujezdsky <oujezdsky2@gmail.com>
Signed-off-by: Jiri Oujezdsky <oujezdsky2@gmail.com>
…tency

Signed-off-by: Jiri Oujezdsky <oujezdsky2@gmail.com>
Signed-off-by: Jiri Oujezdsky <oujezdsky2@gmail.com>
Signed-off-by: Jiri Oujezdsky <oujezdsky2@gmail.com>
@oujezdsky
Copy link
Author

@nathaliellenaa Thanks for the feedback! I've addressed all the comments.

@jiapingzeng
Copy link
Contributor

Thanks for the PR! Overall the changes look good to me from a tools perspective.

One question is that when using these MCP tools with an agent, e.g. Claude desktop or Q/Kiro CLI, is it able to recognize that it needs to create a container before it can use the other Agentic Memory tools? Or would the user need to guide it through prompt to create container then add/get/update/delete memory?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

[FEATURE] Add memory tools

4 participants