Support "dynamic servers"?
Enhancement Description
Is it possible to use this framework to build "dynamic servers" as documented in the official TypeScript SDK? https://github.com/modelcontextprotocol/typescript-sdk/tree/main?tab=readme-ov-file#dynamic-servers
Use Case
My organization is interested in building an MCP Server that provides more structure/predefined workflow to LLM to by changing/adding/removing the available tools depending on some internal state.
Proposed Implementation
Hi @minznerjosh! I'm pretty sure adding tools will work out-of-the-box. We don't currently have a public method for removing tools, but I think we could add it as an enhancement (you could try deleting the corresponding entry from mcp._tool_manager._tools if you need this ASAP).
Because of how FastMCP works, I don't think this requires any architectural changes, as we always visit the tool manager on every call to see what tools exist. So I really think it's just adding a public remove method that is user-accessible to the tool manager and the server.
Just to call out - these tool additions/removals would apply to all clients of the server. This is separate from some work we have planned on more tailored include/exclude functionality on a per-client basis.
Here's a quick sketch of what works right now to add tools dynamically (here, from calling another tool):
from fastmcp import FastMCP, Client
mcp = FastMCP()
@mcp.tool()
def tool_1()-> None:
@mcp.tool()
def tool_2():
return "Hello, world!"
async with Client(mcp) as client:
assert len(await client.list_tools()) == 1
try:
await client.call_tool("tool_2")
except Exception as e:
print("Tool 2 unavailable")
await client.call_tool("tool_1")
assert len(await client.list_tools()) == 2
result = await client.call_tool("tool_2")
assert result[0].text == "Hello, world!"
print("Tool 2 available")
I’ve opened a PR to add support for removing tools at runtime: #437
It adds a remove_tool method to both ToolManager and FastMCP, along with tests and cache clearing.
Let me know if you’d like any changes!
Thanks @jlowin! Do you know if your provided solution will emit the list changed notification? https://modelcontextprotocol.io/specification/2025-03-26/server/tools#list-changed-notification
It definitely should! I'll look into whether that's been codified in the SDK
Here's a quick sketch of what works right now to add tools dynamically (here, from calling another tool):以下是_目前_动态添加工具的快速草图(此处,通过调用另一个工具):
from fastmcp import FastMCP, Client
mcp = FastMCP()
@mcp.tool() def tool_1()-> None:
@mcp.tool() def tool_2(): return "Hello, world!"async with Client(mcp) as client: assert len(await client.list_tools()) == 1
try: await client.call_tool("tool_2") except Exception as e: print("Tool 2 unavailable") await client.call_tool("tool_1") assert len(await client.list_tools()) == 2 result = await client.call_tool("tool_2") assert result[0].text == "Hello, world!" print("Tool 2 available")
I already have an MCP Server and have created a client connection. If I want to dynamically add a tool by providing function code, function name, function description, etc., is it possible?