Skip to content

Conversation

AlexNiny
Copy link
Contributor

@AlexNiny AlexNiny commented Apr 17, 2025

New Features

Introducing a new Hook method: AddOnRequestInitialization
Enabling users to perform validation or preprocessing operations before the actual request handling—functioning similarly to middleware. Execution proceeds only upon successful validation; otherwise, an error is returned.

Usage

hooks := &Hooks{}

hooks.AddOnRequestInitialization(func(ctx context.Context, id any, message any) error {
		// do something...
		return nil
	})
// ...
server := NewMCPServer(
		"test-server",
		"1.0.0",
		WithHooks(hooks),
		WithToolCapabilities(true),
	)

Summary by CodeRabbit

Summary by CodeRabbit

  • New Features
    • Introduced a new hook that allows actions to be performed before handling any request, enabling advanced pre-processing or validation.
  • Tests
    • Enhanced server tests to verify that the new pre-request hook is triggered appropriately for all relevant methods.

Copy link
Contributor

coderabbitai bot commented Apr 17, 2025

Walkthrough

This change introduces a new hook mechanism, AddOnRequestInitialization, to the MCP server's hooks system. The hook allows registration of callback functions that are executed during request initialization, after base JSON-RPC message validation but before dispatching to method-specific handlers. If any registered hook returns an error, request processing is halted and an error response is returned. The new hook is demonstrated in the example server with a logging callback and is covered by enhanced unit tests verifying its invocation count.

Changes

Files/Paths Change Summary
server/hooks.go Added OnRequestInitializationFunc type and OnRequestInitialization slice to Hooks struct. Added methods to register and invoke these hooks before request handling.
server/request_handler.go Added call to s.hooks.onRequestInitialization after base JSON-RPC message validation and before method dispatch; returns error response if hook returns error.
examples/everything/main.go Registered a sample AddOnRequestInitialization hook that logs request identifier and message, intended for authorization and preprocessing.
server/server_test.go Extended TestMCPServer_WithHooks to register the new hook and assert it is called the expected number of times during tests.

Possibly related PRs

  • Feature: Request Hooks #62: Introduced the original hooks framework for request lifecycle events, which this PR extends by adding the new pre-request initialization hook.

Tip

⚡💬 Agentic Chat (Pro Plan, General Availability)
  • We're introducing multi-step agentic chat in review comments and issue comments, within and outside of PR's. This feature enhances review and issue discussions with the CodeRabbit agentic chat by enabling advanced interactions, including the ability to create pull requests directly from comments and add commits to existing pull requests.

📜 Recent review details

Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between fcc7d57 and ee6caad.

