Skip to content

Commit f0e8268

Browse files
committed
more progress on tests
1 parent c85232b commit f0e8268

File tree

10 files changed

+246
-992
lines changed

10 files changed

+246
-992
lines changed
Lines changed: 11 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,4 @@
11
import { test, expect, inject } from 'vitest'
2-
import { z } from 'zod'
32

43
const mcpServerPort = inject('mcpServerPort')
54
const mcpServerUrl = `http://localhost:${mcpServerPort}`
@@ -12,18 +11,15 @@ test(`The MCP server correctly proxies to the OAuth server for authorization ser
1211
resourceMetadataResponse.ok,
1312
'🚨 fetching authorization server metadata should succeed',
1413
).toBe(true)
15-
16-
const resourceMetadataResult = z
17-
.object({
18-
registration_endpoint: z.string(),
19-
authorization_endpoint: z.string(),
20-
token_endpoint: z.string(),
21-
})
22-
.safeParse(await resourceMetadataResponse.json())
23-
if (!resourceMetadataResult.success) {
24-
throw new Error(
25-
'🚨 Invalid authorization server metadata: ' +
26-
resourceMetadataResult.error.message,
27-
)
28-
}
14+
const resourceMetadata = await resourceMetadataResponse.json()
15+
expect(
16+
resourceMetadata,
17+
'🚨 authorization server metadata should be valid',
18+
).toEqual(
19+
expect.objectContaining({
20+
registration_endpoint: expect.any(String),
21+
authorization_endpoint: expect.any(String),
22+
token_endpoint: expect.any(String),
23+
}),
24+
)
2925
})
Lines changed: 11 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,4 @@
11
import { test, expect, inject } from 'vitest'
2-
import { z } from 'zod'
32

43
const mcpServerPort = inject('mcpServerPort')
54
const mcpServerUrl = `http://localhost:${mcpServerPort}`
@@ -12,18 +11,15 @@ test(`The MCP server correctly proxies to the OAuth server for authorization ser
1211
resourceMetadataResponse.ok,
1312
'🚨 fetching authorization server metadata should succeed',
1413
).toBe(true)
15-
16-
const resourceMetadataResult = z
17-
.object({
18-
registration_endpoint: z.string(),
19-
authorization_endpoint: z.string(),
20-
token_endpoint: z.string(),
21-
})
22-
.safeParse(await resourceMetadataResponse.json())
23-
if (!resourceMetadataResult.success) {
24-
throw new Error(
25-
'🚨 Invalid authorization server metadata: ' +
26-
resourceMetadataResult.error.message,
27-
)
28-
}
14+
const resourceMetadata = await resourceMetadataResponse.json()
15+
expect(
16+
resourceMetadata,
17+
'🚨 authorization server metadata should be valid',
18+
).toEqual(
19+
expect.objectContaining({
20+
registration_endpoint: expect.any(String),
21+
authorization_endpoint: expect.any(String),
22+
token_endpoint: expect.any(String),
23+
}),
24+
)
2925
})
Lines changed: 6 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
import { test, expect, inject } from 'vitest'
2-
import { z } from 'zod'
2+
import { EPIC_ME_AUTH_SERVER_URL } from '../src/client.ts'
33

44
const mcpServerPort = inject('mcpServerPort')
55
const mcpServerUrl = `http://localhost:${mcpServerPort}`
@@ -12,16 +12,9 @@ test(`Protected resource metadata is discoverable`, async () => {
1212
resourceMetadataResponse.ok,
1313
'🚨 fetching resource metadata should succeed',
1414
).toBe(true)
15-
16-
const resourceMetadataResult = z
17-
.object({
18-
resource: z.string(),
19-
authorization_servers: z.array(z.string()).length(1),
20-
})
21-
.safeParse(await resourceMetadataResponse.json())
22-
if (!resourceMetadataResult.success) {
23-
throw new Error(
24-
'🚨 Invalid resource metadata: ' + resourceMetadataResult.error.message,
25-
)
26-
}
15+
const resourceMetadata = await resourceMetadataResponse.json()
16+
expect(resourceMetadata, '🚨 resource metadata should be valid').toEqual({
17+
resource: expect.any(String),
18+
authorization_servers: expect.arrayContaining([EPIC_ME_AUTH_SERVER_URL]),
19+
})
2720
})
Lines changed: 6 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
import { test, expect, inject } from 'vitest'
2-
import { z } from 'zod'
2+
import { EPIC_ME_AUTH_SERVER_URL } from '../src/client.ts'
33

44
const mcpServerPort = inject('mcpServerPort')
55
const mcpServerUrl = `http://localhost:${mcpServerPort}`
@@ -12,16 +12,9 @@ test(`Protected resource metadata is discoverable`, async () => {
1212
resourceMetadataResponse.ok,
1313
'🚨 fetching resource metadata should succeed',
1414
).toBe(true)
15-
16-
const resourceMetadataResult = z
17-
.object({
18-
resource: z.string(),
19-
authorization_servers: z.array(z.string()).length(1),
20-
})
21-
.safeParse(await resourceMetadataResponse.json())
22-
if (!resourceMetadataResult.success) {
23-
throw new Error(
24-
'🚨 Invalid resource metadata: ' + resourceMetadataResult.error.message,
25-
)
26-
}
15+
const resourceMetadata = await resourceMetadataResponse.json()
16+
expect(resourceMetadata, '🚨 resource metadata should be valid').toEqual({
17+
resource: expect.any(String),
18+
authorization_servers: expect.arrayContaining([EPIC_ME_AUTH_SERVER_URL]),
19+
})
2720
})

