---
schema: rendered-html/v1
title: "Custom Providers - FastMCP"
source_url: https://gofastmcp.com/servers/providers/custom
generated_at: 2026-06-11T19:39:42.174281+00:00
---




[FastMCP home page![light logo](images/gofastmcp__com__servers__providers__custom__wordmark.avif)![dark logo](images/gofastmcp__com__servers__providers__custom__wordmark-white.avif)](gofastmcp__com.md)







MCP Providers

Custom Providers









  - [Overview

    NEW](gofastmcp__com__servers__providers__overview.md)
  - [Local

    NEW](gofastmcp__com__servers__providers__local.md)
  - [Filesystem

    NEW](gofastmcp__com__servers__providers__filesystem.md)
  - [MCP Proxy](gofastmcp__com__servers__providers__proxy.md)
  - [Skills

    NEW](gofastmcp__com__servers__providers__skills.md)
  - [Composition](gofastmcp__com__servers__composition.md)
  - [Custom

    NEW](/servers/providers/custom)














- [When to Build Custom](#when-to-build-custom)
- [Providers vs Middleware](#providers-vs-middleware)
- [The Provider Interface](#the-provider-interface)
- [What Providers Return](#what-providers-return)
- [Registering Providers](#registering-providers)
- [A Simple Provider](#a-simple-provider)
- [Lifecycle Management](#lifecycle-management)
- [Full Example: API-Backed Resources](#full-example-api-backed-resources)

MCP Providers

# Custom Providers


Build providers that source components from any data source


Custom providers let you source components from anywhere - databases, APIs, configuration systems, or dynamic runtime logic. If you can write Python code to fetch or generate a component, you can wrap it in a provider.

## [​](#when-to-build-custom) When to Build Custom

The built-in providers handle common cases: decorators (`LocalProvider`), composition (`FastMCPProvider`), and proxying (`ProxyProvider`). Build a custom provider when your components come from somewhere else:

- **Database-backed tools**: Admin users define tools in a database, and your server exposes them dynamically
- **API-backed resources**: Resources that fetch content from external services on demand
- **Configuration-driven components**: Components loaded from YAML/JSON config files at startup
- **Multi-tenant systems**: Different users see different tools based on their permissions
- **Plugin systems**: Third-party code registers components at runtime

## [​](#providers-vs-middleware) Providers vs Middleware

Both providers and [middleware](gofastmcp__com__servers__middleware.md) can influence what components a client sees, but they work at different levels.
**Providers** are objects that source components. They make it easy to reason about where tools, resources, and prompts come from - a database, another server, an API.
**Middleware** intercepts individual requests. It’s well-suited for request-specific decisions like logging, rate limiting, or authentication.
You *could* use middleware to dynamically add tools based on request context. But it’s often cleaner to have a provider source all possible tools, then use middleware or [visibility controls](gofastmcp__com__servers__visibility.md) to filter what each request can see. This separation makes it easier to reason about how components are sourced and how they interact with other server machinery.

## [​](#the-provider-interface) The Provider Interface

A provider implements protected `_list_*` methods that return available components. The public `list_*` methods handle transforms automatically - you override the underscore-prefixed versions:

from collections.abc import Sequence
from fastmcp.server.providers import Provider
from fastmcp.tools import Tool
from fastmcp.resources import Resource
from fastmcp.prompts import Prompt

class MyProvider(Provider):
    async def _list_tools(self) -> Sequence[Tool]:
        """Return all tools this provider offers."""
        return []

    async def _list_resources(self) -> Sequence[Resource]:
        """Return all resources this provider offers."""
        return []

    async def _list_prompts(self) -> Sequence[Prompt]:
        """Return all prompts this provider offers."""
        return []

You only need to implement the methods for component types you provide. The base class returns empty sequences by default.
The `_get_*` methods (`_get_tool`, `_get_resource`, `_get_prompt`) have default implementations that search through the list results. Override them only if you can fetch individual components more efficiently than iterating the full list.

## [​](#what-providers-return) What Providers Return

Providers return component objects that are ready to use. When a client calls a tool, FastMCP invokes the tool’s function - your provider isn’t involved in execution. This means the `Tool`, `Resource`, or `Prompt` you return must actually work.
The easiest way to create components is from functions:

from fastmcp.tools import Tool

def add(a: int, b: int) -> int:
    """Add two numbers."""
    return a + b

tool = Tool.from_function(add)

The function’s type hints become the input schema, and the docstring becomes the description. You can override these:

tool = Tool.from_function(
    add,
    name="calculator_add",
    description="Add two integers together"

Similar `from_function` methods exist for `Resource` and `Prompt`.

## [​](#registering-providers) Registering Providers

Add providers when creating the server:

mcp = FastMCP(
    "MyServer",
    providers=[
        DatabaseProvider(db_url),
        ConfigProvider(config_path),

Or add them after creation:

mcp = FastMCP("MyServer")
mcp.add_provider(DatabaseProvider(db_url))

## [​](#a-simple-provider) A Simple Provider

Here’s a minimal provider that serves tools from a dictionary:

from collections.abc import Callable, Sequence
from fastmcp.server.providers import Provider
from fastmcp.tools import Tool

class DictProvider(Provider):
    def __init__(self, tools: dict[str, Callable]):
        super().__init__()
        self._tools = [
            Tool.from_function(fn, name=name)
            for name, fn in tools.items()

    async def _list_tools(self) -> Sequence[Tool]:
        return self._tools

Use it like this:

def add(a: int, b: int) -> int:
    """Add two numbers."""
    return a + b

def multiply(a: int, b: int) -> int:
    """Multiply two numbers."""
    return a * b

mcp = FastMCP("Calculator", providers=[
    DictProvider({"add": add, "multiply": multiply})
])

## [​](#lifecycle-management) Lifecycle Management

Providers often need to set up connections when the server starts and clean them up when it stops. Override the `lifespan` method:

from contextlib import asynccontextmanager
from collections.abc import AsyncIterator, Sequence

class DatabaseProvider(Provider):
    def __init__(self, db_url: str):
        super().__init__()
        self.db_url = db_url
        self.db = None

    @asynccontextmanager
    async def lifespan(self) -> AsyncIterator[None]:
        self.db = await connect_database(self.db_url)
        try:
            yield
        finally:
            await self.db.close()

    async def _list_tools(self) -> Sequence[Tool]:
        rows = await self.db.fetch("SELECT * FROM tools")
        return [self._make_tool(row) for row in rows]

FastMCP calls your provider’s `lifespan` during server startup and shutdown. The connection is available to your methods while the server runs.

## [​](#full-example-api-backed-resources) Full Example: API-Backed Resources

Here’s a complete provider that fetches resources from an external REST API:

from contextlib import asynccontextmanager
from collections.abc import AsyncIterator, Sequence
from fastmcp.server.providers import Provider
from fastmcp.resources import Resource
import httpx

class ApiResourceProvider(Provider):
    """Provides resources backed by an external API."""

    def __init__(self, base_url: str, api_key: str):
        super().__init__()
        self.base_url = base_url
        self.api_key = api_key
        self.client = None

    @asynccontextmanager
    async def lifespan(self) -> AsyncIterator[None]:
        self.client = httpx.AsyncClient(
            base_url=self.base_url,
            headers={"Authorization": f"Bearer {self.api_key}"}
        try:
            yield
        finally:
            await self.client.aclose()

    async def _list_resources(self) -> Sequence[Resource]:
        response = await self.client.get("/resources")
        response.raise_for_status()
        return [
            self._make_resource(item)
            for item in response.json()["items"]

    def _make_resource(self, data: dict) -> Resource:
        resource_id = data["id"]

        async def read_content() -> str:
            response = await self.client.get(
                f"/resources/{resource_id}/content"
            return response.text

        return Resource.from_function(
            read_content,
            uri=f"api://resources/{resource_id}",
            name=data["name"],
            description=data.get("description", ""),
            mime_type=data.get("mime_type", "text/plain")

Register it like any other provider:


mcp = FastMCP("API Resources", providers=[
    ApiResourceProvider("https://api.example.com", "my-api-key")
])

[Composing Servers

Previous](gofastmcp__com__servers__composition.md)[User Elicitation

Next](gofastmcp__com__servers__elicitation.md)






