Cirrus Solar MCP
README.md
# Cirrus Solar MCP Deployment Package
Portable deployment package for the Cirrus Solar Salesforce hosted MCP demo
agent. The agent is built with Google ADK, serves through FastAPI, deploys to
Cloud Run, reads demo operational data from BigQuery, invokes Salesforce hosted
MCP prompt-template retrieval for diagnostics, and can create Salesforce
`WorkOrder` records when a replacement workflow is needed.
This repository is sanitized for reuse in another Salesforce org and Google
Cloud project. It intentionally contains no org-specific credentials, tokens,
keys, project IDs, Salesforce org aliases, generated Salesforce record IDs, or
local virtual environment files.
## What Is Included
- `app/`: ADK agent, FastAPI app, Salesforce MCP client, OAuth helper logic,
BigQuery tools, telemetry setup, and local mock/offline data.
- `deployment/terraform/single-project/`: optional single-project GCP
infrastructure for Cloud Run service identity, APIs, telemetry storage, and
BigQuery analytics resources.
- `salesforce-dx/`: Salesforce DX metadata and Knowledge article seed content
for target org setup.
- `scripts/`: setup and smoke-test helpers for Salesforce hosted MCP, PKCE
OAuth, BigQuery demo data, and deployed trigger testing.
- `tests/`: unit and integration tests plus ADK evaluation scaffolding.
- `Dockerfile`, `pyproject.toml`, `uv.lock`, and `agents-cli-manifest.yaml`:
deploy/runtime metadata.
## What Is Intentionally Excluded
- `.env`, `.venv`, caches, `.terraform`, local ADK state, and local CLI state.
- Salesforce generated record ID maps such as `knowledge_draft_ids.csv`.
- Generated Knowledge import/update CSVs containing target-org record IDs.
- Any refresh tokens, bearer tokens, client secrets, service account keys, or
concrete environment-specific values.
## Prerequisites
- Python 3.11 through 3.13.
- `uv`: <https://docs.astral.sh/uv/getting-started/installation/>
- Google Agents CLI:
```bash
uv tool install google-agents-cli
uvx google-agents-cli setup
```
- Google Cloud SDK authenticated to the target project.
- Salesforce CLI authenticated to the target Salesforce org.
- Terraform, only if you plan to provision the optional infrastructure under
`deployment/terraform/single-project`.
## Local Setup
Install dependencies:
```bash
agents-cli install
```
Create a local environment file from the template:
```bash
cp .env.example .env
```
Run the deterministic offline smoke test:
```bash
DEMO_OFFLINE_MODE=true agents-cli run "Triage signal SIG-FATAL-MINV-0001"
```
Start the local playground:
```bash
agents-cli playground
```
Run tests:
```bash
uv run pytest tests/unit tests/integration
```
## Environment Variables
Use `.env.example` as the authoritative list of runtime configuration values.
Do not commit `.env` or any file that contains real tokens or secrets.
For deployed environments, prefer Google Secret Manager for sensitive values:
- `SALESFORCE_OAUTH_REFRESH_TOKEN`
- `SALESFORCE_OAUTH_CLIENT_SECRET`, only if your Salesforce External Client App
requires one.
- `SALESFORCE_MCP_BEARER_TOKEN`, only if you use bearer-token mode.
Non-sensitive deployment variables can be passed with `agents-cli deploy
--update-env-vars` or configured in your deployment system.
## Salesforce Target Org Setup
### Hosted MCP Documentation Notes
Official Salesforce documentation:
- [Salesforce Hosted MCP Servers overview](https://developer.salesforce.com/docs/platform/hosted-mcp-servers/guide/hosted-mcp-servers-overview.html)
- [Create an External Client App](https://developer.salesforce.com/docs/platform/hosted-mcp-servers/guide/create-external-client-app.html)
Key points from the Hosted MCP docs that matter for this deployment:
- Hosted MCP Servers let MCP-compatible AI clients connect to Salesforce data,
automation, Prompt Builder templates, SObject operations, Apex/Flow/custom
tools, and product integrations through Salesforce governance and sharing.
- Hosted MCP is intended for per-user OAuth access, so actions should respect
each authorized user's Salesforce permissions, field-level security, and
sharing rules.
- Salesforce requires an External Client App for MCP clients. Connected Apps
are not supported for hosted MCP access.
- External Client Apps can take up to 30 minutes to become operational after
creation.
- Scratch org setup is different: Salesforce notes that External Client Apps
cannot be created directly in scratch orgs through Setup UI. Create the app
in a Dev Hub org, package it, and install it into the target scratch org.
- Required OAuth scopes for this project are `mcp_api` and `refresh_token`.
- Recommended External Client App security controls include limiting access to
authorized users with a permission set, using client secrets only where they
can be safely stored server-side, considering IP restrictions for stable
server-side clients, enabling refresh-token rotation, shortening refresh-token
validity, and enabling single logout when immediate revocation is required.
1. Authenticate to the target Salesforce org:
```bash
sf org login web --alias "<target-org-alias>"
```
2. Confirm Salesforce Knowledge is enabled in the target org.
3. Deploy the Knowledge metadata and seed articles:
```bash
cd salesforce-dx
SALESFORCE_ORG_ALIAS="<target-org-alias>" \
KNOWLEDGE_RECORD_TYPE_ID="<target-knowledge-record-type-id>" \
./scripts/deploy_and_import_knowledge.sh
cd ..
```
The `KNOWLEDGE_RECORD_TYPE_ID` value must come from the target org. The script
builds `salesforce-dx/data/knowledge_articles_kav_import.csv` locally at deploy
time so no source-controlled CSV carries a record type from another org.
4. Create a Salesforce External Client App for hosted MCP access. Follow
[SALESFORCE_MCP_AUTH.md](SALESFORCE_MCP_AUTH.md).
5. Generate a refresh token with the local PKCE helper:
```bash
uv run python scripts/salesforce_oauth_pkce.py \
--client-id "<external-client-app-consumer-key>" \
--login-url "https://<target-my-domain>.my.salesforce.com"
```
6. Discover hosted MCP tool names:
```bash
SALESFORCE_OAUTH_CLIENT_ID="<external-client-app-consumer-key>" \
SALESFORCE_OAUTH_REFRESH_TOKEN="<refresh-token-from-pkce-flow>" \
SALESFORCE_LOGIN_URL="https://<target-my-domain>.my.salesforce.com" \
uv run python scripts/test_salesforce_mcp.py
```
Update these placeholders if the discovered names differ:
- `SALESFORCE_PROMPT_TEMPLATE_NAME`
- `SALESFORCE_MCP_PROMPT_TOOL`
- `SALESFORCE_MCP_RECORD_TOOL`
- `SALESFORCE_WORK_ORDER_OBJECT`
## BigQuery Demo Data
Authenticate to Google Cloud:
```bash
gcloud auth login
gcloud auth application-default login
gcloud config set project "<target-gcp-project-id>"
```
Load the demo datasets:
```bash
GCP_PROJECT_ID="<target-gcp-project-id>" \
GCP_REGION="<target-region>" \
uv run python scripts/setup_bigquery_demo.py
```
By default the agent expects:
- `BQ_PANEL_TELEMETRY_DATASET=panel_telemetry`
- `BQ_PARTS_MASTER_DATASET=parts_master`
Override these variables if you load data into different datasets.
## Optional Terraform Infrastructure
Review and edit the placeholder values in:
```text
deployment/terraform/single-project/vars/env.tfvars
```
Then provision:
```bash
cd deployment/terraform/single-project
terraform init
terraform plan -var-file=vars/env.tfvars
terraform apply -var-file=vars/env.tfvars
cd ../../..
```
The Terraform creates an application service account and telemetry-related
resources. Review IAM roles before applying in production.
## Cloud Run Deployment
Deploy with `agents-cli` after Salesforce, BigQuery, and secrets are ready:
```bash
agents-cli deploy \
--project "<target-gcp-project-id>" \
--region "<target-region>" \
--service-account "<app-service-account-email>" \
--secrets "SALESFORCE_OAUTH_REFRESH_TOKEN=<secret-id>" \
--update-env-vars "DEMO_OFFLINE_MODE=false,GCP_PROJECT_ID=<target-gcp-project-id>,GCP_REGION=<target-region>,SALESFORCE_LOGIN_URL=https://<target-my-domain>.my.salesforce.com,SALESFORCE_OAUTH_CLIENT_ID=<external-client-app-consumer-key>,SALESFORCE_MCP_AUTH_MODE=oauth,SALESFORCE_MCP_PROMPT_SERVER_URL=https://api.salesforce.com/platform/mcp/v1/custom/prompttemplates,SALESFORCE_MCP_RECORD_SERVER_URL=https://api.salesforce.com/platform/mcp/v1/platform/sobject-all,SALESFORCE_PROMPT_TEMPLATE_NAME=<target-prompt-template-name>,SALESFORCE_MCP_RECORD_TOOL=<target-record-tool-name>,SALESFORCE_WORK_ORDER_OBJECT=WorkOrder"
```
If your External Client App requires a client secret, store it in Secret Manager
and add it to the `--secrets` argument:
```bash
--secrets "SALESFORCE_OAUTH_REFRESH_TOKEN=<refresh-token-secret-id>,SALESFORCE_OAUTH_CLIENT_SECRET=<client-secret-id>"
```
## Post-Deployment Validation
Run a deployed trigger smoke test:
```bash
CLOUD_RUN_URL="<deployed-cloud-run-url>" \
uv run python scripts/run_demo_trigger.py
```
Ask the deployed agent to triage:
```text
Triage signal SIG-FATAL-MINV-0001
```
Expected flow:
1. Read fault signal details.
2. Read panel details.
3. Invoke Salesforce hosted MCP prompt-template diagnosis.
4. Check BigQuery part inventory.
5. Plan a resolution action.
6. Create a Salesforce `WorkOrder` only when replacement is required.
## GitHub Actions
`.github/workflows/deploy-cloud-run.yml` is a placeholder CI/CD workflow. It is
safe to commit because it contains no credentials. Before enabling it:
- Configure Google Workload Identity Federation.
- Add repository variables such as `GCP_PROJECT_ID`, `GCP_REGION`, and
`GCP_SERVICE_ACCOUNT_EMAIL`.
- Add Salesforce non-secret configuration as repository variables.
- Store sensitive Salesforce values in Google Secret Manager, not GitHub.
## Security Notes
- Never commit `.env`, service account JSON files, OAuth refresh tokens, bearer
tokens, generated access tokens, or Salesforce client secrets.
- Use target-org placeholders in docs and scripts until deployment time.
- Keep Salesforce record IDs out of source control; generate import/update CSVs
per target org.
- Review Terraform IAM roles before use in regulated or production
environments.
## Useful Commands
```bash
agents-cli install
agents-cli run "Triage signal SIG-FATAL-MINV-0001"
agents-cli playground
uv run pytest tests/unit tests/integration
agents-cli deploy --help
```
This server cannot be deployed
Maintenance
ActivityStale
ResponsivenessNo issues