@authn8/mcp-server 1.0.0 → 1.0.1
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/dist/index.js +17 -19
- package/package.json +8 -2
- package/src/client.ts +18 -15
- package/src/index.ts +4 -4
- package/src/tools.ts +8 -10
package/dist/index.js
CHANGED
|
@@ -69,12 +69,12 @@ async function listAccounts() {
|
|
|
69
69
|
if (accountsCache && Date.now() - accountsCache.timestamp < CACHE_TTL_MS) {
|
|
70
70
|
return accountsCache.accounts;
|
|
71
71
|
}
|
|
72
|
-
const
|
|
72
|
+
const response = await apiRequest("/api/pat/accounts");
|
|
73
73
|
accountsCache = {
|
|
74
|
-
accounts,
|
|
74
|
+
accounts: response.accounts,
|
|
75
75
|
timestamp: Date.now()
|
|
76
76
|
};
|
|
77
|
-
return accounts;
|
|
77
|
+
return response.accounts;
|
|
78
78
|
}
|
|
79
79
|
async function getOtp(accountId) {
|
|
80
80
|
return apiRequest(`/api/pat/otp/${accountId}`);
|
|
@@ -83,12 +83,12 @@ async function findAccountByName(name) {
|
|
|
83
83
|
const accounts = await listAccounts();
|
|
84
84
|
const lowerName = name.toLowerCase();
|
|
85
85
|
const matches = accounts.filter(
|
|
86
|
-
(acc) => acc.name.toLowerCase().includes(lowerName) || acc.
|
|
86
|
+
(acc) => acc.name.toLowerCase().includes(lowerName) || acc.issuerDomain.toLowerCase().includes(lowerName)
|
|
87
87
|
);
|
|
88
88
|
if (matches.length === 0) {
|
|
89
89
|
throw new Authn8Error(
|
|
90
90
|
`No account found matching "${name}". Available accounts:
|
|
91
|
-
${accounts.map((a) => ` - ${a.name} (${a.
|
|
91
|
+
${accounts.map((a) => ` - ${a.name} (${a.issuerDomain})`).join("\n")}`
|
|
92
92
|
);
|
|
93
93
|
}
|
|
94
94
|
if (matches.length === 1) {
|
|
@@ -143,8 +143,7 @@ async function handleListAccounts() {
|
|
|
143
143
|
const formatted = accounts.map((acc) => ({
|
|
144
144
|
id: acc.id,
|
|
145
145
|
name: acc.name,
|
|
146
|
-
|
|
147
|
-
issuer: acc.issuer
|
|
146
|
+
issuer: acc.issuerDomain
|
|
148
147
|
}));
|
|
149
148
|
return {
|
|
150
149
|
content: [
|
|
@@ -192,7 +191,7 @@ async function handleGetOtp(args) {
|
|
|
192
191
|
{
|
|
193
192
|
type: "text",
|
|
194
193
|
text: `Multiple accounts match "${account_name}". Please be more specific:
|
|
195
|
-
${result.matches.map((a) => ` - ${a.name} (${a.
|
|
194
|
+
${result.matches.map((a) => ` - ${a.name} (${a.issuerDomain}) - ID: ${a.id}`).join("\n")}`
|
|
196
195
|
}
|
|
197
196
|
]
|
|
198
197
|
};
|
|
@@ -208,8 +207,7 @@ ${result.matches.map((a) => ` - ${a.name} (${a.issuer}) - ID: ${a.id}`).join("\
|
|
|
208
207
|
text: JSON.stringify(
|
|
209
208
|
{
|
|
210
209
|
account: accountName,
|
|
211
|
-
|
|
212
|
-
expires_in_seconds: otp.expires_in_seconds
|
|
210
|
+
code: otp.code
|
|
213
211
|
},
|
|
214
212
|
null,
|
|
215
213
|
2
|
|
@@ -226,11 +224,11 @@ async function handleWhoami() {
|
|
|
226
224
|
type: "text",
|
|
227
225
|
text: JSON.stringify(
|
|
228
226
|
{
|
|
229
|
-
business: info.
|
|
230
|
-
token_name: info.
|
|
231
|
-
scoped_groups: info.
|
|
232
|
-
account_count: info.
|
|
233
|
-
expires_at: info.
|
|
227
|
+
business: info.businessName,
|
|
228
|
+
token_name: info.tokenName,
|
|
229
|
+
scoped_groups: info.scopedGroups.map((g) => g.name),
|
|
230
|
+
account_count: info.accountCount,
|
|
231
|
+
expires_at: info.expiresAt
|
|
234
232
|
},
|
|
235
233
|
null,
|
|
236
234
|
2
|
|
@@ -251,10 +249,10 @@ function formatDate(isoDate) {
|
|
|
251
249
|
}
|
|
252
250
|
function displayStartupInfo(info) {
|
|
253
251
|
console.error("Authn8 MCP Server");
|
|
254
|
-
console.error(`Business: ${info.
|
|
255
|
-
console.error(`Token: ${info.
|
|
256
|
-
console.error(`Accounts: ${info.
|
|
257
|
-
console.error(`Expires: ${formatDate(info.
|
|
252
|
+
console.error(`Business: ${info.businessName}`);
|
|
253
|
+
console.error(`Token: ${info.tokenName}`);
|
|
254
|
+
console.error(`Accounts: ${info.accountCount}`);
|
|
255
|
+
console.error(`Expires: ${formatDate(info.expiresAt)}`);
|
|
258
256
|
console.error("");
|
|
259
257
|
}
|
|
260
258
|
async function main() {
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@authn8/mcp-server",
|
|
3
|
-
"version": "1.0.
|
|
3
|
+
"version": "1.0.1",
|
|
4
4
|
"description": "MCP server for Authn8 2FA code access",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"bin": {
|
|
@@ -12,7 +12,13 @@
|
|
|
12
12
|
"dev": "node --loader ts-node/esm src/index.ts",
|
|
13
13
|
"start": "node dist/index.js"
|
|
14
14
|
},
|
|
15
|
-
"keywords": [
|
|
15
|
+
"keywords": [
|
|
16
|
+
"mcp",
|
|
17
|
+
"2fa",
|
|
18
|
+
"totp",
|
|
19
|
+
"authn8",
|
|
20
|
+
"authenticator"
|
|
21
|
+
],
|
|
16
22
|
"repository": {
|
|
17
23
|
"type": "git",
|
|
18
24
|
"url": "https://github.com/authn8/mcp-server"
|
package/src/client.ts
CHANGED
|
@@ -3,24 +3,27 @@ const API_KEY = process.env.AUTHN8_API_KEY;
|
|
|
3
3
|
const USER_AGENT = "authn8-mcp/1.0.0";
|
|
4
4
|
|
|
5
5
|
export interface TokenInfo {
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
6
|
+
businessName: string;
|
|
7
|
+
tokenName: string;
|
|
8
|
+
scopedGroups: Array<{ id: string; name: string }>;
|
|
9
|
+
accountCount: number;
|
|
10
|
+
expiresAt: string;
|
|
11
11
|
}
|
|
12
12
|
|
|
13
13
|
export interface Account {
|
|
14
14
|
id: string;
|
|
15
15
|
name: string;
|
|
16
|
-
|
|
17
|
-
|
|
16
|
+
issuerDomain: string;
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
interface AccountsResponse {
|
|
20
|
+
accounts: Account[];
|
|
18
21
|
}
|
|
19
22
|
|
|
20
23
|
export interface OtpResponse {
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
+
name: string;
|
|
25
|
+
code: string;
|
|
26
|
+
length: number;
|
|
24
27
|
}
|
|
25
28
|
|
|
26
29
|
class Authn8Error extends Error {
|
|
@@ -99,15 +102,15 @@ export async function listAccounts(): Promise<Account[]> {
|
|
|
99
102
|
return accountsCache.accounts;
|
|
100
103
|
}
|
|
101
104
|
|
|
102
|
-
const
|
|
105
|
+
const response = await apiRequest<AccountsResponse>("/api/pat/accounts");
|
|
103
106
|
|
|
104
107
|
// Update cache
|
|
105
108
|
accountsCache = {
|
|
106
|
-
accounts,
|
|
109
|
+
accounts: response.accounts,
|
|
107
110
|
timestamp: Date.now(),
|
|
108
111
|
};
|
|
109
112
|
|
|
110
|
-
return accounts;
|
|
113
|
+
return response.accounts;
|
|
111
114
|
}
|
|
112
115
|
|
|
113
116
|
export async function getOtp(accountId: string): Promise<OtpResponse> {
|
|
@@ -123,12 +126,12 @@ export async function findAccountByName(
|
|
|
123
126
|
const matches = accounts.filter(
|
|
124
127
|
(acc) =>
|
|
125
128
|
acc.name.toLowerCase().includes(lowerName) ||
|
|
126
|
-
acc.
|
|
129
|
+
acc.issuerDomain.toLowerCase().includes(lowerName)
|
|
127
130
|
);
|
|
128
131
|
|
|
129
132
|
if (matches.length === 0) {
|
|
130
133
|
throw new Authn8Error(
|
|
131
|
-
`No account found matching "${name}". Available accounts:\n${accounts.map((a) => ` - ${a.name} (${a.
|
|
134
|
+
`No account found matching "${name}". Available accounts:\n${accounts.map((a) => ` - ${a.name} (${a.issuerDomain})`).join("\n")}`
|
|
132
135
|
);
|
|
133
136
|
}
|
|
134
137
|
|
package/src/index.ts
CHANGED
|
@@ -19,10 +19,10 @@ function formatDate(isoDate: string): string {
|
|
|
19
19
|
|
|
20
20
|
function displayStartupInfo(info: TokenInfo): void {
|
|
21
21
|
console.error("Authn8 MCP Server");
|
|
22
|
-
console.error(`Business: ${info.
|
|
23
|
-
console.error(`Token: ${info.
|
|
24
|
-
console.error(`Accounts: ${info.
|
|
25
|
-
console.error(`Expires: ${formatDate(info.
|
|
22
|
+
console.error(`Business: ${info.businessName}`);
|
|
23
|
+
console.error(`Token: ${info.tokenName}`);
|
|
24
|
+
console.error(`Accounts: ${info.accountCount}`);
|
|
25
|
+
console.error(`Expires: ${formatDate(info.expiresAt)}`);
|
|
26
26
|
console.error("");
|
|
27
27
|
}
|
|
28
28
|
|
package/src/tools.ts
CHANGED
|
@@ -56,8 +56,7 @@ export async function handleListAccounts(): Promise<{
|
|
|
56
56
|
const formatted = accounts.map((acc) => ({
|
|
57
57
|
id: acc.id,
|
|
58
58
|
name: acc.name,
|
|
59
|
-
|
|
60
|
-
issuer: acc.issuer,
|
|
59
|
+
issuer: acc.issuerDomain,
|
|
61
60
|
}));
|
|
62
61
|
|
|
63
62
|
return {
|
|
@@ -115,7 +114,7 @@ export async function handleGetOtp(args: {
|
|
|
115
114
|
content: [
|
|
116
115
|
{
|
|
117
116
|
type: "text",
|
|
118
|
-
text: `Multiple accounts match "${account_name}". Please be more specific:\n${result.matches.map((a) => ` - ${a.name} (${a.
|
|
117
|
+
text: `Multiple accounts match "${account_name}". Please be more specific:\n${result.matches.map((a) => ` - ${a.name} (${a.issuerDomain}) - ID: ${a.id}`).join("\n")}`,
|
|
119
118
|
},
|
|
120
119
|
],
|
|
121
120
|
};
|
|
@@ -134,8 +133,7 @@ export async function handleGetOtp(args: {
|
|
|
134
133
|
text: JSON.stringify(
|
|
135
134
|
{
|
|
136
135
|
account: accountName,
|
|
137
|
-
|
|
138
|
-
expires_in_seconds: otp.expires_in_seconds,
|
|
136
|
+
code: otp.code,
|
|
139
137
|
},
|
|
140
138
|
null,
|
|
141
139
|
2
|
|
@@ -156,11 +154,11 @@ export async function handleWhoami(): Promise<{
|
|
|
156
154
|
type: "text",
|
|
157
155
|
text: JSON.stringify(
|
|
158
156
|
{
|
|
159
|
-
business: info.
|
|
160
|
-
token_name: info.
|
|
161
|
-
scoped_groups: info.
|
|
162
|
-
account_count: info.
|
|
163
|
-
expires_at: info.
|
|
157
|
+
business: info.businessName,
|
|
158
|
+
token_name: info.tokenName,
|
|
159
|
+
scoped_groups: info.scopedGroups.map((g) => g.name),
|
|
160
|
+
account_count: info.accountCount,
|
|
161
|
+
expires_at: info.expiresAt,
|
|
164
162
|
},
|
|
165
163
|
null,
|
|
166
164
|
2
|