Embed MCP Servers
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.
Overview
Embed MCP servers are native Go implementations that run within the AI Proxy process. They offer several advantages over external MCP servers:
- Performance: No network overhead, direct function calls
- Type Safety: Compile-time validation of server implementations
- Resource Efficiency: Shared memory and resources with the main application
- Hot Reloading: Dynamic configuration without server restart
- Integrated Monitoring: Built-in metrics and logging
Architecture
Registration System
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
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,
},
}
Configuration Types
ConfigRequiredTypeInitOnly
: Required during server initialization, set once globally
ConfigRequiredTypeReusingOnly
: Required as reusing parameter, can vary by group
ConfigRequiredTypeInitOrReusingOnly
: Required in either init or reusing config (mutually exclusive)
ConfigRequiredTypeInitOptional
: Optional during initialization
ConfigRequiredTypeReusingOptional
: Optional as reusing parameter
Server Implementation
func 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
}
API Reference
Management Endpoints
List Available Embed MCP Servers
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"
}
}
Testing Endpoints
Test SSE Connection
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 parameters
reusing[key]=value
: Reusing configuration parameters
Test Streamable Connection
GET|POST|DELETE /api/test-embedmcp/{id}?key=adminkey&config[key]=value&reusing[key]=value
HTTP-based request/response interface for testing.
Send Test Message
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"
}
Usage Examples
Testing an Embed MCP Server
1. Start SSE Connection
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"}
2. Send Messages (in another terminal)
http://localhost:3000/api/test-embedmcp/message?key=adminkey&sessionId=abc123
3. Test Streamable Interface
http://localhost:3000/api/test-embedmcp/aiproxy-openapi?key=adminkey&config[host]=http://localhost:3000&reusing[authorization]=admin-key
Configuration Examples
Complex Configuration
# 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"
Optional Parameters
# Only required parameters
curl "http://localhost:3000/api/test-embedmcp/my-server/sse?key=adminkey&config[api_key]=sk-123"
Development Guide
Creating a New Embed MCP Server
1. Create Server Directory
core/mcpservers/my-server/
├── server.go
└── README.md
2. Implement the Server
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",
})
}
3. Register in Init System
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
)
4. Test Your Server
http://localhost:3000/api/test-embedmcp/my-server/sse?key=adminkey&config[api_endpoint]=https://api.example.com&reusing[api_key]=sk-test-key
Advanced Features
Server Caching
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
}
Dynamic Configuration
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)
}
Error Handling
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)
}
Built-in Servers
AI Proxy OpenAPI Server
The aiproxy-openapi
server demonstrates a complete embed MCP implementation that exposes AI Proxy's REST API as MCP tools.
Features:
- Automatic OpenAPI to MCP conversion
- Admin authentication support
- Full CRUD operations for channels, tokens, groups
- Resource management capabilities
Configuration:
host
(required): AI Proxy server URL
authorization
(optional): Admin authentication key
Example Tools:
get_channels
: List all channels
create_channel
: Create a new channel
get_tokens
: List tokens
create_token
: Create authentication tokens
get_groups
: List user groups
This server serves as both a practical tool and a reference implementation for creating embed MCP servers.