Skip to content

Commit 300e963

Browse files
feat(webauthn): add webauthn_add_authenticator tool
Implements the ability to add virtual authenticators with configurable: - protocol (u2f, ctap2) - transport (usb, nfc, ble, internal) - hasResidentKey (passkey support) - hasUserVerification - isUserVerified Returns the authenticatorId for use in subsequent operations. Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
1 parent ce3a0ed commit 300e963

2 files changed

Lines changed: 86 additions & 1 deletion

File tree

src/tools/webauthn.ts

Lines changed: 52 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@
55
*/
66

77
import type {CDPSession} from '../third_party/index.js';
8+
import {zod} from '../third_party/index.js';
89

910
import {ToolCategory} from './categories.js';
1011
import {defineTool} from './ToolDefinition.js';
@@ -25,3 +26,54 @@ export const enableWebAuthn = defineTool({
2526
response.appendResponseLine('WebAuthn virtual authenticator environment enabled.');
2627
},
2728
});
29+
30+
export const addVirtualAuthenticator = defineTool({
31+
name: 'webauthn_add_authenticator',
32+
description: 'Add a virtual WebAuthn authenticator.',
33+
annotations: {
34+
category: ToolCategory.EMULATION,
35+
readOnlyHint: false,
36+
},
37+
schema: {
38+
protocol: zod
39+
.enum(['u2f', 'ctap2'])
40+
.describe('The protocol the virtual authenticator speaks.'),
41+
transport: zod
42+
.enum(['usb', 'nfc', 'ble', 'internal'])
43+
.describe('The transport for the authenticator.'),
44+
hasResidentKey: zod
45+
.boolean()
46+
.optional()
47+
.describe('Whether the authenticator supports resident keys (passkeys).'),
48+
hasUserVerification: zod
49+
.boolean()
50+
.optional()
51+
.describe('Whether the authenticator supports user verification.'),
52+
isUserVerified: zod
53+
.boolean()
54+
.optional()
55+
.describe('Whether user verification is currently enabled/verified.'),
56+
},
57+
handler: async (request, response, context) => {
58+
const page = context.getSelectedPage();
59+
// @ts-expect-error _client is internal Puppeteer API
60+
const session = page._client() as CDPSession;
61+
62+
const {protocol, transport, hasResidentKey, hasUserVerification, isUserVerified} =
63+
request.params;
64+
65+
const result = await session.send('WebAuthn.addVirtualAuthenticator', {
66+
options: {
67+
protocol,
68+
transport,
69+
hasResidentKey: hasResidentKey ?? false,
70+
hasUserVerification: hasUserVerification ?? false,
71+
isUserVerified: isUserVerified ?? false,
72+
},
73+
});
74+
75+
response.appendResponseLine(
76+
`Added virtual authenticator (authenticatorId: ${result.authenticatorId})`,
77+
);
78+
},
79+
});

tests/tools/webauthn.test.ts

Lines changed: 34 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,10 @@
77
import assert from 'node:assert';
88
import {describe, it} from 'node:test';
99

10-
import {enableWebAuthn} from '../../src/tools/webauthn.js';
10+
import {
11+
addVirtualAuthenticator,
12+
enableWebAuthn,
13+
} from '../../src/tools/webauthn.js';
1114
import {withMcpContext} from '../utils.js';
1215

1316
describe('webauthn', () => {
@@ -34,4 +37,34 @@ describe('webauthn', () => {
3437
});
3538
});
3639
});
40+
41+
describe('webauthn_add_authenticator', () => {
42+
it('adds a virtual authenticator and returns its ID', async () => {
43+
await withMcpContext(async (response, context) => {
44+
// First enable WebAuthn
45+
await enableWebAuthn.handler({params: {}}, response, context);
46+
47+
// Then add authenticator via tool
48+
await addVirtualAuthenticator.handler(
49+
{
50+
params: {
51+
protocol: 'ctap2',
52+
transport: 'internal',
53+
hasResidentKey: true,
54+
hasUserVerification: true,
55+
isUserVerified: true,
56+
},
57+
},
58+
response,
59+
context,
60+
);
61+
62+
// Response should contain the authenticator ID
63+
const hasAuthenticatorId = response.responseLines.some(line =>
64+
line.includes('authenticatorId'),
65+
);
66+
assert.ok(hasAuthenticatorId, 'Should include authenticator ID in response');
67+
});
68+
});
69+
});
3770
});

0 commit comments

Comments
 (0)