⛔ Files ignored due to path filters (2)
  • server/internal/gen/hooks.go.tmpl is excluded by !**/gen/**
  • server/internal/gen/request_handler.go.tmpl is excluded by !**/gen/**
📒 Files selected for processing (4)
  • examples/everything/main.go (1 hunks)
  • server/hooks.go (3 hunks)
  • server/request_handler.go (1 hunks)
  • server/server_test.go (3 hunks)
🚧 Files skipped from review as they are similar to previous changes (4)
  • server/request_handler.go
  • examples/everything/main.go
  • server/server_test.go
  • server/hooks.go

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share
🪧 Tips

Chat

There are 3 ways to chat with CodeRabbit:

  • Review comments: Directly reply to a review comment made by CodeRabbit. Example:
    • I pushed a fix in commit <commit_id>, please review it.
    • Generate unit testing code for this file.
    • Open a follow-up GitHub issue for this discussion.
  • Files and specific lines of code (under the "Files changed" tab): Tag @coderabbitai in a new review comment at the desired location with your query. Examples:
    • @coderabbitai generate unit testing code for this file.
    • @coderabbitai modularize this function.
  • PR comments: Tag @coderabbitai in a new PR comment to ask questions about the PR branch. For the best results, please provide a very specific query, as very limited context is provided in this mode. Examples:
    • @coderabbitai gather interesting stats about this repository and render them as a table. Additionally, render a pie chart showing the language distribution in the codebase.
    • @coderabbitai read src/utils.ts and generate unit testing code.
    • @coderabbitai read the files in the src/scheduler package and generate a class diagram using mermaid and a README in the markdown format.
    • @coderabbitai help me debug CodeRabbit configuration file.

Note: Be mindful of the bot's finite context window. It's strongly recommended to break down tasks such as reading entire modules into smaller chunks. For a focused discussion, use review comments to chat about specific files and their changes, instead of using the PR comments.

CodeRabbit Commands (Invoked using PR comments)

  • @coderabbitai pause to pause the reviews on a PR.
  • @coderabbitai resume to resume the paused reviews.
  • @coderabbitai review to trigger an incremental review. This is useful when automatic reviews are disabled for the repository.
  • @coderabbitai full review to do a full review from scratch and review all the files again.
  • @coderabbitai summary to regenerate the summary of the PR.
  • @coderabbitai generate docstrings to generate docstrings for this PR.
  • @coderabbitai resolve resolve all the CodeRabbit review comments.
  • @coderabbitai configuration to show the current CodeRabbit configuration for the repository.
  • @coderabbitai help to get help.

Other keywords and placeholders

  • Add @coderabbitai ignore anywhere in the PR description to prevent this PR from being reviewed.
  • Add @coderabbitai summary to generate the high-level summary at a specific location in the PR description.
  • Add @coderabbitai anywhere in the PR title to generate the title automatically.

CodeRabbit Configuration File (.coderabbit.yaml)

  • You can programmatically configure CodeRabbit by adding a .coderabbit.yaml file to the root of your repository.
  • Please see the configuration documentation for more information.
  • If your editor has YAML language server enabled, you can add the path at the top of this file to enable auto-completion and validation: # yaml-language-server: $schema=https://coderabbit.ai/integrations/schema.v2.json

Documentation and Community

  • Visit our Documentation for detailed information on how to use CodeRabbit.
  • Join our Discord Community to get help, request features, and share feedback.
  • Follow us on X/Twitter for updates and announcements.

Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 2

🧹 Nitpick comments (3)
server/hooks.go (2)

56-58: Improve hook documentation for clearer usage

The documentation for OnBeforeHandleRequestFunc could be more descriptive and include grammatical corrections.

-// OnBeforeHandleRequestFunc is a function that called before handle diff request method
-// Should any errors arise during func execution, the service will promptly return the corresponding error message.
+// OnBeforeHandleRequestFunc is a function that is called before handling a request.
+// It can be used for validation, authorization, or other preprocessing tasks.
+// If the function returns an error, request processing will be halted and an error
+// response will be returned to the client with the error message.

235-246: Implementation looks good with proper error handling

The beforeHandleRequest method correctly implements the sequential execution of hooks with early return on error.

Consider adding a brief comment explaining that the first hook that returns an error will stop the execution chain:

 func (c *Hooks) beforeHandleRequest(ctx context.Context, id any, message any) error {
 	if c == nil {
 		return nil
 	}
+	// Execute hooks sequentially, returning early if any hook returns an error
 	for _, hook := range c.OnBeforeHandleRequest {
 		err := hook(ctx, id, message)
 		if err != nil {
 			return err
 		}
 	}
 	return nil
 }
examples/everything/main.go (1)

47-51: Enhance example with authorization demonstration

The hook example is simple and clear, but could be improved by showing a real-world use case of authorization verification.

Consider enhancing the example to demonstrate authorization:

 hooks.AddBeforeHandleRequest(func(ctx context.Context, id any, message any) error {
 	fmt.Printf("beforeHandleRequest: %v, %v\n", id, message)
 	// authorization verification and other preprocessing tasks are performed.
+	
+	// Example of authorization check based on request properties
+	// If this was a real application, you might check authentication tokens,
+	// permissions, rate limits, etc.
+	/*
+	if shouldRejectRequest(message) {
+		return fmt.Errorf("request rejected: unauthorized or invalid")
+	}
+	*/
+	
 	return nil
 })
📜 Review details

Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 37ac814 and 5730fba.

📒 Files selected for processing (4)
  • examples/everything/main.go (1 hunks)
  • server/hooks.go (3 hunks)
  • server/request_handler.go (1 hunks)
  • server/server_test.go (3 hunks)
🧰 Additional context used
🧬 Code Graph Analysis (1)
server/request_handler.go (1)
mcp/types.go (1)
  • PARSE_ERROR (222-222)
🔇 Additional comments (4)
server/hooks.go (2)

92-92: LGTM - Field addition looks good

