Skip to main content
Glama
srobbins-sfdc

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
```