Build Responsive MCP Servers

    Kent C. Dodds
    Kent C. Dodds

    Imagine you're building a website. When a user logs in, you show them different navigation options. When new data arrives, you update the UI in real-time. When their permissions change, you immediately reflect those changes in the interface.

    Your MCP server should work the same way.

    Most developers think of MCP servers as static APIs that expose a fixed set of tools and resources. But the Model Context Protocol is designed for dynamic, responsive applications that adapt to changing conditions—just like modern websites.

    The Problem with Static MCP Servers

    When you build a traditional API, you define your endpoints once and they stay the same until you deploy a new version. But AI applications often need to respond to:

    • User authentication state (logged in/out, role changes)
    • Data availability (new files uploaded, database changes)
    • System state (available resources, current workload)
    • User preferences (settings changes, feature toggles)

    If your MCP server doesn't adapt to these changes, users get a poor experience. They might see tools that don't work, miss new functionality, or get confused by outdated information.

    Enter MCP Change Notifications

    The Model Context Protocol provides a robust system for notifying clients about changes in real-time. When your server's capabilities or data change, you can immediately notify connected clients, who can then update their interfaces accordingly.

    Three Types of Changes

    MCP supports three main types of change notifications:

    1. Tools List Changes - When tools are added, removed, or updated
    2. Resources List Changes - When available resources change
    3. Resource Content Updates - When specific resource content changes

    Let's look at each one:

    1. Tools List Changes

    When the set of available tools changes, send a notifications/tools/list_changed notification:

    // Enable a tool when conditions are met
    if (userHasPermission('admin')) {
    adminTool.enable()
    // The SDK automatically sends the notification
    }
    // Disable a tool when it's no longer available
    if (!databaseConnection.healthy) {
    databaseTool.disable()
    // The SDK automatically sends the notification
    }

    Real-world example: A project management MCP server might enable a "Create Sprint" tool only when the current sprint is complete, or disable a "Deploy to Production" tool when the deployment pipeline is busy.

    2. Resources List Changes

    Resources can be static (like a file) or dynamic (like a database table). When the set of available resources changes, send a notifications/resources/list_changed notification:

    const projectResource = server.registerResource(
    'project',
    new ResourceTemplate('project://{id}', {
    list: async () => {
    // This list can change as projects are created/deleted
    return await getProjectsForUser(userId)
    },
    }),
    {
    title: 'Project',
    description: 'A project by ID',
    },
    async (uri, { id }) => {
    // Handle individual project resource
    return {
    contents: [
    {
    uri: uri.href,
    text: `Project ${id} data`,
    },
    ],
    }
    },
    )
    // When a new project is created
    await createProject(newProject)
    // The next time list() is called, it will include the new project
    // Send notification to update clients

    Real-world example: A file management MCP server might update its resource list when files are uploaded or deleted.

    3. Resource Content Updates

    When the content of a specific resource changes, notify subscribed clients:

    // Client subscribes to a resource
    await client.subscribeResource({
    uri: 'project://123',
    })
    // Later, when the project content changes
    await updateProject(123, { status: 'completed' })
    // Then the server can notify subscribed clients
    await server.server.notification({
    method: 'notifications/resources/updated',
    params: {
    uri: 'project://123',
    title: 'Project Alpha',
    },
    })

    Real-world example: A monitoring MCP server might notify clients when a system's status changes from "healthy" to "degraded", allowing the client to immediately update its dashboard.

    Thinking Like a Website

    The key insight is to think of your MCP server as a dynamic website, not a static API. Here's how the patterns map:

    Website PatternMCP Equivalent
    Navigation menu updatesTools list changes
    File browser updatesResources list changes
    Real-time data updatesResource content updates
    User role-based UIConditional tool enabling
    Live notificationsResource subscriptions

    The Future of Dynamic MCP

    While not all MCP clients currently support change notifications well, this will change. As the ecosystem matures, clients will:

    • Automatically refresh tools in LLM context when tools are added/removed
    • Update resource browsers when new resources become available
    • Show real-time updates for subscribed resources
    • Provide visual feedback when capabilities change

    This will create a much more responsive and intuitive user experience, similar to how modern web applications feel dynamic and alive.

    Tips

    1. Be proactive about changes - Don't wait for clients to poll for updates
    2. Batch notifications when possible - Avoid spamming clients with too many updates
    3. Handle client capabilities gracefully - Some clients might not support all notification types
    4. Think in terms of user experience - What would a website do in this situation?
    5. Document your dynamic behavior - Help users understand how your server adapts

    Conclusion

    MCP servers should be dynamic, responsive applications that adapt to changing conditions—just like modern websites. Change notifications are the key to building AI applications that feel alive and responsive to user needs.

    While client support for these features is still evolving, building with change notifications in mind will future-proof your MCP servers and provide a significantly better user experience when clients catch up.

    The difference between a static MCP server and a dynamic one is like the difference between a static HTML page and a modern React application. One feels like a document, the other feels like an application.

    Start thinking of your MCP server as a website replacement, and you'll naturally build more responsive, user-friendly AI applications.

    If you want to dive into this more, join me for a hands-on MCP Workshop.


    Resources:

    Start designing the future of intelligent user experiences

    Join the EpicAI.pro newsletter to get updates on events, articles, and more as they’re released

    I respect your privacy. Unsubscribe at any time.

    Share