01 May Building Metis: An AI CloudOps Co-pilot on OCI – Part 1: The Architecture
I wanted to share a project that has been keeping me busy on the weekends to learn about MCP, Functions, Vaults and other cool stuff : Metis, an AI CloudOps Co-pilot I have been building for my own OCI tenancy. The idea started simple enough: I wanted one place where I could see everything in my tenancy, chat with my data in natural language, and have it tie into both my cloud resources and even some of my personal data (Strava activities, in this case). Four iterations later, I think it is in a good enough place to start writing about it.
This is going to be a four-part blog series. In this first post I want to walk through the architecture as a whole, and in the following posts I will go deep on three of the OCI services that made this possible: Autonomous Database 26ai with MCP, OCI Functions for the Strava sync, and OCI Vault for secrets management.
Why I Built This
If you have been following my blog or my talks, you know I spend a lot of time working with OCI. And while the OCI Console is great, I wanted something that I could open in the morning, see the state of my tenancy, ask a question in natural language (“how much did I spend on compute last month?”), and have an answer in seconds. I also wanted to learn the new pieces: MCP, agentic AI, Vault-based secrets, OIDC with Identity Domains, by actually using them, not by reading about them.
So Metis was born. The name comes from Greek mythology, “Metis” was the Titaness of wisdom and deep thought. Felt appropriate for an AI co-pilot.
The Stack
Here is what is running under the hood:
Backend
- Node.js 18+ with Express.js — REST API on port 3000
- OCI SDK for JavaScript — all OCI API calls go through the SDK, no more
execSyncagainstociCLI express-session+ manual OIDC flow with Identity Domains — for the login pageaxiosfor outbound calls to Gemini and Stravadotenvfor non-secret config
OCI Services
- Autonomous Database 26ai (with the new MCP endpoint baked in)
- OCI Vault (secrets at startup, not in
.env) - OCI Functions (Python 3.11, deployed via Docker for the Strava sync)
- OCI Identity Domain (Confidential App for OIDC)
- OCI Usage API (cost tracking)
- OCI Cloud Guard (governance problems feed)
- OCI Audit (24h event log)
AI Layer
- Google Gemini 2.5 Flash for the chat co-pilot and natural-language-to-SQL
- ADB 26ai MCP server for structured data queries against my Strava activity history
Frontend
- Vanilla JS + HTML — no build step, no bundler, served by Express
- Chart.js for the charts
- D3.js v7 for the tenancy + network visualizer
I deliberately kept the frontend simple. I am not a frontend guy, and I wanted to focus on the OCI integration side, not on a webpack config.
The High-Level Flow
When I open Metis in the morning, this is what happens:
- The browser hits
http://localhost:3000. Express checks if I have a session cookie. - No session → redirect to
/login.html. I click “Sign in with OCI IAM”. - OCI Identity Domain handles the login, redirects back to
/auth/callbackwith an authorization code. - Server exchanges the code for tokens, decodes the ID token to get my name and email, creates a session.
- Browser lands on the main dashboard. The dashboard fires parallel calls to
/api/instances,/api/volumes,/api/costs,/api/network,/api/governance,/api/audit,/api/strava/summary, and a few others. - Each of those calls goes through the OCI SDK (or to ADB via the MCP endpoint for Strava), with results cached for 5 minutes in memory.
The whole dashboard loads in about a second. Behind the scenes there is a lot more going on, but that is the user-facing flow.
Two Things That Surprised Me
A couple of things I want to call out before the deep dives.
The OCI SDK is so much better than shelling out to oci CLI. My V1 of Metis had 61 execSync calls against oci. It worked, but it was slow (the CLI re-authenticates on every call) and brittle (every command needed JSON parsing, error handling, retry logic). Migrating to the OCI SDK for JavaScript dropped my dashboard load time from about 8 seconds to under 1 second. If you are building anything against OCI from Node, just use the SDK from day one.
The ADB MCP endpoint is a game changer for AI apps. Instead of writing custom REST endpoints for every piece of data I want to expose, I can register PL/SQL functions as MCP tools, and the AI co-pilot can call them directly. I will go deep on this in the next post.
What Is Coming Next
In the next three posts I will go deep on:
- Autonomous Database 26ai with MCP — how I am using the Model Context Protocol endpoint on ADB to expose my Strava activity data to the AI co-pilot. This was the most interesting piece of the build.
- OCI Functions (Strava Sync) — how I am running a Python OCI Function on a schedule to pull Strava activities and push them into ADB. Includes the Docker build, the VCN/subnet config, and the Vault integration.
- OCI Vault for Secrets — how I moved every secret out of
.envand into Vault, with the server reading them at startup. No more secrets on disk on my laptop.
If you have questions or want me to cover anything specific in the deep dives, drop me a note. Otherwise, see you in part two.
Sorry, the comment form is closed at this time.