SibylMaking Science
Back to Sibyl

Connect Sibyl to an AI agent

Sibyl trains BigQuery ML propensity models on a GA4 property's BigQuery export and delivers High / Medium / Low audiences back to GA4, all inside your own Google Cloud project. Every install also serves a Model Context Protocol endpoint, so an agent can operate it in conversation: performance briefings, building and running models, run status, export health. Two ways to connect a Gemini Enterprise agent are below; any MCP client works the same way.

The endpoint belongs to your install, not to this website — it is your own Cloud Run service, at /api/mcp. Queries hit it directly, so nothing about your models or your GA4 data passes through Making Science.

  • Connection details
  • Path A — native connector
  • Path B — ADK agent
  • System instructions
  • The tools
  • Demo script
  • Troubleshooting

Connection details

Everything below uses these two values — the only blanks on this page. If someone else runs the install you're connecting to, they send you both.

MCP endpointSIBYL_MCP_URL — e.g. https://sibyl-app-acme-backend-xxxxxxxxxx-uc.a.run.app/api/mcp. It is the install's backend service, a different host from the dashboard you sign into — the dashboard's address will not work. Sibyl's own Settings → Agent access shows the exact URL, copyable.
CredentialPath A: none to pass around — the install allowlists the service-account email your connector authenticates as. Path B: the install's access key (SIBYL_ACCESS_KEY) — the same key the dashboard asks for. Keep it server-side.

Path A — native connector (no code)

  1. Gemini Enterprise console → add a data source → Custom MCP Server (Preview).
  2. URL: the MCP endpoint above. Authentication: the GCP service-account token option.
  3. The install allowlists the service account your connector authenticates as. Whoever operates it runs one env-var update (additive — it disturbs nothing else) and the connect succeeds:
    gcloud run services update <prefix>-backend --region <region> \
      --update-env-vars "SIBYL_MCP_INVOKERS=<connector-sa>@<project>.iam.gserviceaccount.com"
  4. "Reload custom actions" imports the 14 tools; enable them all. Read tools run without per-action confirmation; action tools prompt first — keep that.
  5. Create a dedicated agent that uses these actions and paste the system instructions below into its instructions field.

If your tenant doesn't show the Custom MCP Server source or its service-account auth option yet, use Path B.

Path B — ADK agent

A small agent built with Google's Agent Development Kit, deployed to Vertex AI Agent Engine, registered in Gemini Enterprise. The system instructions ship in the code.

sibyl-analyst/
  .env                     # local trial only — never commit
  requirements.txt         # google-adk[mcp]>=2.6,<3   (the [mcp] extra is required)
  sibyl_analyst/
    __init__.py            # from .agent import root_agent
    agent.py               # below, verbatim

agent.py

"""The Sibyl analyst — an ADK agent over Sibyl's MCP surface."""
from __future__ import annotations

import os

from google.adk.agents import LlmAgent
from google.adk.tools.mcp_tool import McpToolset, StreamableHTTPConnectionParams

SIBYL_MCP_URL = os.environ["SIBYL_MCP_URL"]
SIBYL_ACCESS_KEY = os.environ.get("SIBYL_ACCESS_KEY", "")

INSTRUCTION = """\
You are the Sibyl analyst — the conversational operator of this
organization's Sibyl install (predictive GA4 audiences, running in the
customer's own Google Cloud project).

You have 14 Sibyl tools. Reach for them instead of asking the user for
anything a tool can fetch. Route intents like this:
- "How are my models doing / which performs best?" →
  summarize_model_performance. It returns the ranking, lifts and caveats
  precomputed — narrate it exactly; never recompute or re-rank.
- "What could I build a model on?" → list_candidate_events.
- "Build a model for X and run it" → list_candidate_events to confirm X is
  trainable → confirm the audience policy with the user (publication_scope
  is PERMANENT once the GA4 audiences are created) → create_model → report
  the run_id → get_run_status when they ask later.
- "Run everything / retrain / just prediction / just delivery" →
  run_pipeline with scope all | retrain | predict | deliver.
- "Is it done? What happened?" → get_run_status (namespace for a live
  model, run_id for a first run).
- "How is the export / the data?" → get_export_health.
- Pause, resume or change a schedule → configure_automation.
  Cancel a run → cancel_run. Delete a model → delete_model, only after the
  user names the model and confirms — then pass confirm=True.
- One model in depth → get_model. "What is this install?" →
  get_install_overview.

Numbers:
- Every figure comes from a tool result in this conversation; rates are
  already percent. Quote them with their qualifiers, and repeat every
  caveat the tool returns. "No conversions observed yet" is a young model,
  not a failing one — say so.

Actions:
- Before any action tool: say exactly what will happen and get a yes here
  in chat first.
- After dispatching: run_pipeline waits briefly for the worker.
  confirmed=true → name the running stage. confirmed=false → "accepted,
  not yet confirmed" — usually a cold start, not a failure. Either way the
  run continues unattended on Google's side: the user can leave and ask
  later.
- Offer to WATCH a dispatched run: get_run_status with wait_seconds=300
  streams progress and returns when it settles, so the user is told it
  finished instead of asking repeatedly. Say you're watching it.
- If a tool refuses because a model's first run is still in flight, relay
  Sibyl's explanation and offer to watch that run instead.

Style:
- Lead with the answer, then the two or three numbers that support it.
  Short paragraphs. Call models by their objective event ("the sign_up
  model"), not by namespace, unless asked for identifiers.
"""

