@@ -159,6 +159,44 @@ struct RunRequest {
159159 #[ serde( flatten) ]
160160 common : CommonParams ,
161161 parameters : Option < std:: collections:: HashMap < String , String > > ,
162+ /// The environment to run the app in (defaults to "default")
163+ environment : Option < String > ,
164+ }
165+
166+ #[ derive( Debug , Deserialize , JsonSchema ) ]
167+ struct DeployRequest {
168+ #[ serde( flatten) ]
169+ common : CommonParams ,
170+ /// The environment to deploy to (defaults to "default")
171+ environment : Option < String > ,
172+ }
173+
174+ #[ derive( Debug , Deserialize , JsonSchema ) ]
175+ struct ListAppsRequest {
176+ /// Filter apps by environment. If not provided, apps across all environments are returned.
177+ environment : Option < String > ,
178+ }
179+
180+ #[ derive( Debug , Deserialize , JsonSchema ) ]
181+ struct ShowAppRequest {
182+ /// Name of the app
183+ name : String ,
184+ /// The environment to resolve the app against (defaults to "default")
185+ environment : Option < String > ,
186+ }
187+
188+ #[ derive( Debug , Deserialize , JsonSchema ) ]
189+ struct ListCatalogsRequest {
190+ /// The environment to list catalogs from (defaults to "default")
191+ environment : Option < String > ,
192+ }
193+
194+ #[ derive( Debug , Deserialize , JsonSchema ) ]
195+ struct ShowCatalogRequest {
196+ /// Name of the catalog
197+ name : String ,
198+ /// The environment the catalog belongs to (defaults to "default")
199+ environment : Option < String > ,
162200}
163201
164202pub fn mcp_cmd ( ) -> Command {
@@ -464,8 +502,12 @@ impl TowerService {
464502 // share constants directly. MCP-only descriptions (with Prerequisites/Optional) are
465503 // intentionally more detailed and don't need a CLI counterpart.
466504 #[ tool( description = "List all apps in your Tower account" ) ]
467- async fn tower_apps_list ( & self ) -> Result < CallToolResult , McpError > {
468- match api:: list_apps ( & self . config ) . await {
505+ async fn tower_apps_list (
506+ & self ,
507+ Parameters ( request) : Parameters < ListAppsRequest > ,
508+ ) -> Result < CallToolResult , McpError > {
509+ let environment = request. environment . as_deref ( ) ;
510+ match api:: list_apps ( & self . config , environment) . await {
469511 Ok ( apps) => {
470512 let apps: Vec < Value > = apps
471513 . into_iter ( )
@@ -474,6 +516,7 @@ impl TowerService {
474516 json ! ( {
475517 "name" : app. name,
476518 "description" : app. short_description,
519+ "version" : app. version,
477520 "created_at" : app. created_at,
478521 "status" : format!( "{:?}" , app. status)
479522 } )
@@ -499,9 +542,10 @@ impl TowerService {
499542 #[ tool( description = "Show details for a Tower app and its recent runs" ) ]
500543 async fn tower_apps_show (
501544 & self ,
502- Parameters ( request) : Parameters < NameRequest > ,
545+ Parameters ( request) : Parameters < ShowAppRequest > ,
503546 ) -> Result < CallToolResult , McpError > {
504- match api:: describe_app ( & self . config , & request. name ) . await {
547+ let environment = request. environment . as_deref ( ) . unwrap_or ( "default" ) ;
548+ match api:: describe_app ( & self . config , & request. name , Some ( environment) ) . await {
505549 Ok ( response) => {
506550 let data = json ! ( {
507551 "app" : {
@@ -657,6 +701,61 @@ impl TowerService {
657701 }
658702 }
659703
704+ #[ tool( description = "List catalogs in your Tower account" ) ]
705+ async fn tower_catalogs_list (
706+ & self ,
707+ Parameters ( request) : Parameters < ListCatalogsRequest > ,
708+ ) -> Result < CallToolResult , McpError > {
709+ let environment = request. environment . as_deref ( ) . unwrap_or ( "default" ) ;
710+ match api:: list_catalogs ( & self . config , environment, false ) . await {
711+ Ok ( catalogs) => {
712+ let catalogs: Vec < Value > = catalogs
713+ . into_iter ( )
714+ . map ( |catalog| {
715+ json ! ( {
716+ "name" : catalog. name,
717+ "type" : catalog. r#type,
718+ "environment" : catalog. environment,
719+ } )
720+ } )
721+ . collect ( ) ;
722+ Self :: json_success ( json ! ( { "catalogs" : catalogs} ) )
723+ }
724+ Err ( e) => Self :: error_result ( "Failed to list catalogs" , e) ,
725+ }
726+ }
727+
728+ #[ tool( description = "Show details for a catalog, including its property names" ) ]
729+ async fn tower_catalogs_show (
730+ & self ,
731+ Parameters ( request) : Parameters < ShowCatalogRequest > ,
732+ ) -> Result < CallToolResult , McpError > {
733+ let environment = request. environment . as_deref ( ) . unwrap_or ( "default" ) ;
734+ match api:: describe_catalog ( & self . config , & request. name , environment) . await {
735+ Ok ( response) => {
736+ let catalog = & response. catalog ;
737+ let properties: Vec < Value > = catalog
738+ . properties
739+ . iter ( )
740+ . map ( |prop| {
741+ json ! ( {
742+ "name" : prop. name,
743+ "environment_variable" : prop. environment_variable,
744+ "preview" : prop. preview,
745+ } )
746+ } )
747+ . collect ( ) ;
748+ Self :: json_success ( json ! ( {
749+ "name" : catalog. name,
750+ "type" : catalog. r#type,
751+ "environment" : catalog. environment,
752+ "properties" : properties,
753+ } ) )
754+ }
755+ Err ( e) => Self :: error_result ( "Failed to show catalog" , e) ,
756+ }
757+ }
758+
660759 #[ tool( description = "List teams you belong to" ) ]
661760 async fn tower_teams_list ( & self ) -> Result < CallToolResult , McpError > {
662761 if self . config . api_key . is_some ( ) {
@@ -703,14 +802,15 @@ impl TowerService {
703802 }
704803
705804 #[ tool(
706- description = "Deploy to Tower cloud. Prerequisites: Towerfile, tower_apps_create. Optional: working_directory."
805+ description = "Deploy to Tower cloud. Prerequisites: Towerfile, tower_apps_create. Optional: working_directory, environment ."
707806 ) ]
708807 async fn tower_deploy (
709808 & self ,
710- Parameters ( request) : Parameters < EmptyRequest > ,
809+ Parameters ( request) : Parameters < DeployRequest > ,
711810 ) -> Result < CallToolResult , McpError > {
712811 let working_dir = Self :: resolve_working_directory ( & request. common ) ;
713- let deploy_target = deploy:: DeployTarget :: Environment ( "default" . to_string ( ) ) ;
812+ let env = request. environment . unwrap_or_else ( || "default" . to_string ( ) ) ;
813+ let deploy_target = deploy:: DeployTarget :: Environment ( env) ;
714814
715815 match deploy:: deploy_from_dir ( self . config . clone ( ) , working_dir, true , deploy_target) . await {
716816 Ok ( _) => Self :: text_success ( "Deploy completed successfully" . to_string ( ) ) ,
@@ -770,7 +870,7 @@ impl TowerService {
770870 let config = self . config . clone ( ) ;
771871 let working_dir = Self :: resolve_working_directory ( & request. common ) ;
772872 let path = working_dir;
773- let env = "default" ;
873+ let env = request . environment . unwrap_or_else ( || "default" . to_string ( ) ) ;
774874 let params = request. parameters . unwrap_or_default ( ) ;
775875
776876 // Load Towerfile to get app name
@@ -782,7 +882,7 @@ impl TowerService {
782882 let app_name = towerfile. app . name . clone ( ) ;
783883
784884 let ( result, output) = Self :: execute_with_streaming ( & ctx, || {
785- run:: do_run_remote ( config, path, env, params, None , true )
885+ run:: do_run_remote ( config, path, & env, params, None , true )
786886 } )
787887 . await ;
788888 match result {
0 commit comments