Molecule SDK Reference
The Molecule SDK provides the types, interfaces, and helpers for building molecule plugins in Go. Molecules can provide discovery, MCP tools, skills, and visualizations.
Installation
go get github.com/sixdegree-ai/molecule-sdk
Requirements:
- Go 1.24 or later
Core Interfaces
Molecule
The base interface that all molecules must implement:
type Molecule interface {
// GetMetadata returns the molecule's identity and capabilities.
GetMetadata(ctx context.Context) (*MoleculeMetadata, error)
// Configure sets up the molecule with per-capability configuration.
Configure(ctx context.Context, config *MoleculeConfig) error
// Shutdown gracefully stops the molecule.
Shutdown(ctx context.Context) error
}
Discoverer
For molecules that discover entities. Extends Molecule:
type Discoverer interface {
Molecule
// Discover executes discovery and streams results via a channel.
Discover(ctx context.Context, opts *DiscoveryOptions) (<-chan *DiscoveryResult, error)
}
ToolProvider
For molecules that provide MCP tools. Extends Molecule:
type ToolProvider interface {
Molecule
// ListTools returns the available MCP tools.
ListTools(ctx context.Context) ([]ToolDefinition, error)
// CallTool executes an MCP tool and returns the result.
CallTool(ctx context.Context, req *ToolCallRequest) (*ToolCallResponse, error)
}
VisualizationProvider
For molecules that render visualizations. Extends Molecule:
type VisualizationProvider interface {
Molecule
// ListVisualizations returns the available visualizations.
ListVisualizations(ctx context.Context) ([]VisualizationDefinition, error)
// RenderVisualization renders a visualization for an entity.
RenderVisualization(ctx context.Context, req *VisualizationRenderRequest) (*VisualizationRenderResponse, error)
}
WebhookHandler
Optional interface for real-time event handling:
type WebhookHandler interface {
// HandleWebhook processes an incoming webhook event.
HandleWebhook(ctx context.Context, req *WebhookRequest) (*WebhookResponse, error)
}
FullMolecule
Convenience interface for molecules that implement all capabilities:
type FullMolecule interface {
Discoverer
ToolProvider
VisualizationProvider
ConfigWidgetProvider
}
BaseMolecule
Embed BaseMolecule in your struct to get default implementations for GetMetadata, Configure, and Shutdown:
type MyMolecule struct {
*molecule.BaseMolecule
}
func NewMyMolecule() *MyMolecule {
return &MyMolecule{
BaseMolecule: molecule.NewBaseMolecule(&molecule.MoleculeMetadata{
Namespace: "molecules.sixdegree.ai",
Name: "my-molecule",
Version: "1.0.0",
DisplayName: "My Molecule",
Description: "Discovers entities from my service",
Discovery: &molecule.DiscoveryCapability{
Supported: true,
Modes: []molecule.DiscoveryMode{molecule.DiscoveryModePolling},
EntityTypes: []molecule.EntityTypeDefinition{
{
Group: "entities.sixdegree.ai",
Version: "v1",
Kind: "MyResource",
Description: "A resource from my service",
},
},
},
}),
}
}
Data Structures
Entity
Follows a Kubernetes-inspired structure:
type Entity struct {
APIVersion string `json:"apiVersion"` // e.g., "entities.sixdegree.ai/v1"
Kind string `json:"kind"` // e.g., "GithubRepository"
Metadata EntityMetadata `json:"metadata"`
Spec map[string]any `json:"spec"`
Status *EntityStatus `json:"status,omitempty"`
}
type EntityMetadata struct {
Name string `json:"name"`
Namespace string `json:"namespace"`
UID string `json:"uid,omitempty"`
Labels map[string]string `json:"labels,omitempty"`
Annotations map[string]string `json:"annotations,omitempty"`
}
Relation
type Relation struct {
Namespace string `json:"namespace"`
RelationType string `json:"relation"` // e.g., "OWNS", "DEPLOYS"
Source EntityReference `json:"source"`
Target EntityReference `json:"target"`
Labels map[string]string `json:"labels,omitempty"`
Spec map[string]any `json:"spec,omitempty"`
Weight *float64 `json:"weight,omitempty"` // For graph algorithms
}
type EntityReference struct {
APIVersion string `json:"apiVersion"`
Kind string `json:"kind"`
Name string `json:"name"`
Namespace string `json:"namespace"`
}
MoleculeMetadata
type MoleculeMetadata struct {
Namespace string `json:"namespace"`
Name string `json:"name"`
Version string `json:"version"`
DisplayName string `json:"display_name"`
Description string `json:"description,omitempty"`
Author *AuthorInfo `json:"author,omitempty"`
License string `json:"license,omitempty"`
// Structured capabilities
Discovery *DiscoveryCapability `json:"discovery,omitempty"`
MCP *MCPCapability `json:"mcp,omitempty"`
Visualizations *VisualizationCapability `json:"visualizations,omitempty"`
HomepageURL string `json:"homepage_url,omitempty"`
DocsURL string `json:"docs_url,omitempty"`
Logo []byte `json:"logo,omitempty"`
}
DiscoveryOptions
Controls how discovery runs:
type DiscoveryOptions struct {
// IncrementalFrom limits discovery to changes since this time.
// If nil, performs a full discovery.
IncrementalFrom *time.Time `json:"incremental_from,omitempty"`
// Filters restricts discovery scope.
Filters map[string]string `json:"filters,omitempty"`
// DryRun validates without persisting entities.
DryRun bool `json:"dry_run"`
}
DiscoveryResult
Streamed back from Discover():
type DiscoveryResult struct {
Entity *Entity `json:"entity,omitempty"`
Relation *Relation `json:"relation,omitempty"`
Error *DiscoveryError `json:"error,omitempty"`
Progress int `json:"progress"` // 0-100
Message string `json:"message,omitempty"`
}
ToolDefinition
Describes an MCP tool:
type ToolDefinition struct {
Name string `json:"name"`
Description string `json:"description"`
InputSchema json.RawMessage `json:"input_schema"`
// EntityTypes for late tool disclosure — tool is only shown to the LLM
// after these entity types appear in the conversation.
EntityTypes []string `json:"entity_types,omitempty"`
}
Builders
The SDK provides builder helpers to reduce boilerplate.
EntityBuilder
entity := molecule.NewEntityBuilder("entities.sixdegree.ai/v1", "GithubRepository").
Name("api-service").
Namespace("default").
Label("language", "go").
Label("visibility", "private").
Annotation("source-url", "https://github.com/org/api-service").
Spec("url", "https://github.com/org/api-service").
Spec("language", "Go").
Spec("stars", 42).
Build()
RelationBuilder
relation := molecule.NewRelationBuilder("OWNS").
Namespace("default").
From("entities.sixdegree.ai/v1", "GithubOrganization", "default", "my-org").
To("entities.sixdegree.ai/v1", "GithubRepository", "default", "api-service").
Label("role", "owner").
Build()
You can also use entities directly:
relation := molecule.NewRelationBuilder("CONTRIBUTES_TO").
Namespace("default").
FromEntity(userEntity).
ToEntity(repoEntity).
Build()
NewEntityRef
Helper for creating entity references:
ref := molecule.NewEntityRef("GithubRepository", "api-service", "default")
// → EntityReference{APIVersion: "entities.sixdegree.ai/v1", Kind: "GithubRepository", ...}
ResultChannel
Helper for streaming discovery results:
func (m *MyMolecule) Discover(ctx context.Context, opts *molecule.DiscoveryOptions) (<-chan *molecule.DiscoveryResult, error) {
rc := molecule.NewResultChannel(100) // buffered channel
go func() {
defer rc.Close()
rc.SendProgress(0, "Starting discovery...")
// Discover entities
repos, err := m.fetchRepos(ctx)
if err != nil {
rc.SendError("FETCH_FAILED", err.Error())
return
}
for i, repo := range repos {
entity := molecule.NewEntityBuilder("entities.sixdegree.ai/v1", "MyResource").
Name(repo.Name).
Namespace(m.Config().Namespace).
Spec("url", repo.URL).
Build()
rc.SendEntity(entity)
rc.SendProgress(((i + 1) * 100) / len(repos), fmt.Sprintf("Discovered %d/%d", i+1, len(repos)))
}
}()
return rc.Chan(), nil
}
Configuration Helpers
Reading Settings
func (m *MyMolecule) Configure(ctx context.Context, config *molecule.MoleculeConfig) error {
// Store config via BaseMolecule
m.BaseMolecule.Configure(ctx, config)
// Read required settings
token, err := molecule.RequireCapabilitySetting[string](config.Discovery, "token")
if err != nil {
return err
}
// Read optional settings with defaults
pageSize := molecule.GetCapabilitySetting(config.Discovery, "page_size", 100)
org := molecule.GetCapabilitySetting(config.Discovery, "organization", "")
// Check which capabilities are enabled
if molecule.IsCapabilityEnabled(config, molecule.CapabilityDiscovery) {
m.setupDiscovery(token, org, pageSize)
}
if molecule.IsCapabilityEnabled(config, molecule.CapabilityMCP) {
m.setupMCPTools(token)
}
return nil
}
Config Schema
Define a JSON Schema for your configuration so the UI can render a configuration form:
Discovery: &molecule.DiscoveryCapability{
Supported: true,
ConfigSchema: json.RawMessage(`{
"type": "object",
"required": ["token"],
"properties": {
"token": {
"type": "string",
"title": "API Token",
"description": "Authentication token for the service",
"x-sixdegree": {"sensitive": true}
},
"organization": {
"type": "string",
"title": "Organization",
"description": "Organization to discover resources from"
},
"page_size": {
"type": "integer",
"title": "Page Size",
"default": 100,
"minimum": 10,
"maximum": 1000
}
}
}`),
},
MCP Tools
Defining Tools
MCP: &molecule.MCPCapability{
Supported: true,
Tools: []molecule.ToolDefinition{
{
Name: "my_search",
Description: "Search for resources in my service",
InputSchema: json.RawMessage(`{
"type": "object",
"required": ["query"],
"properties": {
"query": {"type": "string", "description": "Search query"}
}
}`),
EntityTypes: []string{"entities.sixdegree.ai/v1/MyResource"},
},
},
},
Handling Tool Calls
func (m *MyMolecule) CallTool(ctx context.Context, req *molecule.ToolCallRequest) (*molecule.ToolCallResponse, error) {
switch req.Name {
case "my_search":
query, _ := req.Arguments["query"].(string)
results, err := m.client.Search(ctx, query)
if err != nil {
return &molecule.ToolCallResponse{
Success: false,
Error: err.Error(),
}, nil
}
return &molecule.ToolCallResponse{
Success: true,
Result: map[string]any{"results": results},
}, nil
default:
return &molecule.ToolCallResponse{
Success: false,
Error: fmt.Sprintf("unknown tool: %s", req.Name),
}, nil
}
}
Webhooks
Handling Webhook Events
func (m *MyMolecule) HandleWebhook(ctx context.Context, req *molecule.WebhookRequest) (*molecule.WebhookResponse, error) {
switch req.EventType {
case "resource.created", "resource.updated":
return &molecule.WebhookResponse{
Acknowledged: true,
TriggerDiscovery: true, // triggers incremental discovery
}, nil
case "resource.deleted":
var payload struct {
ResourceName string `json:"resource_name"`
}
json.Unmarshal(req.Payload, &payload)
return &molecule.WebhookResponse{
Acknowledged: true,
AffectedEntities: []molecule.EntityReference{
molecule.NewEntityRef("MyResource", payload.ResourceName, "default"),
},
}, nil
default:
return &molecule.WebhookResponse{Acknowledged: true}, nil
}
}
Discovery Modes
Declare supported discovery modes in metadata:
Discovery: &molecule.DiscoveryCapability{
Supported: true,
Modes: []molecule.DiscoveryMode{
molecule.DiscoveryModePolling, // interval-based
molecule.DiscoveryModeWebhook, // event-driven
molecule.DiscoveryModeBoth, // both simultaneously
},
},
Next Steps
- Building Molecules — Step-by-step guide to creating a molecule
- Building Standalone MCP Servers — Adding standalone AI tools
- Building Visualizations — Creating dynamic visualizations
- Testing Guide — Testing your molecule