root_agent = LlmAgent(
    # Set SIBYL_AGENT_MODEL to your organization's current Gemini model.
    model=os.environ.get("SIBYL_AGENT_MODEL", "gemini-2.5-pro"),
    name="sibyl_analyst",
    description=(
        "Analyzes and operates this organization's Sibyl install: model "
        "performance briefings, building and running predictive-audience "
        "models, run status, GA4 export health."),
    instruction=INSTRUCTION,
    tools=[
        McpToolset(
            connection_params=StreamableHTTPConnectionParams(
                url=SIBYL_MCP_URL,
                headers={"x-sibyl-access": SIBYL_ACCESS_KEY},
            ),
        ),
    ],
)

Run locally, then deploy

# .env — the two values from Connection details, plus your Vertex project
SIBYL_MCP_URL=...
SIBYL_ACCESS_KEY=...
SIBYL_AGENT_MODEL=gemini-2.5-pro
GOOGLE_GENAI_USE_VERTEXAI=1
GOOGLE_CLOUD_PROJECT=...
GOOGLE_CLOUD_LOCATION=us-central1

pip install -r requirements.txt
adk web                                  # local chat against the live install

adk deploy agent_engine \
  --project ... --region us-central1 \
  --staging_bucket gs://... \
  ./sibyl_analyst

Set SIBYL_MCP_URL and SIBYL_ACCESS_KEY as environment variables on the deployment (the key via Secret Manager), then register the Agent Engine agent in your Gemini Enterprise agent gallery.

System instructions

The tools arrive with their schemas and descriptions when they import, so the agent already knows they exist and what each does. This block adds the part that doesn't travel with tools: which tool answers which request, when to chain them, what to confirm before acting, and the voice. Paste it as-is into the agent's instructions field (Path A) — it is already inside agent.py on Path B.

You are the Sibyl analyst — the conversational operator of this
organization's Sibyl install (predictive GA4 audiences, running in the
customer's own Google Cloud project).

You have 14 Sibyl tools. Reach for them instead of asking the user for
anything a tool can fetch. Route intents like this:
- "How are my models doing / which performs best?" →
  summarize_model_performance. It returns the ranking, lifts and caveats
  precomputed — narrate it exactly; never recompute or re-rank.
- "What could I build a model on?" → list_candidate_events.
- "Build a model for X and run it" → list_candidate_events to confirm X is
  trainable → confirm the audience policy with the user (publication_scope
  is PERMANENT once the GA4 audiences are created) → create_model → report
  the run_id → get_run_status when they ask later.
- "Run everything / retrain / just prediction / just delivery" →
  run_pipeline with scope all | retrain | predict | deliver.
- "Is it done? What happened?" → get_run_status (namespace for a live
  model, run_id for a first run).
- "How is the export / the data?" → get_export_health.
- Pause, resume or change a schedule → configure_automation.
  Cancel a run → cancel_run. Delete a model → delete_model, only after the
  user names the model and confirms — then pass confirm=True.
- One model in depth → get_model. "What is this install?" →
  get_install_overview.

Numbers:
- Every figure comes from a tool result in this conversation; rates are
  already percent. Quote them with their qualifiers, and repeat every
  caveat the tool returns. "No conversions observed yet" is a young model,
  not a failing one — say so.

Actions:
- Before any action tool: say exactly what will happen and get a yes here
  in chat first.
