Agent Authenticator exists because 2FA was still a manual step in otherwise-automated workflows at Forge Nord.
The problem was simple. The agent could handle the UI, submit the login form, and continue once authenticated. But when the site asked for a TOTP code, the workflow stopped and a human had to read six digits from a phone.
The obvious workaround is to give the agent the TOTP seed and let it generate codes directly. Forge Nord did not want to do that. The seed is a long-lived secret. The current TOTP code is not. Those should not be treated as the same thing.
So Forge Nord built Agent Authenticator: an MCP server that stores TOTP seeds in an encrypted local vault and only exposes operations that return the current code or manage accounts. There is no API for reading the underlying seed back out through MCP.
Design
The project is intentionally narrow.
- store TOTP seeds encrypted at rest
- return the current code on demand
- keep the default transport local
- work with existing MCP clients such as Claude Code and Cursor
That is the whole scope. This is not a password manager, not a general secrets product, and not a broader auth system.
Tool surface
The MCP interface is small:
- list accounts
- inspect non-secret account metadata
- generate the current TOTP code
- add an account from a seed or
otpauth://URI - remove an account
The main constraint is deliberate: the model can request a code, but it cannot retrieve the seed that generates future codes.
What needed fixing before release
The first internal version worked, but it was not ready to publish as-is. A few things needed cleanup first.
Concurrent vault writes
The vault already used file locking, but not across the full read-modify-write sequence. That is fine until multiple processes touch the same file. The release version wraps the full mutation path so writes are atomic.
First-run key handling
Printing key material to standard output is a bad default in general, and especially awkward when the primary transport is MCP over stdio. The first-run flow was reworked so key handling is quieter and less likely to leak into logs or transcripts.
HTTP defaults
If a tool can bind to the network, the default matters more than the warning text in the README. The HTTP mode now defaults to loopback-only and requires an explicit opt-in for remote binding.
Why I think the pattern matters
The implementation is small, but the interface pattern is useful.
When building agent infrastructure, the better question is usually not “what secret does the model need?” but “what is the narrowest useful operation to expose?”
In this case the answer was straightforward:
- not the TOTP seed
- just the current TOTP code
I think the same pattern applies elsewhere:
- not the database password, but a narrow query interface
- not the cloud login, but a deployment action
- not a general secrets manager, but one explicit capability
That is the kind of boundary that is easier to audit and easier to operate.
Open source release
Before publishing the repo, I added a few things that internal tools often skip:
- hardened vault write handling
- cleaner key setup
- a proper CLI with
serve,doctor, andkeygen - CI and release automation
- clearer security documentation
The code is on GitHub.