The field addition in the Hooks struct is appropriately positioned with other similar hook fields.


231-233: LGTM - AddBeforeHandleRequest method is consistent

The implementation follows the same pattern as other hook registration methods.

server/server_test.go (2)

1208-1209: LGTM - Counter addition for the new hook

The counter variable addition is correctly aligned with other hook counters.


1343-1344: LGTM - Hook invocation count verification

The assertion for the hook invocation count is correct and ensures the hook is called exactly once for each request.

Comment on lines 1272 to 1275
hooks.AddBeforeHandleRequest(func(ctx context.Context, id any, message any) error {
beforeHandleRequestCount++
return nil
})
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🛠️ Refactor suggestion

Add error path test for hook functionality

The hook implementation in the test looks good but only tests the success path where the hook returns nil. Consider adding a test that verifies the error handling path.

Add a test that verifies error handling:

 hooks.AddBeforeHandleRequest(func(ctx context.Context, id any, message any) error {
 	beforeHandleRequestCount++
+	
+	// To test error handling, you could return an error for a specific request
+	// For example, when calling a specific method:
+	/*
+	jsonReq := make(map[string]interface{})
+	if err := json.Unmarshal(message.(json.RawMessage), &jsonReq); err == nil {
+		if method, ok := jsonReq["method"].(string); ok && method == "tools/call" {
+			return errors.New("hook rejection test")
+		}
+	}
+	*/
+	
 	return nil
 })

Also, add a test case to verify the error response:

// Test case for hook error
errorMessage := server.HandleMessage(context.Background(), []byte(`{
    "jsonrpc": "2.0",
    "id": 5,
    "method": "tools/call",
    "params": {
        "name": "test-hook-error"
    }
}`))

// Verify error response has the correct error message
errorResp, ok := errorMessage.(mcp.JSONRPCError)
assert.True(t, ok)
assert.Equal(t, mcp.PARSE_ERROR, errorResp.Error.Code)
assert.Contains(t, errorResp.Error.Message, "hook rejection test")

use mcp.INVALID_REQUEST replace mcp.PARSE_ERROR
server/hooks.go Outdated
@@ -86,6 +89,7 @@ type Hooks struct {
OnBeforeAny []BeforeAnyHookFunc
OnSuccess []OnSuccessHookFunc
OnError []OnErrorHookFunc
OnBeforeHandleRequest []OnBeforeHandleRequestFunc
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

two things:

  1. if there is a beforexx, there will always a afterxx
  2. beforexx method body will always invoke beforeAny(...) first

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This hook primarily serves as a pre-processing step for requests. The current naming convention "beforeXX" is somewhat ambiguous, so I should consider renaming it.
How about OnRequestInitialization

rename OnBeforeHandleRequest to OnRequestInitialization
@AlexNiny AlexNiny changed the title feat: Add server hooks:beforeHandleRequest feat: Add server hooks:OnRequestInitialization Apr 17, 2025
Comment on lines +58 to +65
handleErr := s.hooks.onRequestInitialization(ctx, baseMessage.ID, message)
if handleErr != nil {
return createErrorResponse(
baseMessage.ID,
mcp.INVALID_REQUEST,
handleErr.Error(),
)
}
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

FYI - this and server/hooks.go are a generated files, you'll have to update the template (see comment at the top)

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thank you for your reminder. The revised amendments have been submitted.

update tmpl file generate hooks.go/request_handler.go by "go generate"
fix example function name error
update test message
…reHandleRequest

# Conflicts:
#	server/hooks.go
#	server/internal/gen/hooks.go.tmpl
#	server/internal/gen/request_handler.go.tmpl
#	server/request_handler.go
@ezynda3 ezynda3 merged commit b46fa54 into mark3labs:main Apr 25, 2025
2 checks passed
adlternative pushed a commit to adlternative/mcp-go that referenced this pull request May 20, 2025
* add hooks:beforeHandleRequest

* Update request_handler.go

use mcp.INVALID_REQUEST replace mcp.PARSE_ERROR

* rename hook name

rename OnBeforeHandleRequest to OnRequestInitialization

* update tmpl file

update tmpl file generate hooks.go/request_handler.go by "go generate"
fix example function name error

* update test

update test message

---------

Co-authored-by: nine <[email protected]>
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.

4 participants