@@ -12,13 +12,16 @@ import (
12
12
"github.com/hashicorp/go-hclog"
13
13
)
14
14
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.
16
18
type Manager struct {
17
19
logger hclog.Logger
18
20
enabled bool
19
21
}
20
22
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".
22
25
func NewManager (logger hclog.Logger ) * Manager {
23
26
if logger == nil {
24
27
logger = hclog .NewNullLogger ()
@@ -30,46 +33,73 @@ func NewManager(logger hclog.Logger) *Manager {
30
33
}
31
34
}
32
35
33
- // IsEnabled returns if identity is enabled
36
+ // IsEnabled returns whether identity verification is enabled.
37
+ // This method is safe for concurrent use.
34
38
func (m * Manager ) IsEnabled () bool {
35
39
return m .enabled
36
40
}
37
41
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.
39
45
func (m * Manager ) VerifyServer (ctx context.Context , serverName string ) error {
40
46
if ! m .enabled {
41
47
return nil
42
48
}
43
49
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
+ }
47
55
48
56
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 )
51
58
return nil
52
59
}
53
60
54
61
m .logger .Info ("Identity verified" , "server" , serverName )
55
62
return nil
56
63
}
57
64
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.
59
68
func (m * Manager ) InitServer (serverName , organization string ) error {
60
69
if ! m .enabled {
61
70
return fmt .Errorf ("identity not enabled (set MCPD_IDENTITY_ENABLED=true)" )
62
71
}
63
72
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 {
67
82
return fmt .Errorf ("failed to create identity directory: %w" , err )
68
83
}
69
84
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 {} {
71
100
id := fmt .Sprintf ("did:agntcy:dev:%s:%s" , organization , serverName )
72
- identity := map [string ]interface {}{
101
+
102
+ return map [string ]interface {}{
73
103
"id" : id ,
74
104
"resolverMetadata" : map [string ]interface {}{
75
105
"id" : id ,
@@ -92,13 +122,14 @@ func (m *Manager) InitServer(serverName, organization string) error {
92
122
},
93
123
},
94
124
}
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 )
101
132
}
102
133
103
- return nil
134
+ return filepath . Join ( homeDir , ".config" , "mcpd" , "identity" , serverName + ".json" ), nil
104
135
}
0 commit comments