@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.
Files changed (112) hide show
  1. package/LICENSE +201 -0
  2. package/README.md +1358 -0
  3. package/jest-preset.js +61 -0
  4. package/package.json +94 -0
  5. package/src/assertions/index.d.ts +5 -0
  6. package/src/assertions/index.js +18 -0
  7. package/src/assertions/index.js.map +1 -0
  8. package/src/assertions/mcp-assertions.d.ts +81 -0
  9. package/src/assertions/mcp-assertions.js +220 -0
  10. package/src/assertions/mcp-assertions.js.map +1 -0
  11. package/src/auth/auth-headers.d.ts +29 -0
  12. package/src/auth/auth-headers.js +62 -0
  13. package/src/auth/auth-headers.js.map +1 -0
  14. package/src/auth/index.d.ts +9 -0
  15. package/src/auth/index.js +15 -0
  16. package/src/auth/index.js.map +1 -0
  17. package/src/auth/token-factory.d.ts +94 -0
  18. package/src/auth/token-factory.js +181 -0
  19. package/src/auth/token-factory.js.map +1 -0
  20. package/src/auth/user-fixtures.d.ts +26 -0
  21. package/src/auth/user-fixtures.js +92 -0
  22. package/src/auth/user-fixtures.js.map +1 -0
  23. package/src/client/index.d.ts +7 -0
  24. package/src/client/index.js +12 -0
  25. package/src/client/index.js.map +1 -0
  26. package/src/client/mcp-test-client.builder.d.ts +72 -0
  27. package/src/client/mcp-test-client.builder.js +111 -0
  28. package/src/client/mcp-test-client.builder.js.map +1 -0
  29. package/src/client/mcp-test-client.d.ts +360 -0
  30. package/src/client/mcp-test-client.js +929 -0
  31. package/src/client/mcp-test-client.js.map +1 -0
  32. package/src/client/mcp-test-client.types.d.ts +216 -0
  33. package/src/client/mcp-test-client.types.js +7 -0
  34. package/src/client/mcp-test-client.types.js.map +1 -0
  35. package/src/errors/index.d.ts +45 -0
  36. package/src/errors/index.js +85 -0
  37. package/src/errors/index.js.map +1 -0
  38. package/src/expect.d.ts +67 -0
  39. package/src/expect.js +31 -0
  40. package/src/expect.js.map +1 -0
  41. package/src/fixtures/fixture-types.d.ts +166 -0
  42. package/src/fixtures/fixture-types.js +7 -0
  43. package/src/fixtures/fixture-types.js.map +1 -0
  44. package/src/fixtures/index.d.ts +7 -0
  45. package/src/fixtures/index.js +16 -0
  46. package/src/fixtures/index.js.map +1 -0
  47. package/src/fixtures/test-fixture.d.ts +41 -0
  48. package/src/fixtures/test-fixture.js +280 -0
  49. package/src/fixtures/test-fixture.js.map +1 -0
  50. package/src/http-mock/http-mock.d.ts +84 -0
  51. package/src/http-mock/http-mock.js +544 -0
  52. package/src/http-mock/http-mock.js.map +1 -0
  53. package/src/http-mock/http-mock.types.d.ts +124 -0
  54. package/src/http-mock/http-mock.types.js +10 -0
  55. package/src/http-mock/http-mock.types.js.map +1 -0
  56. package/src/http-mock/index.d.ts +6 -0
  57. package/src/http-mock/index.js +11 -0
  58. package/src/http-mock/index.js.map +1 -0
  59. package/src/index.d.ts +65 -0
  60. package/src/index.js +128 -0
  61. package/src/index.js.map +1 -0
  62. package/src/interceptor/index.d.ts +7 -0
  63. package/src/interceptor/index.js +15 -0
  64. package/src/interceptor/index.js.map +1 -0
  65. package/src/interceptor/interceptor-chain.d.ts +77 -0
  66. package/src/interceptor/interceptor-chain.js +207 -0
  67. package/src/interceptor/interceptor-chain.js.map +1 -0
  68. package/src/interceptor/interceptor.types.d.ts +131 -0
  69. package/src/interceptor/interceptor.types.js +7 -0
  70. package/src/interceptor/interceptor.types.js.map +1 -0
  71. package/src/interceptor/mock-registry.d.ts +82 -0
  72. package/src/interceptor/mock-registry.js +189 -0
  73. package/src/interceptor/mock-registry.js.map +1 -0
  74. package/src/matchers/index.d.ts +7 -0
  75. package/src/matchers/index.js +12 -0
  76. package/src/matchers/index.js.map +1 -0
  77. package/src/matchers/matcher-types.d.ts +266 -0
  78. package/src/matchers/matcher-types.js +10 -0
  79. package/src/matchers/matcher-types.js.map +1 -0
  80. package/src/matchers/mcp-matchers.d.ts +47 -0
  81. package/src/matchers/mcp-matchers.js +391 -0
  82. package/src/matchers/mcp-matchers.js.map +1 -0
  83. package/src/playwright/index.d.ts +37 -0
  84. package/src/playwright/index.js +49 -0
  85. package/src/playwright/index.js.map +1 -0
  86. package/src/server/index.d.ts +6 -0
  87. package/src/server/index.js +10 -0
  88. package/src/server/index.js.map +1 -0
  89. package/src/server/test-server.d.ts +99 -0
  90. package/src/server/test-server.js +286 -0
  91. package/src/server/test-server.js.map +1 -0
  92. package/src/setup.d.ts +22 -0
  93. package/src/setup.js +30 -0
  94. package/src/setup.js.map +1 -0
  95. package/src/transport/index.d.ts +6 -0
  96. package/src/transport/index.js +10 -0
  97. package/src/transport/index.js.map +1 -0
  98. package/src/transport/streamable-http.transport.d.ts +65 -0
  99. package/src/transport/streamable-http.transport.js +432 -0
  100. package/src/transport/streamable-http.transport.js.map +1 -0
  101. package/src/transport/transport.interface.d.ts +124 -0
  102. package/src/transport/transport.interface.js +7 -0
  103. package/src/transport/transport.interface.js.map +1 -0
  104. package/src/ui/index.d.ts +17 -0
  105. package/src/ui/index.js +23 -0
  106. package/src/ui/index.js.map +1 -0
  107. package/src/ui/ui-assertions.d.ts +94 -0
  108. package/src/ui/ui-assertions.js +215 -0
  109. package/src/ui/ui-assertions.js.map +1 -0
  110. package/src/ui/ui-matchers.d.ts +39 -0
  111. package/src/ui/ui-matchers.js +275 -0
  112. 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":"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","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"]}