exercises/05.scopes/01.problem.check-scopes/test/index.test.ts

Lines changed: 2 additions & 86 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,6 @@ import {
44
JSONRPCMessageSchema,
55
} from '@modelcontextprotocol/sdk/types.js'
66
import { test, expect, inject } from 'vitest'
7-
import { z } from 'zod'
87

98
const mcpServerPort = inject('mcpServerPort')
109
const EPIC_ME_AUTH_SERVER_URL = 'http://localhost:7788'
@@ -100,88 +99,7 @@ type Scopes =
10099
| 'tags:read'
101100
| 'tags:write'
102101
async function getAuthToken({ scopes }: { scopes: Array<Scopes> }) {
103-
const unauthorizedResponse = await fetch(`${mcpServerUrl}/mcp`, {
104-
method: 'POST',
105-
headers: {
106-
'content-type': 'application/json',
107-
accept: 'application/json, text/event-stream',
108-
},
109-
body: JSON.stringify({
110-
jsonrpc: '2.0',
111-
id: crypto.randomUUID(),
112-
method: 'tools/list',
113-
}),
114-
})
115-
116-
expect(
117-
unauthorizedResponse.status,
118-
'🚨 Expected 401 status for unauthorized request',
119-
).toBe(401)
120-
121-
const wwwAuthHeader = unauthorizedResponse.headers.get('WWW-Authenticate')
122-
expect(
123-
wwwAuthHeader,
124-
'🚨 WWW-Authenticate header should be present',
125-
).toBeTruthy()
126-
expect(
127-
wwwAuthHeader,
128-
'🚨 WWW-Authenticate header should contain Bearer realm',
129-
).toContain('Bearer realm="EpicMe"')
130-
131-
// Extract the resource_metadata url from the WWW-Authenticate header
132-
const resourceMetadataUrl = wwwAuthHeader
133-
?.split(',')
134-
.find((h) => h.includes('resource_metadata='))
135-
?.split('=')[1]
136-
137-
expect(
138-
resourceMetadataUrl,
139-
'🚨 Resource metadata URL should be present in WWW-Authenticate header',
140-
).toBeTruthy()
141-
142-
const resourceMetadataResponse = await fetch(resourceMetadataUrl!)
143-
expect(
144-
resourceMetadataResponse.ok,
145-
'🚨 fetching resource metadata should succeed',
146-
).toBe(true)
147-
148-
const resourceMetadataResponseData = await resourceMetadataResponse.json()
149-
expect(resourceMetadataResponseData, '🚨 Invalid resource metadata').toEqual({
150-
resource: expect.any(String),
151-
authorization_servers: expect.any(Array),
152-
})
153-
154-
const resourceMetadata = z
155-
.object({
156-
resource: z.string(),
157-
authorization_servers: z.array(z.string()).length(1),
158-
})
159-
.parse(resourceMetadataResponseData)
160-
161-
const authorizationUrl = resourceMetadata.authorization_servers[0]!
162-
163-
// Step 1: Metadata discovery
164-
// Test OAuth Authorization Server discovery
165-
const authServerDiscoveryResponse = await fetch(
166-
`${authorizationUrl}/.well-known/oauth-authorization-server`,
167-
)
168-
expect(
169-
authServerDiscoveryResponse.ok,
170-
'🚨 OAuth authorization server discovery should succeed',
171-
).toBe(true)
172-
173-
const authServerConfig =
174-
(await authServerDiscoveryResponse.json()) as AuthServerConfig
175-
expect(
176-
authServerConfig.authorization_endpoint,
177-
'🚨 Authorization endpoint should be present in discovery',
178-
).toBeTruthy()
179-
expect(
180-
authServerConfig.token_endpoint,
181-
'🚨 Token endpoint should be present in discovery',
182-
).toBeTruthy()
183-
184-
// Step 2: Dynamic client registration
102+
const redirectUri = `https://example.com/test-mcp-client`
185103
const clientRegistrationResponse = await fetch(
186104
`${EPIC_ME_AUTH_SERVER_URL}/oauth/register`,
187105
{
@@ -192,7 +110,7 @@ async function getAuthToken({ scopes }: { scopes: Array<Scopes> }) {
192110
},
193111
body: JSON.stringify({
194112
client_name: 'Test MCP Client',
195-
redirect_uris: [`${mcpServerUrl}/mcp`],
113+
redirect_uris: [redirectUri],
196114
}),
197115
},
198116
)
@@ -208,11 +126,9 @@ async function getAuthToken({ scopes }: { scopes: Array<Scopes> }) {
208126
'🚨 Client ID should be returned from registration',
209127
).toBeTruthy()
210128

211-
// Step 3: Preparing Authorization (getting the auth URL)
212129
const { codeVerifier, codeChallenge, codeChallengeMethod } =
213130
generateCodeChallenge()
214131
const state = crypto.randomUUID()
215-
const redirectUri = `${mcpServerUrl}/mcp`
216132

217133
// Step 4: Requesting the auth code programmatically
218134
const testAuthUrl = new URL(`${EPIC_ME_AUTH_SERVER_URL}/test-auth`)

exercises/05.scopes/01.solution.check-scopes/test/index.test.ts

Lines changed: 2 additions & 86 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,6 @@ import {
44
JSONRPCMessageSchema,
55
} from '@modelcontextprotocol/sdk/types.js'
66
import { test, expect, inject } from 'vitest'
7-
import { z } from 'zod'
87

98
const mcpServerPort = inject('mcpServerPort')
109
const EPIC_ME_AUTH_SERVER_URL = 'http://localhost:7788'
@@ -100,88 +99,7 @@ type Scopes =
10099
| 'tags:read'
101100
| 'tags:write'
102101
async function getAuthToken({ scopes }: { scopes: Array<Scopes> }) {
103-
const unauthorizedResponse = await fetch(`${mcpServerUrl}/mcp`, {
104-
method: 'POST',
105-
headers: {
106-
'content-type': 'application/json',
107-
accept: 'application/json, text/event-stream',
108-
},
109-
body: JSON.stringify({
110-
jsonrpc: '2.0',
111-
id: crypto.randomUUID(),
112-
method: 'tools/list',
113-
}),
114-
})
115-
116-
expect(
117-
unauthorizedResponse.status,
118-
'🚨 Expected 401 status for unauthorized request',
119-
).toBe(401)
120-
121-
const wwwAuthHeader = unauthorizedResponse.headers.get('WWW-Authenticate')
122-
expect(
123-
wwwAuthHeader,
124-
'🚨 WWW-Authenticate header should be present',
125-
).toBeTruthy()
126-
expect(
127-
wwwAuthHeader,
128-
'🚨 WWW-Authenticate header should contain Bearer realm',
129-
).toContain('Bearer realm="EpicMe"')
130-
131-
// Extract the resource_metadata url from the WWW-Authenticate header
132-
const resourceMetadataUrl = wwwAuthHeader
133-
?.split(',')
134-
.find((h) => h.includes('resource_metadata='))
135-
?.split('=')[1]
136-
137-
expect(
138-
resourceMetadataUrl,
139-
'🚨 Resource metadata URL should be present in WWW-Authenticate header',
140-
).toBeTruthy()
141-
142-
const resourceMetadataResponse = await fetch(resourceMetadataUrl!)
143-
expect(
144-
resourceMetadataResponse.ok,
145-
'🚨 fetching resource metadata should succeed',
146-
).toBe(true)
147-
148-
const resourceMetadataResponseData = await resourceMetadataResponse.json()
149-
expect(resourceMetadataResponseData, '🚨 Invalid resource metadata').toEqual({
150-
resource: expect.any(String),
151-
authorization_servers: expect.any(Array),
152-
})
153-
154-
const resourceMetadata = z
155-
.object({
156-
resource: z.string(),
157-
authorization_servers: z.array(z.string()).length(1),
158-
})
159-
.parse(resourceMetadataResponseData)
160-
161-
const authorizationUrl = resourceMetadata.authorization_servers[0]!
162-
163-
// Step 1: Metadata discovery
164-
// Test OAuth Authorization Server discovery
165-
const authServerDiscoveryResponse = await fetch(
166-
`${authorizationUrl}/.well-known/oauth-authorization-server`,
167-
)
168-
expect(
169-
authServerDiscoveryResponse.ok,
170-
'🚨 OAuth authorization server discovery should succeed',
171-
).toBe(true)
172-
173-
const authServerConfig =
174-
(await authServerDiscoveryResponse.json()) as AuthServerConfig
175-
expect(
176-
authServerConfig.authorization_endpoint,
177-
'🚨 Authorization endpoint should be present in discovery',
178-
).toBeTruthy()
179-
expect(
180-
authServerConfig.token_endpoint,
181-
'🚨 Token endpoint should be present in discovery',
182-
).toBeTruthy()
183-
184-
// Step 2: Dynamic client registration
102+
const redirectUri = `https://example.com/test-mcp-client`
185103
const clientRegistrationResponse = await fetch(
186104
`${EPIC_ME_AUTH_SERVER_URL}/oauth/register`,
187105
{
@@ -192,7 +110,7 @@ async function getAuthToken({ scopes }: { scopes: Array<Scopes> }) {
192110
},
193111
body: JSON.stringify({
194112
client_name: 'Test MCP Client',
195-
redirect_uris: [`${mcpServerUrl}/mcp`],
113+
redirect_uris: [redirectUri],
196114
}),
197115
},
198116
)
@@ -208,11 +126,9 @@ async function getAuthToken({ scopes }: { scopes: Array<Scopes> }) {
208126
'🚨 Client ID should be returned from registration',
209127
).toBeTruthy()
210128

211-
// Step 3: Preparing Authorization (getting the auth URL)
212129
const { codeVerifier, codeChallenge, codeChallengeMethod } =
213130
generateCodeChallenge()
214131
const state = crypto.randomUUID()
215-
const redirectUri = `${mcpServerUrl}/mcp`
216132

217133
// Step 4: Requesting the auth code programmatically
218134
const testAuthUrl = new URL(`${EPIC_ME_AUTH_SERVER_URL}/test-auth`)

0 commit comments

Comments
 (0)