Trial Strategy: Multi-Server Plugin Discovery using @mcp.tool Decorators
Summary
Each plugin is implemented as a standalone FastMCP sub-server that defines one or more tools using the native @mcp.tool decorator.
At runtime, the main application walks the plugin folder tree, imports each sub-server, and composes them into a single aggregated FastMCP instance using main.import_server(...).
This approach keeps full FastMCP compatibility, preserves metadata supplied through decorator arguments, and supports modular composition for large tool libraries.
Design Goals
- Allow each plugin to be fully self-contained, with its own
FastMCP instance.
- Support normal FastMCP decorator arguments (
description, tags, etc.).
- Automatically discover and import all plugin sub-servers at startup.
- Preserve namespaces and prevent naming collisions through prefixes.
- Keep the system compatible with manual or build-time registry generation if performance tuning becomes necessary later.
Example Folder Layout
toolvault/
server.py
plugins/
geo/
__init__.py
filters/
__init__.py
acoustic/
__init__.py
Example Plugin (plugins/geo/__init__.py)
from fastmcp import FastMCP
mcp = FastMCP(name="geo")
@mcp.tool(
description="Set color to red for a given feature",
tags=["geo", "style"]
)
def change_color_to_red(feature: dict) -> dict:
f = dict(feature)
f.setdefault("properties", {})["color"] = "red"
return f
Each plugin can define multiple tools and resources on its own FastMCP instance.
Main Aggregating Server (server.py)
from fastmcp import FastMCP
import importlib, pkgutil
main = FastMCP(name="ToolVaultLike")
def import_plugins(root_pkg: str):
"""Walk a package tree and import any FastMCP subservers."""
pkg = importlib.import_module(root_pkg)
for m in pkgutil.walk_packages(pkg.__path__, prefix=f"{root_pkg}."):
mod = importlib.import_module(m.name)
sub = getattr(mod, "mcp", None)
if sub:
prefix = m.name.split(".")[-1]
main.import_server(
sub,
prefix=prefix,
on_duplicate_tools="error",
on_duplicate_resources="ignore",
on_duplicate_prompts="ignore",
)
if __name__ == "__main__":
import_plugins("plugins")
main.run()
Behavior
- Each discovered plugin is imported once.
- All
@mcp.tool metadata (e.g., description, tags) is preserved automatically.
- Tool names are prefixed using their folder name, preventing collisions.
- Tools, prompts, and resources are merged into the unified server.
Benefits
- Full FastMCP compliance: Tools use the official
@mcp.tool decorator and schema inference.
- Zero coupling: Each plugin can be developed and tested as an independent server.
- Automatic composition: No manual registry maintenance required during development.
- Extensible: Registry generation or lazy-loading can be added later if startup becomes heavy.
Limitations
- Every plugin module must be importable at startup (imports drive discovery).
- Startup time scales with number of plugins; for large libraries, a build-time registry or lazy-load mechanism can later be introduced.
- Duplicate tool names must be avoided or handled via
prefix or duplicate-handling flags.
Future Enhancements
- Registry generation: Build-time creation of a static import manifest for faster startup.
- Lazy import: Generate lightweight proxy entries for large plugin sets.
- Namespace management: Optionally group subservers by category or domain.
- Hot-reload mode: File watcher to reload individual plugin servers without restarting the main process.
Acceptance Criteria
Labels: trial, architecture, fastmcp, plugin-system
Trial Strategy: Multi-Server Plugin Discovery using
@mcp.toolDecoratorsSummary
Each plugin is implemented as a standalone FastMCP sub-server that defines one or more tools using the native
@mcp.tooldecorator.At runtime, the main application walks the plugin folder tree, imports each sub-server, and composes them into a single aggregated FastMCP instance using
main.import_server(...).This approach keeps full FastMCP compatibility, preserves metadata supplied through decorator arguments, and supports modular composition for large tool libraries.
Design Goals
FastMCPinstance.description,tags, etc.).Example Folder Layout
Example Plugin (
plugins/geo/__init__.py)Each plugin can define multiple tools and resources on its own
FastMCPinstance.Main Aggregating Server (
server.py)Behavior
@mcp.toolmetadata (e.g.,description,tags) is preserved automatically.Benefits
@mcp.tooldecorator and schema inference.Limitations
prefixor duplicate-handling flags.Future Enhancements
Acceptance Criteria
@mcp.tool(...)./tools/list.plugins/folder.Labels:
trial,architecture,fastmcp,plugin-system