Skip to content

Python: Fix: Prevent duplicate MCP tools and prompts (#1876) - #1890

Merged
moonbox3 merged 13 commits into
microsoft:mainfrom
ishanrajsingh:fix/mcp-duplicate-tools-1876
Nov 14, 2025
Merged

Python: Fix: Prevent duplicate MCP tools and prompts (#1876)#1890
moonbox3 merged 13 commits into
microsoft:mainfrom
ishanrajsingh:fix/mcp-duplicate-tools-1876

Conversation

@ishanrajsingh

Copy link
Copy Markdown
Contributor
  • Added deduplication logic in MCPTool.load_tools() method
  • Added deduplication logic in MCPTool.load_prompts() method
  • Track existing function names before loading from MCP server
  • Skip tools/prompts that are already registered in _functions list
  • Prevents 400 error from Azure AI Foundry caused by duplicate tool names

The issue occurred because load_tools() was being called multiple times (during connect() and by notification handlers), causing tools to be appended without duplicate checking.

Changes made:

  1. In load_tools(): Added existing_names set to track registered functions
  2. In load_tools(): Added check to skip tools already in existing_names
  3. In load_prompts(): Applied same deduplication pattern

Testing:

  • Created unit test verifying deduplication logic
  • Confirmed duplicates are skipped correctly
  • Confirmed new functions are added correctly
  • Prevents duplicate tool names being sent to LLM

Fixes #1876

@markwallace-microsoft markwallace-microsoft added the python Usage: [Issues, PRs], Target: Python label Nov 4, 2025
@ishanrajsingh ishanrajsingh changed the title Fix: Prevent duplicate MCP tools and prompts (#1876) Fix: Prevent duplicate MCP tools and prompts Nov 4, 2025
@github-actions github-actions Bot changed the title Fix: Prevent duplicate MCP tools and prompts Python: Fix: Prevent duplicate MCP tools and prompts (#1876) Nov 4, 2025
Comment thread python/packages/core/agent_framework/_mcp.py
Comment thread python/packages/core/tests/test_mcp_fix.py Outdated

@ishanrajsingh ishanrajsingh left a comment

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

Address review feedback: Prevent multiple calls to load_tools and load_prompts

Comment thread python/packages/core/agent_framework/_mcp.py Outdated
Comment thread python/packages/core/agent_framework/_mcp.py Outdated
Comment thread python/packages/core/agent_framework/_mcp.py Outdated
@markwallace-microsoft

markwallace-microsoft commented Nov 4, 2025

Copy link
Copy Markdown
Contributor

Python Test Coverage

Python Test Coverage Report •
FileStmtsMissCoverMissing
packages/core/agent_framework
   _mcp.py3485883%140, 150–151, 172, 197, 212, 218, 222, 224, 308, 335, 369–370, 372–380, 382–384, 387–388, 434, 449, 467, 508, 521, 524–525, 529, 539, 563, 566–567, 571, 581, 612, 631, 633, 640–641, 660, 662, 668–671, 688–692, 820
TOTAL13047194385% 

Python Unit Test Overview

Tests Skipped Failures Errors Time
1743 107 💤 0 ❌ 0 🔥 35.549s ⏱️

@ishanrajsingh ishanrajsingh left a comment

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

Address review feedback from @eavanvalkenburg : Move flag checks to connect() and remove comment

Comment thread python/packages/core/agent_framework/_mcp.py
Comment thread python/packages/core/agent_framework/_mcp.py

@ishanrajsingh ishanrajsingh left a comment

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

The mentioned changes have been comitted and addresses review feedback from @eavanvalkenburg

@eavanvalkenburg

Copy link
Copy Markdown
Member

@ishanrajsingh there are some failures in the CI, please rebase from main and then we'll run everything again, thanks!

- Added deduplication logic in MCPTool.load_tools() method
- Added deduplication logic in MCPTool.load_prompts() method
- Track existing function names before loading from MCP server
- Skip tools/prompts that are already registered in _functions list
- Prevents 400 error from Azure AI Foundry caused by duplicate tool names

The issue occurred because load_tools() was being called multiple times
(during connect() and by notification handlers), causing tools to be
appended without duplicate checking.

Changes made:
1. In load_tools(): Added existing_names set to track registered functions
2. In load_tools(): Added check to skip tools already in existing_names
3. In load_prompts(): Applied same deduplication pattern

Testing:
- Created unit test verifying deduplication logic
- Confirmed duplicates are skipped correctly
- Confirmed new functions are added correctly
- Prevents duplicate tool names being sent to LLM

Fixes microsoft#1876
…d_prompts

- Added _tools_loaded and _prompts_loaded flags to MCPTool class
- Modified load_tools() to check if already loaded and return early
- Modified load_prompts() to check if already loaded and return early
- Moved test cases from test_mcp_fix.py to test_mcp.py
- Added tests for multiple call prevention
- Deleted separate test_mcp_fix.py file

Addresses review feedback from @eavanvalkenburg:
- Prevents accidental multiple calls to load_tools()
- Prevents accidental multiple calls to load_prompts()
- Test file now in proper location (test_mcp.py)
…ments

- Removed verbose comments from code
- Moved _tools_loaded and _prompts_loaded checks to connect() method
- Allows manual calls to load_tools() and load_prompts() for updates
- Updated tests to reflect new behavior
- connect() now prevents duplicate loading during connection
- Users can still manually call load_tools()/load_prompts() to refresh

Addresses feedback from @eavanvalkenburg
auto-merge was automatically disabled November 6, 2025 16:18

Head branch was pushed to by a user without write access

@ishanrajsingh
ishanrajsingh force-pushed the fix/mcp-duplicate-tools-1876 branch from da5de39 to b02a941 Compare November 6, 2025 16:18
- Applied black formatting
- Fixed ruff linting issues
- All tests passing locally
@eavanvalkenburg

Copy link
Copy Markdown
Member

you need to rerun uv lock @ishanrajsingh

@ishanrajsingh

Copy link
Copy Markdown
Contributor Author

I've re-run uv lock @eavanvalkenburg as per the feedback.
The lockfile is now fresh and dependencies are stable (266 packages resolved).
Ready for CI checks to proceed.

@ishanrajsingh

Copy link
Copy Markdown
Contributor Author

I have run the pre commit checks locally and they have passed. I think the CI checks should pass now and there should not be any failure @eavanvalkenburg .

@moonbox3
moonbox3 added this pull request to the merge queue Nov 14, 2025
Merged via the queue into microsoft:main with commit 36c1217 Nov 14, 2025
23 checks passed
arisng pushed a commit to arisng/agent-framework that referenced this pull request Feb 2, 2026
…microsoft#1890)

* Fix: Prevent duplicate MCP tools and prompts (microsoft#1876)

- Added deduplication logic in MCPTool.load_tools() method
- Added deduplication logic in MCPTool.load_prompts() method
- Track existing function names before loading from MCP server
- Skip tools/prompts that are already registered in _functions list
- Prevents 400 error from Azure AI Foundry caused by duplicate tool names

The issue occurred because load_tools() was being called multiple times
(during connect() and by notification handlers), causing tools to be
appended without duplicate checking.

Changes made:
1. In load_tools(): Added existing_names set to track registered functions
2. In load_tools(): Added check to skip tools already in existing_names
3. In load_prompts(): Applied same deduplication pattern

Testing:
- Created unit test verifying deduplication logic
- Confirmed duplicates are skipped correctly
- Confirmed new functions are added correctly
- Prevents duplicate tool names being sent to LLM

Fixes microsoft#1876

* Address review feedback: Prevent multiple calls to load_tools and load_prompts

- Added _tools_loaded and _prompts_loaded flags to MCPTool class
- Modified load_tools() to check if already loaded and return early
- Modified load_prompts() to check if already loaded and return early
- Moved test cases from test_mcp_fix.py to test_mcp.py
- Added tests for multiple call prevention
- Deleted separate test_mcp_fix.py file

Addresses review feedback from @eavanvalkenburg:
- Prevents accidental multiple calls to load_tools()
- Prevents accidental multiple calls to load_prompts()
- Test file now in proper location (test_mcp.py)

* Address review feedback: Move flag checks to connect() and remove comments

- Removed verbose comments from code
- Moved _tools_loaded and _prompts_loaded checks to connect() method
- Allows manual calls to load_tools() and load_prompts() for updates
- Updated tests to reflect new behavior
- connect() now prevents duplicate loading during connection
- Users can still manually call load_tools()/load_prompts() to refresh

Addresses feedback from @eavanvalkenburg

* Fix: Code quality and formatting issues

- Applied black formatting
- Fixed ruff linting issues
- All tests passing locally

* chore: Re-run uv lock per review request

* Apply pre-commit formatting: consolidate type annotations

- Consolidate multi-line type annotations to single line
- Remove unnecessary parentheses
- Apply ruff format and security checks
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

python Usage: [Issues, PRs], Target: Python

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Python: When using the MCPStreamableHTTPTool with a ChatAgent, it advertises duplicate tools to the LLM, causing a failure.

5 participants