Skip to content

mozilla-ai/mcpd-plugins-sdk-go

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

5 Commits
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

mcpd plugins SDK for Go

Go SDK for developing mcpd middleware plugins.

Overview

This SDK provides Go types and gRPC interfaces for building middleware plugins that integrate with mcpd. Plugins can process HTTP requests and responses, implementing capabilities like authentication, rate limiting, content transformation, and observability.

Installation

go get github.com/mozilla-ai/mcpd-plugins-sdk-go@latest

Then in your project:

go mod tidy

Usage

The SDK provides two approaches: with helpers (recommended) for convenience, and explicit for full control.

Option 1: Using SDK Helpers (Recommended)

The SDK provides the Serve() helper and BasePlugin struct to minimize boilerplate:

package main

import (
	"context"
	"log"

	pluginv1 "github.com/mozilla-ai/mcpd-plugins-sdk-go/pkg/plugins/v1/plugins"
	"google.golang.org/protobuf/types/known/emptypb"
)

type MyPlugin struct {
	pluginv1.BasePlugin // Provides sensible defaults for all methods.
}

func (p *MyPlugin) GetMetadata(ctx context.Context, _ *emptypb.Empty) (*pluginv1.Metadata, error) {
	return &pluginv1.Metadata{
		Name:        "my-plugin",
		Version:     "1.0.0",
		Description: "Example plugin that does something useful",
	}, nil
}

func (p *MyPlugin) GetCapabilities(ctx context.Context, _ *emptypb.Empty) (*pluginv1.Capabilities, error) {
	return &pluginv1.Capabilities{
		Flows: []pluginv1.Flow{pluginv1.FlowRequest},
	}, nil
}

func (p *MyPlugin) HandleRequest(ctx context.Context, req *pluginv1.HTTPRequest) (*pluginv1.HTTPResponse, error) {
	// Custom request processing logic here.

	return &pluginv1.HTTPResponse{
		Continue:   true,
		StatusCode: 0,
		Headers:    req.Headers,
		Body:       req.Body,
	}, nil
}

func main() {
	if err := pluginv1.Serve(&MyPlugin{}); err != nil {
		log.Fatal(err)
	}
}

What BasePlugin provides:

  • CheckHealth() - returns OK
  • CheckReady() - returns OK
  • Configure(), Stop() - no-ops
  • HandleRequest(), HandleResponse() - pass through unchanged

Override only the methods you need!

Option 2: Explicit Implementation

For full control over the server lifecycle:

package main

import (
	"context"
	"flag"
	"log"
	"net"
	"os"

	pluginv1 "github.com/mozilla-ai/mcpd-plugins-sdk-go/pkg/plugins/v1/plugins"
	"google.golang.org/grpc"
	"google.golang.org/protobuf/types/known/emptypb"
)

type MyPlugin struct {
	pluginv1.UnimplementedPluginServer
}

func (p *MyPlugin) GetMetadata(ctx context.Context, _ *emptypb.Empty) (*pluginv1.Metadata, error) {
	return &pluginv1.Metadata{
		Name:        "my-plugin",
		Version:     "1.0.0",
		Description: "Example plugin",
	}, nil
}

func (p *MyPlugin) GetCapabilities(ctx context.Context, _ *emptypb.Empty) (*pluginv1.Capabilities, error) {
	return &pluginv1.Capabilities{
		Flows: []pluginv1.Flow{pluginv1.FlowRequest},
	}, nil
}

func (p *MyPlugin) CheckHealth(ctx context.Context, _ *emptypb.Empty) (*emptypb.Empty, error) {
	return &emptypb.Empty{}, nil
}

func (p *MyPlugin) CheckReady(ctx context.Context, _ *emptypb.Empty) (*emptypb.Empty, error) {
	return &emptypb.Empty{}, nil
}

func (p *MyPlugin) Configure(ctx context.Context, cfg *pluginv1.PluginConfig) (*emptypb.Empty, error) {
	return &emptypb.Empty{}, nil
}

func (p *MyPlugin) Stop(ctx context.Context, _ *emptypb.Empty) (*emptypb.Empty, error) {
	return &emptypb.Empty{}, nil
}

