Skip to content

feat: Progressive disclosure — visibility control per session #3

@superWorldSavior

Description

@superWorldSavior

Motivation

A production MCP server with many tools (e.g. mcp-erpnext has 120+) floods the LLM context window. The model gets confused, picks wrong tools, or ignores relevant ones. We need a way to show only what's relevant and reveal more tools as the session context evolves.

Proposal

Add a visibility system that allows hiding/showing tools by tag, and per-session state to toggle visibility dynamically.

Registration with tags

server.registerTool(
  {
    name: "delete_all_records",
    description: "Nuclear option",
    tags: ["admin", "dangerous"],
    visible: false, // hidden by default
    inputSchema: { ... },
  },
  handler,
);

Visibility middleware

// Hide all admin tools by default
server.disable({ tags: ["admin"] });

// A gatekeeper tool that unlocks admin tools for the current session
server.registerTool(
  {
    name: "unlock_admin",
    description: "Unlock admin tools (requires authentication)",
    requiredScopes: ["admin:write"],
    inputSchema: {},
  },
  async (args, ctx) => {
    ctx.session.enable({ tags: ["admin"] });
    // Next tools/list call for this session will include admin tools
    return "Admin tools unlocked.";
  },
);

How it works

  1. tools/list filters results based on session visibility state
  2. Tools hidden by default don't appear until explicitly enabled
  3. Visibility is per-session — one client unlocking admin doesn't affect others
  4. Works with the existing middleware pipeline (auth check → scope check → visibility check)

Use cases

  • Multi-tenant SaaS: free tier sees 10 tools, paid tier sees 50
  • Progressive onboarding: start with basics, reveal advanced tools as the agent demonstrates competence
  • Security layers: admin/destructive tools hidden until authenticated
  • Context optimization: reduce token usage by only exposing relevant tool subset

Prior art

  • FastMCP 3.0 visibility system (disable(tags=...) + ctx.enable_components())
  • Feature flags / progressive rollout patterns

Scope

  • tags and visible fields on tool/resource registration
  • VisibilityFilter middleware with per-session state
  • enable() / disable() methods on session context
  • tools/list respects visibility state
  • Documentation + examples
  • Tests

Metadata

Metadata

Assignees

No one assigned

    Labels

    enhancementNew feature or request

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions