feat(server): connect a GCP project from the conversation - #37
Open
JeroenSoeters wants to merge 10 commits into
Open
feat(server): connect a GCP project from the conversation#37JeroenSoeters wants to merge 10 commits into
JeroenSoeters wants to merge 10 commits into
Conversation
The skill could ask which cloud and then dead-end on GCP. It no longer does. GCP gets one tool where AWS has three, and that asymmetry is the cloud's rather than an inconsistency here. The AWS trio is link-then-register because CloudFormation's quick-create URL lets the operator apply a stack in their own console and come back with a role. GCP retired its only console-deployable template service, so there is no link to hand anyone: formae provisions with the operator's own credentials, and provisioning and registering are a single call. Splitting that into two tools would invent a step that does not exist. The optional workload_identity_provider is not a second mode a caller picks freely. Supplying it means the operator stood the federation up themselves, which is the only case where formae has nothing to provision, and the description says what that path does not check so "registered" cannot be read as "working". registeredDoc carries whichever coordinate its cloud uses, and GCP gets its own renderer rather than reusing the AWS one: renderRegistered prints a role line, and a GCP connection has no role. Printing an empty one would invite the reader to believe in a value that never existed. The tool carries DestructiveHint for the same reason provision_cloud_role does: the mutation happens immediately, with no console step and nothing for the user to apply themselves. The skill says what is about to be granted, in those words, before the call rather than after.
The CLI grew four GCP failure codes and this map did not, so a run with no Google credentials reported "formae connect failed (credentials_required)": a refusal with no remedy, when the remedy is one command the producer already names in the failure's details. Found by running the flow rather than by reading it, which is why the test added here checks the codes carry a description at all and that the one whose remedy is a command actually names it.
The operator is in front of this server: it runs on their machine, started by their own agent session. Machine output says how results are rendered, not whether a person is present, so without saying so explicitly the sign-in was unreachable from here and every operator was handed a command to run by hand. --no-input still applies and still means what it says: no terminal prompt this server would have to answer.
The description stopped at "the user must install it", which invites the agent to tell them to log in as well. There is one more step and it is calling this tool again: the sign-in happens then.
JeroenSoeters
marked this pull request as ready for review
August 28, 2026 22:15
…ject home Cursor 2.4 reads the same ~/.agents/skills location Codex does, so one symlink serves both and the guide is the Codex one with Cursor's own MCP registration: ~/.cursor/mcp.json, since Cursor has no CLI for it. The guide states the one thing that does not port - several skills cross-reference each other as /formae:<name>, which is Claude Code syntax and means nothing elsewhere - rather than leaving it to be discovered. The connect flow proposed the current directory as the new project's home unconditionally, on the reasoning that git init, npm init and cargo init do the same. They do not: the user cd'd there and typed the command, so they chose it. We are proposing, and a harness that starts in / then has us propose scattering three files into the filesystem root. Seen for real in a container, where Claude Code starts in /. Now: the current directory unless it is / or the home directory itself, and otherwise ~/<label>, reusing the target label rather than asking a second naming question.
…find Both came out of driving the server over stdio the way Cursor launches it, under a deliberately narrow PATH. formae itself was a prerequisite the guide listed and never explained. The Claude Code plugin provisions formae and the oidc auth plugin behind the scenes; go install provides neither, so a reader who only ever used the plugin has no reason to know they are missing. A hosted sign-in without oidc cannot succeed. FORMAE_BIN is the one that misleads. A formae the server cannot reach is not caught at startup: it registers, lists all 43 tools and looks healthy, then every call fails with exec: "formae": executable file not found in $PATH, because resolution is lazy and per call. The guide warned about a narrow PATH for the server binary, where the failure is obvious, and said nothing about the one where it is not. Also notes that go install honours GOBIN before GOPATH/bin, which is where the binary actually lands under a version-managed Go.
…nted The headless case was a dead end, and the last mile was here rather than in the CLI. Where a browser cannot be opened, gcloud prints a sign-in URL and waits for a verification code on a stdin that is /dev/null under this server. The run fails having already printed the one thing that would let the operator finish, the CLI now carries it in the failure details - and this build decoded schemaVersion, code and message only, so the details never crossed and the caller got a canned line telling them to run a command that fails the same way. Details are now relayed by an allowlist, per code and per key. Not a passthrough: the producer may attach anything to any failure, and a blanket relay would make every future detail a disclosure decision nobody took. The producer's message stays withheld exactly as before, for the reason already recorded - it is built from plugin error strings and a Pkl failure quotes profile source, which for a classic profile can hold an inline password. A named key from a named code is a different thing. Three tests: the URL reaches the caller while the message does not, an unlisted code relays nothing, and a failure with no details reads as it always did.
…t cannot work The remedy named for credentials_required was "run gcloud auth application-default login and try again", which is right where a browser can be opened and useless where one cannot: gcloud then falls back to printing a URL and reading a verification code typed back, so running it the same way fails identically. Says where to run it, and why. The relayed transcript underneath already showed the EOF, but the instruction above it still read as "try harder".
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
The skill could ask which cloud and then dead-end on GCP. It no longer does.
GCP gets one tool where AWS has three, and that asymmetry is the cloud's rather than an inconsistency here. The AWS trio is link-then-register because CloudFormation's quick-create URL lets the operator apply a stack in their own console and come back with a role. GCP retired its only console-deployable template service, so there is no link to hand anyone: formae provisions with the operator's own credentials, and provisioning and registering are a single call. Splitting that into two tools would invent a step that does not exist.
workload_identity_provideris optional but it is not a second mode a caller picks freely — supplying it means the operator stood the federation up themselves (Terraform, say, because they will not give a CLI provisioning rights), which is the only case where formae has nothing to provision. Its description states what that path does not check, so "registered" cannot be read as "working".Details worth flagging
registeredDoccarries whichever coordinate its cloud uses. GCP gets its own renderer rather than reusing the AWS one:renderRegisteredprints aRole:line and a GCP connection has no role, so reuse would invite the reader to believe in a value that never existed. A test mutating it back torenderRegisteredgoes red.DestructiveHint, likeprovision_cloud_role: the mutation happens immediately, with no console step and nothing for the user to apply.gcloud auth application-default login.gcp.ConfigwithOidcAuthin place of theaws.Config,discoverableset explicitly, and the coordinate taken from the registration rather than the user's keyboard.Base
Targets
mcp-connectrather than main, because that is where the connect tools live. Rebase onto main if PLA-700 lands first.Depends on
formaePR #685 forconnect gcpand its GCP registration document.