openops builds three MCP servers inside its image and pins two Python packages by hand
The batteries-included, No-Code FinOps automation platform, with the AI you trust.
At a glance
- What is it?
- A no-code FinOps automation platform sold as a managed service or as a docker-compose stack, with workflow versioning, approvals across channels and its own spreadsheet-like database. The interesting engineering is not the product copy, it is the Dockerfile, which clones three other repositories at build time and carries a comment explaining exactly how a rebuild broke the assistant.
- Who is it for?
- openops fits a FinOps team that already has visibility tooling and lacks the ability to act on what it finds, and it does not fit a team that wants to run the cloud cost logic itself. Three things to settle first.
- Can I use it commercially?
- Check first. The repository uses a licence we do not classify automatically, so read its LICENSE file before any commercial use.
- Is it still maintained?
- Yes. The repository last received commits 2 days ago.
- What is it written in?
- Mainly TypeScript, according to GitHub's language statistics.
Answers come from the project's GitHub data, last synced on October 3, 2026, and from our analysis. They are not legal advice.
Editorial analysis
The Dockerfile clones two repositories and one of them is sparse checked out
The build stage starts from a pinned Alpine Node image and immediately installs a native toolchain, with a comment naming the reason: native addons and MCP dependencies. So a JavaScript application image is being taught to compile Python extensions.
Then it installs the Python package manager from its own install script, piped into a shell, with an unmanaged install path so the binary lands in a fixed location, and immediately sets an environment variable telling it never to download a Python interpreter. Everything after that runs on the system Python inside the image.
Two external repositories are cloned at build time.
The first is OpenOps's own MCP server repository, cloned and then checked out to one specific commit hash, followed by a dependency sync that is frozen, skips dev dependencies and skips installing the project itself.
The second is the awslabs MCP repository, cloned at depth one against a dated branch tag, filtered to skip blobs and to be sparse, then narrowed to three directories: the cost explorer server, the AWS pricing server and the billing cost management server. The git metadata is deleted afterwards so the three servers are the only thing left.
So the assistant capability of this product depends on three upstream servers being fetchable at build time, from two repositories it does not vendor.
Two Python packages are pinned by a hand written constraints file
The build carries a comment that is worth reading twice, because it explains a failure in terms of how it appeared rather than how it was caused.
The claim is that two packages must stay pinned. The reason given is that the upstream servers declare both of them with no upper bound, so checking out a fixed git tag pins their source while their dependencies still resolve fresh from the package index on every single rebuild. In other words, the same commit produces different software depending on what the index served that day.
The incident behind the comment: version 2.0 of one of those packages renamed a submodule the third server imported. A rebuild silently picked up the 2.x line, all three servers died at startup with a module not found error for the old submodule path, and the visible symptom was not a crash.
It surfaced as the AI assistant hanging, with the stream eventually cut by nginx, rather than as a build failure. Nothing in the image build turned red. A container started, the web application started, and the feature that uses the assistant simply stopped working while looking like a slow request.
The fix is a one line constraints file written during the build with two exact versions, one package at 1.30.0 and the other at 2.14.7. Given that a rebuild resolves fresh by default, a manual constraints file inside a Dockerfile is the mechanism doing the actual work here, and the comment is the only reason a reader would know it exists.
The compose stack publishes Postgres and reuses your admin login for Tables
The development compose file is named for the development environment, and it is what the advertised self install path runs on. Its first service is the bundled spreadsheet database, pulled from a private registry at a pinned tag.
That service receives a long list of settings from environment variables with a project prefix: the public and private URLs, an encryption key, a JWT signing key, the admin username and password, refresh token lifetime in hours, access token lifetime in minutes, and the database name, host, port, user and password. Two of those values are worth stopping on. The OpenOps admin email and password are handed to the Tables service as its own administrator account, so one login becomes the admin of a second service. And an extra allowed hosts value is set to a wildcard, which is a development convenience rather than a deployment setting.
A volume check is also disabled outright, and the service is given 512 megabytes of shared memory and a health check that calls the application's own health check script, with ten retries at twenty second intervals. It waits for Redis and Postgres to report healthy before starting.
Postgres runs at a pinned version and publishes port 5432 to the host. That is the line to look at before running this stack anywhere reachable from another machine: the database port is on the host interface, and the file is a development file that the documentation points at for a free self-hosted install.
The self install is one clause, and the configuration surface is a dozen variables
The requirements section offers exactly two shapes and describes them in three lines each.
One is a managed cloud service: no infrastructure to run, automatic updates and maintenance, premium support and service level agreements, with a pricing page behind it. The other is described as a free, ready to install installation based on docker-compose, which can run locally or in the cloud.
That is the whole install story. There is no command for the compose path, no prerequisite list, no minimum hardware, no note about what to back up, and no statement of which services the stack starts. A reader who wants the self-hosted option has to find the compose file in the repository and infer the rest.
The configuration surface is not small. The compose file reads more than a dozen variables with a project prefix, covering the public URL of the bundled tables, an encryption key, a JWT secret and a token lifetime, the administrator email and password, the Postgres user, password and database name, the database host, and the frontend URL. The repository ships a template environment file, and the package manifest copies it into place automatically during the prepare step if no environment file exists yet.
So the practical picture is a managed product with a self-hosted path whose documentation is one sentence, and a configuration file that expects you to fill in secrets before anything starts.
The manifest says 0.100.0 and the newest tag is 0.7.1
The package manifest records the version as 0.100.0 and carries a matching release candidate field with the same value. The published releases do not agree. The most recent tags are 0.7.1 on 24 September 2026 and 0.7.0 on 23 September, and before those, 0.6.25 on 14 May 2026.
Two observations follow. The manifest version is not tracking the release line, so it cannot be used to tell you which build you have, and a version comparison against 0.100.0 will tell you your install is newer than any published release, which is not true.
The cadence is also uneven. There is a four month gap between 0.6.25 in May and 0.7.0 in late September, then two releases on consecutive days. The default branch received a push on 1 October 2026, the day after the newest tag, and the archive flag is off, so there is work in flight rather than a finished state.
For anyone pinning, the tags are the only reliable marker of a published state, and the manifest number is a placeholder. Nothing in the file explains why the two disagree.
Apache 2.0 in the document, unasserted in the metadata, plus a third party list
The licence story has three layers and they do not line up perfectly.
The document says OpenOps is licensed under the Apache License 2.0, and the badge row at the top links the Apache licence page. The repository root carries a licence file, a NOTICE file, and a separate file listing third party licences. There is also a package script whose job is to regenerate that third party file in place, using a checked in generator configuration.
The repository's own licence metadata, though, records no assertion rather than a licence identifier. So the file, the notice and the badge say one thing, and the machine readable field says nothing was determined.
That combination is common in repositories whose licence was verified by a person and never encoded for tooling, and it has a practical cost: any automated compliance check that reads the metadata will not find a licence, and any packaging step that reads the metadata will treat the project as unlicensed. A human reading the root gets a clear answer.
The third party file is the part that carries real obligations for this product specifically. The platform integrates with cloud providers, FinOps tooling, communication services and project management tools, and it ships with a bundled spreadsheet product as its own database, so the licences of those dependencies are part of what you inherit when you run the self-hosted stack.
Blocks are the unit you create, sync and publish
The manifest describes a four process development environment rather than a single server. One script builds the server worker, builds what the file calls blocks, links the local packages, and then runs four things concurrently under the labels GUI, WORKER, ENG and APP with four different terminal colours.
The two server processes differ by an environment variable that names the container type. One runs as a worker on port 3010, the other runs as the app. That split is why there are two Dockerfiles in the repository, one for the main application and one named for the worker, and it is also why the compose file and the deployment directory have to keep two shapes in step.
Blocks are the extension unit. The command line interface is run through ts-node against a path in the packages directory, and it has subcommands to create blocks, to create actions, to create triggers, and to sync blocks. A separate script publishes a block, and it lives in the tools directory rather than in the CLI, so publishing is a release step rather than a day to day one.
The rest of the repository is a large TypeScript workspace: an Nx configuration, jest configuration split across three files, two eslint configurations plus a prettier setup, husky hooks with a lint staged configuration, a Netlify configuration and a chromatic configuration for the frontend, nginx as a template, a dev container definition, a Crowdin based translation flow, two AI agent instruction files at the root, a prompts directory, and configuration for two automated review tools.
The product argument is that visibility tools find savings and cannot act on them
The problem statement is specific enough to be worth quoting rather than summarising. FinOps practitioners struggle with visibility tools that surface cost saving opportunities but have no ability to implement them. Traditional automation tools, whether custom built or bought, fail to balance flexibility against maintainability.
So the platform is built as the execution layer between detection and change. The feature list supports that: human in the loop controls across multiple channels for approval workflows that matter, workflow versioning with testable steps and logs for every action taken, and centralised tables where an opportunity can be approved, dismissed, marked as a false positive, or snoozed.
That snooze and dismiss vocabulary is the tell about what the tool assumes about its own output. A system that expects a meaningful share of its findings to be wrong has to give you somewhere to say so.
Two pieces ship with it rather than integrating: an Excel-like database for tables and a visualisation system, each with its own documentation section. The named cloud providers are three, AWS, Azure and Google Cloud, stated identically in the feature section and in the integration section, and the third party integrations are described by category, naming databases, FinOps tools, communication platforms and task management services without listing any of them here.
The claim to test before adopting is the no-code part. The product is described as approachable for non technical practitioners while still allowing a drop into code, and the workflow editor is the surface where both claims have to hold at once.
Editorial conclusion
openops fits a FinOps team that already has visibility tooling and lacks the ability to act on what it finds, and it does not fit a team that wants to run the cloud cost logic itself. Three things to settle first. Read the Dockerfile before you build it, because the image depends on three external repositories at pinned commits, so your build inherits their availability and your network has to reach them. Decide between the managed service and the compose stack knowing that the file gives you no commands for the stack and the configuration surface is a dozen environment variables. And settle the licensing question by reading the root files rather than the metadata, which records no assertion while the file itself says Apache 2.0 and ships a third party licence list.
Frequently asked questions
How do I install openops?
Two ways are described: a managed cloud service with no infrastructure to run, automatic updates and premium support with service level agreements, or a free docker-compose based installation that can run locally or in the cloud. The file gives no command for the compose path, and its services take their configuration from environment variables copied from a template file during the prepare step.
What licence is openops released under?
The document says Apache License 2.0, and the repository root carries a licence file, a NOTICE file and a separate third party licence list that a package script regenerates. The repository's own licence metadata records no assertion, so automated tools reading the metadata will not find a licence.
Which cloud providers does openops support?
Three are named, AWS, Azure and Google Cloud. Beyond that it integrates by category with databases, third party FinOps visibility tools, communication platforms and project management services, and those integrations are not named individually in this file.
What are blocks in openops?
They are the authoring unit. The command line interface, run through ts-node against a path in the packages directory, has subcommands to create blocks, actions and triggers and to sync blocks, while publishing a block is a separate script in the tools directory.
Why does the openops image clone other GitHub repositories?
To build the MCP servers the assistant uses. The image clones the project's own MCP server repository at a fixed commit, and clones the awslabs MCP repository at a dated tag with a sparse checkout of the cost explorer, AWS pricing and billing cost management servers, deleting the git metadata afterwards.
Official sources
Add this badge to your README
If you maintain this project, the badge below links readers to this analysis and shows its maintenance status from the daily GitHub snapshot. Paste the markdown into your README; add ?metric=license or ?metric=stars to the image URL for a different field.
[](https://hysenlabs.com/projects/openops-cloud-openops)