Skip to main content
Glama
mgcrea
by mgcrea

@mgcrea/mcp-totp

Model Context Protocol server that mints TOTP verification codes on macOS, with the seeds kept in the login keychain.

It exists so that npm publishing — and anything else gated behind a six-digit code — can run without a human clicking an approval every five minutes.

What this is NOT

It cannot read verification codes out of Passwords.app. No interface for that exists, and this is worth stating plainly because it is the first thing everyone assumes:

Route

Why not

AppleScript

Passwords.app has no scripting dictionary — sdef errors -192, and there is no NSAppleScriptEnabled

App Intents / Shortcuts

No Metadata.appintents in the bundle; nothing registers a Passwords action

otpauth:// URL scheme

Registered, but inbound only — it imports a seed, it never emits a code

/usr/bin/security

No OTP subcommand, and its legacy API cannot see synchronizable iCloud items at all

A helper using SecItemCopyMatching

Passwords.app reads TOTP through the com.apple.password-manager keychain access group. Apple does not sign that entitlement for third parties

Reading keychain-2.db

Readable as a file, encrypted under Secure-Enclave-wrapped class keys

UI scripting

Needs Accessibility and Automation grants and still raises a Touch ID prompt per reveal — so not automation

So this server keeps its own copy of the seed and computes codes locally. What it does offer is the other direction: totp_import_uri can hand the same seed to Passwords.app through the otpauth:// scheme it claims, so your phone and Mac keep working normally and nothing drifts out of sync.

Related MCP server: proton-pass-community-mcp

Security

Read this before deciding to use it.

Storing a TOTP seed on the machine that also holds the credential it protects means automation on that machine is effectively single-factor. Anything that can read the keychain item can mint codes forever. That is the deliberate trade for unattended publishing, and it is why every seed-writing tool sits behind TOTP_ALLOW_WRITES.

Two narrower properties worth knowing:

  • Seeds are passed to security in argv, because add-generic-password has no stdin form — its only alternative is an interactive tty prompt. A local process watching ps could catch one during the milliseconds a write takes.

  • The item's ACL trusts /usr/bin/security, which is what makes reads silent rather than prompting. It also means anything on the machine that can run security can read the seed.

If you do not need unattended operation, you probably do not need this. For npm specifically, trusted publishing over OIDC needs no second factor at all — configure that first, and use this only for local publishes and account management.

Configure

Variable

Meaning

TOTP_ALLOW_WRITES

1 registers the seed-importing and seed-removing tools. Off by default

TOTP_SECRET_<LABEL>

A seed supplied by environment, for Docker/CI where there is no keychain. Either an otpauth:// URI or a bare base32 key

TOTP_KEYCHAIN_SERVICE

Keychain service the seeds are filed under. Defaults to com.mgcrea.mcp-totp

TOTP_DEBUG

Verbose stderr logging

Seeds resolve environment first, then keychain, per label — so a TOTP_SECRET_NPM in a container beats whatever the machine holds, without editing anything.

Labels are lower-case letters, digits and underscores, starting alphanumeric (npm, aws_root). That restriction is load-bearing: it keeps the mapping to TOTP_SECRET_<LABEL> bijective, so a label you see listed is a label you can look up.

Quick start

A. npx

{
  "mcpServers": {
    "totp": {
      "command": "npx",
      "args": ["-y", "@mgcrea/mcp-totp"],
      "env": { "TOTP_ALLOW_WRITES": "1" }
    }
  }
}

B. From source

pnpm install && pnpm build
TOTP_ALLOW_WRITES=1 node dist/cli.js

Inspect the tools

printf '%s\n' \
  '{"jsonrpc":"2.0","id":1,"method":"initialize","params":{"protocolVersion":"2024-11-05","capabilities":{},"clientInfo":{"name":"ci","version":"0"}}}' \
  '{"jsonrpc":"2.0","method":"notifications/initialized"}' \
  '{"jsonrpc":"2.0","id":2,"method":"tools/list"}' \
| node dist/cli.js 2>/dev/null | grep -o '"name":"totp_[a-z_]*"' | sort -u

Tools

W = requires TOTP_ALLOW_WRITES=1. ⚠ = requires confirm: true.

Tool

Purpose

totp_auth_status

What the server can do, which seeds exist, and the setup guide as data

totp_list

Registered seeds and their parameters. Never a secret

totp_get_code

Mint the current code for a label

totp_import_uri

W

Store a seed from an otpauth:// URI or base32 key; optionally share it with Passwords.app

totp_scan_export

W

List the OTP-bearing entries of a Passwords.app CSV export. Returns no passwords, notes or secrets

totp_import_from_export

W

Import one entry from that export, by index

totp_remove

W ⚠

Permanently delete a seed

Getting a seed in

Primary path — never writes every password to plaintext. When a service first hands you the seed, capture it then:

npm profile enable-2fa auth-and-writes        # prints an otpauth:// URI
→ totp_import_uri { label: "npm", uri: "otpauth://...", share_with_passwords_app: true }

The same seed lands in the keychain and in Passwords.app, so nothing about your normal flow changes.

Secondary path — when you do not want to rotate the service's 2FA. Export from Passwords.app (File › Export All Passwords…, which needs the UI and a biometric confirmation and cannot be driven from here), then:

→ totp_scan_export { file_path: "/Users/you/Passwords.csv" }   # pick an index
→ totp_import_from_export { file_path: "...", index: 0, label: "npm" }
→ rm /Users/you/Passwords.csv                                   # it is every credential you have

Traps worth knowing

  • Modifying a keychain item prompts on first use; creating and deleting do not. On a machine that has not yet granted /usr/bin/security access to an item, add-generic-password -U raises an authorization dialog — and with no tty the CLI blocks on it forever, taking the server with it. Once allowed, -U succeeds silently, so this is a first-use gate rather than a permanent one; that is exactly why it must not sit on the write path, since it fires on a fresh install. Writes here are therefore delete-then-add, which stays inside the two operations that never prompt. Every security call is also bounded by a 15-second timeout, so a dialog can never wedge the server — it becomes an error that names the dialog instead.

  • HOTP is rejected, not coerced. A counter-based seed minted here would desynchronise the counter held by the real authenticator.

  • A code returned by totp_get_code enters the transcript. It is a bearer-equivalent second factor. Where an integration can read the store directly, prefer that.

  • The keychain item is not a backup. totp_remove is irreversible; unless the same seed still exists in Passwords.app or on a phone, the account's second factor is gone.

Troubleshooting

A tool is missing. Call totp_auth_status — an absent tool means configuration, not a bug. The seed tools need a reachable store (macOS keychain, or one TOTP_SECRET_<LABEL>); the write tools additionally need TOTP_ALLOW_WRITES=1.

A call fails with "timed out after 15s". macOS raised a keychain authorization dialog and is waiting for an answer. Look for it on screen and allow it. Until it is dismissed, every subsequent keychain write is queued behind it.

Connection closed with no tools. Run node dist/cli.js by hand with the same environment — the startup banner and any error go to stderr, which the client swallows.

Develop

pnpm lint && pnpm format:check && pnpm typecheck && pnpm test && pnpm build

The correctness proof is test/totp.test.ts: the RFC 6238 Appendix B vectors across SHA-1, SHA-256 and SHA-512. They are deterministic and need no credentials, and the suite never touches the real keychain — test/helpers.ts injects an in-memory double.

