Dynamic discovery capability of the MCP protocol

Written by
Clara Bennett
Updated on:July-09th-2025
Recommendation

MCP protocol dynamic discovery capability, a new breakthrough in the interaction between AI models and tools.

Core content:
1. Differences between MCP and traditional APIs: Introduction to dynamic discovery capabilities
2. Implementation details of dynamic discovery tools and services
3. Code examples: Server-side and client-side interaction demonstration

Yang Fangxian
Founder of 53AI/Most Valuable Expert of Tencent Cloud (TVP)

Compared with traditional APIs, an important capability of MCP (Model Context Protocol) is dynamic discovery : MCP allows AI models to dynamically discover and interact with available tools without the need to pre-set fixed code for each integration.

This dynamic discovery is divided into two levels:

  • Dynamic tool discovery : Discover tools on a specified MCP server, always supported.

  • Dynamic discovery service : defines how clients discover and connect to remote MCP servers. This is planned to be completed in the first half of 25 years.


1. Tool discovery and update

MCP supports dynamic tool discovery.

https://modelcontextprotocol.io/docs/concepts/tools#tool-discovery-and-updates

1. The client can list available tools at any time

The following is a simple code example that demonstrates the dynamic discovery feature, both on the server and client side:

Server-side code example (server.py)

from  mcp . server . fastmcp  import  FastMCP

# Create an MCP server
mcp  =  FastMCP ( "Demo" )

# Add an addition tool
@mcp . tool ( )
def  add ( a : int ,  b : int ) - > int :
    """Add two numbers"""
    return  a  +  b

# Add a dynamic greeting resource
@mcp . resource ( "greeting://{name}" )
def  get_greeting ( name : str ) - > str :
    """Get a personalized greeting"""
    return  f"Hello,  { name } !"

# Run the server
if  __name__  == "__main__" :
    mcp . run ( )

Client code example (main.py)

import  asyncio
from  mcp  import  ClientSession ,  StdioServerParameters
from  mcp . client . stdio  import  stdio_client

async  def  main ( ) :
    # Configure the server
    server_params  =  StdioServerParameters (
        command = "python" ,
        args = [ "server.py" ]
    )

    # Create a client session
    async  with  stdio_client ( server_params as  ( read ,  write ) :
        async  with  ClientSession ( read ,  write as  session :
            await  session.initialize ( )

            # List the tools provided by the server
            tools  await  session . list_tools ( )
            print ( "Available tools:" ,  tools )

            # Execute tool
            result  await  session . call_tool ( "add" , { "a" : 5 , "b" : 3 } )
            print ( "Result of add tool:" ,  result )

            # Get dynamic greetings
            greeting  await  session . read_resource ( "greeting://Alice" )
            print ( "Greeting:" ,  greeting )

if  __name__  == "__main__" :
    asyncio . run ( main ( ) )

Here, a Stdio type server is used. MCP currently supports two communication mechanisms. The difference between them can be seen in  the communication mechanism of MCP .

The above code examples show how to dynamically create tools and resources on the server side and dynamically discover and call these tools and resources on the client side.


2. The server notifies the client of tool changes

When tools change, the server can use notifications/tools/list_changed Notify the client

This will allow you to:

  • Tools can be added or removed at runtime
  • Tool definitions can be updated (although this should be done with caution)

Code example, a new multiplication tool is added to the server to notify the client of the change

The initial version of the server code is the same as the previous example, and changes to the following:

from  mcp . server . fastmcp  import  FastMCP
from  mcp  import  types

# Create an MCP server
mcp  =  FastMCP ( "Demo" )

# Addition tool
@mcp . tool ( )
def  add ( a : int ,  b : int ) - > int :
    """Add two numbers"""
    return  a  +  b

# Dynamic Greeting Resources
@mcp . resource ( "greeting://{name}" )
def  get_greeting ( name : str ) - > str :
    """Get a personalized greeting"""
    return  f"Hello,  { name } !"

# Add a multiplication tool
@mcp . tool ( )
def  multiply ( a : int ,  b : int ) - > int :
    """Multiply two numbers"""
    return  a  *  b

# Notify the client every time the tool changes
async  def  notify_tool_changes ( ) :
    await  mcp . notify ( types . ListToolsChangedNotification ( ) )

# Run the server
if  __name__  == "__main__" :
    import  asyncio

    async  def  main ( ) :
        await  notify_tool_changes ( )
        mcp . run ( )

    asyncio . run ( main ( ) )

Client code example (main.py)

The client will listen to tool change notifications and dynamically update the tool list.

import  asyncio
from  mcp  import  ClientSession ,  StdioServerParameters
from  mcp . client . stdio  import  stdio_client

async  def  main ( ) :
    # Configure the server
    server_params  =  StdioServerParameters (
        command = "python" ,
        args = [ "server.py" ]
    )

    # Create a client session
    async  with  stdio_client ( server_params as  ( read ,  write ) :
        async  with  ClientSession ( read ,  write as  session :
            await  session.initialize ( )

            # List the tools provided by the server
            tools  await  session . list_tools ( )
            print ( "Available tools:" ,  tools )

            # Listen for tool change notifications
            async  def  on_tool_change ( notification ) :
                print ( "Tools have changed:" ,  notification )
                # List updated tools
                updated_tools  await  session . list_tools ( )
                print ( "Updated tools:" ,  updated_tools )

            session .subscribe ( "notifications/tools/list_changed " ,  on_tool_change )

            # Execute the addition tool
            result  await  session . call_tool ( "add" , { "a" : 5 , "b" : 3 } )
            print ( "Result of add tool:" ,  result )

            # Execute the multiplication tool
            result  await  session . call_tool ( "multiply" , { "a" : 5 , "b" : 3 } )
            print ( "Result of multiply tool:" ,  result )

            # Get dynamic greetings
            greeting  await  session . read_resource ( "greeting://Alice" )
            print ( "Greeting:" ,  greeting )

if  __name__  == "__main__" :
    asyncio . run ( main ( ) )

The above code example shows how to add a new multiplication tool on the server side and notify the client of these changes. The client will listen to these notifications and dynamically update the tool list.


2. Dynamic Discovery Service

According to the plan, it will be completed in the first half of 25 years, see: https://modelcontextprotocol.io/development/roadmap . 

According to the discussion here https://github.com/modelcontextprotocol/specification/discussions/69 , is to prepare:  

This limitation was solved by using a protocol that overlaps with MCP and using custom URIs, which allows processes such as pasting a URI in the chat and letting the LLM decide if it needs to integrate with the tool, when to use it, etc...

The general process is:

  1. The agent encounters a custom URI, such as mcp://api.myservice.com

  2. The agent parses the URI and gets detailed information about the service. For example, it performs an HTTP GET request to a predefined endpoint, such as: https://api.myservice.com/llms.txt 

  3. The service responds with a JSON or text file containing all relevant metadata, including: authentication, description of the service and its capabilities, list of features/tools/resources provided, full API documentation, pricing, payment methods or details of supported payment protocols.

  4. Based on the information retrieved above, the Agent performs permission verification, function mapping, and starts interaction.

Through the above method, dynamic discovery of services is completed.


Summary: Dynamic discovery is a key capability of MCP

Essentially: MCP comes in handy when you want to introduce tools for an Agent that you don't control.

As for how to let uncontrollable agents discover your services, dynamic discovery is a necessary capability. From the above explanation, it can be seen that MCP will soon be able to improve this capability, which is worth looking forward to.