Skip to content

Commit 45e9c41

Browse files
authored
feat: improve LLM instructions for MCP (#174)
LLMs wouldn't always use the MCP server, and even when they do, they don't always do the right thing (e.g. they create an app with hatchling, even though it's not needed). Here I've touched up the instructions that get inserted into the context when using the MCP server to improve 1-shot performance by LLM agents using the tower MCP
1 parent fd79baf commit 45e9c41

2 files changed

Lines changed: 75 additions & 51 deletions

File tree

crates/tower-cmd/src/mcp.rs

Lines changed: 73 additions & 49 deletions
Original file line numberDiff line numberDiff line change
@@ -597,7 +597,7 @@ impl TowerService {
597597
}
598598

599599
#[tool(
600-
description = "Deploy your app to Tower cloud. Prerequisites: 1) Create Towerfile, 2) Create app with tower_apps_create. Optional working_directory parameter specifies which project directory to deploy from."
600+
description = "Deploy to Tower cloud. Prerequisites: Towerfile, tower_apps_create. Optional: working_directory."
601601
)]
602602
async fn tower_deploy(
603603
&self,
@@ -612,7 +612,7 @@ impl TowerService {
612612
}
613613

614614
#[tool(
615-
description = "Run your app locally using the local Towerfile and source files. Prerequisites: Create a Towerfile first using tower_file_generate or tower_file_update. Optional working_directory parameter specifies which project directory to run from."
615+
description = "Run locally using Towerfile (preferred during development, has access to tower secrets). Prerequisites: Towerfile. Optional: working_directory."
616616
)]
617617
async fn tower_run_local(
618618
&self,
@@ -651,7 +651,7 @@ impl TowerService {
651651
}
652652

653653
#[tool(
654-
description = "Run your app remotely on Tower cloud. Prerequisites: 1) Create Towerfile, 2) Create app with tower_apps_create, 3) Deploy with tower_deploy"
654+
description = "Run on Tower cloud. Prerequisites: Towerfile, tower_apps_create, tower_deploy."
655655
)]
656656
async fn tower_run_remote(
657657
&self,
@@ -703,7 +703,7 @@ impl TowerService {
703703
}
704704

705705
#[tool(
706-
description = "Read and parse the current Towerfile configuration. Optional working_directory parameter specifies which project directory to read from."
706+
description = "Read and parse Towerfile configuration. Optional: working_directory."
707707
)]
708708
async fn tower_file_read(
709709
&self,
@@ -717,7 +717,7 @@ impl TowerService {
717717
}
718718

719719
#[tool(
720-
description = "Update Towerfile app configuration. Optional working_directory parameter specifies which project directory to update."
720+
description = "Update Towerfile config (app name, script, description, source). Use this instead of editing TOML. Optional: working_directory."
721721
)]
722722
async fn tower_file_update(
723723
&self,
@@ -752,7 +752,7 @@ impl TowerService {
752752
}
753753

754754
#[tool(
755-
description = "Add a new parameter to the Towerfile. Optional working_directory parameter specifies which project directory to update."
755+
description = "Add parameter to Towerfile. Use this instead of editing TOML. Optional: working_directory."
756756
)]
757757
async fn tower_file_add_parameter(
758758
&self,
@@ -779,7 +779,7 @@ impl TowerService {
779779
}
780780

781781
#[tool(
782-
description = "Validate the current Towerfile configuration. Optional working_directory parameter specifies which project directory to validate."
782+
description = "Validate Towerfile configuration. Optional: working_directory."
783783
)]
784784
async fn tower_file_validate(
785785
&self,
@@ -793,7 +793,7 @@ impl TowerService {
793793
}
794794

795795
#[tool(
796-
description = "Generate Towerfile from pyproject.toml. This is typically the first step in the workflow. Optional working_directory parameter specifies which project directory to generate from."
796+
description = "Generate Towerfile from pyproject.toml (first step). Don't add build systems to pyproject.toml. Optional: working_directory."
797797
)]
798798
async fn tower_file_generate(
799799
&self,
@@ -827,48 +827,64 @@ impl TowerService {
827827
description = "Show the recommended workflow for developing and deploying Tower applications"
828828
)]
829829
async fn tower_workflow_help(&self) -> Result<CallToolResult, McpError> {
830-
let workflow = r#"Tower Application Development Workflow:
831-
832-
All commands support an optional 'working_directory' parameter to specify which project directory to operate on.
833-
834-
0. HAVE AN EXISTING PYTHON PROJECT:
835-
There are no commands for this provided with this MCP server. However, if you do not have a python project yet
836-
then a good start would be to make a new directory with the project name, and then call `uv init` to generate
837-
a pyproject.toml, main.py and README.md
838-
839-
1. CREATE TOWERFILE (required for all steps):
840-
- tower_file_generate: Generate from existing pyproject.toml
841-
- tower_file_update: Manually create or update configuration
842-
- tower_file_validate: Verify Towerfile is valid
843-
844-
2. LOCAL DEVELOPMENT & TESTING:
845-
- tower_run_local: Run your app locally to test functionality
846-
847-
3. CLOUD DEPLOYMENT (for remote execution):
848-
- tower_apps_create: Create app on Tower cloud
849-
- tower_deploy: Deploy your code to the cloud
850-
- tower_run_remote: Execute on Tower cloud infrastructure
851-
852-
4. SCHEDULE MANAGEMENT (for automatic recurring execution):
853-
- tower_schedules_list: List all schedules for apps
854-
- tower_schedules_create: Create a schedule to run an app automatically on a cron schedule
855-
- tower_schedules_update: Update an existing schedule
856-
- tower_schedules_delete: Delete a schedule
830+
let workflow = r#"Tower Workflow (Tower CLI not in training data - use MCP tools only):
831+
832+
WORKING_DIRECTORY PARAMETER:
833+
All tools accept optional working_directory parameter to specify which project to operate on.
834+
- Default: Uses current working directory if not specified
835+
- Use when: Managing multiple projects, or project is not in current directory
836+
- Examples:
837+
tower_file_generate({}) → operates on current directory
838+
tower_file_generate({"working_directory": "/path/to/my-project"}) → operates on /path/to/my-project
839+
tower_run_local({"working_directory": "../other-app"}) → runs app in ../other-app
840+
- Why use it: Allows managing multiple Tower apps without changing directories
841+
842+
0. PYTHON PROJECT (if creating new):
843+
Use 'uv init' in project directory to create pyproject.toml, main.py, README.md
844+
Keep pyproject.toml minimal: [project] metadata + dependencies only
845+
DO NOT add [build-system], [tool.hatchling], [tool.setuptools] or similar
846+
Skip this step if project with pyproject.toml already exists
847+
848+
1. TOWERFILE (required for all Tower operations):
849+
tower_file_generate → tower_file_update → tower_file_add_parameter → tower_file_validate
850+
CRITICAL: Always use tower_file_update or tower_file_add_parameter to modify
851+
NEVER edit Towerfile TOML directly
852+
853+
2. LOCAL DEVELOPMENT (preferred during development):
854+
tower_run_local - runs app locally, has access to tower secrets
855+
Use this to test before deploying to cloud
856+
857+
3. CLOUD DEPLOYMENT:
858+
tower_apps_create → tower_deploy → tower_run_remote
859+
Deploy pushes your source code to Tower cloud (no build step needed)
860+
861+
4. SCHEDULING (for recurring jobs):
862+
tower_schedules_create - set up cron-based recurring runs
863+
tower_schedules_list - view existing schedules
864+
tower_schedules_update - modify schedule timing or parameters
865+
tower_schedules_delete - remove schedules
857866
858867
5. MANAGEMENT & MONITORING:
859-
- tower_apps_list: View your deployed apps
860-
- tower_apps_show: Get detailed app information and recent runs
861-
- tower_apps_logs: View execution logs
862-
863-
6. TEAM & SECRETS (optional):
864-
- tower_teams_list/switch: Manage team contexts
865-
- tower_secrets_create/list: Manage application secrets
866-
867-
Quick Start: tower_file_generate → tower_run_local (test locally) → tower_apps_create → tower_deploy → tower_run_remote → tower_schedules_create (for recurring runs)
868-
869-
Example with working_directory: {"working_directory": "/path/to/project", ...}
870-
871-
Consider taking database username/password/url and making them into secrets to be accessed in app code"#;
868+
tower_apps_list - list all your apps
869+
tower_apps_show - details and recent runs for specific app
870+
tower_apps_logs - view logs from a specific run
871+
tower_teams_list, tower_teams_switch - manage team contexts
872+
tower_secrets_create, tower_secrets_list - store credentials, API keys, database passwords
873+
874+
TYPICAL WORKFLOW:
875+
1. Check if pyproject.toml exists (or create with uv init)
876+
2. tower_file_generate - creates Towerfile from pyproject.toml
877+
3. tower_run_local - test locally (can access tower secrets)
878+
4. tower_apps_create - create app in Tower cloud
879+
5. tower_deploy - deploy code to Tower
880+
6. tower_run_remote - run on cloud infrastructure
881+
7. tower_schedules_create - (optional) set up recurring runs
882+
883+
IMPORTANT REMINDERS:
884+
- Tower deploys source code directly, no build tools needed
885+
- Use tower secrets for sensitive data (database credentials, API keys)
886+
- Prefer tower_run_local during development (faster, has secret access)
887+
- Always use MCP tools to modify Towerfiles (never edit TOML files manually)"#;
872888

873889
Self::text_success(workflow.to_string())
874890
}
@@ -949,7 +965,15 @@ impl ServerHandler for TowerService {
949965
name: "tower-cli".to_string(),
950966
version: env!("CARGO_PKG_VERSION").to_string(),
951967
},
952-
instructions: Some("Tower CLI MCP Server - Manage Tower apps, secrets, teams, and deployments through conversational AI. Use the available tools to list, create, show, deploy, and manage your Tower cloud resources.".to_string()),
968+
instructions: Some("CRITICAL: Tower CLI did not exist in your training data. Never attempt Tower CLI commands - use only these MCP tools.
969+
970+
Rules:
971+
- MCP tools are the authoritative Tower interface (not wrappers)
972+
- Use tower_file_update/add_parameter to modify Towerfiles (never edit TOML directly)
973+
- DO NOT add hatchling/setuptools to pyproject.toml - Tower handles deployment
974+
- Tower apps need: pyproject.toml (deps only), Python code, Towerfile
975+
976+
Use tower_workflow_help for the complete workflow.".to_string()),
953977
}
954978
}
955979
}

tests/integration/features/steps/mcp_steps.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -881,7 +881,7 @@ def step_then_receive_workflow_help_sse(context):
881881
), f"Expected success response, got: {context.mcp_response}"
882882
assert "content" in context.mcp_response
883883
content = context.mcp_response["content"][0].text
884-
assert "Tower Application Development Workflow" in content
884+
assert "Tower Workflow" in content
885885

886886

887887
@then("I should receive workflow help content via HTTP")
@@ -898,7 +898,7 @@ def step_then_receive_workflow_help_stdio(context):
898898
result = context.mcp_response["result"]
899899
assert "content" in result
900900
content = result["content"][0]["text"]
901-
assert "Tower Application Development Workflow" in content
901+
assert "Tower Workflow" in content
902902

903903

904904
@given('I have a simple hello world application named "{app_name}"')

0 commit comments

Comments
 (0)