Skip to content

Add RegisteredTool receiver #144

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 1 commit into
base: main
Choose a base branch
from

Conversation

mbiamont
Copy link

@mbiamont mbiamont commented Jul 9, 2025

Add the Server as the receiver of the RegisteredTool handler lambda.
Same for RegisteredPrompt and RegisteredResource.

Motivation and Context

  • It's currently not easy to call methods like sendLoggingMessage() from a tool as you need an instance of the server.

Before:

// The server needs to be instantiated before any other tool
val server: Server = (...)

val registeredTool = RegisteredTool(
   tool = Tool(...),
)  {
   server.sendLoggingMessage(...)
}

server.addTools(listOf(registeredTool))

After:

// No need for Server instance
val registeredTool = RegisteredTool(
   tool = Tool(...),
)  {
  sendLoggingMessage(...)
}

val server: Server = (...).apply {
   addTools(listOf(registeredTool))
}

How Has This Been Tested?

I've added a unit test.

Breaking Changes

No breaking change

Types of changes

  • Bug fix (non-breaking change which fixes an issue)
  • New feature (non-breaking change which adds functionality)
  • Breaking change (fix or feature that would cause existing functionality to change)
  • Documentation update

Checklist

  • I have read the MCP Documentation
  • My code follows the repository's style guidelines
  • New and existing tests pass locally
  • I have added appropriate error handling
  • I have added or updated documentation as needed

Additional context

In the Python MCP SDK, a tool can have a ctx: Context parameter and this context has the methods for sending a notification message.

Example:

from mcp.server.fastmcp import Context, FastMCP

mcp = FastMCP(name="Notifications Example")


@mcp.tool()
async def process_data(data: str, ctx: Context) -> str:
    """Process data with logging."""
    # Different log levels
    await ctx.debug(f"Debug: Processing '{data}'")
    await ctx.info("Info: Starting processing")
    await ctx.warning("Warning: This is experimental")
    await ctx.error("Error: (This is just a demo)")

    # Notify about resource changes
    await ctx.session.send_resource_list_changed()

    return f"Processed: {data}"

We may also want to not pass the whole Server instance as context of the lambda, but just a Context which could be defined as

interface McpServerContext {
   suspend fun sendLoggingMessage(params: LoggingMessageNotification)
   suspend fun sendResourceUpdated(params: ResourceUpdatedNotification)
   suspend fun createMessage(params: CreateMessageRequest, options: RequestOptions? = null): CreateMessageResult
}

We could also want one per MCP primitive as:

interface ToolContext {
   suspend fun sendLoggingMessage(params: LoggingMessageNotification)
   suspend fun createMessage(params: CreateMessageRequest, options: RequestOptions? = null): CreateMessageResult
}

interface ResourceContext {
   suspend fun sendResourceUpdated(params: ResourceUpdatedNotification)
}

What do you think?

@mbiamont mbiamont changed the title Add RegisteredTool context Add RegisteredTool receiver Jul 9, 2025
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

1 participant