|
|
4 mesi fa | |
|---|---|---|
| .. | ||
| hosted | 6 mesi fa | |
| local | 6 mesi fa | |
| mcpregister | 6 mesi fa | |
| .golangci.yml | 4 mesi fa | |
| README.md | 6 mesi fa | |
| go.mod | 4 mesi fa | |
| go.sum | 4 mesi fa | |
| mcp.go | 6 mesi fa | |
| register.go | 6 mesi fa | |
| server.go | 4 mesi fa | |
| tools.go | 6 mesi fa | |
This directory contains the implementation of embedded Model Context Protocol (MCP) servers for AI Proxy. Embed MCP allows native Go implementations to be registered directly within the application, providing high-performance, type-safe MCP servers without external dependencies.
Embed MCP servers are native Go implementations that run within the AI Proxy process. They offer several advantages over external MCP servers:
Embed MCP servers use a simple registration pattern during application startup:
func init() {
mcpservers.Register(mcpservers.EmbedMcp{
ID: "my-mcp-server",
Name: "My MCP Server",
NewServer: NewServer,
ConfigTemplates: configTemplates,
Tags: []string{"example", "demo"},
Readme: "Description of the server functionality",
})
}
Configuration templates define the parameters required by your MCP server:
var configTemplates = map[string]mcpservers.ConfigTemplate{
"api_key": {
Name: "API Key",
Required: mcpservers.ConfigRequiredTypeInitOnly,
Example: "sk-example-key",
Description: "The API key for authentication",
Validator: validateAPIKey,
},
"endpoint": {
Name: "Endpoint URL",
Required: mcpservers.ConfigRequiredTypeReusingOptional,
Example: "https://api.example.com",
Description: "The base URL for the API",
Validator: validateURL,
},
}
ConfigRequiredTypeInitOnly: Required during server initialization, set once globallyConfigRequiredTypeReusingOnly: Required as reusing parameter, can vary by groupConfigRequiredTypeInitOrReusingOnly: Required in either init or reusing config (mutually exclusive)ConfigRequiredTypeInitOptional: Optional during initializationConfigRequiredTypeReusingOptional: Optional as reusing parameterfunc NewServer(config map[string]string, reusingConfig map[string]string) (*server.MCPServer, error) {
// Access configuration
apiKey := config["api_key"] // From init config
endpoint := reusingConfig["endpoint"] // From reusing config
// Create and configure your MCP server
mcpServer := server.NewMCPServer("my-server", server.WithMCPCapabilities(
server.MCPServerCapabilities{
Tools: &server.MCPCapabilitiesTools{},
Resources: &server.MCPCapabilitiesResources{},
},
))
// Register tools, resources, etc.
mcpServer.AddTool(server.Tool{
Name: "example_tool",
Description: "An example tool",
// ... tool implementation
})
return mcpServer, nil
}
GET /api/embedmcp/
Returns all registered embed MCP servers with their configuration templates and enabled status.
Response:
[
{
"id": "aiproxy-openapi",
"enabled": true,
"name": "AI Proxy OpenAPI",
"readme": "Exposes AI Proxy API as MCP tools",
"tags": ["openapi", "admin"],
"config_templates": {
"host": {
"name": "Host",
"required": true,
"example": "http://localhost:3000",
"description": "The host of the OpenAPI server"
},
"authorization": {
"name": "Authorization",
"required": false,
"example": "admin-key",
"description": "The admin key for authentication"
}
}
}
]
POST /api/embedmcp/
Configure and enable/disable an embed MCP server.
Request:
{
"id": "aiproxy-openapi",
"enabled": true,
"init_config": {
"host": "http://localhost:3000"
}
}
GET /api/test-embedmcp/{id}/sse?key=adminkey&config[key]=value&reusing[key]=value
Establishes a Server-Sent Events connection for testing the embed MCP server.
Query Parameters:
config[key]=value: Initial configuration parametersreusing[key]=value: Reusing configuration parametersGET|POST|DELETE /api/test-embedmcp/{id}?key=adminkey&config[key]=value&reusing[key]=value
HTTP-based request/response interface for testing.
POST /api/test-embedmcp/message?key=adminkey&sessionId={session}
Send messages to active SSE test sessions.
Request Body: JSON-RPC message
{
"jsonrpc": "2.0",
"id": 1,
"method": "tools/list"
}
http://localhost:3000/api/test-embedmcp/aiproxy-openapi/sse?key=adminkey&config[host]=http://localhost:3000&reusing[authorization]=admin-key
This will establish an SSE connection and return:
event: endpoint
data: /api/test-embedmcp/message?sessionId=abc123&key=your-token
event: message
data: {"jsonrpc":"2.0","id":1,"method":"ping"}
http://localhost:3000/api/test-embedmcp/message?key=adminkey&sessionId=abc123
http://localhost:3000/api/test-embedmcp/aiproxy-openapi?key=adminkey&config[host]=http://localhost:3000&reusing[authorization]=admin-key
# Multiple configuration parameters
curl "http://localhost:3000/api/test-embedmcp/my-server/sse?key=adminkey&config[api_key]=sk-123&config[timeout]=30&reusing[endpoint]=https://api.example.com&reusing[region]=us-east-1"
# Only required parameters
curl "http://localhost:3000/api/test-embedmcp/my-server/sse?key=adminkey&config[api_key]=sk-123"
core/mcpservers/my-server/
├── server.go
└── README.md
server.go:
package myserver
import (
"fmt"
"net/url"
"github.com/labring/aiproxy/core/mcpservers"
"github.com/mark3labs/mcp-go/mcp"
"github.com/mark3labs/mcp-go/server"
)
// Configuration templates define required parameters
var configTemplates = map[string]mcpservers.ConfigTemplate{
"api_endpoint": {
Name: "API Endpoint",
Required: mcpservers.ConfigRequiredTypeInitOnly,
Example: "https://api.example.com",
Description: "The API endpoint URL",
Validator: validateURL,
},
"api_key": {
Name: "API Key",
Required: mcpservers.ConfigRequiredTypeReusingOnly,
Example: "sk-example-key",
Description: "Authentication key for the API",
Validator: validateAPIKey,
},
"timeout": {
Name: "Timeout",
Required: mcpservers.ConfigRequiredTypeInitOptional,
Example: "30",
Description: "Request timeout in seconds",
Validator: validateTimeout,
},
}
// Validation functions
func validateURL(value string) error {
u, err := url.Parse(value)
if err != nil {
return err
}
if u.Scheme != "http" && u.Scheme != "https" {
return fmt.Errorf("invalid scheme: %s", u.Scheme)
}
return nil
}
func validateAPIKey(value string) error {
if len(value) < 10 {
return fmt.Errorf("API key too short")
}
return nil
}
func validateTimeout(value string) error {
// Validation logic here
return nil
}
// NewServer creates a new instance of the MCP server
func NewServer(config map[string]string, reusingConfig map[string]string) (*server.MCPServer, error) {
endpoint := config["api_endpoint"]
apiKey := reusingConfig["api_key"]
// Create MCP server with capabilities
mcpServer := server.NewMCPServer("my-server", server.WithMCPCapabilities(
server.MCPServerCapabilities{
Tools: &server.MCPCapabilitiesTools{},
Resources: &server.MCPCapabilitiesResources{},
},
))
// Add tools
mcpServer.AddTool(server.Tool{
Name: "get_data",
Description: "Retrieve data from the API",
InputSchema: mcp.ToolInputSchema{
Type: "object",
Properties: map[string]any{
"query": {
"type": "string",
"description": "Search query",
},
},
Required: []string{"query"},
},
}, func(arguments map[string]any) (*server.ToolResult, error) {
query := arguments["query"].(string)
// Implement your tool logic here
// Use endpoint and apiKey for API calls
return &server.ToolResult{
Content: []any{
server.TextContent{
Type: "text",
Text: fmt.Sprintf("Retrieved data for query: %s", query),
},
},
}, nil
})
// Add resources if needed
mcpServer.AddResource(server.Resource{
URI: "file:///data.json",
Name: "Data File",
Description: "Sample data resource",
MimeType: "application/json",
}, func() ([]byte, error) {
// Return resource content
return []byte(`{"example": "data"}`), nil
})
return mcpServer, nil
}
// Register the server during package initialization
func init() {
mcpservers.Register(mcpservers.EmbedMcp{
ID: "my-server",
Name: "My Custom Server",
NewServer: NewServer,
ConfigTemplates: configTemplates,
Tags: []string{"example", "custom"},
Readme: "A custom MCP server implementation for demonstration",
})
}
Add import to core/mcpservers/mcpregister/init.go:
package mcpregister
import (
// register embed mcp
_ "github.com/labring/aiproxy/core/mcpservers/aiproxy-openapi"
_ "github.com/labring/aiproxy/core/mcpservers/my-server" // Add this line
)
http://localhost:3000/api/test-embedmcp/my-server/sse?key=adminkey&config[api_endpoint]=https://api.example.com&reusing[api_key]=sk-test-key
For servers without configuration requirements, the system automatically caches instances:
// No configuration required - server will be cached
var configTemplates = map[string]mcpservers.ConfigTemplate{}
func NewServer(config map[string]string, reusingConfig map[string]string) (*server.MCPServer, error) {
// This server instance will be cached and reused
return server.NewMCPServer("static-server"), nil
}
Servers can access both init and reusing configuration:
func NewServer(config map[string]string, reusingConfig map[string]string) (*server.MCPServer, error) {
// Init config: Set once per server deployment
baseURL := config["base_url"]
// Reusing config: Can vary per group/user
apiKey := reusingConfig["api_key"]
region := reusingConfig["region"]
// Create server with group-specific configuration
return createServerWithConfig(baseURL, apiKey, region)
}
Implement robust error handling:
func NewServer(config map[string]string, reusingConfig map[string]string) (*server.MCPServer, error) {
endpoint := config["endpoint"]
if endpoint == "" {
return nil, fmt.Errorf("endpoint is required")
}
// Validate endpoint accessibility
if err := validateEndpointConnectivity(endpoint); err != nil {
return nil, fmt.Errorf("endpoint validation failed: %w", err)
}
return createServer(endpoint)
}
The aiproxy-openapi server demonstrates a complete embed MCP implementation that exposes AI Proxy's REST API as MCP tools.
Features:
Configuration:
host (required): AI Proxy server URLauthorization (optional): Admin authentication keyExample Tools:
get_channels: List all channelscreate_channel: Create a new channelget_tokens: List tokenscreate_token: Create authentication tokensget_groups: List user groupsThis server serves as both a practical tool and a reference implementation for creating embed MCP servers.