@carrierllc/mcp 0.13.29 → 0.13.30

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -21,12 +21,148 @@ carrier status # plugin + MCP + next steps
21
21
  carrier plugin install # zero-cred MCP URL; OAuth on first use in Claude
22
22
  carrier open signup # create account
23
23
  carrier examples # paste-ready “talk to fleet” prompts
24
- carrier ask "fleet health" # natural-language fallback; needs CARRIER_API_KEY=ak_…
24
+ carrier login # browser once; native OAuth refreshes silently
25
+ carrier ask "fleet health" # uses CLI OAuth / compatible Claude Code OAuth / explicit key
26
+ carrier exec -- bash # real child terminal with CARRIER_API_KEY in its environment
25
27
  ```
26
28
 
27
29
  **Entry A:** register `https://mcp.carrier.llc/mcp` with no token. The first tool
28
30
  call in Claude/Cursor opens Clerk OAuth (Google / GitHub / email).
29
31
 
32
+ ### OAuth and terminal handoff
33
+
34
+ Carrier commands, status and Ask the Fleet share credential resolution. Explicit
35
+ `CARRIER_API_KEY` / `CARRIER_ORG_API_KEY` always win. Native `carrier login` stores
36
+ a private refreshable session with one cross-process owner lock and atomic writes.
37
+ Login, refresh and logout serialize; a completed logout cannot be resurrected by
38
+ an earlier refresh. A crashed CLI owner leaves a fail-closed `credentials.lock`
39
+ directory: verify that no CLI login/refresh is running before manually removing
40
+ that directory. Changing the callback port triggers fresh client registration.
41
+ Native login and refresh request the exact production MCP resource. A present
42
+ wrong/malformed token-response resource is rejected before credential storage;
43
+ legacy absence is distinct and refresh retains a previously known binding.
44
+
45
+ ### Existing bash/zsh terminal (explicit setup)
46
+
47
+ ```bash
48
+ source "$(carrier shell-path bash)" # use zsh instead of bash in zsh
49
+ carrier_auth_export
50
+ # CARRIER_API_KEY is now exported in THIS shell and its subsequent children.
51
+ # Before an arbitrary headless job, refresh this snapshot again:
52
+ carrier_auth_export && your-headless-job
53
+ carrier logout
54
+ carrier_auth_clear # erase this shell's snapshot too
55
+ ```
56
+
57
+ Only a shipped static file is sourced. No secret is printed, evaluated as code,
58
+ put in command arguments/history, or written to a startup file. The function
59
+ reads an anonymous private pipe via an inherited descriptor. It refuses shell
60
+ traps and turns off xtrace/verbose **without restoring them**, because the next
61
+ caller command could expand the newly exported environment. Bash opt-in loading
62
+ enables errtrace so caller ERR traps are visible for refusal. Trusted commands,
63
+ same-UID process environment readers and crash dumps can still expose a bearer;
64
+ this is not protection from a compromised shell/OS. Do not re-enable tracing
65
+ around credentials.
66
+
67
+ Shell acceptance requires **both bash and zsh**: `pnpm test:oauth-shell`.
68
+ `CARRIER_TEST_ZSH` may point to an isolated zsh binary and
69
+ `CARRIER_TEST_ZSH_MODULE_PATH` to its matching modules. The general repair suite
70
+ reports a missing zsh interpreter as an explicit SKIP, never a zsh pass; the
71
+ acceptance command fails when either interpreter is unavailable.
72
+
73
+ OAuth exports carry `CARRIER_OAUTH_ORIGIN`, `CARRIER_OAUTH_EXPIRES_AT` (epoch ms)
74
+ and a `CARRIER_OAUTH_HANDOFF` fingerprint plus non-secret `CARRIER_OAUTH_BINDING`.
75
+ Carrier invocations reread only the selected owner, source directory/file, server,
76
+ registration and opaque subject/grant. Same-owner token rotation is allowed;
77
+ expiry, logout, owner/config/account/org changes fail closed, never switch to
78
+ another valid client session. Old exports without binding must be exported again.
79
+ These metadata equality checks are not cryptographic account/org proof.
80
+ Arbitrary programs retain it until expiry: re-run `carrier_auth_export` before
81
+ consumption. Replacing `CARRIER_API_KEY` intentionally overrides the fingerprint
82
+ and remains authoritative. `carrier_auth_clear` removes this shell's exported
83
+ key and metadata, not the other client's login.
84
+
85
+ `carrier exec -- <command> [args...]` remains available for a trusted child only;
86
+ no setup required, no parent-shell mutation, and child exit/signal is preserved.
87
+ OAuth is a short-lived bearer, **not** an `ak_` key.
88
+
89
+ ### Supported read-only MCP owners
90
+
91
+ Without a native session, a current compatible MCP access token may be reused;
92
+ no refresh grant is copied, rotated or written by Carrier. If the owner expires,
93
+ refresh it in that client or use native `carrier login`. No owner reauth command
94
+ is invoked. Multiple current owners require `CARRIER_MCP_OAUTH_OWNER=hermes` or
95
+ `claude`; the CLI never guesses which account to use.
96
+
97
+ - **Claude Code 2.1.277 and 2.1.296:** exact inspected config and storage adapters.
98
+ The owner's `.claude.json` lives under `CLAUDE_CONFIG_DIR || ~`; an existing
99
+ legacy `.config.json` takes precedence. For the consuming CLI's cwd, local
100
+ `projects[real git root || real cwd].mcpServers` wins over approved ancestor
101
+ `.mcp.json` project config, which wins over user config. Other projects are not
102
+ candidates. Project import supports explicit trusted user settings approval
103
+ only; pending/rejected or ambiguous policy/settings fail closed.
104
+ Hashes the actual `{type,url,headers:headers||{}}` in original insertion order:
105
+ HTTP, SSE and absent `type` remain distinct. No hardcoded empty-header hash.
106
+ Managed selection remains unsupported and fails closed; no inferred
107
+ plugin/proxy/CLI override resolution. Authorization/API-key/cookie headers and
108
+ unresolved environment substitutions are not imported as OAuth.
109
+ `CLAUDE_SECURESTORAGE_CONFIG_DIR` takes precedence by presence for credential
110
+ storage; present-empty selects `~/.claude`, while nonempty and `CLAUDE_CONFIG_DIR`
111
+ retain the exact NFC strings (no trim or resolve before the Keychain hash).
112
+ `USER || os.userInfo().username` selects the exact account, with Claude's
113
+ invalid-account fallback. An approved custom OAuth environment selects only
114
+ its own suffix; unrelated suffixes/accounts are never enumerated.
115
+ Linux reads the private `.credentials.json`. `CARRIER_MCP_OAUTH_FILE` explicitly
116
+ selects that file backend on either platform, without consulting Keychain.
117
+ CamelCase expiry is epoch milliseconds.
118
+ - **Hermes:** selected `HERMES_HOME` (default `~/.hermes`), exact configured
119
+ `mcp_servers.carrier.url`, with private `mcp-tokens/carrier.json`,
120
+ `.client.json` and `.meta.json`. Real snake_case access-token fields,
121
+ `hermes_issuer`, Bearer type and absolute `expires_at` in seconds are required.
122
+ Issuer/discovery endpoints, client registration and resource configuration are
123
+ checked. Legacy relative-only expiry is refused. Config JSON and simple scalar
124
+ block YAML are supported; nested/alias/flow constructs fail closed.
125
+
126
+ `CARRIER_MCP_OAUTH_SERVER` selects an alternative explicit name. Private mode
127
+ and current-user file ownership, exact issuer/resource, `read` scope and finite
128
+ future expiry are required. `CARRIER_OAUTH_ACCOUNT` optionally selects the
129
+ Carrier opaque token's user prefix; it is **not** cryptographic account/org
130
+ proof. Only the server validates actual token audience, organization and grant
131
+ permissions. Invalid native state never falls through to another owner.
132
+
133
+ On macOS the packaged `native/claude-keychain.js` uses the built-in JXA
134
+ Objective-C bridge and Apple Security Framework: one generic-password query,
135
+ exact service and account, `kSecMatchLimitOne`, `kSecReturnData`,
136
+ `kSecUseAuthenticationUIFail`, plus process-local legacy UI inhibition.
137
+ There is no compiler/download/install-at-login dependency, no `security -w`,
138
+ no broad dump, and no owner lock/refresh/login. Only non-secret selectors reach
139
+ stdin. Only the selected access-token fields reach an inherited private FD;
140
+ stdout/stderr are discarded. Owner refresh grants, client secrets and unrelated
141
+ credentials never leave the helper. Apple may report an ACL prompt requirement
142
+ or locked store identically (`errSecInteractionNotAllowed`): `locked` denotes
143
+ that noninteractive refusal, not a diagnosis of the physical Keychain state.
144
+ `errSecAuthFailed`/user-cancel are `denied`, parse errors are `malformed`, and
145
+ other failures are `unavailable`. None falls back to plaintext or Hermes.
146
+ Only `errSecItemNotFound` for the exact item permits Claude's documented private
147
+ file fallback. An existing item without the exact MCP entry does not fall back.
148
+ Keychain reuse requires `claude --version` to be exactly 2.1.277 or 2.1.296;
149
+ other versions fail closed. Compatibility is an explicit inspected allowlist,
150
+ not a version range. The source contracts are tested on Linux; a real Darwin
151
+ absent-item probe also executes the packaged helper byte-for-byte without
152
+ stdout/stderr. Successful existing-item access and installed end-to-end Mac
153
+ OAuth remain unproved. The inspected Mac 2.1.296 query returned `denied`
154
+ (OSStatus -25293), not absence; this adapter never broadens Keychain access or
155
+ falls back after that refusal.
156
+ Claude Desktop, Cursor, Windsurf and mcp-remote remain unsupported owners.
157
+ Issuer-less entries are intentionally rejected. `carrier logout` disables MCP
158
+ reuse until a successful native login and never edits the owner's store or
159
+ another shell's explicit keys.
160
+
161
+ Native API references: [Apple SecItemCopyMatching](https://developer.apple.com/documentation/security/secitemcopymatching(_:_:)),
162
+ [Apple SecItem.h](https://github.com/apple-oss-distributions/Security/blob/main/keychain/headers/SecItem.h),
163
+ [Apple JXA release notes](https://developer.apple.com/library/archive/releasenotes/InterapplicationCommunication/RN-JavaScriptForAutomation/),
164
+ [Claude authentication storage](https://code.claude.com/docs/en/authentication).
165
+
30
166
  ### Domain commands
31
167
 
32
168
  With a headless key in the environment, each capability has its own command,
@@ -1855,16 +1855,22 @@ function storefrontScreen(input) {
1855
1855
  // package.json
1856
1856
  var package_default = {
1857
1857
  name: "@carrierllc/mcp",
1858
- version: "0.13.29",
1858
+ version: "0.13.30",
1859
1859
  description: "Carrier MCP \u2014 natural-language control of MVNO/eSIM fleets via eSIMVault OCS. Stdio mode for direct integration with Claude Desktop, Cursor, Windsurf, and MCP-compatible clients. Ships the `carrier` CLI (plugin install + white-label eSIM storefront scaffold).",
1860
1860
  license: "MIT",
1861
1861
  author: "Carrier (Lifecycle Innovations Limited)",
1862
1862
  homepage: "https://mcp.carrier.llc",
1863
1863
  type: "module",
1864
+ carrierCompatibility: {
1865
+ claudeOAuthOwnerVersion: "2.1.277",
1866
+ claudeOAuthOwnerVersions: ["2.1.277", "2.1.296"]
1867
+ },
1864
1868
  main: "./dist/index.js",
1865
1869
  files: [
1866
1870
  "dist",
1867
1871
  "plugin",
1872
+ "shell",
1873
+ "native",
1868
1874
  "README.md",
1869
1875
  "templates",
1870
1876
  "!templates/**/node_modules",
@@ -1882,7 +1888,9 @@ var package_default = {
1882
1888
  lint: "eslint src",
1883
1889
  prepublishOnly: "pnpm run build",
1884
1890
  "build:test": "tsup --config tsup.test.config.ts",
1885
- test: "pnpm run build && pnpm run build:test && node --test test/*.test.js",
1891
+ test: "pnpm run build && pnpm run build:test && node --test-concurrency=1 --test test/*.test.js && pnpm run test:oauth-repair",
1892
+ "test:oauth-repair": "node --experimental-transform-types --test-concurrency=1 --test test/oauth-repair.test.mjs test/claude-owner.test.mjs test/current-owner.test.mjs",
1893
+ "test:oauth-shell": "node scripts/check-oauth-shell.mjs",
1886
1894
  "check:pack": "node scripts/check-pack-size.mjs",
1887
1895
  "generate:domains": "node scripts/generate-domains.mjs"
1888
1896
  },
@@ -5480,6 +5488,7 @@ export {
5480
5488
  walletScreen,
5481
5489
  greenzoneScreen,
5482
5490
  storefrontScreen,
5491
+ package_default,
5483
5492
  CARRIER_VERSION
5484
5493
  };
5485
- //# sourceMappingURL=chunk-LJPYVILK.js.map
5494
+ //# sourceMappingURL=chunk-ZJY7H2QW.js.map