@authn8/mcp-server 1.1.1 → 1.1.3
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 +73 -48
- package/dist/index.js +30 -2
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -1,34 +1,67 @@
|
|
|
1
1
|
# @authn8/mcp-server
|
|
2
2
|
|
|
3
|
-
MCP server
|
|
3
|
+
MCP server for [Authn8](https://authn8.com), shared 2FA for teams. It lets AI agents
|
|
4
|
+
fetch TOTP codes for the 2FA accounts your team shares in Authn8, so an agent can
|
|
5
|
+
finish a sign-in without anyone reading a code out of a phone. Every code it fetches
|
|
6
|
+
is recorded in Authn8's access log with the name of the token that asked for it.
|
|
4
7
|
|
|
5
|
-
|
|
8
|
+
Listed in the [MCP Registry](https://registry.modelcontextprotocol.io) as
|
|
9
|
+
`io.github.authn8/mcp-server`.
|
|
6
10
|
|
|
7
|
-
|
|
8
|
-
- A Personal Access Token (PAT) created in the Authn8 dashboard
|
|
11
|
+
## Requirements
|
|
9
12
|
|
|
10
|
-
|
|
13
|
+
- An Authn8 business on a paid plan. MCP tokens are not available on the Free plan,
|
|
14
|
+
and a business's tokens stop working if its subscription ends.
|
|
15
|
+
- An MCP token. Create one in Authn8 under **Settings → MCP Tokens**
|
|
16
|
+
([how to create an MCP token](https://authn8.com/knowledge-base/how-to-create-an-mcp-token)).
|
|
17
|
+
Tokens start with `pat_`. A token only reaches the 2FA accounts its creator can
|
|
18
|
+
already access, and you can narrow it further to chosen groups and give it an
|
|
19
|
+
expiry date.
|
|
20
|
+
- Node.js 18 or later, if you run the npm package. The hosted endpoint needs nothing
|
|
21
|
+
installed.
|
|
22
|
+
|
|
23
|
+
## Two ways to connect
|
|
24
|
+
|
|
25
|
+
| | Hosted endpoint | npm package |
|
|
26
|
+
|---|---|---|
|
|
27
|
+
| Install | None | `npx` runs it locally |
|
|
28
|
+
| Transport | Streamable HTTP | stdio |
|
|
29
|
+
| Address | `https://api.authn8.com/mcp` | `npx -y @authn8/mcp-server` |
|
|
30
|
+
| Token | `Authorization: Bearer pat_...` header | `AUTHN8_API_KEY` environment variable |
|
|
31
|
+
|
|
32
|
+
Both offer the same three tools: `list_accounts`, `get_otp` and `whoami`.
|
|
33
|
+
|
|
34
|
+
## Hosted endpoint
|
|
35
|
+
|
|
36
|
+
Point any MCP client that supports streamable HTTP at `https://api.authn8.com/mcp`
|
|
37
|
+
and send your token in the `Authorization` header as `Bearer pat_your_token_here`.
|
|
38
|
+
|
|
39
|
+
### Claude Code
|
|
11
40
|
|
|
12
41
|
```bash
|
|
13
|
-
|
|
42
|
+
claude mcp add --transport http --scope user authn8 https://api.authn8.com/mcp \
|
|
43
|
+
--header "Authorization: Bearer pat_your_token_here"
|
|
14
44
|
```
|
|
15
45
|
|
|
16
|
-
|
|
46
|
+
## npm package
|
|
17
47
|
|
|
18
|
-
|
|
48
|
+
### Claude Code
|
|
19
49
|
|
|
20
50
|
```bash
|
|
21
|
-
|
|
51
|
+
claude mcp add --env AUTHN8_API_KEY=pat_your_token_here --transport stdio --scope user authn8 \
|
|
52
|
+
-- npx -y @authn8/mcp-server
|
|
22
53
|
```
|
|
23
54
|
|
|
24
|
-
|
|
55
|
+
`--scope user` makes the server available in all your projects. Leave it out to add
|
|
56
|
+
it to the current project only.
|
|
25
57
|
|
|
26
58
|
### Claude Desktop
|
|
27
59
|
|
|
28
|
-
|
|
60
|
+
Open **Settings → Developer → Edit Config**, or edit the file directly:
|
|
29
61
|
|
|
30
|
-
**macOS:** `~/Library/Application Support/Claude/claude_desktop_config.json`
|
|
31
|
-
**Windows:** `%APPDATA%\Claude\claude_desktop_config.json`
|
|
62
|
+
- **macOS:** `~/Library/Application Support/Claude/claude_desktop_config.json`
|
|
63
|
+
- **Windows:** `%APPDATA%\Claude\claude_desktop_config.json`
|
|
64
|
+
- **Linux:** `~/.config/Claude/claude_desktop_config.json`
|
|
32
65
|
|
|
33
66
|
```json
|
|
34
67
|
{
|
|
@@ -44,12 +77,12 @@ Add to your Claude Desktop configuration file:
|
|
|
44
77
|
}
|
|
45
78
|
```
|
|
46
79
|
|
|
47
|
-
|
|
80
|
+
Quit and restart Claude Desktop after saving.
|
|
48
81
|
|
|
49
|
-
|
|
82
|
+
### Cursor
|
|
50
83
|
|
|
51
|
-
|
|
52
|
-
|
|
84
|
+
Add this to `~/.cursor/mcp.json` for all projects, or to `.cursor/mcp.json` in a
|
|
85
|
+
project:
|
|
53
86
|
|
|
54
87
|
```json
|
|
55
88
|
{
|
|
@@ -65,32 +98,21 @@ Add to your Claude Code configuration file:
|
|
|
65
98
|
}
|
|
66
99
|
```
|
|
67
100
|
|
|
68
|
-
###
|
|
101
|
+
### Other clients
|
|
69
102
|
|
|
70
|
-
|
|
103
|
+
Run `npx -y @authn8/mcp-server` as a stdio server with `AUTHN8_API_KEY` set.
|
|
71
104
|
|
|
72
|
-
|
|
73
|
-
{
|
|
74
|
-
"mcpServers": {
|
|
75
|
-
"authn8": {
|
|
76
|
-
"command": "npx",
|
|
77
|
-
"args": ["-y", "@authn8/mcp-server"],
|
|
78
|
-
"env": {
|
|
79
|
-
"AUTHN8_API_KEY": "pat_your_token_here"
|
|
80
|
-
}
|
|
81
|
-
}
|
|
82
|
-
}
|
|
83
|
-
}
|
|
84
|
-
```
|
|
85
|
-
|
|
86
|
-
## Environment Variables
|
|
105
|
+
### Environment variables
|
|
87
106
|
|
|
88
107
|
| Variable | Required | Default | Description |
|
|
89
108
|
|----------|----------|---------|-------------|
|
|
90
|
-
| `AUTHN8_API_KEY` | Yes | - | Your
|
|
91
|
-
| `AUTHN8_API_URL` | No | `https://api.authn8.com` | API
|
|
109
|
+
| `AUTHN8_API_KEY` | Yes | - | Your MCP token (`pat_...`) |
|
|
110
|
+
| `AUTHN8_API_URL` | No | `https://api.authn8.com` | API base URL |
|
|
111
|
+
|
|
112
|
+
On startup the server checks the token and prints the business name, token name,
|
|
113
|
+
account count and expiry date to stderr. It exits if the token is missing or rejected.
|
|
92
114
|
|
|
93
|
-
##
|
|
115
|
+
## Tools
|
|
94
116
|
|
|
95
117
|
All tools declare an output schema and return `structuredContent` alongside the
|
|
96
118
|
text block, so clients get typed results without re-parsing JSON out of text.
|
|
@@ -117,11 +139,12 @@ Returns all 2FA accounts accessible to this token.
|
|
|
117
139
|
Generates a TOTP code for a specific account.
|
|
118
140
|
|
|
119
141
|
**Parameters:**
|
|
120
|
-
- `account_id` (string, optional)
|
|
121
|
-
- `account_name` (string, optional)
|
|
142
|
+
- `account_id` (string, optional): UUID of the account
|
|
143
|
+
- `account_name` (string, optional): name or issuer domain to search for
|
|
144
|
+
(case-insensitive partial match)
|
|
122
145
|
|
|
123
|
-
Provide either `account_id` or `account_name`. If
|
|
124
|
-
name, the tool returns them in `multipleMatches` so you can retry with an
|
|
146
|
+
Provide either `account_id` or `account_name`. If more than one account matches
|
|
147
|
+
the name, the tool returns them in `multipleMatches` so you can retry with an
|
|
125
148
|
`account_id`.
|
|
126
149
|
|
|
127
150
|
**Example response:**
|
|
@@ -155,17 +178,19 @@ Returns information about the current token.
|
|
|
155
178
|
**Example response:**
|
|
156
179
|
```json
|
|
157
180
|
{
|
|
158
|
-
"tokenName": "
|
|
159
|
-
"businessName": "
|
|
181
|
+
"tokenName": "Claude Code",
|
|
182
|
+
"businessName": "Acme Ltd",
|
|
160
183
|
"scopedGroups": [
|
|
161
|
-
{ "id": "cfeba14a-e990-49e8-b6e5-61d63f7d68c8", "name": "
|
|
184
|
+
{ "id": "cfeba14a-e990-49e8-b6e5-61d63f7d68c8", "name": "Engineering" }
|
|
162
185
|
],
|
|
163
|
-
"expiresAt": "
|
|
164
|
-
"accountCount":
|
|
186
|
+
"expiresAt": "2027-06-30T23:59:59Z",
|
|
187
|
+
"accountCount": 12
|
|
165
188
|
}
|
|
166
189
|
```
|
|
167
190
|
|
|
168
191
|
## Links
|
|
169
192
|
|
|
170
|
-
- [Authn8](https://authn8.com)
|
|
171
|
-
- [
|
|
193
|
+
- [Authn8](https://authn8.com): shared 2FA for teams
|
|
194
|
+
- [How to create an MCP token](https://authn8.com/knowledge-base/how-to-create-an-mcp-token)
|
|
195
|
+
- [GitHub repository](https://github.com/authn8/mcp-server)
|
|
196
|
+
- [MCP Registry entry](https://registry.modelcontextprotocol.io/v0/servers?search=io.github.authn8/mcp-server)
|
package/dist/index.js
CHANGED
|
@@ -21,10 +21,32 @@ var Authn8Error = class extends Error {
|
|
|
21
21
|
};
|
|
22
22
|
var accountsCache = null;
|
|
23
23
|
var CACHE_TTL_MS = 60 * 1e3;
|
|
24
|
+
async function readApiError(response) {
|
|
25
|
+
try {
|
|
26
|
+
const body = await response.json();
|
|
27
|
+
if (Array.isArray(body.errors)) {
|
|
28
|
+
const messages = body.errors.filter(
|
|
29
|
+
(error) => typeof error === "string" && error.length > 0
|
|
30
|
+
);
|
|
31
|
+
if (messages.length > 0) {
|
|
32
|
+
return messages.join(" ");
|
|
33
|
+
}
|
|
34
|
+
}
|
|
35
|
+
if (typeof body.detail === "string" && body.detail.length > 0) {
|
|
36
|
+
return body.detail;
|
|
37
|
+
}
|
|
38
|
+
if (typeof body.title === "string" && body.title.length > 0) {
|
|
39
|
+
return body.title;
|
|
40
|
+
}
|
|
41
|
+
return null;
|
|
42
|
+
} catch {
|
|
43
|
+
return null;
|
|
44
|
+
}
|
|
45
|
+
}
|
|
24
46
|
async function apiRequest(endpoint, method = "GET") {
|
|
25
47
|
if (!API_KEY) {
|
|
26
48
|
throw new Authn8Error(
|
|
27
|
-
"AUTHN8_API_KEY environment variable is not set.
|
|
49
|
+
"AUTHN8_API_KEY environment variable is not set. Set it to an MCP token from Settings > MCP Tokens in Authn8."
|
|
28
50
|
);
|
|
29
51
|
}
|
|
30
52
|
const url = `${API_URL}${endpoint}`;
|
|
@@ -39,10 +61,16 @@ async function apiRequest(endpoint, method = "GET") {
|
|
|
39
61
|
if (!response.ok) {
|
|
40
62
|
if (response.status === 401) {
|
|
41
63
|
throw new Authn8Error(
|
|
42
|
-
"Token is invalid or
|
|
64
|
+
"Token is invalid, expired or revoked. Check it under Settings > MCP Tokens in Authn8.",
|
|
43
65
|
401
|
|
44
66
|
);
|
|
45
67
|
}
|
|
68
|
+
if (response.status !== 429) {
|
|
69
|
+
const apiMessage = await readApiError(response);
|
|
70
|
+
if (apiMessage) {
|
|
71
|
+
throw new Authn8Error(apiMessage, response.status);
|
|
72
|
+
}
|
|
73
|
+
}
|
|
46
74
|
if (response.status === 403) {
|
|
47
75
|
throw new Authn8Error(
|
|
48
76
|
"Token does not have permission to access this resource.",
|