A replica set is more than three containers. The members have to find each other, share a secret, agree on a primary, and replicate your writes. This page walks through asking the LLM (I'll use Claude for this guide) to build one on Cycle with the Cycle MCP server, then prove it works.
The concept
A MongoDB replica set on Cycle is three stateful containers, each running a single instance, in one environment. Generally, this is deployed together as a stack. Each member gets its own volume and its own hostname (mongo-0, mongo-1, mongo-2). The members reach each other by hostname over the environment's private network, which in most cases is IPv6-only. So the MCP will naturally run mongod with --ipv6 as well as --bind_ip_all.
Authentication adds two secrets. The keyfile is a shared secret the members use to authenticate each other. Setting it also turns on access control, so every client has to log in too. The admin password is for you and your applications. The MCP will generally understand that neither belongs in the stack, because stacks store command arguments and environment variables in plain text (unless you're using stack variables). In testing the MCP was able to disseminate that each variable would be best as a scoped variable marked secret, which Cycle writes into each member as a file when it starts.
The order follows from that. The containers are created stopped. The secrets are created next, then the containers start, so every member boots with its keyfile already in place. Only then can the replica set be initiated from inside one member.
If using the connector Claude or Codex will need the write and exec scopes for this: write to create resources, and exec to run mongosh inside a member. If the connector is missing either, see this article on managing permissions.
Do it
This example builds replica set rs0 in a new environment acme-db on the production cluster.
- Ask Claude in one prompt. Naming the environment and asking for confirmations up front means Claude doesn't have to choose either for you:
"Create a new environment calledacme-dbin theproductioncluster, then deploy a MongoDB replica set to it and prove that it's up and working. Before each change, tell me exactly what you're about to do and wait for my OK." - Claude checks the ground and gets the MongoDB hint. It reads the cluster with
list_serversand checks the name is free withlist_environments. It also callsdeploy_applicationwithapplication: mongodband no containers. That returns Cycle's recommended MongoDB configuration and changes nothing:mongo:7,mongod --replSet rs0 --bind_ip_all --ipv6, a 10G volume at/data/db, and one stateful container per member. - Confirm the environment and choose authentication. Claude asks you to approve the environment, and asks how the replica set should authenticate.
Choosing: without authentication, anything on the environment's private network can read and write the database. That's acceptable for a throwaway test. With a keyfile and an admin user, members authenticate each other and every client needs credentials. This example uses a keyfile and an admin user, which adds a step to create the two secrets and a command to create the admin user.
After you approve,create_environmentcreatesacme-dbwith legacy networking off and starts it. - Confirm the stack. Claude previews the deploy, then describes it:
"I'm about to create stackacme-mongoand deploy it intoacme-db. It holds 3 containers,mongo-0,mongo-1andmongo-2, each with imagemongo:7, commandmongod --replSet rs0 --bind_ip_all --ipv6 --keyFile /etc/mongo/keyfile, 1 stateful instance, a 10G volume at/data/db, port27017:27017, and public network disabled. The containers are created stopped. OK to deploy?"
After you confirm,deploy_applicationbuilds the stack and creates the three containers, all stopped. - Confirm the secrets and the start. Claude generates a random keyfile and a random admin password, previews both scoped variables, and asks two questions in one prompt. The first is:
"I'm about to create 2 secret scoped variables inacme-db, both reachingmongo-0,mongo-1andmongo-2:mongo-keyfile, delivered as the file/etc/mongo/keyfile, andmongo-admin-password, delivered as the file/etc/mongo/admin-password. Both files have mode0400and are owned by uid and gid999, themongodbuser. OK to create both?"
The second asks whether to start all three containers once the secrets exist.
After you confirm,manage_scoped_variablecreates both variables andcycle_control_containerstarts each member. Claude then waits withget_logsformongodto logWaiting for connections, and checks withlist_containersthat all three are running.
Note for real usage: when Claude generates the secrets, their values pass through the conversation. For anything beyond a test, create the two scoped variables yourself in the portal, with the same file paths, mode0400and owner uid and gid999, and give Claude only their identifiers. - Confirm the replica set setup. Claude previews two commands for
run_instance_commandonmongo-0, and asks before running them. The first initiates the replica set and waits formongo-0to become primary, the second creates theadminuser with therootrole, reading the password from the file inside the container:
Both should returneok: 1, andmongo-0reportedisWritablePrimary=true. - Confirm the proof. Claude previews two more commands and asks before running them, as it does for every command it runs inside a container. One of them writes a test document, the only data change in the proof. In this example they returned:
Check
Where
Result
Request without credentials
mongo-0Rejected with
Unauthorizedrs.status()over the replica-set URImongo-0,mongo-1,mongo-2/?replicaSet=rs0mongo-0mongo-0PRIMARY,mongo-1andmongo-2SECONDARY, all health 1Insert
{_id:"proof-1"}intomcp_proof.checkswith write concernmajoritymongo-0Acknowledged
Read
proof-1back, connected directly to the membermongo-2secondary=true,primary=mongo-0:27017, document returned
What just happened
Each check in the proof tests a different layer. The rejected request shows that authentication is enforced, not just configured. rs.status() ran on the primary, and it reports health 1 for a member only while the primary's heartbeats to that member succeed. So all three being healthy means the primary reaches both secondaries by hostname over IPv6. A write with write concern majority is acknowledged only after at least two of the three members have it. Reading the same document on a secondary, over a direct connection to that member, shows it replicated rather than being read from the primary, which also means that secondary reaches the primary.
The keyfile is checked twice. mongod refuses to start when its keyfile is missing or readable by other users, so mongo-0 logging Waiting for connections shows it read its keyfile. Members also authenticate to each other with the keyfile, so mongo-1 and mongo-2 becoming healthy secondaries shows their keyfiles matched. Listing /etc/mongo inside mongo-0 showed both files owned by mongodb with mode 0400, as the scoped variables specified.
Nobody needed a password to set the replica set up. Until the first user exists, MongoDB's localhost exception lets a connection from inside the server run a small set of setup commands, including rs.initiate and creating that first user. Both ran through it, from inside mongo-0 with run_instance_command. Creating the admin user closes that door, which is why the unauthenticated request in the proof was rejected.
The password never appears in the command text Claude shows you. Every command reads it from /etc/mongo/admin-password inside the container, so the text you approve contains only the file path. That isn't the same as keeping it off the command line. In the proof commands, the shell expands -p "$PW" into mongosh's arguments, so the password is briefly visible in that member's process list. createUser reads it inside JavaScript instead, which avoids that. The values did pass through the conversation, when Claude generated them and sent them to manage_scoped_variable. That's why step 5 suggests creating the variables yourself for real data.
Every run_instance_command call was previewed first. The preview echoes the exact command and target without connecting, so you approve exactly what runs. That matters more here than elsewhere, because exec gives Claude a shell inside your database.