Dynamic discovery capability of the MCP protocol

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
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:
The agent encounters a custom URI, such as mcp://api.myservice.com
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
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.
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.