@@ -97,6 +97,26 @@ enum Command {
9797 /// Register with an AI agent: "claude-code", "cursor", or "windsurf".
9898 #[ arg( long) ]
9999 register : Option < String > ,
100+
101+ /// Generate and add a new API key.
102+ #[ arg( long) ]
103+ add_api_key : bool ,
104+
105+ /// Name for the new API key (requires --add-api-key).
106+ #[ arg( long, requires = "add_api_key" ) ]
107+ key_name : Option < String > ,
108+
109+ /// Permissions for the new key: "read" or "write" (requires --add-api-key).
110+ #[ arg( long, requires = "add_api_key" ) ]
111+ key_permissions : Option < String > ,
112+
113+ /// List all API keys.
114+ #[ arg( long) ]
115+ list_api_keys : bool ,
116+
117+ /// Revoke an API key by name.
118+ #[ arg( long) ]
119+ revoke_api_key : Option < String > ,
100120 } ,
101121
102122 /// Manage embedding models.
@@ -106,7 +126,20 @@ enum Command {
106126 } ,
107127
108128 /// Start MCP stdio server for AI agent access.
109- Serve ,
129+ Serve {
130+ /// Enable HTTP REST API alongside MCP.
131+ #[ arg( long) ]
132+ http : bool ,
133+ /// HTTP port (default: from config or 3000).
134+ #[ arg( long) ]
135+ port : Option < u16 > ,
136+ /// HTTP host to bind to (default: 127.0.0.1).
137+ #[ arg( long) ]
138+ host : Option < String > ,
139+ /// Disable API key authentication (local development only, 127.0.0.1 only).
140+ #[ arg( long) ]
141+ no_auth : bool ,
142+ } ,
110143
111144 /// Inspect vault graph connections.
112145 Graph {
@@ -618,6 +651,11 @@ async fn main() -> Result<()> {
618651 enable_obsidian_cli,
619652 disable_obsidian_cli,
620653 register,
654+ add_api_key,
655+ key_name,
656+ key_permissions,
657+ list_api_keys,
658+ revoke_api_key,
621659 } => {
622660 let mut cfg = Config :: load ( ) ?;
623661
@@ -717,6 +755,48 @@ async fn main() -> Result<()> {
717755 }
718756 }
719757
758+ if add_api_key {
759+ let name = key_name. unwrap_or_else ( || "default" . into ( ) ) ;
760+ let perms = key_permissions. unwrap_or_else ( || "read" . into ( ) ) ;
761+ if perms != "read" && perms != "write" {
762+ anyhow:: bail!( "Permissions must be 'read' or 'write', got: {perms}" ) ;
763+ }
764+ let key = engraph:: http:: generate_api_key ( ) ;
765+ cfg. http . api_keys . push ( engraph:: config:: ApiKeyConfig {
766+ key : key. clone ( ) ,
767+ name : name. clone ( ) ,
768+ permissions : perms. clone ( ) ,
769+ } ) ;
770+ cfg. save ( ) ?;
771+ println ! ( "API key created:" ) ;
772+ println ! ( " Name: {name}" ) ;
773+ println ! ( " Permissions: {perms}" ) ;
774+ println ! ( " Key: {key}" ) ;
775+ println ! ( "\n Save this key — it won't be shown again." ) ;
776+ }
777+
778+ if list_api_keys {
779+ if cfg. http . api_keys . is_empty ( ) {
780+ println ! ( "No API keys configured." ) ;
781+ } else {
782+ println ! ( "API keys:" ) ;
783+ for k in & cfg. http . api_keys {
784+ println ! ( " {} ({})" , k. name, k. permissions) ;
785+ }
786+ }
787+ }
788+
789+ if let Some ( ref name) = revoke_api_key {
790+ let before = cfg. http . api_keys . len ( ) ;
791+ cfg. http . api_keys . retain ( |k| k. name != * name) ;
792+ if cfg. http . api_keys . len ( ) < before {
793+ cfg. save ( ) ?;
794+ println ! ( "Revoked API key: {name}" ) ;
795+ } else {
796+ println ! ( "No API key found with name: {name}" ) ;
797+ }
798+ }
799+
720800 cfg. save ( ) ?;
721801 println ! (
722802 "Configuration saved to {}" ,
@@ -1051,12 +1131,22 @@ async fn main() -> Result<()> {
10511131 }
10521132 }
10531133
1054- Command :: Serve => {
1134+ Command :: Serve { http , port , host , no_auth } => {
10551135 if !index_exists ( & data_dir) {
10561136 eprintln ! ( "No index found. Run 'engraph index <path>' first." ) ;
10571137 std:: process:: exit ( 1 ) ;
10581138 }
1059- engraph:: serve:: run_serve ( & data_dir, None ) . await ?;
1139+ let http_opts = if http {
1140+ let cfg = Config :: load ( ) ?;
1141+ Some ( engraph:: serve:: HttpServeOpts {
1142+ port : port. unwrap_or ( cfg. http . port ) ,
1143+ host : host. unwrap_or ( cfg. http . host . clone ( ) ) ,
1144+ no_auth,
1145+ } )
1146+ } else {
1147+ None
1148+ } ;
1149+ engraph:: serve:: run_serve ( & data_dir, http_opts) . await ?;
10601150 }
10611151
10621152 Command :: Write { action } => {
0 commit comments