fix(mcp): honour --url in stdio, make --mcp-authorizer-url inert - #768
Merged
Conversation
The two feed different mechanisms. --url sets the trusted URL, which GetHostFromRequest returns before it looks at any header; --mcp-authorizer-url only stamps `x-authorizer-url` metadata. Now that --url is required (#764) and inherited by the subcommand, it always wins — so --mcp-authorizer-url is inert wherever --url is set. That is the reason to deprecate rather than leave it: passing both is not an error and warns about nothing, so a divergent value looks configured and silently does nothing. examples/with-agent-permissions already passes both, so the flag is dead there today. Not removed. It still reaches the header path when `authorizer mcp` runs without --url, and breaking a 2.3.x stdio setup in a minor release to delete a flag whose whole subcommand goes in 2.5.0 buys nothing.
`authorizer mcp` inherits the root flag set, so --url was always accepted there — but parsers.SetTrustedURL was only ever called from runRoot. The flag therefore did nothing in this path: issuer validation stayed on header derivation, and --mcp-authorizer-url was the only mechanism that worked. Caught by deleting --mcp-authorizer-url from the example on the theory that it was already redundant. It was not; the stdio probe failed with `rpc error: code = Unauthenticated`. runMCP now pins the trusted URL as the server does, and the same probe passes with --url alone. This is what makes the deprecation in the previous commit true rather than assumed.
lakhansamani
added a commit
to authorizerdev/examples
that referenced
this pull request
Aug 14, 2026
--url alone now suffices: authorizerdev/authorizer#768 makes `authorizer mcp` honour it. Verified with `node mcp-agent.mjs --verify` against a live server — all six assertions pass. The example passed --url and --mcp-authorizer-url with the same value. Removing the latter WITHOUT the server fix failed with `rpc error: code = Unauthenticated`, which is how the underlying bug was found.
BREAKING CHANGE: --mcp-authorizer-url is gone; pass --url instead. The flag shipped in 2.3.0, so this is breaking for stdio MCP users. It lands in 2.4.0 rather than 2.5.0 because 2.4.0 already forces every deployment to add --url (#764) — the invocation is being edited anyway, so this rides along instead of costing a second migration. --url now does the job here: runMCP pins the trusted URL, which GetHostFromRequest consults before any header, and mcp.Options takes its value. Verified end to end with a live server via `node mcp-agent.mjs --verify` — all six assertions pass with the flag absent. Also refuses --mcp-bearer without --url at startup. That combination previously failed later as a bare `Unauthenticated` on every tool call, which reads as a bad token rather than missing config.
Reverts the deletion in 4a3b1af. The flag stays parsed so a 2.3.x invocation keeps starting instead of dying on `unknown flag`, but nothing reads it — --url supplies the value now that runMCP pins the trusted URL. Verified inert end to end: with --url correct and --mcp-authorizer-url=https://WRONG.example, all six assertions of `node mcp-agent.mjs --verify` still pass against a live server. Before the runMCP fix that wrong value would have broken issuer validation. Drops the flag from internal/e2e/smoke_test.go, which now passes --url instead — the same migration the deprecation notice prescribes.
lakhansamani
added a commit
to authorizerdev/examples
that referenced
this pull request
Aug 14, 2026
* fix: document the flags the server actually requires
The setup line repeated in 11 READMEs was v1-era and missing FOUR flags
the 2.4.0 server refuses to start without. As written it fails on the
first one before ever reaching the others:
$ ./authorizer --database-type sqlite --database-url authorizer.db \
--admin-secret secret
Error: --encryption-key is required: ...
Replaced with a command verified to boot against a build of authorizer
main: adds --url (authorizerdev/authorizer#764), --encryption-key,
--jwt-type/--jwt-secret and --client-id/--client-secret.
Also adds --url to the two org-SSO compose files and the k8s-tokenreview
manifest; all three map 8080:8080, so the container's own address and the
address the demo dials agree.
* fix(agent-permissions): drop redundant --mcp-authorizer-url
--url alone now suffices: authorizerdev/authorizer#768 makes
`authorizer mcp` honour it. Verified with `node mcp-agent.mjs --verify`
against a live server — all six assertions pass.
The example passed --url and --mcp-authorizer-url with the same value.
Removing the latter WITHOUT the server fix failed with
`rpc error: code = Unauthenticated`, which is how the underlying bug
was found.
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.
What
Three things, in the order that makes each one true:
fix(mcp)—authorizer mcpnow honours--url.deprecate(mcp)—--mcp-authorizer-urlis now inert: still accepted, warns, read by nothing.internal/e2e/smoke_test.go, which passes--urlinstead.The bug that made this possible
authorizer mcpinherits the root flag set, so--urlwas always accepted there. Butparsers.SetTrustedURLwas only ever called fromrunRoot:So inside the stdio subcommand
trustedURLstayed empty,GetHostFromRequestfell through to header derivation, and--urldid nothing.authorizer mcp --url=https://auth.example.comlooked configured and wasn't — while--mcp-authorizer-urlwas the only mechanism that actually worked.runMCPnow pins the trusted URL exactly as the server does. That is what lets the old flag become inert without breaking the stdio path.How the bug was found
I first assumed
--mcp-authorizer-urlwas already redundant, reasoning fromGetHostFromRequest's precedence, and deleted it fromexamples/with-agent-permissions/mcp-agent.mjs. The stdio probe failed immediately:Correct about the function, wrong about the process:
SetTrustedURLwas never called there.Verified inert, not just deprecated
With
--urlcorrect and a deliberately wrong--mcp-authorizer-url, all six assertions still pass against a live server:Before the
runMCPfix, that wrong value would have broken issuer validation. It is now read by nothing.Still parsed, not deleted, so an existing 2.3.x invocation keeps starting instead of dying on
unknown flag. It shipped in 2.3.0, so deleting it would be a breaking change; it goes with the subcommand in 2.5.0.Also
--mcp-bearerwithout--urlis now refused at startup with an explanatory message. That combination previously failed later as a bareUnauthenticatedon every tool call, which reads as a bad token rather than missing config — exactly the confusion that hid the bug above.Verification
go build ./...,go vet ./cmd/,go vet -tags smoke ./internal/e2e/,gofmt -l,go test ./cmd/all clean. End-to-end verified against a live server.Related
--urlmcp-agent.mjsno longer passes itRefs #764