This project does two things:
- A Next.js chat UI for Chrome Enterprise Premium.
- An MCP server so external agents (Claude Desktop, Gemini CLI) can manage the fleet.
It talks to real Google Cloud APIs (Admin SDK, Chrome Management, Cloud Identity, Chrome Policy).
To run this application, you must create a Google Cloud Project and configure OAuth credentials.
- Go to the Google Cloud Console.
- Create a new project (e.g.,
cep-hero). - Enable the following APIs (API & Services > Library):
- Admin SDK (
admin.googleapis.com) - For audit logs, org units, users, groups - Chrome Management API (
chromemanagement.googleapis.com) - For Chrome reports and profiles - Chrome Policy API (
chromepolicy.googleapis.com) - For reading/writing Chrome policies - Cloud Identity API (
cloudidentity.googleapis.com) - For DLP rules and Cloud Identity policies
- Admin SDK (
- Go to APIs & Services > OAuth consent screen.
- Select Internal (if you are a Workspace user) or External (for testing).
- Fill in the app name and email.
- Scopes: Add the following scopes:
https://www.googleapis.com/auth/chrome.management.reports.readonly- Read Chrome reportshttps://www.googleapis.com/auth/chrome.management.profiles.readonly- Read Chrome profileshttps://www.googleapis.com/auth/chrome.management.policy- Read/write Chrome policies (required for applying policy changes)https://www.googleapis.com/auth/cloud-identity.policies- Read/write Cloud Identity policies (required for creating DLP rules)https://www.googleapis.com/auth/admin.reports.audit.readonly- Read audit logshttps://www.googleapis.com/auth/admin.directory.orgunit- Read/write org unitshttps://www.googleapis.com/auth/admin.directory.group- Read groupshttps://www.googleapis.com/auth/admin.directory.user- Read usershttps://www.googleapis.com/auth/cloud-platform- Cloud platform accesshttps://www.googleapis.com/auth/ediscovery- eDiscovery accessopenid,email,profile- Basic identity
- Save and continue.
- Go to APIs & Services > Credentials.
- Click Create Credentials > OAuth client ID.
- Application type: Web application.
- Name:
CEP Hero. - Authorized Redirect URIs (Add BOTH):
http://localhost:3000/api/auth/callback/google(Web UI)http://localhost:3000/callback(CLI Login script)
- Click Create.
- Copy the Client ID and Client Secret.
Create a .env.local file in the root of the project:
# Google OAuth Credentials (Required)
GOOGLE_CLIENT_ID=your_client_id_here
GOOGLE_CLIENT_SECRET=your_client_secret_here
# Better Auth Configuration
BETTER_AUTH_URL=http://localhost:3000
NEXT_PUBLIC_BETTER_AUTH_URL=http://localhost:3000
BETTER_AUTH_SECRET=generate_a_random_string_here
# AI Configuration (Gemini API)
GOOGLE_GENERATIVE_AI_API_KEY=your_gemini_api_key
# Upstash Vector (for grounding)
UPSTASH_VECTOR_REST_URL=your_vector_url
UPSTASH_VECTOR_REST_TOKEN=your_vector_token
# Optional: Service account for test bypass and self-enrollment
GOOGLE_SERVICE_ACCOUNT_JSON='{"type":"service_account",...}'
GOOGLE_TOKEN_EMAIL=admin@your-domain.com
# Optional: Auto-sign-in as the delegated admin (GOOGLE_TOKEN_EMAIL)
# When enabled, skips OAuth and uses the service account directly.
# WARNING: Disables authentication entirely. For development/demo only.
USE_DEFAULT_USER=true
# Self-enrollment password for the registration form
SELF_ENROLLMENT_PASSWORD=your_secret_enrollment_passwordIntegration tests require a service account with domain-wide delegation to call Google Workspace Admin APIs.
- Go to Google Cloud Console > IAM & Admin > Service Accounts
- Click Create Service Account
- Name it (e.g.,
cep-hero-testing) - Grant no roles (delegation provides access)
- Click Done, then click the service account
- Go to Keys > Add Key > Create new key > JSON
- Save the downloaded JSON file
- On the service account page, click Show domain-wide delegation
- Check Enable Google Workspace Domain-wide Delegation
- Copy the Client ID (numeric)
- Go to Admin Console > Security > Access and data control > API controls
- Click Manage Domain-wide Delegation
- Click Add new
- Enter the Client ID from above
- Add these OAuth scopes (comma-separated):
https://www.googleapis.com/auth/admin.directory.user, https://www.googleapis.com/auth/admin.directory.orgunit, https://www.googleapis.com/auth/admin.directory.group, https://www.googleapis.com/auth/admin.reports.audit.readonly, https://www.googleapis.com/auth/chrome.management.policy, https://www.googleapis.com/auth/chrome.management.policy.readonly, https://www.googleapis.com/auth/chrome.management.reports.readonly, https://www.googleapis.com/auth/chrome.management.profiles.readonly, https://www.googleapis.com/auth/cloud-identity.policies, https://www.googleapis.com/auth/cloud-identity.policies.readonly, https://www.googleapis.com/auth/cloud-platform - Click Authorize
Add to .env.local:
# Service account JSON (minified or pretty-printed both work)
GOOGLE_SERVICE_ACCOUNT_JSON='{"type":"service_account","project_id":"...","private_key":"...","client_email":"..."}'
# Admin email for impersonation (must be a super admin)
GOOGLE_TOKEN_EMAIL=admin@your-domain.com
# Optional: Customer ID (auto-detected if not set)
GOOGLE_CUSTOMER_ID=C01234567bun installJust start the app. You will be prompted to sign in with Google when you visit the page.
bun devUse an OAuth token from the web sign-in flow. Application Default Credentials and local credential files are not supported.
Streamable HTTP Endpoint: http://localhost:3000/api/mcp
Authorization:
- Use the same OAuth bearer token issued by the web UI session:
Authorization: Bearer <token>.
Client headers (MCP Streamable HTTP):
- Initialization requests must
POSTwithAccept: application/json, text/event-streamandContent-Type: application/json. - After initialization, include
Mcp-Session-Id: <sessionId>on all requests. - For event streams,
GETwithAccept: text/event-streamandMcp-Session-Id.
curl -N \
-H "Authorization: Bearer <token>" \
-H "Content-Type: application/json" \
-H "Accept: application/json, text/event-stream" \
-X POST \
--data '{
"jsonrpc":"2.0",
"id":1,
"method":"initialize",
"params":{
"protocolVersion":"2025-03-26",
"capabilities":{},
"clientInfo":{"name":"curl","version":"1.0.0"}
}
}' \
http://localhost:3000/api/mcpCEP-Hero uses two types of quality assurance: unit tests for code correctness and evals for AI behavior quality.
# Run unit tests
bun test
# Run integration tests (requires service account)
bun test tests/dlp-api.test.ts
# Run evals (server auto-starts)
EVAL_FIXTURES=1 bun run evals
# Run a specific eval
EVAL_IDS=EC-057 EVAL_FIXTURES=1 bun run evalsIntegration tests validate live Google API behavior. They automatically skip when credentials are missing.
# DLP API tests (list, create, delete rules)
bun test tests/dlp-api.test.ts
# Validate DLP API directly
bun scripts/validate-dlp-api.tsTests verify:
- Cloud Identity API v1beta1 usage (required for DLP)
- Customer ID resolution
- DLP rule CRUD operations
- Error handling for permission issues
Evals are behavioral tests for the AI assistant. They verify that given a troubleshooting scenario, the AI provides helpful, accurate, and actionable guidance. Unlike unit tests with binary pass/fail outcomes, evals assess quality along multiple dimensions.
The eval framework uses fixture injection to provide deterministic test data without calling live Google APIs. This enables fast, reproducible, quota-free testing while exercising the full AI reasoning pipeline.
For comprehensive eval documentation, see:
- evals/README.md - Eval-specific details and fixture format
- evals/cases/README.md - Case index and category coverage
# Run all evals
EVAL_FIXTURES=1 bun run evals
# Run by category
EVAL_CATEGORY=connector EVAL_FIXTURES=1 bun run evals
EVAL_CATEGORY=policy EVAL_FIXTURES=1 bun run evals
EVAL_CATEGORY=dlp EVAL_FIXTURES=1 bun run evals
# Run in serial mode (for rate limiting)
EVAL_SERIAL=1 EVAL_FIXTURES=1 bun run evals
# Capture live fixtures
bun run fixtures:captureDLP rule operations require the v1beta1 API version:
const service = googleApis.cloudidentity({ version: "v1beta1", auth });Filter Limitations: The Cloud Identity policies.list API only supports filtering by customer:
customer == "customers/{customerId}"
It does NOT support setting.type.matches() or other filter expressions. DLP rules are filtered client-side using the pattern ^rule\.dlp on setting.type.
Uses v1 for policy resolution and modification. The my_customer alias works for most operations.
lib/mcp/registry.ts: Central re-export hub for MCP schemas and executor.lib/mcp/executor/: CepToolExecutor implementation with Google API integrations.lib/mcp/server-factory.ts: MCP tool registrations and Streamable HTTP transport.lib/mcp/errors.ts: UnifiedApiResult<T>type, type guards, and logging utilities.lib/mcp/constants.ts: Shared constants (MS_PER_DAY, CONNECTOR_POLICY_SCHEMAS).lib/mcp/formatters.ts: Human-readable formatting for Cloud Identity settings.lib/mcp/org-units.ts: Org unit name resolution and display mapping.lib/mcp/fleet-overview/summarize.ts: Dashboard summarization with deterministic styling and fallback.lib/overview.ts: Dashboard types (OverviewData, OverviewCard, Suggestion) and PII sanitization.lib/chat/chat-service.ts: AI orchestration with system prompt, tool registration, and guards.components/ai-elements/tool-result-card.tsx: Renders structured results (success/error/manual steps) from action tools inline.components/chat/chat-console.tsx: Main chat UI with Sources display, streaming indicators, org unit context, and tool result rendering.components/chat/welcome-message.ts: Dynamic welcome messages based on fleet health.components/ui/org-unit-context.tsx: React context for org unit ID-to-name resolution.components/ui/org-unit-display.tsx: Inline component for rendering friendly org unit names.app/api/chat/route.ts: Chat endpoint that exposes tools to the UI.app/api/mcp/route.ts: MCP Server endpoint via Streamable HTTP.app/api/overview/route.ts: Fleet overview endpoint backed bygetFleetOverview.
For AI agents and contributors, see AGENTS.md for:
- API Result Pattern - Use
ApiResult<T>discriminated unions - Unified Logging - Use
logApiRequest,logApiResponse,logApiError - Shared Constants - Add to
lib/mcp/constants.ts - Output Guardrails - No
[object Object], no literalundefinedstrings in tool outputs - Org Unit Display - Use
OrgUnitDisplaycomponent with context for friendly names - Quote Stripping - Use
stripQuotesfromlib/gimme/validation.tsfor env vars - Anti-patterns to Avoid - No barrel files, no duplicate types, no unnecessary wrappers
Quick commands:
bun x ultracite fix # Auto-format code
bun x ultracite check # Lint check
bun test # Run testsFor a comprehensive architecture walkthrough, see WALKTHROUGH.md.