pkg/rules/mcp/server_setup.go (124 lines of code) (raw):
// Copyright (c) 2025 Alibaba Group Holding Ltd.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
package mcp
import (
"context"
"fmt"
_ "unsafe"
"github.com/alibaba/opentelemetry-go-auto-instrumentation/pkg/api"
"github.com/mark3labs/mcp-go/mcp"
"github.com/mark3labs/mcp-go/server"
)
//go:linkname hookBeforeAnyOnEnter github.com/mark3labs/mcp-go/server.hookBeforeAnyOnEnter
func hookBeforeAnyOnEnter(call api.CallContext, c *server.Hooks,
ctx context.Context, id any, method mcp.MCPMethod, message any) {
if method == mcp.MethodPing {
return
}
request := mcpRequest{
operationName: "execute_other:" + string(method),
system: "mcp",
methodType: string(method),
CallId: fmt.Sprintf("%v", id),
input: map[string]any{},
output: map[string]any{},
}
//var subRequest *mcp.Request
subRequest := getSubRequest(method, &request, message)
if subRequest == nil {
return
}
Ctx := ServerInstrumenter.Start(ctx, request)
//subRequest.OtelRequest = request
subRequest.OtelContext = Ctx
}
//go:linkname hookOnSuccessOnEnter github.com/mark3labs/mcp-go/server.hookOnSuccessOnEnter
func hookOnSuccessOnEnter(call api.CallContext, c *server.Hooks,
ctx context.Context, id any, method mcp.MCPMethod, message any, result any) {
subRequest := getSubRequest(method, nil, message)
if subRequest == nil {
return
}
request := mcpRequest{}
if subRequest.OtelContext == nil {
return
}
ctx, ok := subRequest.OtelContext.(context.Context)
if !ok {
return
}
ServerInstrumenter.End(ctx, request, nil, nil)
}
//go:linkname hookOnErrorOnEnter github.com/mark3labs/mcp-go/server.hookOnErrorOnEnter
func hookOnErrorOnEnter(call api.CallContext, c *server.Hooks,
ctx context.Context, id any, method mcp.MCPMethod, message any, err error) {
subRequest := getSubRequest(method, nil, message)
if subRequest == nil {
return
}
if subRequest.OtelContext == nil {
return
}
ctx, ok := subRequest.OtelContext.(context.Context)
if !ok {
return
}
request := mcpRequest{}
ServerInstrumenter.End(ctx, request, nil, err)
}
func getSubRequest(method mcp.MCPMethod, request *mcpRequest, message any) *mcp.Request {
switch method {
case mcp.MethodToolsCall:
if msg, ok := message.(*mcp.CallToolRequest); ok {
if request != nil {
request.operationName = "execute_tool"
request.methodName = msg.Params.Name
}
return &msg.Request
}
case mcp.MethodPromptsGet:
if msg, ok := message.(*mcp.GetPromptRequest); ok {
if request != nil {
request.input["prompt_name"] = msg.Params.Name
}
return &msg.Request
}
case mcp.MethodResourcesRead:
if msg, ok := message.(*mcp.ReadResourceRequest); ok {
if request != nil {
request.input["resources_uri"] = msg.Params.URI
}
return &msg.Request
}
case mcp.MethodInitialize:
if msg, ok := message.(*mcp.InitializeRequest); ok {
if request != nil {
request.input["client_info_name"] = msg.Params.ClientInfo.Name
request.input["client_info_version"] = msg.Params.ClientInfo.Version
}
return &msg.Request
}
case mcp.MethodResourcesList:
if msg, ok := message.(*mcp.ListResourcesRequest); ok {
if request != nil {
request.input["cursor"] = msg.Params.Cursor
}
return &msg.Request
}
case mcp.MethodResourcesTemplatesList:
if msg, ok := message.(*mcp.ListResourceTemplatesRequest); ok {
if request != nil {
request.input["cursor"] = msg.Params.Cursor
}
return &msg.Request
}
case mcp.MethodPromptsList:
if msg, ok := message.(*mcp.ListPromptsRequest); ok {
if request != nil {
request.input["cursor"] = msg.Params.Cursor
}
return &msg.Request
}
case mcp.MethodToolsList:
if msg, ok := message.(*mcp.ListToolsRequest); ok {
if request != nil {
request.input["cursor"] = msg.Params.Cursor
}
return &msg.Request
}
}
return nil
}