@mgcrea/mcp-totp/core is a published entry point exposing the dependency-free half (TOTP, otpauth:// parsing, the keychain store) so other servers can mint codes without loading the MCP SDK. Nothing under src/core/ may import @modelcontextprotocol/server or zod.

License

MIT

Available Tools

1 tool
totp_auth_statusTOTP: StatusA
Read-onlyIdempotent

Report what this server can and cannot do: whether a seed store is reachable, which labels are registered and where each one comes from, and whether writes are enabled. Call this first when a tool you expected is missing — an absent tool means missing configuration rather than a bug.

Note what this server is NOT: it cannot read codes out of Passwords.app. No such interface exists — Passwords.app has no scripting dictionary and no App Intents, and its keychain items sit behind an Apple-private access group. This server holds its own copy of the seed and mints codes locally; totp_import_uri can hand the same seed to Passwords.app so both stay in sync.

ParametersJSON Schema
NameRequiredDescriptionDefault

No parameters

TDQS

A4.9/5.0
Behavior5/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

The annotations already state readOnlyHint, idempotentHint, and destructiveHint false, and the description adds behavior beyond those: it explains the server cannot read Passwords.app because no interface exists, and that the server mints codes locally from its own seed copy. This gives the agent critical context about system limitations without contradicting the annotations.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness5/5

Is the description appropriately sized, front-loaded, and free of redundancy?

The description is front-loaded with the core purpose in the first sentence, then moves to usage guidance and a clarifying limitation. The length is justified because it conveys essential integration context about Passwords.app that would otherwise be invisible to an agent. Every sentence earns its place and no filler is present.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness5/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

With no output schema, the description enumerates exactly what the agent will learn from the call: reachability of the seed store, registered labels and their sources, and write-enable status. It also covers when to call and what the tool cannot do, making it fully self-contained for an agent to invoke and interpret correctly.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters4/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

The tool has zero parameters and the schema is empty, so there is nothing for the description to add about parameters. The baseline of 4 for a no-parameter tool applies, and the description does not need to compensate for any schema gaps since none exist.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose5/5

Does the description clearly state what the tool does and how it differs from similar tools?

The description opens with a specific verb and resource: it 'reports' the server's capabilities, listing concrete output items such as seed store reachability, registered labels and their origins, and write-enable state. This is unambiguous and cannot be confused with any other operation, especially since there are no sibling tools.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines5/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

It explicitly instructs when to call: 'Call this first when a tool you expected is missing — an absent tool means missing configuration rather than a bug.' It also clarifies what the server is NOT and points to totp_import_uri as the relevant alternative for syncing seeds, giving the agent both a trigger condition and a related tool reference.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

Tool Schema Changelog

Recent tool additions, removals, and schema changes observed during successful MCP inspections. Dates show when Glama detected each change.

  1. 1 tool updatev0.1.0
    • First observedtotp_auth_status

TDQS

A4.4/5.0
Disambiguation5/5

With only one tool exposed, there is no possibility of selecting the wrong tool. The tool's purpose as a status/diagnostic endpoint is clearly distinct from any other functionality.

Naming Consistency5/5

The single tool name uses consistent snake_case and clearly indicates its role as a status report. With no other tools, there is no naming pattern to conflict.

Tool Count2/5

A single status tool is far below the expected scope for a TOTP server, which should include operations for key management and code generation. The description even references a totp_import_uri tool that is not exposed, making the set feel incomplete.

Completeness1/5

The tool only reports capabilities and configuration state; there are no tools to actually create, import, or use TOTP secrets. This is a severe gap for a server named mcp-totp.

Maintenance

ActivityMaintained
ResponsivenessNo issues

Resources

Unclaimed servers have limited discoverability.

Looking for Admin?

If you are the server author, to access and configure the admin panel.

Related MCP Connectors

Related MCP Servers

  • F
    license
    Not graded
    quality
    Not graded
    maintenance
    Enables AI agents to perform symmetric and asymmetric encryption of text and files using secure storage in the macOS Keychain. It provides tools for identity management and secure messaging compatible with the CryptoSeed iOS app and CLI.
    -
  • A
    license
    A
    quality
    D
    maintenance
    Encrypted token store for Claude Code sessions, providing MCP tools for secure secret management with macOS Keychain integration, per-project allowlists, and native dialog input.
    6
    16
    6
    Cryptographic Autonomy 1.0 (Combined Work Exception)

Latest Blog Posts

MCP directory API

We provide all the information about MCP servers via our MCP API.

curl -X GET 'https://glama.ai/api/mcp/v1/servers/mgcrea/mcp-totp'

If you have feedback or need assistance with the MCP directory API, please join our Discord server