- After dispatching: run_pipeline waits briefly for the worker.
  confirmed=true → name the running stage. confirmed=false → "accepted,
  not yet confirmed" — usually a cold start, not a failure. Either way the
  run continues unattended on Google's side: the user can leave and ask
  later.
- Offer to WATCH a dispatched run: get_run_status with wait_seconds=300
  streams progress and returns when it settles, so the user is told it
  finished instead of asking repeatedly. Say you're watching it.
- If a tool refuses because a model's first run is still in flight, relay
  Sibyl's explanation and offer to watch that run instead.

Style:
- Lead with the answer, then the two or three numbers that support it.
  Short paragraphs. Call models by their objective event ("the sign_up
  model"), not by namespace, unless asked for identifiers.

Agent name: Sibyl analyst. Description: Analyzes and operates this organization's Sibyl install: model performance briefings, building and running predictive-audience models, run status, GA4 export health.

The tools

ToolWhat it doesNotes
get_install_overviewWhich install this is: project, connected GA4 property, versions.Good first call in a conversation.
list_modelsEvery model with objective, trained date, band sizes, latest per-band conversion rates.Rates arrive as conversion_rate_pct — already percent.
get_modelOne model in depth: schedules, recent activity, performance trend.—
summarize_model_performanceCross-model comparison, pre-ranked by High-vs-Low lift, caveats attached.The answer to “how are my models performing?” — the agent narrates, never recomputes.
list_candidate_eventsGA4 events that could be a model's objective, ranked; blocked events say why.no_positives / no_negatives are the two blockers.
get_export_healthGA4→BigQuery export freshness and daily volume vs the standard-tier cap.Includes the grant command when a cross-project export still needs one.
get_run_statusLive stage-by-stage state for a model (namespace) or a first run (run_id).wait_seconds (≤300) turns it into a watch: streams progress, returns when the run settles.
create_modelCreate a model for an objective event and start its first training run.publication_scope is permanent — the agent must confirm it first.
run_pipelineRun now: scope all · retrain · predict · deliver. Waits briefly for the worker's first heartbeat.confirmed=false means accepted, not failed.
continue_first_runAdvance a staged first run (predict, then deliver).Only for models created with stop_after_training.
cancel_runCancel the active run for a model or a first run.Schedules untouched; delivered audiences are not undone.
configure_automationChange cadence or pause/resume: retrain, or the coupled predict_deliver.Presets: daily, weekly, monthly, hourly, every 6/12 hours — or cron.
delete_modelPermanently delete one model and everything Sibyl created for it.Refuses without confirm=true; Gemini Enterprise will also ask.
update_model_engineRebuild a model's generated SQL on the current engine version.Frozen (whole-script-overridden) stages are reported, not silently skipped.

One behavior worth knowing: a run takes minutes to hours, so no tool blocks on completion. run_pipeline dispatches and waits up to ~90s for the worker's first heartbeat — confirmed: true names the running stage and includes a Cloud Console link; confirmed: false means accepted-but-not-yet-reporting (normal during a cold start, not a failure). Either way the run continues unattended; asking "did that finish?" later reads the same durable state the Sibyl dashboard renders, so chat and dashboard can't disagree. Or ask the agent to watch: get_run_status with wait_seconds streams progress and answers the moment the run settles.

Demo script — the first conversation

  1. “What is this install connected to?”
  2. “How is the export looking?”
  3. “What events could I build a model on?”
  4. “How are my models performing?”
  5. “Build a model that optimizes toward sign_up and run it.” — the agent confirms the audience policy (permanent), creates the model, reports the run id, and tells you that you can leave.
  6. “Run just the prediction for the sign_up model.”
  7. Come back later: “Did that run finish?”

Troubleshooting

SymptomFix
401 on connect (Path A)The token's identity isn't on SIBYL_MCP_INVOKERS — check the exact service-account email. The backend log names what it received; the audience can then be pinned with SIBYL_MCP_AUDIENCE.
401 (Path B)Wrong or missing access key. It rides the x-sibyl-access header (the agent code does this); Authorization: Bearer <key> also works on the MCP endpoint.
No Custom MCP Server source in your consoleThe Preview hasn't reached your tenant — use Path B.
“accepted, not yet confirmed” after starting a runCold start; nothing to fix. Ask for the run status a minute later.
A tool call returns a product messageSibyl's own guardrails speaking — “this model is already live”, “deletion is permanent — confirm first”. They are answers, not failures.

Questions: sibyl@group.makingscience.com. Data handling: privacy policy.