Skip to content

Commit fd3d4b3

Browse files
author
Anivar Aravind
committed
refactor: Improve identity code structure and documentation
- Match mcpd code style with comprehensive godoc comments - Add helper methods for better maintainability - Improve error handling with proper context - Add verbose logging option to CLI - Follow existing manager patterns from codebase
1 parent b9dcf7f commit fd3d4b3

File tree

2 files changed

+84
-27
lines changed

2 files changed

+84
-27
lines changed

cmd/identity.go

Lines changed: 31 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -3,26 +3,50 @@ package cmd
33
import (
44
"fmt"
55

6+
"github.com/hashicorp/go-hclog"
67
"github.com/spf13/cobra"
78

89
"github.com/mozilla-ai/mcpd/v2/internal/identity"
910
)
1011

1112
var identityCmd = &cobra.Command{
1213
Use: "identity",
13-
Short: "Manage MCP server identities (AGNTCY-compatible)",
14-
Long: `Optional identity management for MCP servers using AGNTCY standards.`,
14+
Short: "Manage MCP server identities",
15+
Long: `Manage AGNTCY-compliant identities for MCP servers.
16+
17+
Identity support is optional and disabled by default. Enable with:
18+
export MCPD_IDENTITY_ENABLED=true
19+
20+
Identities follow the AGNTCY Identity specification:
21+
https://spec.identity.agntcy.org/docs/id/definitions`,
1522
}
1623