func (p *MyPlugin) HandleRequest(ctx context.Context, req *pluginv1.HTTPRequest) (*pluginv1.HTTPResponse, error) {
	return &pluginv1.HTTPResponse{
		Continue:   true,
		Headers:    req.Headers,
		Body:       req.Body,
	}, nil
}

func (p *MyPlugin) HandleResponse(ctx context.Context, resp *pluginv1.HTTPResponse) (*pluginv1.HTTPResponse, error) {
	return &pluginv1.HTTPResponse{
		Continue:   true,
		StatusCode: resp.StatusCode,
		Headers:    resp.Headers,
		Body:       resp.Body,
	}, nil
}

func main() {
	var address, network string
	flag.StringVar(&address, "address", "", "gRPC address (socket path for unix, host:port for tcp)")
	flag.StringVar(&network, "network", "unix", "Network type (unix or tcp)")
	flag.Parse()

	if address == "" {
		log.Fatal("--address flag is required")
	}

	lis, err := net.Listen(network, address)
	if err != nil {
		log.Fatalf("failed to listen on %s %s: %v", network, address, err)
	}

	if network == "unix" {
		defer func() { _ = os.Remove(address) }()
	}

	grpcServer := grpc.NewServer()
	pluginv1.RegisterPluginServer(grpcServer, &MyPlugin{})

	log.Printf("Plugin server listening on %s %s", network, address)
	if err := grpcServer.Serve(lis); err != nil {
		log.Fatalf("failed to serve: %v", err)
	}
}

Import Alias Convention

Following Kubernetes conventions (e.g., corev1, appsv1), this SDK uses pluginv1 as the recommended import alias:

import pluginv1 "github.com/mozilla-ai/mcpd-plugins-sdk-go/pkg/plugins/v1/plugins"

Proto Versioning

The SDK follows the versioning of mcpd-proto:

  • API Version: plugins/v1/ (in proto repo) maps to pkg/plugins/v1/plugins/ (in SDK)
  • Release Version: Proto repo tags like v0.0.1, v0.0.2, etc.
  • SDK Version: This repo's tags track SDK releases and may differ from proto versions

Current proto version: v0.0.2

Repository Structure

mcpd-plugins-sdk-go/
├── README.md           # This file.
├── LICENSE             # Apache 2.0 license.
├── Makefile            # Proto fetching and code generation.
├── go.mod              # Go module definition.
├── go.sum              # Dependency checksums.
├── .gitignore          # Ignores tmp/ directory.
├── tmp/                # Downloaded protos (gitignored).
└── pkg/
    └── plugins/
        └── v1/
            └── plugins/
                ├── base.go            # BasePlugin helper.
                ├── server.go          # Serve() helper.
                ├── plugin.pb.go       # Generated protobuf types.
                └── plugin_grpc.pb.go  # Generated gRPC service.

For SDK Maintainers

Prerequisites

  • Go 1.25.1 or later
  • protoc (Protocol Buffer Compiler)
  • protoc-gen-go and protoc-gen-go-grpc plugins

Install protoc plugins:

go install google.golang.org/protobuf/cmd/protoc-gen-go@latest
go install google.golang.org/grpc/cmd/protoc-gen-go-grpc@latest

Regenerating Code

The SDK uses a Makefile-based approach to fetch proto definitions and generate Go code:

Fetch protos and generate:

make all
go mod tidy

Update to a new proto version:

  1. Edit PROTO_VERSION in the Makefile (e.g., v0.0.2)
  2. Run make clean all
  3. Run go mod tidy
  4. Commit the updated generated files

Run linter:

make lint

Clean generated files:

make clean

Note: The clean target only removes generated .pb.go files, preserving helper files like base.go and server.go.

Health Checking

The SDK follows gRPC Health Checking Protocol conventions:

rpc CheckHealth(google.protobuf.Empty) returns (google.protobuf.Empty);
rpc CheckReady(google.protobuf.Empty) returns (google.protobuf.Empty);

License

Apache 2.0 - See LICENSE file for details.

Contributing

This is an early PoC. Contribution guidelines coming soon.

About

No description, website, or topics provided.

Resources

License

Stars

Watchers

Forks

Packages

No packages published