@frontmcp/skills 1.1.2-beta.1 → 1.2.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/catalog/TEMPLATE.md +16 -11
- package/catalog/frontmcp-authorities/SKILL.md +116 -11
- package/catalog/frontmcp-authorities/references/authority-profiles.md +39 -36
- package/catalog/frontmcp-authorities/references/claims-mapping.md +7 -0
- package/catalog/frontmcp-authorities/references/custom-evaluators.md +63 -14
- package/catalog/frontmcp-channels/SKILL.md +36 -0
- package/catalog/frontmcp-channels/examples/channel-sources/file-watcher.md +8 -2
- package/catalog/frontmcp-channels/examples/channel-sources/replay-buffer.md +111 -30
- package/catalog/frontmcp-channels/examples/channel-two-way/whatsapp-bridge.md +45 -3
- package/catalog/frontmcp-channels/references/channel-sources.md +11 -3
- package/catalog/frontmcp-channels/references/channel-two-way.md +60 -89
- package/catalog/frontmcp-config/SKILL.md +111 -8
- package/catalog/frontmcp-config/examples/configure-auth-modes/local-self-signed-tokens.md +4 -4
- package/catalog/frontmcp-config/examples/configure-auth-modes/remote-enterprise-oauth.md +7 -1
- package/catalog/frontmcp-config/examples/configure-deployment-targets/distributed-ha-config.md +1 -1
- package/catalog/frontmcp-config/examples/configure-deployment-targets/json-schema-ide-support.md +1 -1
- package/catalog/frontmcp-config/examples/configure-deployment-targets/multi-target-with-security.md +12 -9
- package/catalog/frontmcp-config/examples/configure-http/cors-restricted-origins.md +2 -2
- package/catalog/frontmcp-config/examples/configure-http/entry-path-reverse-proxy.md +1 -1
- package/catalog/frontmcp-config/examples/configure-security-headers/csp-report-only.md +1 -1
- package/catalog/frontmcp-config/examples/configure-security-headers/full-production-headers.md +1 -1
- package/catalog/frontmcp-config/examples/configure-skills-http/audit-log-basic.md +76 -0
- package/catalog/frontmcp-config/examples/configure-skills-http/audit-log-redis.md +116 -0
- package/catalog/frontmcp-config/examples/configure-skills-http/inject-instructions.md +59 -0
- package/catalog/frontmcp-config/references/configure-auth-modes.md +5 -5
- package/catalog/frontmcp-config/references/configure-deployment-targets.md +27 -24
- package/catalog/frontmcp-config/references/configure-http.md +14 -10
- package/catalog/frontmcp-config/references/configure-security-headers.md +2 -2
- package/catalog/frontmcp-config/references/configure-session.md +25 -25
- package/catalog/frontmcp-config/references/configure-skills-http.md +157 -0
- package/catalog/frontmcp-config/references/configure-throttle.md +1 -1
- package/catalog/frontmcp-config/references/configure-transport.md +2 -2
- package/catalog/frontmcp-deployment/SKILL.md +112 -9
- package/catalog/frontmcp-deployment/examples/build-for-browser/browser-build-with-custom-entry.md +23 -11
- package/catalog/frontmcp-deployment/examples/build-for-browser/browser-crypto-and-storage.md +44 -17
- package/catalog/frontmcp-deployment/examples/build-for-browser/react-provider-setup.md +53 -21
- package/catalog/frontmcp-deployment/examples/build-for-cli/cli-binary-build.md +1 -1
- package/catalog/frontmcp-deployment/examples/build-for-cli/unix-socket-daemon.md +1 -1
- package/catalog/frontmcp-deployment/examples/build-for-mcpb/mcpb-bundle-build.md +1 -1
- package/catalog/frontmcp-deployment/examples/build-for-sdk/connect-openai.md +1 -1
- package/catalog/frontmcp-deployment/examples/build-for-sdk/multi-platform-connect.md +1 -1
- package/catalog/frontmcp-deployment/examples/deploy-to-cloudflare/basic-worker-deploy.md +7 -8
- package/catalog/frontmcp-deployment/examples/deploy-to-cloudflare/worker-custom-domain.md +8 -6
- package/catalog/frontmcp-deployment/examples/deploy-to-cloudflare/worker-with-kv-storage.md +5 -4
- package/catalog/frontmcp-deployment/examples/deploy-to-lambda/cdk-deployment.md +8 -5
- package/catalog/frontmcp-deployment/examples/deploy-to-lambda/lambda-handler-with-cors.md +20 -18
- package/catalog/frontmcp-deployment/examples/deploy-to-lambda/sam-template-basic.md +8 -5
- package/catalog/frontmcp-deployment/examples/deploy-to-node/docker-compose-with-redis.md +3 -3
- package/catalog/frontmcp-deployment/examples/deploy-to-node/pm2-with-nginx.md +1 -1
- package/catalog/frontmcp-deployment/examples/deploy-to-node/resource-limits.md +2 -2
- package/catalog/frontmcp-deployment/examples/deploy-to-node-dockerfile/basic-multistage-dockerfile.md +2 -2
- package/catalog/frontmcp-deployment/examples/deploy-to-node-dockerfile/secure-nonroot-dockerfile.md +1 -1
- package/catalog/frontmcp-deployment/examples/deploy-to-vercel/vercel-mcp-endpoint-test.md +23 -21
- package/catalog/frontmcp-deployment/examples/deploy-to-vercel/vercel-with-kv.md +25 -22
- package/catalog/frontmcp-deployment/examples/deploy-to-vercel/vercel-with-skills-cache.md +23 -30
- package/catalog/frontmcp-deployment/examples/deploy-to-vercel-config/minimal-vercel-config.md +52 -28
- package/catalog/frontmcp-deployment/examples/deploy-to-vercel-config/vercel-config-with-security-headers.md +32 -55
- package/catalog/frontmcp-deployment/examples/mcp-client-integration/http-remote.md +9 -0
- package/catalog/frontmcp-deployment/references/build-for-browser.md +40 -17
- package/catalog/frontmcp-deployment/references/build-for-cli.md +8 -8
- package/catalog/frontmcp-deployment/references/deploy-to-cloudflare.md +43 -24
- package/catalog/frontmcp-deployment/references/deploy-to-lambda.md +36 -25
- package/catalog/frontmcp-deployment/references/deploy-to-node-dockerfile.md +56 -14
- package/catalog/frontmcp-deployment/references/deploy-to-node.md +9 -6
- package/catalog/frontmcp-deployment/references/deploy-to-vercel-config.md +57 -58
- package/catalog/frontmcp-deployment/references/deploy-to-vercel.md +49 -59
- package/catalog/frontmcp-deployment/references/mcp-client-integration.md +2 -0
- package/catalog/frontmcp-development/SKILL.md +186 -11
- package/catalog/frontmcp-development/examples/create-agent/custom-multi-pass-agent.md +1 -1
- package/catalog/frontmcp-development/examples/create-agent/nested-agents-with-swarm.md +30 -27
- package/catalog/frontmcp-development/examples/create-job/job-with-permissions.md +13 -8
- package/catalog/frontmcp-development/examples/create-provider/basic-database-provider.md +33 -23
- package/catalog/frontmcp-development/examples/create-provider/config-and-api-providers.md +19 -10
- package/catalog/frontmcp-development/examples/create-tool/tool-with-rate-limiting-and-progress.md +3 -3
- package/catalog/frontmcp-development/examples/create-workflow/webhook-triggered-workflow.md +6 -4
- package/catalog/frontmcp-development/examples/decorators-guide/agent-skill-job-workflow.md +1 -1
- package/catalog/frontmcp-development/examples/decorators-guide/basic-server-with-app-and-tools.md +13 -8
- package/catalog/frontmcp-development/examples/decorators-guide/multi-app-with-plugins-and-providers.md +50 -23
- package/catalog/frontmcp-development/references/create-agent.md +47 -30
- package/catalog/frontmcp-development/references/create-job.md +69 -54
- package/catalog/frontmcp-development/references/create-plugin-hooks.md +45 -28
- package/catalog/frontmcp-development/references/create-plugin.md +10 -8
- package/catalog/frontmcp-development/references/create-prompt.md +3 -3
- package/catalog/frontmcp-development/references/create-provider.md +91 -51
- package/catalog/frontmcp-development/references/create-resource.md +3 -3
- package/catalog/frontmcp-development/references/create-skill.md +2 -2
- package/catalog/frontmcp-development/references/create-tool.md +7 -7
- package/catalog/frontmcp-development/references/create-workflow.md +8 -10
- package/catalog/frontmcp-development/references/decorators-guide.md +92 -56
- package/catalog/frontmcp-development/references/official-plugins.md +4 -3
- package/catalog/frontmcp-development/references/openapi-adapter.md +1 -1
- package/catalog/frontmcp-extensibility/SKILL.md +70 -10
- package/catalog/frontmcp-extensibility/examples/skill-audit-log/custom-store.md +197 -0
- package/catalog/frontmcp-extensibility/examples/skill-audit-log/verify-chain.md +68 -0
- package/catalog/frontmcp-extensibility/examples/vectoriadb/product-catalog-search.md +3 -5
- package/catalog/frontmcp-extensibility/examples/vectoriadb/semantic-search-with-persistence.md +4 -11
- package/catalog/frontmcp-extensibility/examples/vectoriadb/tfidf-keyword-search.md +41 -30
- package/catalog/frontmcp-extensibility/references/skill-audit-log.md +233 -0
- package/catalog/frontmcp-extensibility/references/vectoriadb.md +73 -63
- package/catalog/frontmcp-guides/SKILL.md +84 -27
- package/catalog/frontmcp-guides/examples/example-knowledge-base/agent-and-plugin.md +72 -62
- package/catalog/frontmcp-guides/examples/example-knowledge-base/vector-search-and-resources.md +32 -43
- package/catalog/frontmcp-guides/examples/example-task-manager/auth-and-crud-tools.md +24 -17
- package/catalog/frontmcp-guides/examples/example-task-manager/authenticated-e2e-tests.md +23 -21
- package/catalog/frontmcp-guides/examples/example-task-manager/redis-provider-with-di.md +47 -39
- package/catalog/frontmcp-guides/examples/example-weather-api/server-and-app-setup.md +16 -6
- package/catalog/frontmcp-guides/examples/example-weather-api/unit-and-e2e-tests.md +9 -8
- package/catalog/frontmcp-guides/references/example-knowledge-base.md +192 -265
- package/catalog/frontmcp-guides/references/example-task-manager.md +60 -54
- package/catalog/frontmcp-guides/references/example-weather-api.md +22 -24
- package/catalog/frontmcp-observability/SKILL.md +66 -2
- package/catalog/frontmcp-observability/examples/telemetry-api/skill-counters.md +100 -0
- package/catalog/frontmcp-observability/examples/tracing-setup/production-tracing.md +7 -2
- package/catalog/frontmcp-observability/examples/vendor-integrations/coralogix-setup.md +6 -2
- package/catalog/frontmcp-observability/references/telemetry-api.md +72 -8
- package/catalog/frontmcp-observability/references/testing-observability.md +33 -49
- package/catalog/frontmcp-observability/references/tracing-setup.md +12 -5
- package/catalog/frontmcp-observability/references/vendor-integrations.md +46 -1
- package/catalog/frontmcp-production-readiness/SKILL.md +134 -3
- package/catalog/frontmcp-production-readiness/examples/common-checklist/caching-and-performance.md +57 -36
- package/catalog/frontmcp-production-readiness/examples/common-checklist/observability-setup.md +1 -1
- package/catalog/frontmcp-production-readiness/examples/common-checklist/security-hardening.md +102 -6
- package/catalog/frontmcp-production-readiness/examples/production-cli-daemon/daemon-socket-config.md +2 -1
- package/catalog/frontmcp-production-readiness/examples/production-cli-daemon/graceful-shutdown-cleanup.md +66 -58
- package/catalog/frontmcp-production-readiness/examples/production-cli-daemon/security-and-permissions.md +5 -3
- package/catalog/frontmcp-production-readiness/examples/production-cloudflare/durable-objects-state.md +2 -1
- package/catalog/frontmcp-production-readiness/examples/production-cloudflare/wrangler-config.md +55 -76
- package/catalog/frontmcp-production-readiness/examples/production-lambda/cold-start-connection-reuse.md +43 -40
- package/catalog/frontmcp-production-readiness/examples/production-lambda/sam-template.md +63 -94
- package/catalog/frontmcp-production-readiness/examples/production-lambda/scaling-and-monitoring.md +28 -18
- package/catalog/frontmcp-production-readiness/examples/production-node-sdk/multi-instance-cleanup.md +29 -14
- package/catalog/frontmcp-production-readiness/examples/production-node-server/graceful-shutdown.md +58 -42
- package/catalog/frontmcp-production-readiness/examples/production-node-server/redis-session-scaling.md +5 -2
- package/catalog/frontmcp-production-readiness/examples/production-vercel/cold-start-optimization.md +41 -24
- package/catalog/frontmcp-production-readiness/examples/production-vercel/vercel-edge-config.md +56 -65
- package/catalog/frontmcp-production-readiness/references/common-checklist.md +17 -5
- package/catalog/frontmcp-production-readiness/references/production-cli-daemon.md +5 -5
- package/catalog/frontmcp-production-readiness/references/production-cloudflare.md +5 -5
- package/catalog/frontmcp-production-readiness/references/production-lambda.md +5 -5
- package/catalog/frontmcp-production-readiness/references/production-node-sdk.md +5 -5
- package/catalog/frontmcp-production-readiness/references/production-node-server.md +1 -1
- package/catalog/frontmcp-production-readiness/references/production-vercel.md +5 -5
- package/catalog/frontmcp-setup/SKILL.md +88 -0
- package/catalog/frontmcp-setup/examples/project-structure-nx/nx-workspace-with-apps.md +10 -4
- package/catalog/frontmcp-setup/examples/project-structure-standalone/dev-workflow-commands.md +21 -8
- package/catalog/frontmcp-setup/examples/readme-guide/node-server-readme.md +3 -3
- package/catalog/frontmcp-setup/references/multi-app-composition.md +4 -3
- package/catalog/frontmcp-setup/references/project-structure-nx.md +15 -6
- package/catalog/frontmcp-setup/references/project-structure-standalone.md +18 -15
- package/catalog/frontmcp-setup/references/readme-guide.md +1 -1
- package/catalog/frontmcp-setup/references/setup-project.md +19 -5
- package/catalog/frontmcp-setup/references/setup-redis.md +27 -39
- package/catalog/frontmcp-setup/references/setup-sqlite.md +25 -18
- package/catalog/frontmcp-testing/SKILL.md +102 -15
- package/catalog/frontmcp-testing/examples/setup-testing/unit-test-tool-resource-prompt.md +3 -3
- package/catalog/frontmcp-testing/examples/test-auth/oauth-flow-test.md +50 -39
- package/catalog/frontmcp-testing/examples/test-auth/role-based-access-test.md +52 -29
- package/catalog/frontmcp-testing/examples/test-auth/token-factory-test.md +37 -20
- package/catalog/frontmcp-testing/examples/test-direct-client/basic-create-test.md +25 -15
- package/catalog/frontmcp-testing/examples/test-direct-client/openai-claude-format-test.md +27 -21
- package/catalog/frontmcp-testing/examples/test-e2e-handler/basic-e2e-test.md +29 -20
- package/catalog/frontmcp-testing/examples/test-e2e-handler/manual-client-with-transport.md +5 -3
- package/catalog/frontmcp-testing/examples/test-e2e-handler/tool-call-and-error-e2e.md +35 -26
- package/catalog/frontmcp-testing/examples/test-tool-unit/basic-tool-test.md +8 -3
- package/catalog/frontmcp-testing/examples/test-tool-unit/schema-validation-test.md +4 -1
- package/catalog/frontmcp-testing/examples/test-tool-unit/tool-error-handling-test.md +6 -3
- package/catalog/frontmcp-testing/references/setup-testing.md +35 -39
- package/catalog/frontmcp-testing/references/test-auth.md +86 -43
- package/catalog/frontmcp-testing/references/test-browser-build.md +1 -1
- package/catalog/frontmcp-testing/references/test-direct-client.md +29 -19
- package/catalog/frontmcp-testing/references/test-e2e-handler.md +31 -19
- package/catalog/frontmcp-testing/references/test-tool-unit.md +6 -2
- package/catalog/skills-manifest.json +428 -339
- package/package.json +1 -1
- package/src/manifest.d.ts +13 -0
- package/src/manifest.js.map +1 -1
|
@@ -5,16 +5,26 @@ description: Test authenticated MCP servers with TestTokenFactory, MockOAuthServ
|
|
|
5
5
|
|
|
6
6
|
# Testing with Authentication
|
|
7
7
|
|
|
8
|
+
Real API references:
|
|
9
|
+
|
|
10
|
+
- `TestTokenFactory.createTestToken(opts)` — `libs/testing/src/auth/token-factory.ts:97` (plus `createAdminToken`, `createUserToken`, `createAnonymousToken`, `createExpiredToken`, `createTokenWithInvalidSignature`).
|
|
11
|
+
- `new MockOAuthServer(tokenFactory, options)` + `.start()` / `.stop()` — `libs/testing/src/auth/mock-oauth-server.ts:159`.
|
|
12
|
+
- `TestServer.start({ command, port })` — `libs/testing/src/server/test-server.ts:101`. Get a client with `McpTestClient.create({ baseUrl }).withToken(token).buildAndConnect()`.
|
|
13
|
+
- Roles, email, and other claims go inside `claims`, not as top-level fields. `CreateTokenOptions` only declares `sub`, `iss`, `aud`, `scopes`, `exp`, `claims`.
|
|
14
|
+
|
|
8
15
|
```typescript
|
|
9
|
-
|
|
10
|
-
import
|
|
16
|
+
// auth.e2e.spec.ts
|
|
17
|
+
import { McpTestClient, TestServer, TestTokenFactory } from '@frontmcp/testing';
|
|
11
18
|
|
|
12
19
|
describe('Authenticated Server', () => {
|
|
13
20
|
let server: TestServer;
|
|
14
21
|
let tokenFactory: TestTokenFactory;
|
|
15
22
|
|
|
16
23
|
beforeAll(async () => {
|
|
17
|
-
server = await TestServer.
|
|
24
|
+
server = await TestServer.start({
|
|
25
|
+
command: 'npx tsx src/main.ts',
|
|
26
|
+
port: 3010,
|
|
27
|
+
});
|
|
18
28
|
tokenFactory = new TestTokenFactory({
|
|
19
29
|
issuer: 'https://test-idp.example.com',
|
|
20
30
|
audience: 'my-api',
|
|
@@ -22,82 +32,115 @@ describe('Authenticated Server', () => {
|
|
|
22
32
|
});
|
|
23
33
|
|
|
24
34
|
afterAll(async () => {
|
|
25
|
-
await server.
|
|
35
|
+
await server.stop();
|
|
26
36
|
});
|
|
27
37
|
|
|
28
|
-
it('
|
|
29
|
-
const client = await server.
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
38
|
+
it('rejects unauthenticated requests', async () => {
|
|
39
|
+
const client = await McpTestClient.create({ baseUrl: server.info.baseUrl })
|
|
40
|
+
.withTransport('streamable-http')
|
|
41
|
+
.withPublicMode() // do not request an anonymous token; send no Authorization header
|
|
42
|
+
.buildAndConnect();
|
|
43
|
+
|
|
44
|
+
const result = await client.tools.call('protected_tool', {});
|
|
45
|
+
expect(result).toBeError();
|
|
46
|
+
|
|
47
|
+
await client.disconnect();
|
|
33
48
|
});
|
|
34
49
|
|
|
35
|
-
it('
|
|
36
|
-
const token = await tokenFactory.
|
|
50
|
+
it('accepts a valid token', async () => {
|
|
51
|
+
const token = await tokenFactory.createTestToken({
|
|
37
52
|
sub: 'user-123',
|
|
38
53
|
scopes: ['read', 'write'],
|
|
39
54
|
});
|
|
40
55
|
|
|
41
|
-
const client = await
|
|
42
|
-
|
|
56
|
+
const client = await McpTestClient.create({ baseUrl: server.info.baseUrl })
|
|
57
|
+
.withTransport('streamable-http')
|
|
58
|
+
.withToken(token)
|
|
59
|
+
.buildAndConnect();
|
|
60
|
+
|
|
61
|
+
const result = await client.tools.call('protected_tool', { data: 'test' });
|
|
43
62
|
expect(result).toBeSuccessful();
|
|
44
|
-
|
|
63
|
+
|
|
64
|
+
await client.disconnect();
|
|
45
65
|
});
|
|
46
66
|
|
|
47
|
-
it('
|
|
48
|
-
const adminToken = await tokenFactory.
|
|
67
|
+
it('enforces role-based access', async () => {
|
|
68
|
+
const adminToken = await tokenFactory.createTestToken({
|
|
49
69
|
sub: 'admin-1',
|
|
50
|
-
roles: ['admin'],
|
|
70
|
+
claims: { roles: ['admin'] },
|
|
51
71
|
});
|
|
52
|
-
const userToken = await tokenFactory.
|
|
72
|
+
const userToken = await tokenFactory.createTestToken({
|
|
53
73
|
sub: 'user-1',
|
|
54
|
-
roles: ['user'],
|
|
74
|
+
claims: { roles: ['user'] },
|
|
55
75
|
});
|
|
56
76
|
|
|
57
|
-
const adminClient = await
|
|
58
|
-
|
|
77
|
+
const adminClient = await McpTestClient.create({ baseUrl: server.info.baseUrl })
|
|
78
|
+
.withTransport('streamable-http')
|
|
79
|
+
.withToken(adminToken)
|
|
80
|
+
.buildAndConnect();
|
|
81
|
+
const adminResult = await adminClient.tools.call('admin_only_tool', {});
|
|
59
82
|
expect(adminResult).toBeSuccessful();
|
|
60
83
|
|
|
61
|
-
const userClient = await
|
|
62
|
-
|
|
63
|
-
|
|
84
|
+
const userClient = await McpTestClient.create({ baseUrl: server.info.baseUrl })
|
|
85
|
+
.withTransport('streamable-http')
|
|
86
|
+
.withToken(userToken)
|
|
87
|
+
.buildAndConnect();
|
|
88
|
+
const userResult = await userClient.tools.call('admin_only_tool', {});
|
|
89
|
+
expect(userResult).toBeError();
|
|
64
90
|
|
|
65
|
-
await adminClient.
|
|
66
|
-
await userClient.
|
|
91
|
+
await adminClient.disconnect();
|
|
92
|
+
await userClient.disconnect();
|
|
67
93
|
});
|
|
68
94
|
});
|
|
95
|
+
```
|
|
96
|
+
|
|
97
|
+
## Mock OAuth / OIDC server
|
|
98
|
+
|
|
99
|
+
`MockOAuthServer` serves JWKS, OAuth metadata, authorization, token, and userinfo endpoints. Construct it with a `TestTokenFactory`, call `.start()` to bind a port, and configure your MCP server to point at the returned `info.issuer` / `info.jwksUrl`.
|
|
69
100
|
|
|
70
|
-
|
|
101
|
+
```typescript
|
|
102
|
+
// mock-oauth.e2e.spec.ts
|
|
103
|
+
import { MockOAuthServer, TestTokenFactory } from '@frontmcp/testing';
|
|
104
|
+
|
|
105
|
+
describe('Mock OAuth server', () => {
|
|
106
|
+
let tokenFactory: TestTokenFactory;
|
|
71
107
|
let mockOAuth: MockOAuthServer;
|
|
72
108
|
|
|
73
109
|
beforeAll(async () => {
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
110
|
+
tokenFactory = new TestTokenFactory();
|
|
111
|
+
mockOAuth = new MockOAuthServer(tokenFactory, {
|
|
112
|
+
autoApprove: true,
|
|
113
|
+
testUser: { sub: 'user-123', email: 'test@example.com' },
|
|
114
|
+
clientId: 'test-client',
|
|
115
|
+
validRedirectUris: ['http://localhost:3001/callback'],
|
|
77
116
|
});
|
|
117
|
+
await mockOAuth.start();
|
|
78
118
|
});
|
|
79
119
|
|
|
80
120
|
afterAll(async () => {
|
|
81
|
-
await mockOAuth.
|
|
121
|
+
await mockOAuth.stop();
|
|
82
122
|
});
|
|
83
123
|
|
|
84
|
-
it('
|
|
85
|
-
const
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
124
|
+
it('exposes JWKS that verifies factory-issued tokens', async () => {
|
|
125
|
+
const jwks = await fetch(mockOAuth.info.jwksUrl).then((r) => r.json());
|
|
126
|
+
expect(jwks.keys.length).toBeGreaterThan(0);
|
|
127
|
+
});
|
|
128
|
+
|
|
129
|
+
it('issues tokens via the same factory', async () => {
|
|
130
|
+
const token = await tokenFactory.createTestToken({ sub: 'user-123' });
|
|
131
|
+
expect(token.split('.')).toHaveLength(3);
|
|
91
132
|
});
|
|
92
133
|
});
|
|
93
134
|
```
|
|
94
135
|
|
|
136
|
+
To run the full authorization-code-with-PKCE flow against the mock server, drive the standard OAuth endpoints (`/oauth/authorize`, `/oauth/token`) directly with `fetch` — the mock server auto-approves when `autoApprove: true` and `testUser` are set.
|
|
137
|
+
|
|
95
138
|
## Examples
|
|
96
139
|
|
|
97
|
-
| Example | Level | Description
|
|
98
|
-
| --------------------------------------------------------------------------- | ------------ |
|
|
99
|
-
| [`oauth-flow-test`](../examples/test-auth/oauth-flow-test.md) | Advanced | Use `MockOAuthServer` to simulate an OAuth identity provider
|
|
100
|
-
| [`role-based-access-test`](../examples/test-auth/role-based-access-test.md) | Intermediate | Verify that tools enforce role-based access by testing admin and user tokens against protected endpoints.
|
|
101
|
-
| [`token-factory-test`](../examples/test-auth/token-factory-test.md) | Basic | Use `TestTokenFactory` to create tokens and verify authenticated and unauthenticated requests.
|
|
140
|
+
| Example | Level | Description |
|
|
141
|
+
| --------------------------------------------------------------------------- | ------------ | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
|
|
142
|
+
| [`oauth-flow-test`](../examples/test-auth/oauth-flow-test.md) | Advanced | Use `MockOAuthServer` to simulate an OAuth/OIDC identity provider. The server publishes a JWKS endpoint backed by your `TestTokenFactory`, so any token created by that factory is valid against the mock IDP. |
|
|
143
|
+
| [`role-based-access-test`](../examples/test-auth/role-based-access-test.md) | Intermediate | Verify that tools enforce role-based access by testing admin and user tokens against protected endpoints. |
|
|
144
|
+
| [`token-factory-test`](../examples/test-auth/token-factory-test.md) | Basic | Use `TestTokenFactory` to create tokens and verify authenticated and unauthenticated requests. |
|
|
102
145
|
|
|
103
146
|
> See all examples in [`examples/test-auth/`](../examples/test-auth/)
|
|
@@ -37,7 +37,7 @@ describe('Browser Build', () => {
|
|
|
37
37
|
## Testing with Playwright (.pw.spec.ts)
|
|
38
38
|
|
|
39
39
|
```typescript
|
|
40
|
-
import {
|
|
40
|
+
import { expect, test } from '@playwright/test';
|
|
41
41
|
|
|
42
42
|
test('browser MCP client loads tools', async ({ page }) => {
|
|
43
43
|
await page.goto('http://localhost:3000');
|
|
@@ -5,20 +5,38 @@ description: In-memory testing with create() and connectOpenAI/connectClaude wit
|
|
|
5
5
|
|
|
6
6
|
# Testing with Direct Client (No HTTP)
|
|
7
7
|
|
|
8
|
-
|
|
8
|
+
Use `create()` for an in-memory `DirectMcpServer` and `connectOpenAI()` / `connectClaude()` for an in-memory `DirectClient` with platform-specific tool formatting. None of these start an HTTP server — they wire client and server through an in-memory transport.
|
|
9
|
+
|
|
10
|
+
Real API references:
|
|
11
|
+
|
|
12
|
+
- `create(config)` — `libs/sdk/src/direct/create.ts`. Returns `DirectMcpServer` with `listTools`, `callTool`, `listResources`, `readResource`, `listPrompts`, `getPrompt`, `dispose`.
|
|
13
|
+
- `connectOpenAI(config, options?)` / `connectClaude(config, options?)` — `libs/sdk/src/direct/connect.ts:159` / `:200`. Both take a `FrontMcpConfigInput` (decorated `@FrontMcp` class or config object) and return a `DirectClient`. There is no `serve` field; the in-memory transport is always used.
|
|
14
|
+
- Tools are class-based using the `@Tool` decorator (`libs/sdk/src/index.ts` — there is no `tool()` factory function).
|
|
9
15
|
|
|
10
16
|
```typescript
|
|
11
|
-
|
|
17
|
+
// direct-client.spec.ts
|
|
18
|
+
import { App, connectOpenAI, create, FrontMcp, Tool, ToolContext, z } from '@frontmcp/sdk';
|
|
12
19
|
|
|
13
|
-
|
|
20
|
+
@Tool({
|
|
14
21
|
name: 'add',
|
|
15
22
|
description: 'Add numbers',
|
|
16
23
|
inputSchema: { a: z.number(), b: z.number() },
|
|
17
24
|
outputSchema: { sum: z.number() },
|
|
18
|
-
})
|
|
25
|
+
})
|
|
26
|
+
class AddTool extends ToolContext {
|
|
27
|
+
async execute(input: { a: number; b: number }) {
|
|
28
|
+
return { sum: input.a + input.b };
|
|
29
|
+
}
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
@App({ name: 'test-app', tools: [AddTool] })
|
|
33
|
+
class TestApp {}
|
|
34
|
+
|
|
35
|
+
@FrontMcp({ info: { name: 'test', version: '1.0.0' }, apps: [TestApp] })
|
|
36
|
+
class TestServerConfig {}
|
|
19
37
|
|
|
20
38
|
describe('Direct Client Testing', () => {
|
|
21
|
-
it('
|
|
39
|
+
it('calls tools via create() with a flat config', async () => {
|
|
22
40
|
const server = await create({
|
|
23
41
|
info: { name: 'test', version: '1.0.0' },
|
|
24
42
|
tools: [AddTool],
|
|
@@ -26,17 +44,14 @@ describe('Direct Client Testing', () => {
|
|
|
26
44
|
});
|
|
27
45
|
|
|
28
46
|
const result = await server.callTool('add', { a: 2, b: 3 });
|
|
29
|
-
|
|
47
|
+
// execute() returns { sum: 5 }; the framework wraps it as a CallToolResult.
|
|
48
|
+
expect(result.structuredContent).toEqual({ sum: 5 });
|
|
30
49
|
|
|
31
50
|
await server.dispose();
|
|
32
51
|
});
|
|
33
52
|
|
|
34
|
-
it('
|
|
35
|
-
const client = await connectOpenAI(
|
|
36
|
-
info: { name: 'test', version: '1.0.0' },
|
|
37
|
-
tools: [AddTool],
|
|
38
|
-
serve: false,
|
|
39
|
-
});
|
|
53
|
+
it('returns OpenAI-formatted tools', async () => {
|
|
54
|
+
const client = await connectOpenAI(TestServerConfig);
|
|
40
55
|
|
|
41
56
|
const tools = await client.listTools();
|
|
42
57
|
// OpenAI format: [{ type: 'function', function: { name, parameters } }]
|
|
@@ -46,13 +61,8 @@ describe('Direct Client Testing', () => {
|
|
|
46
61
|
await client.close();
|
|
47
62
|
});
|
|
48
63
|
|
|
49
|
-
it('
|
|
50
|
-
const
|
|
51
|
-
const client = await connectClaude({
|
|
52
|
-
info: { name: 'test', version: '1.0.0' },
|
|
53
|
-
tools: [AddTool],
|
|
54
|
-
serve: false,
|
|
55
|
-
});
|
|
64
|
+
it('returns Claude-formatted tools', async () => {
|
|
65
|
+
const client = await connectClaude(TestServerConfig);
|
|
56
66
|
|
|
57
67
|
const tools = await client.listTools();
|
|
58
68
|
// Claude format: [{ name, description, input_schema }]
|
|
@@ -5,50 +5,62 @@ description: Full MCP protocol E2E tests over HTTP with McpTestClient and TestSe
|
|
|
5
5
|
|
|
6
6
|
# E2E Testing with McpTestClient (HTTP Handler)
|
|
7
7
|
|
|
8
|
-
Tests the full MCP protocol over HTTP — validates tools, resources, prompts end-to-end.
|
|
8
|
+
Tests the full MCP protocol over HTTP — validates tools, resources, prompts end-to-end. This is the manual alternative to the fixture API in `setup-testing` and is useful when you need fine-grained control over server lifecycle, transport, or auth.
|
|
9
|
+
|
|
10
|
+
Real API references:
|
|
11
|
+
|
|
12
|
+
- `TestServer.start({ command, port })` returns a `TestServer` instance with `info.baseUrl` and `stop()` — `libs/testing/src/server/test-server.ts:101`. There is no `TestServer.create(ServerClass)`.
|
|
13
|
+
- Build a client with `await McpTestClient.create({ baseUrl }).withTransport('streamable-http').buildAndConnect()` — `libs/testing/src/client/mcp-test-client.builder.ts`.
|
|
14
|
+
- The public client API is namespaced: `client.tools.list()`, `client.tools.call(name, args)`, `client.resources.list()`, `client.resources.read(uri)`, `client.prompts.list()`, `client.prompts.get(name, args)`, `client.disconnect()` — `libs/testing/src/client/mcp-test-client.ts:306-402`.
|
|
9
15
|
|
|
10
16
|
```typescript
|
|
17
|
+
// server.e2e.spec.ts
|
|
11
18
|
import { McpTestClient, TestServer } from '@frontmcp/testing';
|
|
12
|
-
import Server from '../src/main';
|
|
13
19
|
|
|
14
20
|
describe('Server E2E', () => {
|
|
15
21
|
let client: McpTestClient;
|
|
16
22
|
let server: TestServer;
|
|
17
23
|
|
|
18
24
|
beforeAll(async () => {
|
|
19
|
-
server = await TestServer.
|
|
20
|
-
|
|
25
|
+
server = await TestServer.start({
|
|
26
|
+
command: 'npx tsx src/main.ts',
|
|
27
|
+
port: 3020,
|
|
28
|
+
});
|
|
29
|
+
|
|
30
|
+
client = await McpTestClient.create({ baseUrl: server.info.baseUrl })
|
|
31
|
+
.withTransport('streamable-http')
|
|
32
|
+
.buildAndConnect();
|
|
21
33
|
});
|
|
22
34
|
|
|
23
35
|
afterAll(async () => {
|
|
24
|
-
await client.
|
|
25
|
-
await server.
|
|
36
|
+
await client.disconnect();
|
|
37
|
+
await server.stop();
|
|
26
38
|
});
|
|
27
39
|
|
|
28
|
-
it('
|
|
29
|
-
const
|
|
40
|
+
it('lists all tools', async () => {
|
|
41
|
+
const tools = await client.tools.list();
|
|
30
42
|
expect(tools.length).toBeGreaterThan(0);
|
|
31
43
|
expect(tools).toContainTool('add_numbers');
|
|
32
44
|
});
|
|
33
45
|
|
|
34
|
-
it('
|
|
35
|
-
const result = await client.
|
|
46
|
+
it('calls a tool and gets a successful result', async () => {
|
|
47
|
+
const result = await client.tools.call('add_numbers', { a: 5, b: 3 });
|
|
36
48
|
expect(result).toBeSuccessful();
|
|
37
|
-
expect(result
|
|
49
|
+
expect(result).toHaveTextContent('8');
|
|
38
50
|
});
|
|
39
51
|
|
|
40
|
-
it('
|
|
41
|
-
const result = await client.
|
|
42
|
-
expect(result
|
|
52
|
+
it('returns an error for invalid input', async () => {
|
|
53
|
+
const result = await client.tools.call('add_numbers', { a: 'bad' });
|
|
54
|
+
expect(result).toBeError();
|
|
43
55
|
});
|
|
44
56
|
|
|
45
|
-
it('
|
|
46
|
-
const
|
|
47
|
-
expect(resources
|
|
57
|
+
it('lists resources', async () => {
|
|
58
|
+
const resources = await client.resources.list();
|
|
59
|
+
expect(Array.isArray(resources)).toBe(true);
|
|
48
60
|
});
|
|
49
61
|
|
|
50
|
-
it('
|
|
51
|
-
const result = await client.
|
|
62
|
+
it('gets a prompt', async () => {
|
|
63
|
+
const result = await client.prompts.get('summarize', { topic: 'testing' });
|
|
52
64
|
expect(result.messages).toBeDefined();
|
|
53
65
|
expect(result.messages.length).toBeGreaterThan(0);
|
|
54
66
|
});
|
|
@@ -12,16 +12,20 @@ import { AddTool } from '../tools/add.tool';
|
|
|
12
12
|
|
|
13
13
|
describe('AddTool', () => {
|
|
14
14
|
it('should add two numbers', async () => {
|
|
15
|
-
//
|
|
15
|
+
// Mock the ExecutionContextBase API surface (`get`, `tryGet`, `scope`, `fail`,
|
|
16
|
+
// `mark`, `fetch`) plus `notify` from ToolContext. Add `notify` only when the
|
|
17
|
+
// tool actually calls `this.notify(...)`.
|
|
18
|
+
// Real API: libs/sdk/src/common/interfaces/execution-context.interface.ts
|
|
16
19
|
const ctx = {
|
|
17
20
|
get: jest.fn(),
|
|
18
21
|
tryGet: jest.fn(),
|
|
22
|
+
scope: { get: jest.fn(), tryGet: jest.fn() },
|
|
19
23
|
fail: jest.fn((err) => {
|
|
20
24
|
throw err;
|
|
21
25
|
}),
|
|
22
26
|
mark: jest.fn(),
|
|
27
|
+
fetch: jest.fn(),
|
|
23
28
|
notify: jest.fn(),
|
|
24
|
-
respondProgress: jest.fn(),
|
|
25
29
|
} as unknown as ToolContext;
|
|
26
30
|
|
|
27
31
|
const tool = new AddTool();
|