1724
var identityInitCmd = &cobra.Command{
1825
Use: "init [server-name]",
1926
Short: "Initialize identity for an MCP server",
20-
Args: cobra.ExactArgs(1),
27+
Long: `Initialize an AGNTCY-compliant identity for an MCP server.
28+
29+
This creates a development identity with:
30+
- DID format: did:agntcy:dev:{organization}:{server}
31+
- ResolverMetadata with assertion methods
32+
- Service endpoints for MCP
33+
34+
The identity is stored in ~/.config/mcpd/identity/{server}.json`,
35+
Args: cobra.ExactArgs(1),
2136
RunE: func(cmd *cobra.Command, args []string) error {
2237
serverName := args[0]
2338
organization, _ := cmd.Flags().GetString("org")
2439

25-
manager := identity.NewManager(nil)
40+
// Create logger based on verbosity
41+
logger := hclog.NewNullLogger()
42+
if verbose, _ := cmd.Flags().GetBool("verbose"); verbose {
43+
logger = hclog.New(&hclog.LoggerOptions{
44+
Name: "identity",
45+
Level: hclog.Debug,
46+
})
47+
}
48+
49+
manager := identity.NewManager(logger)
2650
if err := manager.InitServer(serverName, organization); err != nil {
2751
return err
2852
}
@@ -36,5 +60,7 @@ func init() {
3660
rootCmd.AddCommand(identityCmd)
3761
identityCmd.AddCommand(identityInitCmd)
3862

39-
identityInitCmd.Flags().StringP("org", "o", "mcpd", "Organization name")
63+
// Flags for identity init
64+
identityInitCmd.Flags().StringP("org", "o", "mcpd", "Organization name for the identity")
65+
identityInitCmd.Flags().BoolP("verbose", "v", false, "Enable verbose logging")
4066
}

internal/identity/identity.go

Lines changed: 53 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -12,13 +12,16 @@ import (
1212
"github.com/hashicorp/go-hclog"
1313
)
1414

15-
// Manager handles identity verification with minimal complexity
15+
// Manager handles identity verification for MCP servers.
16+
// It supports AGNTCY Identity specifications with local file storage.
17+
// NewManager should be used to create instances of Manager.
1618
type Manager struct {
1719
logger hclog.Logger
1820
enabled bool
1921
}
2022

21-
// NewManager creates a new identity manager
23+
// NewManager creates a new identity manager instance.
24+
// Identity is disabled by default unless MCPD_IDENTITY_ENABLED is set to "true".
2225
func NewManager(logger hclog.Logger) *Manager {
2326
if logger == nil {
2427
logger = hclog.NewNullLogger()
@@ -30,46 +33,73 @@ func NewManager(logger hclog.Logger) *Manager {
3033
}
3134
}
3235

33-
// IsEnabled returns if identity is enabled
36+
// IsEnabled returns whether identity verification is enabled.
37+
// This method is safe for concurrent use.
3438
func (m *Manager) IsEnabled() bool {
3539
return m.enabled
3640
}
3741

38-
// VerifyServer checks if a server has valid identity credentials
42+
// VerifyServer checks if a server has valid identity credentials.
43+
// If identity is disabled or no credentials exist, it returns nil (non-blocking).
44+
// This method logs verification status but never fails to maintain backward compatibility.
3945
func (m *Manager) VerifyServer(ctx context.Context, serverName string) error {
4046
if !m.enabled {
4147
return nil
4248
}
4349

44-
// For now, just check if credential file exists
45-
homeDir, _ := os.UserHomeDir()
46-
credPath := filepath.Join(homeDir, ".config", "mcpd", "identity", serverName+".json")
50+
credPath, err := m.getCredentialPath(serverName)
51+
if err != nil {
52+
m.logger.Debug("Failed to get credential path", "server", serverName, "error", err)
53+
return nil
54+
}
4755

4856
if _, err := os.Stat(credPath); os.IsNotExist(err) {
49-
m.logger.Debug("No identity credentials found", "server", serverName)
50-
// Don't fail - identity is optional
57+
m.logger.Debug("No identity credentials found", "server", serverName, "path", credPath)
5158
return nil
5259
}
5360

5461
m.logger.Info("Identity verified", "server", serverName)
5562
return nil
5663
}
5764

58-
// InitServer creates AGNTCY-spec identity with ResolverMetadata
65+
// InitServer creates an AGNTCY-compliant identity for the specified server.
66+
// The identity follows the AGNTCY Identity specification with ResolverMetadata.
67+
// Returns an error if identity is disabled or if file operations fail.
5968
func (m *Manager) InitServer(serverName, organization string) error {
6069
if !m.enabled {
6170
return fmt.Errorf("identity not enabled (set MCPD_IDENTITY_ENABLED=true)")
6271
}
6372

64-
homeDir, _ := os.UserHomeDir()
65-
identityDir := filepath.Join(homeDir, ".config", "mcpd", "identity")
66-
if err := os.MkdirAll(identityDir, 0700); err != nil {
73+
identity := m.createIdentity(serverName, organization)
74+
75+
credPath, err := m.getCredentialPath(serverName)
76+
if err != nil {
77+
return fmt.Errorf("failed to get credential path: %w", err)
78+
}
79+
80+
// Ensure directory exists
81+
if err := os.MkdirAll(filepath.Dir(credPath), 0700); err != nil {
6782
return fmt.Errorf("failed to create identity directory: %w", err)
6883
}
6984

70-
// AGNTCY identity format with ResolverMetadata
85+
data, err := json.MarshalIndent(identity, "", " ")
86+
if err != nil {
87+
return fmt.Errorf("failed to marshal identity: %w", err)
88+
}
89+
90+
if err := os.WriteFile(credPath, data, 0600); err != nil {
91+
return fmt.Errorf("failed to write identity: %w", err)
92+
}
93+
94+
m.logger.Info("Created identity", "server", serverName, "path", credPath)
95+
return nil
96+
}
97+
98+
// createIdentity builds the AGNTCY-compliant identity structure.
99+
func (m *Manager) createIdentity(serverName, organization string) map[string]interface{} {
71100
id := fmt.Sprintf("did:agntcy:dev:%s:%s", organization, serverName)
72-
identity := map[string]interface{}{
101+
102+
return map[string]interface{}{
73103
"id": id,
74104
"resolverMetadata": map[string]interface{}{
75105
"id": id,
@@ -92,13 +122,14 @@ func (m *Manager) InitServer(serverName, organization string) error {
92122
},
93123
},
94124
}
95-
96-
data, _ := json.MarshalIndent(identity, "", " ")
97-
credPath := filepath.Join(identityDir, serverName+".json")
98-
99-
if err := os.WriteFile(credPath, data, 0600); err != nil {
100-
return fmt.Errorf("failed to write identity: %w", err)
125+
}
126+
127+
// getCredentialPath returns the file path for a server's identity credentials.
128+
func (m *Manager) getCredentialPath(serverName string) (string, error) {
129+
homeDir, err := os.UserHomeDir()
130+
if err != nil {
131+
return "", fmt.Errorf("failed to get home directory: %w", err)
101132
}
102133

103-
return nil
134+
return filepath.Join(homeDir, ".config", "mcpd", "identity", serverName+".json"), nil
104135
}

0 commit comments

Comments
 (0)