@frontmcp/testing 0.5.0
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/LICENSE +201 -0
- package/README.md +1358 -0
- package/jest-preset.js +61 -0
- package/package.json +94 -0
- package/src/assertions/index.d.ts +5 -0
- package/src/assertions/index.js +18 -0
- package/src/assertions/index.js.map +1 -0
- package/src/assertions/mcp-assertions.d.ts +81 -0
- package/src/assertions/mcp-assertions.js +220 -0
- package/src/assertions/mcp-assertions.js.map +1 -0
- package/src/auth/auth-headers.d.ts +29 -0
- package/src/auth/auth-headers.js +62 -0
- package/src/auth/auth-headers.js.map +1 -0
- package/src/auth/index.d.ts +9 -0
- package/src/auth/index.js +15 -0
- package/src/auth/index.js.map +1 -0
- package/src/auth/token-factory.d.ts +94 -0
- package/src/auth/token-factory.js +181 -0
- package/src/auth/token-factory.js.map +1 -0
- package/src/auth/user-fixtures.d.ts +26 -0
- package/src/auth/user-fixtures.js +92 -0
- package/src/auth/user-fixtures.js.map +1 -0
- package/src/client/index.d.ts +7 -0
- package/src/client/index.js +12 -0
- package/src/client/index.js.map +1 -0
- package/src/client/mcp-test-client.builder.d.ts +72 -0
- package/src/client/mcp-test-client.builder.js +111 -0
- package/src/client/mcp-test-client.builder.js.map +1 -0
- package/src/client/mcp-test-client.d.ts +360 -0
- package/src/client/mcp-test-client.js +929 -0
- package/src/client/mcp-test-client.js.map +1 -0
- package/src/client/mcp-test-client.types.d.ts +216 -0
- package/src/client/mcp-test-client.types.js +7 -0
- package/src/client/mcp-test-client.types.js.map +1 -0
- package/src/errors/index.d.ts +45 -0
- package/src/errors/index.js +85 -0
- package/src/errors/index.js.map +1 -0
- package/src/expect.d.ts +67 -0
- package/src/expect.js +31 -0
- package/src/expect.js.map +1 -0
- package/src/fixtures/fixture-types.d.ts +166 -0
- package/src/fixtures/fixture-types.js +7 -0
- package/src/fixtures/fixture-types.js.map +1 -0
- package/src/fixtures/index.d.ts +7 -0
- package/src/fixtures/index.js +16 -0
- package/src/fixtures/index.js.map +1 -0
- package/src/fixtures/test-fixture.d.ts +41 -0
- package/src/fixtures/test-fixture.js +280 -0
- package/src/fixtures/test-fixture.js.map +1 -0
- package/src/http-mock/http-mock.d.ts +84 -0
- package/src/http-mock/http-mock.js +544 -0
- package/src/http-mock/http-mock.js.map +1 -0
- package/src/http-mock/http-mock.types.d.ts +124 -0
- package/src/http-mock/http-mock.types.js +10 -0
- package/src/http-mock/http-mock.types.js.map +1 -0
- package/src/http-mock/index.d.ts +6 -0
- package/src/http-mock/index.js +11 -0
- package/src/http-mock/index.js.map +1 -0
- package/src/index.d.ts +65 -0
- package/src/index.js +128 -0
- package/src/index.js.map +1 -0
- package/src/interceptor/index.d.ts +7 -0
- package/src/interceptor/index.js +15 -0
- package/src/interceptor/index.js.map +1 -0
- package/src/interceptor/interceptor-chain.d.ts +77 -0
- package/src/interceptor/interceptor-chain.js +207 -0
- package/src/interceptor/interceptor-chain.js.map +1 -0
- package/src/interceptor/interceptor.types.d.ts +131 -0
- package/src/interceptor/interceptor.types.js +7 -0
- package/src/interceptor/interceptor.types.js.map +1 -0
- package/src/interceptor/mock-registry.d.ts +82 -0
- package/src/interceptor/mock-registry.js +189 -0
- package/src/interceptor/mock-registry.js.map +1 -0
- package/src/matchers/index.d.ts +7 -0
- package/src/matchers/index.js +12 -0
- package/src/matchers/index.js.map +1 -0
- package/src/matchers/matcher-types.d.ts +266 -0
- package/src/matchers/matcher-types.js +10 -0
- package/src/matchers/matcher-types.js.map +1 -0
- package/src/matchers/mcp-matchers.d.ts +47 -0
- package/src/matchers/mcp-matchers.js +391 -0
- package/src/matchers/mcp-matchers.js.map +1 -0
- package/src/playwright/index.d.ts +37 -0
- package/src/playwright/index.js +49 -0
- package/src/playwright/index.js.map +1 -0
- package/src/server/index.d.ts +6 -0
- package/src/server/index.js +10 -0
- package/src/server/index.js.map +1 -0
- package/src/server/test-server.d.ts +99 -0
- package/src/server/test-server.js +286 -0
- package/src/server/test-server.js.map +1 -0
- package/src/setup.d.ts +22 -0
- package/src/setup.js +30 -0
- package/src/setup.js.map +1 -0
- package/src/transport/index.d.ts +6 -0
- package/src/transport/index.js +10 -0
- package/src/transport/index.js.map +1 -0
- package/src/transport/streamable-http.transport.d.ts +65 -0
- package/src/transport/streamable-http.transport.js +432 -0
- package/src/transport/streamable-http.transport.js.map +1 -0
- package/src/transport/transport.interface.d.ts +124 -0
- package/src/transport/transport.interface.js +7 -0
- package/src/transport/transport.interface.js.map +1 -0
- package/src/ui/index.d.ts +17 -0
- package/src/ui/index.js +23 -0
- package/src/ui/index.js.map +1 -0
- package/src/ui/ui-assertions.d.ts +94 -0
- package/src/ui/ui-assertions.js +215 -0
- package/src/ui/ui-assertions.js.map +1 -0
- package/src/ui/ui-matchers.d.ts +39 -0
- package/src/ui/ui-matchers.js +275 -0
- package/src/ui/ui-matchers.js.map +1 -0
|
@@ -0,0 +1,94 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @file token-factory.ts
|
|
3
|
+
* @description JWT token factory for testing authentication
|
|
4
|
+
*/
|
|
5
|
+
import { type JWK } from 'jose';
|
|
6
|
+
export interface CreateTokenOptions {
|
|
7
|
+
/** Subject (user ID) - required */
|
|
8
|
+
sub: string;
|
|
9
|
+
/** Issuer URL */
|
|
10
|
+
iss?: string;
|
|
11
|
+
/** Audience */
|
|
12
|
+
aud?: string | string[];
|
|
13
|
+
/** OAuth scopes */
|
|
14
|
+
scopes?: string[];
|
|
15
|
+
/** Expiration time in seconds from now (default: 3600) */
|
|
16
|
+
exp?: number;
|
|
17
|
+
/** Additional custom claims */
|
|
18
|
+
claims?: Record<string, unknown>;
|
|
19
|
+
}
|
|
20
|
+
export interface TokenFactoryOptions {
|
|
21
|
+
/** Default issuer URL */
|
|
22
|
+
issuer?: string;
|
|
23
|
+
/** Default audience */
|
|
24
|
+
audience?: string;
|
|
25
|
+
}
|
|
26
|
+
/**
|
|
27
|
+
* Factory for creating JWT tokens for testing
|
|
28
|
+
*
|
|
29
|
+
* @example
|
|
30
|
+
* ```typescript
|
|
31
|
+
* const factory = new TestTokenFactory();
|
|
32
|
+
*
|
|
33
|
+
* // Create a token with claims
|
|
34
|
+
* const token = await factory.createTestToken({
|
|
35
|
+
* sub: 'user-123',
|
|
36
|
+
* scopes: ['read', 'write'],
|
|
37
|
+
* });
|
|
38
|
+
*
|
|
39
|
+
* // Create convenience tokens
|
|
40
|
+
* const adminToken = await factory.createAdminToken();
|
|
41
|
+
* const userToken = await factory.createUserToken();
|
|
42
|
+
* ```
|
|
43
|
+
*/
|
|
44
|
+
export declare class TestTokenFactory {
|
|
45
|
+
private readonly issuer;
|
|
46
|
+
private readonly audience;
|
|
47
|
+
private privateKey;
|
|
48
|
+
private publicKey;
|
|
49
|
+
private jwk;
|
|
50
|
+
private keyId;
|
|
51
|
+
constructor(options?: TokenFactoryOptions);
|
|
52
|
+
/**
|
|
53
|
+
* Initialize the key pair (called automatically on first use)
|
|
54
|
+
*/
|
|
55
|
+
private ensureKeys;
|
|
56
|
+
/**
|
|
57
|
+
* Create a JWT token with the specified claims
|
|
58
|
+
*/
|
|
59
|
+
createTestToken(options: CreateTokenOptions): Promise<string>;
|
|
60
|
+
/**
|
|
61
|
+
* Create an admin token with full access
|
|
62
|
+
*/
|
|
63
|
+
createAdminToken(sub?: string): Promise<string>;
|
|
64
|
+
/**
|
|
65
|
+
* Create a regular user token
|
|
66
|
+
*/
|
|
67
|
+
createUserToken(sub?: string, scopes?: string[]): Promise<string>;
|
|
68
|
+
/**
|
|
69
|
+
* Create an anonymous user token
|
|
70
|
+
*/
|
|
71
|
+
createAnonymousToken(): Promise<string>;
|
|
72
|
+
/**
|
|
73
|
+
* Create an expired token (for testing token expiration)
|
|
74
|
+
*/
|
|
75
|
+
createExpiredToken(options: Pick<CreateTokenOptions, 'sub'>): Promise<string>;
|
|
76
|
+
/**
|
|
77
|
+
* Create a token with an invalid signature (for testing signature validation)
|
|
78
|
+
*/
|
|
79
|
+
createTokenWithInvalidSignature(options: Pick<CreateTokenOptions, 'sub'>): string;
|
|
80
|
+
/**
|
|
81
|
+
* Get the public JWKS for verifying tokens
|
|
82
|
+
*/
|
|
83
|
+
getPublicJwks(): Promise<{
|
|
84
|
+
keys: JWK[];
|
|
85
|
+
}>;
|
|
86
|
+
/**
|
|
87
|
+
* Get the issuer URL
|
|
88
|
+
*/
|
|
89
|
+
getIssuer(): string;
|
|
90
|
+
/**
|
|
91
|
+
* Get the audience
|
|
92
|
+
*/
|
|
93
|
+
getAudience(): string;
|
|
94
|
+
}
|
|
@@ -0,0 +1,181 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
/**
|
|
3
|
+
* @file token-factory.ts
|
|
4
|
+
* @description JWT token factory for testing authentication
|
|
5
|
+
*/
|
|
6
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
7
|
+
exports.TestTokenFactory = void 0;
|
|
8
|
+
const jose_1 = require("jose");
|
|
9
|
+
// ═══════════════════════════════════════════════════════════════════
|
|
10
|
+
// TOKEN FACTORY CLASS
|
|
11
|
+
// ═══════════════════════════════════════════════════════════════════
|
|
12
|
+
/**
|
|
13
|
+
* Factory for creating JWT tokens for testing
|
|
14
|
+
*
|
|
15
|
+
* @example
|
|
16
|
+
* ```typescript
|
|
17
|
+
* const factory = new TestTokenFactory();
|
|
18
|
+
*
|
|
19
|
+
* // Create a token with claims
|
|
20
|
+
* const token = await factory.createTestToken({
|
|
21
|
+
* sub: 'user-123',
|
|
22
|
+
* scopes: ['read', 'write'],
|
|
23
|
+
* });
|
|
24
|
+
*
|
|
25
|
+
* // Create convenience tokens
|
|
26
|
+
* const adminToken = await factory.createAdminToken();
|
|
27
|
+
* const userToken = await factory.createUserToken();
|
|
28
|
+
* ```
|
|
29
|
+
*/
|
|
30
|
+
class TestTokenFactory {
|
|
31
|
+
issuer;
|
|
32
|
+
audience;
|
|
33
|
+
privateKey = null;
|
|
34
|
+
publicKey = null;
|
|
35
|
+
jwk = null;
|
|
36
|
+
keyId;
|
|
37
|
+
constructor(options = {}) {
|
|
38
|
+
this.issuer = options.issuer ?? 'https://test.frontmcp.local';
|
|
39
|
+
this.audience = options.audience ?? 'frontmcp-test';
|
|
40
|
+
this.keyId = `test-key-${Date.now()}`;
|
|
41
|
+
}
|
|
42
|
+
/**
|
|
43
|
+
* Initialize the key pair (called automatically on first use)
|
|
44
|
+
*/
|
|
45
|
+
async ensureKeys() {
|
|
46
|
+
if (this.privateKey && this.publicKey)
|
|
47
|
+
return;
|
|
48
|
+
// Generate RSA key pair
|
|
49
|
+
const { publicKey, privateKey } = await (0, jose_1.generateKeyPair)('RS256', {
|
|
50
|
+
extractable: true,
|
|
51
|
+
});
|
|
52
|
+
this.privateKey = privateKey;
|
|
53
|
+
this.publicKey = publicKey;
|
|
54
|
+
// Export public key as JWK
|
|
55
|
+
this.jwk = await (0, jose_1.exportJWK)(publicKey);
|
|
56
|
+
this.jwk.kid = this.keyId;
|
|
57
|
+
this.jwk.use = 'sig';
|
|
58
|
+
this.jwk.alg = 'RS256';
|
|
59
|
+
}
|
|
60
|
+
/**
|
|
61
|
+
* Create a JWT token with the specified claims
|
|
62
|
+
*/
|
|
63
|
+
async createTestToken(options) {
|
|
64
|
+
await this.ensureKeys();
|
|
65
|
+
const now = Math.floor(Date.now() / 1000);
|
|
66
|
+
const exp = options.exp ?? 3600;
|
|
67
|
+
const payload = {
|
|
68
|
+
iss: options.iss ?? this.issuer,
|
|
69
|
+
sub: options.sub,
|
|
70
|
+
aud: options.aud ?? this.audience,
|
|
71
|
+
iat: now,
|
|
72
|
+
exp: now + exp,
|
|
73
|
+
scope: options.scopes?.join(' '),
|
|
74
|
+
...options.claims,
|
|
75
|
+
};
|
|
76
|
+
const token = await new jose_1.SignJWT(payload)
|
|
77
|
+
.setProtectedHeader({ alg: 'RS256', kid: this.keyId })
|
|
78
|
+
.sign(this.privateKey);
|
|
79
|
+
return token;
|
|
80
|
+
}
|
|
81
|
+
/**
|
|
82
|
+
* Create an admin token with full access
|
|
83
|
+
*/
|
|
84
|
+
async createAdminToken(sub = 'admin-001') {
|
|
85
|
+
return this.createTestToken({
|
|
86
|
+
sub,
|
|
87
|
+
scopes: ['admin:*', 'read', 'write', 'delete'],
|
|
88
|
+
claims: {
|
|
89
|
+
email: 'admin@test.local',
|
|
90
|
+
name: 'Test Admin',
|
|
91
|
+
role: 'admin',
|
|
92
|
+
},
|
|
93
|
+
});
|
|
94
|
+
}
|
|
95
|
+
/**
|
|
96
|
+
* Create a regular user token
|
|
97
|
+
*/
|
|
98
|
+
async createUserToken(sub = 'user-001', scopes = ['read', 'write']) {
|
|
99
|
+
return this.createTestToken({
|
|
100
|
+
sub,
|
|
101
|
+
scopes,
|
|
102
|
+
claims: {
|
|
103
|
+
email: 'user@test.local',
|
|
104
|
+
name: 'Test User',
|
|
105
|
+
role: 'user',
|
|
106
|
+
},
|
|
107
|
+
});
|
|
108
|
+
}
|
|
109
|
+
/**
|
|
110
|
+
* Create an anonymous user token
|
|
111
|
+
*/
|
|
112
|
+
async createAnonymousToken() {
|
|
113
|
+
return this.createTestToken({
|
|
114
|
+
sub: `anon:${Date.now()}`,
|
|
115
|
+
scopes: ['anonymous'],
|
|
116
|
+
claims: {
|
|
117
|
+
name: 'Anonymous',
|
|
118
|
+
role: 'anonymous',
|
|
119
|
+
},
|
|
120
|
+
});
|
|
121
|
+
}
|
|
122
|
+
/**
|
|
123
|
+
* Create an expired token (for testing token expiration)
|
|
124
|
+
*/
|
|
125
|
+
async createExpiredToken(options) {
|
|
126
|
+
await this.ensureKeys();
|
|
127
|
+
const now = Math.floor(Date.now() / 1000);
|
|
128
|
+
const payload = {
|
|
129
|
+
iss: this.issuer,
|
|
130
|
+
sub: options.sub,
|
|
131
|
+
aud: this.audience,
|
|
132
|
+
iat: now - 7200, // 2 hours ago
|
|
133
|
+
exp: now - 3600, // Expired 1 hour ago
|
|
134
|
+
};
|
|
135
|
+
const token = await new jose_1.SignJWT(payload)
|
|
136
|
+
.setProtectedHeader({ alg: 'RS256', kid: this.keyId })
|
|
137
|
+
.sign(this.privateKey);
|
|
138
|
+
return token;
|
|
139
|
+
}
|
|
140
|
+
/**
|
|
141
|
+
* Create a token with an invalid signature (for testing signature validation)
|
|
142
|
+
*/
|
|
143
|
+
createTokenWithInvalidSignature(options) {
|
|
144
|
+
const now = Math.floor(Date.now() / 1000);
|
|
145
|
+
// Create a fake JWT with an invalid signature
|
|
146
|
+
const header = Buffer.from(JSON.stringify({ alg: 'RS256', kid: this.keyId })).toString('base64url');
|
|
147
|
+
const payload = Buffer.from(JSON.stringify({
|
|
148
|
+
iss: this.issuer,
|
|
149
|
+
sub: options.sub,
|
|
150
|
+
aud: this.audience,
|
|
151
|
+
iat: now,
|
|
152
|
+
exp: now + 3600,
|
|
153
|
+
})).toString('base64url');
|
|
154
|
+
// Invalid signature (just random bytes)
|
|
155
|
+
const signature = Buffer.from('invalid-signature-' + Date.now()).toString('base64url');
|
|
156
|
+
return `${header}.${payload}.${signature}`;
|
|
157
|
+
}
|
|
158
|
+
/**
|
|
159
|
+
* Get the public JWKS for verifying tokens
|
|
160
|
+
*/
|
|
161
|
+
async getPublicJwks() {
|
|
162
|
+
await this.ensureKeys();
|
|
163
|
+
return {
|
|
164
|
+
keys: [this.jwk],
|
|
165
|
+
};
|
|
166
|
+
}
|
|
167
|
+
/**
|
|
168
|
+
* Get the issuer URL
|
|
169
|
+
*/
|
|
170
|
+
getIssuer() {
|
|
171
|
+
return this.issuer;
|
|
172
|
+
}
|
|
173
|
+
/**
|
|
174
|
+
* Get the audience
|
|
175
|
+
*/
|
|
176
|
+
getAudience() {
|
|
177
|
+
return this.audience;
|
|
178
|
+
}
|
|
179
|
+
}
|
|
180
|
+
exports.TestTokenFactory = TestTokenFactory;
|
|
181
|
+
//# sourceMappingURL=token-factory.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"token-factory.js","sourceRoot":"","sources":["../../../src/auth/token-factory.ts"],"names":[],"mappings":";AAAA;;;GAGG;;;AAEH,+BAAsF;AA+BtF,sEAAsE;AACtE,sBAAsB;AACtB,sEAAsE;AAEtE;;;;;;;;;;;;;;;;;GAiBG;AACH,MAAa,gBAAgB;IACV,MAAM,CAAS;IACf,QAAQ,CAAS;IAC1B,UAAU,GAAyB,IAAI,CAAC;IACxC,SAAS,GAAyB,IAAI,CAAC;IACvC,GAAG,GAAe,IAAI,CAAC;IACvB,KAAK,CAAS;IAEtB,YAAY,UAA+B,EAAE;QAC3C,IAAI,CAAC,MAAM,GAAG,OAAO,CAAC,MAAM,IAAI,6BAA6B,CAAC;QAC9D,IAAI,CAAC,QAAQ,GAAG,OAAO,CAAC,QAAQ,IAAI,eAAe,CAAC;QACpD,IAAI,CAAC,KAAK,GAAG,YAAY,IAAI,CAAC,GAAG,EAAE,EAAE,CAAC;IACxC,CAAC;IAED;;OAEG;IACK,KAAK,CAAC,UAAU;QACtB,IAAI,IAAI,CAAC,UAAU,IAAI,IAAI,CAAC,SAAS;YAAE,OAAO;QAE9C,wBAAwB;QACxB,MAAM,EAAE,SAAS,EAAE,UAAU,EAAE,GAAG,MAAM,IAAA,sBAAe,EAAC,OAAO,EAAE;YAC/D,WAAW,EAAE,IAAI;SAClB,CAAC,CAAC;QAEH,IAAI,CAAC,UAAU,GAAG,UAAU,CAAC;QAC7B,IAAI,CAAC,SAAS,GAAG,SAAS,CAAC;QAE3B,2BAA2B;QAC3B,IAAI,CAAC,GAAG,GAAG,MAAM,IAAA,gBAAS,EAAC,SAAS,CAAC,CAAC;QACtC,IAAI,CAAC,GAAG,CAAC,GAAG,GAAG,IAAI,CAAC,KAAK,CAAC;QAC1B,IAAI,CAAC,GAAG,CAAC,GAAG,GAAG,KAAK,CAAC;QACrB,IAAI,CAAC,GAAG,CAAC,GAAG,GAAG,OAAO,CAAC;IACzB,CAAC;IAED;;OAEG;IACH,KAAK,CAAC,eAAe,CAAC,OAA2B;QAC/C,MAAM,IAAI,CAAC,UAAU,EAAE,CAAC;QAExB,MAAM,GAAG,GAAG,IAAI,CAAC,KAAK,CAAC,IAAI,CAAC,GAAG,EAAE,GAAG,IAAI,CAAC,CAAC;QAC1C,MAAM,GAAG,GAAG,OAAO,CAAC,GAAG,IAAI,IAAI,CAAC;QAEhC,MAAM,OAAO,GAAe;YAC1B,GAAG,EAAE,OAAO,CAAC,GAAG,IAAI,IAAI,CAAC,MAAM;YAC/B,GAAG,EAAE,OAAO,CAAC,GAAG;YAChB,GAAG,EAAE,OAAO,CAAC,GAAG,IAAI,IAAI,CAAC,QAAQ;YACjC,GAAG,EAAE,GAAG;YACR,GAAG,EAAE,GAAG,GAAG,GAAG;YACd,KAAK,EAAE,OAAO,CAAC,MAAM,EAAE,IAAI,CAAC,GAAG,CAAC;YAChC,GAAG,OAAO,CAAC,MAAM;SAClB,CAAC;QAEF,MAAM,KAAK,GAAG,MAAM,IAAI,cAAO,CAAC,OAAO,CAAC;aACrC,kBAAkB,CAAC,EAAE,GAAG,EAAE,OAAO,EAAE,GAAG,EAAE,IAAI,CAAC,KAAK,EAAE,CAAC;aACrD,IAAI,CAAC,IAAI,CAAC,UAAW,CAAC,CAAC;QAE1B,OAAO,KAAK,CAAC;IACf,CAAC;IAED;;OAEG;IACH,KAAK,CAAC,gBAAgB,CAAC,GAAG,GAAG,WAAW;QACtC,OAAO,IAAI,CAAC,eAAe,CAAC;YAC1B,GAAG;YACH,MAAM,EAAE,CAAC,SAAS,EAAE,MAAM,EAAE,OAAO,EAAE,QAAQ,CAAC;YAC9C,MAAM,EAAE;gBACN,KAAK,EAAE,kBAAkB;gBACzB,IAAI,EAAE,YAAY;gBAClB,IAAI,EAAE,OAAO;aACd;SACF,CAAC,CAAC;IACL,CAAC;IAED;;OAEG;IACH,KAAK,CAAC,eAAe,CAAC,GAAG,GAAG,UAAU,EAAE,MAAM,GAAG,CAAC,MAAM,EAAE,OAAO,CAAC;QAChE,OAAO,IAAI,CAAC,eAAe,CAAC;YAC1B,GAAG;YACH,MAAM;YACN,MAAM,EAAE;gBACN,KAAK,EAAE,iBAAiB;gBACxB,IAAI,EAAE,WAAW;gBACjB,IAAI,EAAE,MAAM;aACb;SACF,CAAC,CAAC;IACL,CAAC;IAED;;OAEG;IACH,KAAK,CAAC,oBAAoB;QACxB,OAAO,IAAI,CAAC,eAAe,CAAC;YAC1B,GAAG,EAAE,QAAQ,IAAI,CAAC,GAAG,EAAE,EAAE;YACzB,MAAM,EAAE,CAAC,WAAW,CAAC;YACrB,MAAM,EAAE;gBACN,IAAI,EAAE,WAAW;gBACjB,IAAI,EAAE,WAAW;aAClB;SACF,CAAC,CAAC;IACL,CAAC;IAED;;OAEG;IACH,KAAK,CAAC,kBAAkB,CAAC,OAAwC;QAC/D,MAAM,IAAI,CAAC,UAAU,EAAE,CAAC;QAExB,MAAM,GAAG,GAAG,IAAI,CAAC,KAAK,CAAC,IAAI,CAAC,GAAG,EAAE,GAAG,IAAI,CAAC,CAAC;QAE1C,MAAM,OAAO,GAAe;YAC1B,GAAG,EAAE,IAAI,CAAC,MAAM;YAChB,GAAG,EAAE,OAAO,CAAC,GAAG;YAChB,GAAG,EAAE,IAAI,CAAC,QAAQ;YAClB,GAAG,EAAE,GAAG,GAAG,IAAI,EAAE,cAAc;YAC/B,GAAG,EAAE,GAAG,GAAG,IAAI,EAAE,qBAAqB;SACvC,CAAC;QAEF,MAAM,KAAK,GAAG,MAAM,IAAI,cAAO,CAAC,OAAO,CAAC;aACrC,kBAAkB,CAAC,EAAE,GAAG,EAAE,OAAO,EAAE,GAAG,EAAE,IAAI,CAAC,KAAK,EAAE,CAAC;aACrD,IAAI,CAAC,IAAI,CAAC,UAAW,CAAC,CAAC;QAE1B,OAAO,KAAK,CAAC;IACf,CAAC;IAED;;OAEG;IACH,+BAA+B,CAAC,OAAwC;QACtE,MAAM,GAAG,GAAG,IAAI,CAAC,KAAK,CAAC,IAAI,CAAC,GAAG,EAAE,GAAG,IAAI,CAAC,CAAC;QAE1C,8CAA8C;QAC9C,MAAM,MAAM,GAAG,MAAM,CAAC,IAAI,CAAC,IAAI,CAAC,SAAS,CAAC,EAAE,GAAG,EAAE,OAAO,EAAE,GAAG,EAAE,IAAI,CAAC,KAAK,EAAE,CAAC,CAAC,CAAC,QAAQ,CAAC,WAAW,CAAC,CAAC;QACpG,MAAM,OAAO,GAAG,MAAM,CAAC,IAAI,CACzB,IAAI,CAAC,SAAS,CAAC;YACb,GAAG,EAAE,IAAI,CAAC,MAAM;YAChB,GAAG,EAAE,OAAO,CAAC,GAAG;YAChB,GAAG,EAAE,IAAI,CAAC,QAAQ;YAClB,GAAG,EAAE,GAAG;YACR,GAAG,EAAE,GAAG,GAAG,IAAI;SAChB,CAAC,CACH,CAAC,QAAQ,CAAC,WAAW,CAAC,CAAC;QAExB,wCAAwC;QACxC,MAAM,SAAS,GAAG,MAAM,CAAC,IAAI,CAAC,oBAAoB,GAAG,IAAI,CAAC,GAAG,EAAE,CAAC,CAAC,QAAQ,CAAC,WAAW,CAAC,CAAC;QAEvF,OAAO,GAAG,MAAM,IAAI,OAAO,IAAI,SAAS,EAAE,CAAC;IAC7C,CAAC;IAED;;OAEG;IACH,KAAK,CAAC,aAAa;QACjB,MAAM,IAAI,CAAC,UAAU,EAAE,CAAC;QACxB,OAAO;YACL,IAAI,EAAE,CAAC,IAAI,CAAC,GAAI,CAAC;SAClB,CAAC;IACJ,CAAC;IAED;;OAEG;IACH,SAAS;QACP,OAAO,IAAI,CAAC,MAAM,CAAC;IACrB,CAAC;IAED;;OAEG;IACH,WAAW;QACT,OAAO,IAAI,CAAC,QAAQ,CAAC;IACvB,CAAC;CACF;AA/KD,4CA+KC","sourcesContent":["/**\n * @file token-factory.ts\n * @description JWT token factory for testing authentication\n */\n\nimport { SignJWT, generateKeyPair, exportJWK, type JWTPayload, type JWK } from 'jose';\n\n// ═══════════════════════════════════════════════════════════════════\n// TYPES\n// ═══════════════════════════════════════════════════════════════════\n\nexport interface CreateTokenOptions {\n /** Subject (user ID) - required */\n sub: string;\n /** Issuer URL */\n iss?: string;\n /** Audience */\n aud?: string | string[];\n /** OAuth scopes */\n scopes?: string[];\n /** Expiration time in seconds from now (default: 3600) */\n exp?: number;\n /** Additional custom claims */\n claims?: Record<string, unknown>;\n}\n\nexport interface TokenFactoryOptions {\n /** Default issuer URL */\n issuer?: string;\n /** Default audience */\n audience?: string;\n}\n\n// Type for crypto key\ntype CryptoKeyLike = CryptoKey | Uint8Array;\n\n// ═══════════════════════════════════════════════════════════════════\n// TOKEN FACTORY CLASS\n// ═══════════════════════════════════════════════════════════════════\n\n/**\n * Factory for creating JWT tokens for testing\n *\n * @example\n * ```typescript\n * const factory = new TestTokenFactory();\n *\n * // Create a token with claims\n * const token = await factory.createTestToken({\n * sub: 'user-123',\n * scopes: ['read', 'write'],\n * });\n *\n * // Create convenience tokens\n * const adminToken = await factory.createAdminToken();\n * const userToken = await factory.createUserToken();\n * ```\n */\nexport class TestTokenFactory {\n private readonly issuer: string;\n private readonly audience: string;\n private privateKey: CryptoKeyLike | null = null;\n private publicKey: CryptoKeyLike | null = null;\n private jwk: JWK | null = null;\n private keyId: string;\n\n constructor(options: TokenFactoryOptions = {}) {\n this.issuer = options.issuer ?? 'https://test.frontmcp.local';\n this.audience = options.audience ?? 'frontmcp-test';\n this.keyId = `test-key-${Date.now()}`;\n }\n\n /**\n * Initialize the key pair (called automatically on first use)\n */\n private async ensureKeys(): Promise<void> {\n if (this.privateKey && this.publicKey) return;\n\n // Generate RSA key pair\n const { publicKey, privateKey } = await generateKeyPair('RS256', {\n extractable: true,\n });\n\n this.privateKey = privateKey;\n this.publicKey = publicKey;\n\n // Export public key as JWK\n this.jwk = await exportJWK(publicKey);\n this.jwk.kid = this.keyId;\n this.jwk.use = 'sig';\n this.jwk.alg = 'RS256';\n }\n\n /**\n * Create a JWT token with the specified claims\n */\n async createTestToken(options: CreateTokenOptions): Promise<string> {\n await this.ensureKeys();\n\n const now = Math.floor(Date.now() / 1000);\n const exp = options.exp ?? 3600;\n\n const payload: JWTPayload = {\n iss: options.iss ?? this.issuer,\n sub: options.sub,\n aud: options.aud ?? this.audience,\n iat: now,\n exp: now + exp,\n scope: options.scopes?.join(' '),\n ...options.claims,\n };\n\n const token = await new SignJWT(payload)\n .setProtectedHeader({ alg: 'RS256', kid: this.keyId })\n .sign(this.privateKey!);\n\n return token;\n }\n\n /**\n * Create an admin token with full access\n */\n async createAdminToken(sub = 'admin-001'): Promise<string> {\n return this.createTestToken({\n sub,\n scopes: ['admin:*', 'read', 'write', 'delete'],\n claims: {\n email: 'admin@test.local',\n name: 'Test Admin',\n role: 'admin',\n },\n });\n }\n\n /**\n * Create a regular user token\n */\n async createUserToken(sub = 'user-001', scopes = ['read', 'write']): Promise<string> {\n return this.createTestToken({\n sub,\n scopes,\n claims: {\n email: 'user@test.local',\n name: 'Test User',\n role: 'user',\n },\n });\n }\n\n /**\n * Create an anonymous user token\n */\n async createAnonymousToken(): Promise<string> {\n return this.createTestToken({\n sub: `anon:${Date.now()}`,\n scopes: ['anonymous'],\n claims: {\n name: 'Anonymous',\n role: 'anonymous',\n },\n });\n }\n\n /**\n * Create an expired token (for testing token expiration)\n */\n async createExpiredToken(options: Pick<CreateTokenOptions, 'sub'>): Promise<string> {\n await this.ensureKeys();\n\n const now = Math.floor(Date.now() / 1000);\n\n const payload: JWTPayload = {\n iss: this.issuer,\n sub: options.sub,\n aud: this.audience,\n iat: now - 7200, // 2 hours ago\n exp: now - 3600, // Expired 1 hour ago\n };\n\n const token = await new SignJWT(payload)\n .setProtectedHeader({ alg: 'RS256', kid: this.keyId })\n .sign(this.privateKey!);\n\n return token;\n }\n\n /**\n * Create a token with an invalid signature (for testing signature validation)\n */\n createTokenWithInvalidSignature(options: Pick<CreateTokenOptions, 'sub'>): string {\n const now = Math.floor(Date.now() / 1000);\n\n // Create a fake JWT with an invalid signature\n const header = Buffer.from(JSON.stringify({ alg: 'RS256', kid: this.keyId })).toString('base64url');\n const payload = Buffer.from(\n JSON.stringify({\n iss: this.issuer,\n sub: options.sub,\n aud: this.audience,\n iat: now,\n exp: now + 3600,\n }),\n ).toString('base64url');\n\n // Invalid signature (just random bytes)\n const signature = Buffer.from('invalid-signature-' + Date.now()).toString('base64url');\n\n return `${header}.${payload}.${signature}`;\n }\n\n /**\n * Get the public JWKS for verifying tokens\n */\n async getPublicJwks(): Promise<{ keys: JWK[] }> {\n await this.ensureKeys();\n return {\n keys: [this.jwk!],\n };\n }\n\n /**\n * Get the issuer URL\n */\n getIssuer(): string {\n return this.issuer;\n }\n\n /**\n * Get the audience\n */\n getAudience(): string {\n return this.audience;\n }\n}\n"]}
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @file user-fixtures.ts
|
|
3
|
+
* @description Pre-defined test user fixtures
|
|
4
|
+
*/
|
|
5
|
+
export interface TestUserFixture {
|
|
6
|
+
/** User subject ID */
|
|
7
|
+
sub: string;
|
|
8
|
+
/** User email */
|
|
9
|
+
email?: string;
|
|
10
|
+
/** User display name */
|
|
11
|
+
name?: string;
|
|
12
|
+
/** OAuth scopes */
|
|
13
|
+
scopes: string[];
|
|
14
|
+
/** User role */
|
|
15
|
+
role?: string;
|
|
16
|
+
}
|
|
17
|
+
/**
|
|
18
|
+
* Pre-defined test users for common testing scenarios
|
|
19
|
+
*/
|
|
20
|
+
export declare const TestUsers: Record<string, TestUserFixture>;
|
|
21
|
+
/**
|
|
22
|
+
* Create a custom test user
|
|
23
|
+
*/
|
|
24
|
+
export declare function createTestUser(overrides: Partial<TestUserFixture> & {
|
|
25
|
+
sub: string;
|
|
26
|
+
}): TestUserFixture;
|
|
@@ -0,0 +1,92 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
/**
|
|
3
|
+
* @file user-fixtures.ts
|
|
4
|
+
* @description Pre-defined test user fixtures
|
|
5
|
+
*/
|
|
6
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
7
|
+
exports.TestUsers = void 0;
|
|
8
|
+
exports.createTestUser = createTestUser;
|
|
9
|
+
/**
|
|
10
|
+
* Pre-defined test users for common testing scenarios
|
|
11
|
+
*/
|
|
12
|
+
exports.TestUsers = {
|
|
13
|
+
/**
|
|
14
|
+
* Admin user with full access
|
|
15
|
+
*/
|
|
16
|
+
admin: {
|
|
17
|
+
sub: 'admin-001',
|
|
18
|
+
email: 'admin@test.local',
|
|
19
|
+
name: 'Test Admin',
|
|
20
|
+
scopes: ['admin:*', 'read', 'write', 'delete'],
|
|
21
|
+
role: 'admin',
|
|
22
|
+
},
|
|
23
|
+
/**
|
|
24
|
+
* Regular user with read/write access
|
|
25
|
+
*/
|
|
26
|
+
user: {
|
|
27
|
+
sub: 'user-001',
|
|
28
|
+
email: 'user@test.local',
|
|
29
|
+
name: 'Test User',
|
|
30
|
+
scopes: ['read', 'write'],
|
|
31
|
+
role: 'user',
|
|
32
|
+
},
|
|
33
|
+
/**
|
|
34
|
+
* Read-only user
|
|
35
|
+
*/
|
|
36
|
+
readOnly: {
|
|
37
|
+
sub: 'readonly-001',
|
|
38
|
+
email: 'readonly@test.local',
|
|
39
|
+
name: 'Read Only User',
|
|
40
|
+
scopes: ['read'],
|
|
41
|
+
role: 'readonly',
|
|
42
|
+
},
|
|
43
|
+
/**
|
|
44
|
+
* Anonymous user
|
|
45
|
+
*/
|
|
46
|
+
anonymous: {
|
|
47
|
+
sub: 'anon:001',
|
|
48
|
+
name: 'Anonymous',
|
|
49
|
+
scopes: ['anonymous'],
|
|
50
|
+
role: 'anonymous',
|
|
51
|
+
},
|
|
52
|
+
/**
|
|
53
|
+
* User with no scopes (for testing access denied)
|
|
54
|
+
*/
|
|
55
|
+
noScopes: {
|
|
56
|
+
sub: 'noscopes-001',
|
|
57
|
+
email: 'noscopes@test.local',
|
|
58
|
+
name: 'No Scopes User',
|
|
59
|
+
scopes: [],
|
|
60
|
+
role: 'user',
|
|
61
|
+
},
|
|
62
|
+
/**
|
|
63
|
+
* User with only tool execution scope
|
|
64
|
+
*/
|
|
65
|
+
toolsOnly: {
|
|
66
|
+
sub: 'toolsonly-001',
|
|
67
|
+
email: 'toolsonly@test.local',
|
|
68
|
+
name: 'Tools Only User',
|
|
69
|
+
scopes: ['tools:execute'],
|
|
70
|
+
role: 'user',
|
|
71
|
+
},
|
|
72
|
+
/**
|
|
73
|
+
* User with only resource read scope
|
|
74
|
+
*/
|
|
75
|
+
resourcesOnly: {
|
|
76
|
+
sub: 'resourcesonly-001',
|
|
77
|
+
email: 'resourcesonly@test.local',
|
|
78
|
+
name: 'Resources Only User',
|
|
79
|
+
scopes: ['resources:read'],
|
|
80
|
+
role: 'user',
|
|
81
|
+
},
|
|
82
|
+
};
|
|
83
|
+
/**
|
|
84
|
+
* Create a custom test user
|
|
85
|
+
*/
|
|
86
|
+
function createTestUser(overrides) {
|
|
87
|
+
return {
|
|
88
|
+
scopes: [],
|
|
89
|
+
...overrides,
|
|
90
|
+
};
|
|
91
|
+
}
|
|
92
|
+
//# sourceMappingURL=user-fixtures.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"user-fixtures.js","sourceRoot":"","sources":["../../../src/auth/user-fixtures.ts"],"names":[],"mappings":";AAAA;;;GAGG;;;AAmGH,wCAKC;AAzFD;;GAEG;AACU,QAAA,SAAS,GAAoC;IACxD;;OAEG;IACH,KAAK,EAAE;QACL,GAAG,EAAE,WAAW;QAChB,KAAK,EAAE,kBAAkB;QACzB,IAAI,EAAE,YAAY;QAClB,MAAM,EAAE,CAAC,SAAS,EAAE,MAAM,EAAE,OAAO,EAAE,QAAQ,CAAC;QAC9C,IAAI,EAAE,OAAO;KACd;IAED;;OAEG;IACH,IAAI,EAAE;QACJ,GAAG,EAAE,UAAU;QACf,KAAK,EAAE,iBAAiB;QACxB,IAAI,EAAE,WAAW;QACjB,MAAM,EAAE,CAAC,MAAM,EAAE,OAAO,CAAC;QACzB,IAAI,EAAE,MAAM;KACb;IAED;;OAEG;IACH,QAAQ,EAAE;QACR,GAAG,EAAE,cAAc;QACnB,KAAK,EAAE,qBAAqB;QAC5B,IAAI,EAAE,gBAAgB;QACtB,MAAM,EAAE,CAAC,MAAM,CAAC;QAChB,IAAI,EAAE,UAAU;KACjB;IAED;;OAEG;IACH,SAAS,EAAE;QACT,GAAG,EAAE,UAAU;QACf,IAAI,EAAE,WAAW;QACjB,MAAM,EAAE,CAAC,WAAW,CAAC;QACrB,IAAI,EAAE,WAAW;KAClB;IAED;;OAEG;IACH,QAAQ,EAAE;QACR,GAAG,EAAE,cAAc;QACnB,KAAK,EAAE,qBAAqB;QAC5B,IAAI,EAAE,gBAAgB;QACtB,MAAM,EAAE,EAAE;QACV,IAAI,EAAE,MAAM;KACb;IAED;;OAEG;IACH,SAAS,EAAE;QACT,GAAG,EAAE,eAAe;QACpB,KAAK,EAAE,sBAAsB;QAC7B,IAAI,EAAE,iBAAiB;QACvB,MAAM,EAAE,CAAC,eAAe,CAAC;QACzB,IAAI,EAAE,MAAM;KACb;IAED;;OAEG;IACH,aAAa,EAAE;QACb,GAAG,EAAE,mBAAmB;QACxB,KAAK,EAAE,0BAA0B;QACjC,IAAI,EAAE,qBAAqB;QAC3B,MAAM,EAAE,CAAC,gBAAgB,CAAC;QAC1B,IAAI,EAAE,MAAM;KACb;CACF,CAAC;AAEF;;GAEG;AACH,SAAgB,cAAc,CAAC,SAAqD;IAClF,OAAO;QACL,MAAM,EAAE,EAAE;QACV,GAAG,SAAS;KACb,CAAC;AACJ,CAAC","sourcesContent":["/**\n * @file user-fixtures.ts\n * @description Pre-defined test user fixtures\n */\n\nexport interface TestUserFixture {\n /** User subject ID */\n sub: string;\n /** User email */\n email?: string;\n /** User display name */\n name?: string;\n /** OAuth scopes */\n scopes: string[];\n /** User role */\n role?: string;\n}\n\n/**\n * Pre-defined test users for common testing scenarios\n */\nexport const TestUsers: Record<string, TestUserFixture> = {\n /**\n * Admin user with full access\n */\n admin: {\n sub: 'admin-001',\n email: 'admin@test.local',\n name: 'Test Admin',\n scopes: ['admin:*', 'read', 'write', 'delete'],\n role: 'admin',\n },\n\n /**\n * Regular user with read/write access\n */\n user: {\n sub: 'user-001',\n email: 'user@test.local',\n name: 'Test User',\n scopes: ['read', 'write'],\n role: 'user',\n },\n\n /**\n * Read-only user\n */\n readOnly: {\n sub: 'readonly-001',\n email: 'readonly@test.local',\n name: 'Read Only User',\n scopes: ['read'],\n role: 'readonly',\n },\n\n /**\n * Anonymous user\n */\n anonymous: {\n sub: 'anon:001',\n name: 'Anonymous',\n scopes: ['anonymous'],\n role: 'anonymous',\n },\n\n /**\n * User with no scopes (for testing access denied)\n */\n noScopes: {\n sub: 'noscopes-001',\n email: 'noscopes@test.local',\n name: 'No Scopes User',\n scopes: [],\n role: 'user',\n },\n\n /**\n * User with only tool execution scope\n */\n toolsOnly: {\n sub: 'toolsonly-001',\n email: 'toolsonly@test.local',\n name: 'Tools Only User',\n scopes: ['tools:execute'],\n role: 'user',\n },\n\n /**\n * User with only resource read scope\n */\n resourcesOnly: {\n sub: 'resourcesonly-001',\n email: 'resourcesonly@test.local',\n name: 'Resources Only User',\n scopes: ['resources:read'],\n role: 'user',\n },\n};\n\n/**\n * Create a custom test user\n */\nexport function createTestUser(overrides: Partial<TestUserFixture> & { sub: string }): TestUserFixture {\n return {\n scopes: [],\n ...overrides,\n };\n}\n"]}
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @file client/index.ts
|
|
3
|
+
* @description MCP Test Client exports
|
|
4
|
+
*/
|
|
5
|
+
export { McpTestClient } from './mcp-test-client';
|
|
6
|
+
export { McpTestClientBuilder } from './mcp-test-client.builder';
|
|
7
|
+
export type { McpTestClientConfig, McpResponse, McpErrorInfo, TestTransportType, TestAuthConfig, ToolResultWrapper, ResourceContentWrapper, PromptResultWrapper, LogEntry, LogLevel, RequestTrace, NotificationEntry, ProgressUpdate, SessionInfo, AuthState, TransportState, JSONRPCRequest, JSONRPCResponse, InitializeResult, ListToolsResult, CallToolResult, ListResourcesResult, ReadResourceResult, ListResourceTemplatesResult, ListPromptsResult, GetPromptResult, Tool, Resource, ResourceTemplate, Prompt, } from './mcp-test-client.types';
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
/**
|
|
3
|
+
* @file client/index.ts
|
|
4
|
+
* @description MCP Test Client exports
|
|
5
|
+
*/
|
|
6
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
7
|
+
exports.McpTestClientBuilder = exports.McpTestClient = void 0;
|
|
8
|
+
var mcp_test_client_1 = require("./mcp-test-client");
|
|
9
|
+
Object.defineProperty(exports, "McpTestClient", { enumerable: true, get: function () { return mcp_test_client_1.McpTestClient; } });
|
|
10
|
+
var mcp_test_client_builder_1 = require("./mcp-test-client.builder");
|
|
11
|
+
Object.defineProperty(exports, "McpTestClientBuilder", { enumerable: true, get: function () { return mcp_test_client_builder_1.McpTestClientBuilder; } });
|
|
12
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../../src/client/index.ts"],"names":[],"mappings":";AAAA;;;GAGG;;;AAEH,qDAAkD;AAAzC,gHAAA,aAAa,OAAA;AACtB,qEAAiE;AAAxD,+HAAA,oBAAoB,OAAA","sourcesContent":["/**\n * @file client/index.ts\n * @description MCP Test Client exports\n */\n\nexport { McpTestClient } from './mcp-test-client';\nexport { McpTestClientBuilder } from './mcp-test-client.builder';\nexport type {\n McpTestClientConfig,\n McpResponse,\n McpErrorInfo,\n TestTransportType,\n TestAuthConfig,\n ToolResultWrapper,\n ResourceContentWrapper,\n PromptResultWrapper,\n LogEntry,\n LogLevel,\n RequestTrace,\n NotificationEntry,\n ProgressUpdate,\n SessionInfo,\n AuthState,\n TransportState,\n // JSON-RPC types\n JSONRPCRequest,\n JSONRPCResponse,\n // Re-exports from MCP SDK\n InitializeResult,\n ListToolsResult,\n CallToolResult,\n ListResourcesResult,\n ReadResourceResult,\n ListResourceTemplatesResult,\n ListPromptsResult,\n GetPromptResult,\n Tool,\n Resource,\n ResourceTemplate,\n Prompt,\n} from './mcp-test-client.types';\n"]}
|
|
@@ -0,0 +1,72 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @file mcp-test-client.builder.ts
|
|
3
|
+
* @description Builder pattern for creating McpTestClient instances
|
|
4
|
+
*/
|
|
5
|
+
import type { McpTestClientConfig, TestTransportType, TestAuthConfig } from './mcp-test-client.types';
|
|
6
|
+
import { McpTestClient } from './mcp-test-client';
|
|
7
|
+
/**
|
|
8
|
+
* Builder for creating McpTestClient instances with fluent API
|
|
9
|
+
*
|
|
10
|
+
* @example
|
|
11
|
+
* ```typescript
|
|
12
|
+
* const client = await McpTestClient.create({ baseUrl: 'http://localhost:3003' })
|
|
13
|
+
* .withTransport('streamable-http')
|
|
14
|
+
* .withToken('my-jwt-token')
|
|
15
|
+
* .withTimeout(5000)
|
|
16
|
+
* .withDebug()
|
|
17
|
+
* .buildAndConnect();
|
|
18
|
+
* ```
|
|
19
|
+
*/
|
|
20
|
+
export declare class McpTestClientBuilder {
|
|
21
|
+
private config;
|
|
22
|
+
constructor(config: McpTestClientConfig);
|
|
23
|
+
/**
|
|
24
|
+
* Set the authentication configuration
|
|
25
|
+
*/
|
|
26
|
+
withAuth(auth: TestAuthConfig): this;
|
|
27
|
+
/**
|
|
28
|
+
* Set the bearer token for authentication
|
|
29
|
+
*/
|
|
30
|
+
withToken(token: string): this;
|
|
31
|
+
/**
|
|
32
|
+
* Add custom headers to all requests
|
|
33
|
+
*/
|
|
34
|
+
withHeaders(headers: Record<string, string>): this;
|
|
35
|
+
/**
|
|
36
|
+
* Set the transport type
|
|
37
|
+
*/
|
|
38
|
+
withTransport(transport: TestTransportType): this;
|
|
39
|
+
/**
|
|
40
|
+
* Set the request timeout in milliseconds
|
|
41
|
+
*/
|
|
42
|
+
withTimeout(timeoutMs: number): this;
|
|
43
|
+
/**
|
|
44
|
+
* Enable debug logging
|
|
45
|
+
*/
|
|
46
|
+
withDebug(enabled?: boolean): this;
|
|
47
|
+
/**
|
|
48
|
+
* Enable public mode - skip authentication entirely.
|
|
49
|
+
* When true, no Authorization header is sent and anonymous token is not requested.
|
|
50
|
+
* Use this for testing public/unauthenticated endpoints in CI/CD pipelines.
|
|
51
|
+
*/
|
|
52
|
+
withPublicMode(enabled?: boolean): this;
|
|
53
|
+
/**
|
|
54
|
+
* Set the MCP protocol version to request
|
|
55
|
+
*/
|
|
56
|
+
withProtocolVersion(version: string): this;
|
|
57
|
+
/**
|
|
58
|
+
* Set the client info sent during initialization
|
|
59
|
+
*/
|
|
60
|
+
withClientInfo(info: {
|
|
61
|
+
name: string;
|
|
62
|
+
version: string;
|
|
63
|
+
}): this;
|
|
64
|
+
/**
|
|
65
|
+
* Build the McpTestClient instance (does not connect)
|
|
66
|
+
*/
|
|
67
|
+
build(): McpTestClient;
|
|
68
|
+
/**
|
|
69
|
+
* Build the McpTestClient and connect to the server
|
|
70
|
+
*/
|
|
71
|
+
buildAndConnect(): Promise<McpTestClient>;
|
|
72
|
+
}
|
|
@@ -0,0 +1,111 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
/**
|
|
3
|
+
* @file mcp-test-client.builder.ts
|
|
4
|
+
* @description Builder pattern for creating McpTestClient instances
|
|
5
|
+
*/
|
|
6
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
7
|
+
exports.McpTestClientBuilder = void 0;
|
|
8
|
+
const mcp_test_client_1 = require("./mcp-test-client");
|
|
9
|
+
/**
|
|
10
|
+
* Builder for creating McpTestClient instances with fluent API
|
|
11
|
+
*
|
|
12
|
+
* @example
|
|
13
|
+
* ```typescript
|
|
14
|
+
* const client = await McpTestClient.create({ baseUrl: 'http://localhost:3003' })
|
|
15
|
+
* .withTransport('streamable-http')
|
|
16
|
+
* .withToken('my-jwt-token')
|
|
17
|
+
* .withTimeout(5000)
|
|
18
|
+
* .withDebug()
|
|
19
|
+
* .buildAndConnect();
|
|
20
|
+
* ```
|
|
21
|
+
*/
|
|
22
|
+
class McpTestClientBuilder {
|
|
23
|
+
config;
|
|
24
|
+
constructor(config) {
|
|
25
|
+
this.config = { ...config };
|
|
26
|
+
}
|
|
27
|
+
/**
|
|
28
|
+
* Set the authentication configuration
|
|
29
|
+
*/
|
|
30
|
+
withAuth(auth) {
|
|
31
|
+
this.config.auth = { ...this.config.auth, ...auth };
|
|
32
|
+
return this;
|
|
33
|
+
}
|
|
34
|
+
/**
|
|
35
|
+
* Set the bearer token for authentication
|
|
36
|
+
*/
|
|
37
|
+
withToken(token) {
|
|
38
|
+
this.config.auth = { ...this.config.auth, token };
|
|
39
|
+
return this;
|
|
40
|
+
}
|
|
41
|
+
/**
|
|
42
|
+
* Add custom headers to all requests
|
|
43
|
+
*/
|
|
44
|
+
withHeaders(headers) {
|
|
45
|
+
this.config.auth = {
|
|
46
|
+
...this.config.auth,
|
|
47
|
+
headers: { ...this.config.auth?.headers, ...headers },
|
|
48
|
+
};
|
|
49
|
+
return this;
|
|
50
|
+
}
|
|
51
|
+
/**
|
|
52
|
+
* Set the transport type
|
|
53
|
+
*/
|
|
54
|
+
withTransport(transport) {
|
|
55
|
+
this.config.transport = transport;
|
|
56
|
+
return this;
|
|
57
|
+
}
|
|
58
|
+
/**
|
|
59
|
+
* Set the request timeout in milliseconds
|
|
60
|
+
*/
|
|
61
|
+
withTimeout(timeoutMs) {
|
|
62
|
+
this.config.timeout = timeoutMs;
|
|
63
|
+
return this;
|
|
64
|
+
}
|
|
65
|
+
/**
|
|
66
|
+
* Enable debug logging
|
|
67
|
+
*/
|
|
68
|
+
withDebug(enabled = true) {
|
|
69
|
+
this.config.debug = enabled;
|
|
70
|
+
return this;
|
|
71
|
+
}
|
|
72
|
+
/**
|
|
73
|
+
* Enable public mode - skip authentication entirely.
|
|
74
|
+
* When true, no Authorization header is sent and anonymous token is not requested.
|
|
75
|
+
* Use this for testing public/unauthenticated endpoints in CI/CD pipelines.
|
|
76
|
+
*/
|
|
77
|
+
withPublicMode(enabled = true) {
|
|
78
|
+
this.config.publicMode = enabled;
|
|
79
|
+
return this;
|
|
80
|
+
}
|
|
81
|
+
/**
|
|
82
|
+
* Set the MCP protocol version to request
|
|
83
|
+
*/
|
|
84
|
+
withProtocolVersion(version) {
|
|
85
|
+
this.config.protocolVersion = version;
|
|
86
|
+
return this;
|
|
87
|
+
}
|
|
88
|
+
/**
|
|
89
|
+
* Set the client info sent during initialization
|
|
90
|
+
*/
|
|
91
|
+
withClientInfo(info) {
|
|
92
|
+
this.config.clientInfo = info;
|
|
93
|
+
return this;
|
|
94
|
+
}
|
|
95
|
+
/**
|
|
96
|
+
* Build the McpTestClient instance (does not connect)
|
|
97
|
+
*/
|
|
98
|
+
build() {
|
|
99
|
+
return new mcp_test_client_1.McpTestClient(this.config);
|
|
100
|
+
}
|
|
101
|
+
/**
|
|
102
|
+
* Build the McpTestClient and connect to the server
|
|
103
|
+
*/
|
|
104
|
+
async buildAndConnect() {
|
|
105
|
+
const client = this.build();
|
|
106
|
+
await client.connect();
|
|
107
|
+
return client;
|
|
108
|
+
}
|
|
109
|
+
}
|
|
110
|
+
exports.McpTestClientBuilder = McpTestClientBuilder;
|
|
111
|
+
//# sourceMappingURL=mcp-test-client.builder.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"mcp-test-client.builder.js","sourceRoot":"","sources":["../../../src/client/mcp-test-client.builder.ts"],"names":[],"mappings":";AAAA;;;GAGG;;;AAGH,uDAAkD;AAElD;;;;;;;;;;;;GAYG;AACH,MAAa,oBAAoB;IACvB,MAAM,CAAsB;IAEpC,YAAY,MAA2B;QACrC,IAAI,CAAC,MAAM,GAAG,EAAE,GAAG,MAAM,EAAE,CAAC;IAC9B,CAAC;IAED;;OAEG;IACH,QAAQ,CAAC,IAAoB;QAC3B,IAAI,CAAC,MAAM,CAAC,IAAI,GAAG,EAAE,GAAG,IAAI,CAAC,MAAM,CAAC,IAAI,EAAE,GAAG,IAAI,EAAE,CAAC;QACpD,OAAO,IAAI,CAAC;IACd,CAAC;IAED;;OAEG;IACH,SAAS,CAAC,KAAa;QACrB,IAAI,CAAC,MAAM,CAAC,IAAI,GAAG,EAAE,GAAG,IAAI,CAAC,MAAM,CAAC,IAAI,EAAE,KAAK,EAAE,CAAC;QAClD,OAAO,IAAI,CAAC;IACd,CAAC;IAED;;OAEG;IACH,WAAW,CAAC,OAA+B;QACzC,IAAI,CAAC,MAAM,CAAC,IAAI,GAAG;YACjB,GAAG,IAAI,CAAC,MAAM,CAAC,IAAI;YACnB,OAAO,EAAE,EAAE,GAAG,IAAI,CAAC,MAAM,CAAC,IAAI,EAAE,OAAO,EAAE,GAAG,OAAO,EAAE;SACtD,CAAC;QACF,OAAO,IAAI,CAAC;IACd,CAAC;IAED;;OAEG;IACH,aAAa,CAAC,SAA4B;QACxC,IAAI,CAAC,MAAM,CAAC,SAAS,GAAG,SAAS,CAAC;QAClC,OAAO,IAAI,CAAC;IACd,CAAC;IAED;;OAEG;IACH,WAAW,CAAC,SAAiB;QAC3B,IAAI,CAAC,MAAM,CAAC,OAAO,GAAG,SAAS,CAAC;QAChC,OAAO,IAAI,CAAC;IACd,CAAC;IAED;;OAEG;IACH,SAAS,CAAC,OAAO,GAAG,IAAI;QACtB,IAAI,CAAC,MAAM,CAAC,KAAK,GAAG,OAAO,CAAC;QAC5B,OAAO,IAAI,CAAC;IACd,CAAC;IAED;;;;OAIG;IACH,cAAc,CAAC,OAAO,GAAG,IAAI;QAC3B,IAAI,CAAC,MAAM,CAAC,UAAU,GAAG,OAAO,CAAC;QACjC,OAAO,IAAI,CAAC;IACd,CAAC;IAED;;OAEG;IACH,mBAAmB,CAAC,OAAe;QACjC,IAAI,CAAC,MAAM,CAAC,eAAe,GAAG,OAAO,CAAC;QACtC,OAAO,IAAI,CAAC;IACd,CAAC;IAED;;OAEG;IACH,cAAc,CAAC,IAAuC;QACpD,IAAI,CAAC,MAAM,CAAC,UAAU,GAAG,IAAI,CAAC;QAC9B,OAAO,IAAI,CAAC;IACd,CAAC;IAED;;OAEG;IACH,KAAK;QACH,OAAO,IAAI,+BAAa,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC;IACxC,CAAC;IAED;;OAEG;IACH,KAAK,CAAC,eAAe;QACnB,MAAM,MAAM,GAAG,IAAI,CAAC,KAAK,EAAE,CAAC;QAC5B,MAAM,MAAM,CAAC,OAAO,EAAE,CAAC;QACvB,OAAO,MAAM,CAAC;IAChB,CAAC;CACF;AAnGD,oDAmGC","sourcesContent":["/**\n * @file mcp-test-client.builder.ts\n * @description Builder pattern for creating McpTestClient instances\n */\n\nimport type { McpTestClientConfig, TestTransportType, TestAuthConfig } from './mcp-test-client.types';\nimport { McpTestClient } from './mcp-test-client';\n\n/**\n * Builder for creating McpTestClient instances with fluent API\n *\n * @example\n * ```typescript\n * const client = await McpTestClient.create({ baseUrl: 'http://localhost:3003' })\n * .withTransport('streamable-http')\n * .withToken('my-jwt-token')\n * .withTimeout(5000)\n * .withDebug()\n * .buildAndConnect();\n * ```\n */\nexport class McpTestClientBuilder {\n private config: McpTestClientConfig;\n\n constructor(config: McpTestClientConfig) {\n this.config = { ...config };\n }\n\n /**\n * Set the authentication configuration\n */\n withAuth(auth: TestAuthConfig): this {\n this.config.auth = { ...this.config.auth, ...auth };\n return this;\n }\n\n /**\n * Set the bearer token for authentication\n */\n withToken(token: string): this {\n this.config.auth = { ...this.config.auth, token };\n return this;\n }\n\n /**\n * Add custom headers to all requests\n */\n withHeaders(headers: Record<string, string>): this {\n this.config.auth = {\n ...this.config.auth,\n headers: { ...this.config.auth?.headers, ...headers },\n };\n return this;\n }\n\n /**\n * Set the transport type\n */\n withTransport(transport: TestTransportType): this {\n this.config.transport = transport;\n return this;\n }\n\n /**\n * Set the request timeout in milliseconds\n */\n withTimeout(timeoutMs: number): this {\n this.config.timeout = timeoutMs;\n return this;\n }\n\n /**\n * Enable debug logging\n */\n withDebug(enabled = true): this {\n this.config.debug = enabled;\n return this;\n }\n\n /**\n * Enable public mode - skip authentication entirely.\n * When true, no Authorization header is sent and anonymous token is not requested.\n * Use this for testing public/unauthenticated endpoints in CI/CD pipelines.\n */\n withPublicMode(enabled = true): this {\n this.config.publicMode = enabled;\n return this;\n }\n\n /**\n * Set the MCP protocol version to request\n */\n withProtocolVersion(version: string): this {\n this.config.protocolVersion = version;\n return this;\n }\n\n /**\n * Set the client info sent during initialization\n */\n withClientInfo(info: { name: string; version: string }): this {\n this.config.clientInfo = info;\n return this;\n }\n\n /**\n * Build the McpTestClient instance (does not connect)\n */\n build(): McpTestClient {\n return new McpTestClient(this.config);\n }\n\n /**\n * Build the McpTestClient and connect to the server\n */\n async buildAndConnect(): Promise<McpTestClient> {\n const client = this.build();\n await client.connect();\n return client;\n }\n}\n"]}
|