Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
28 changes: 24 additions & 4 deletions exercises/01.ping/01.problem.connect/src/index.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -13,15 +13,35 @@ beforeAll(async () => {
command: 'tsx',
args: ['src/index.ts'],
})
await client.connect(transport)

try {
await client.connect(transport)
} catch (error: any) {
console.error('🚨 Connection failed! This exercise requires implementing the main function in src/index.ts')
console.error('🚨 Replace the "throw new Error(\'Not implemented\')" with the actual MCP server setup')
console.error('🚨 You need to: 1) Create an EpicMeMCP instance, 2) Initialize it, 3) Connect to stdio transport')
console.error('Original error:', error.message || error)
throw error
}
})

afterAll(async () => {
await client.transport?.close()
})

test('Ping', async () => {
const result = await client.ping()

expect(result).toEqual({})
try {
const result = await client.ping()
expect(result).toEqual({})
} catch (error: any) {
if (error.message?.includes('Connection closed') || error.code === -32000) {
console.error('🚨 Ping failed because the MCP server crashed!')
console.error('🚨 This means the main() function in src/index.ts is not properly implemented')
console.error('🚨 Check that you\'ve replaced the "Not implemented" error with actual server setup code')
const enhancedError = new Error('🚨 MCP server implementation required in main() function. ' + (error.message || error))
enhancedError.stack = error.stack
throw enhancedError
}
throw error
}
})
28 changes: 24 additions & 4 deletions exercises/01.ping/01.solution.connect/src/index.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -13,15 +13,35 @@ beforeAll(async () => {
command: 'tsx',
args: ['src/index.ts'],
})
await client.connect(transport)

try {
await client.connect(transport)
} catch (error: any) {
console.error('🚨 Connection failed! This exercise requires implementing the main function in src/index.ts')
console.error('🚨 Replace the "throw new Error(\'Not implemented\')" with the actual MCP server setup')
console.error('🚨 You need to: 1) Create an EpicMeMCP instance, 2) Initialize it, 3) Connect to stdio transport')
console.error('Original error:', error.message || error)
throw error
}
})

afterAll(async () => {
await client.transport?.close()
})

test('Ping', async () => {
const result = await client.ping()

expect(result).toEqual({})
try {
const result = await client.ping()
expect(result).toEqual({})
} catch (error: any) {
if (error.message?.includes('Connection closed') || error.code === -32000) {
console.error('🚨 Ping failed because the MCP server crashed!')
console.error('🚨 This means the main() function in src/index.ts is not properly implemented')
console.error('🚨 Check that you\'ve replaced the "Not implemented" error with actual server setup code')
const enhancedError = new Error('🚨 MCP server implementation required in main() function. ' + (error.message || error))
enhancedError.stack = error.stack
throw enhancedError
}
throw error
}
})
83 changes: 50 additions & 33 deletions exercises/02.tools/01.problem.simple/src/index.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -22,44 +22,61 @@ afterAll(async () => {
})

test('Tool Definition', async () => {
const list = await client.listTools()
const [firstTool] = list.tools
invariant(firstTool, '🚨 No tools found')
try {
const list = await client.listTools()
const [firstTool] = list.tools
invariant(firstTool, '🚨 No tools found')

expect(firstTool).toEqual(
expect.objectContaining({
name: expect.stringMatching(/^add$/i),
description: expect.stringMatching(/^add two numbers$/i),
inputSchema: expect.objectContaining({
type: 'object',
properties: expect.objectContaining({
firstNumber: expect.objectContaining({
type: 'number',
description: expect.stringMatching(/first/i),
}),
expect(firstTool).toEqual(
expect.objectContaining({
name: expect.stringMatching(/^add$/i),
description: expect.stringMatching(/add/i),
inputSchema: expect.objectContaining({
type: 'object',
}),
}),
}),
)
)
} catch (error: any) {
if (error.code === -32601) {
console.error('🚨 Tools capability not implemented!')
console.error('🚨 This exercise requires registering tools with the MCP server')
console.error('🚨 You need to: 1) Add tools: {} to server capabilities, 2) Register an "add" tool in initializeTools()')
console.error('🚨 Check src/tools.ts and make sure you implement the "add" tool')
const enhancedError = new Error('🚨 Tools capability required. Register an "add" tool that hardcodes 1 + 2 = 3. ' + (error.message || error))
enhancedError.stack = error.stack
throw enhancedError
}
throw error
}
})

test('Tool Call', async () => {
const result = await client.callTool({
name: 'add',
arguments: {
firstNumber: 1,
secondNumber: 2,
},
})
try {
const result = await client.callTool({
name: 'add',
arguments: {},
})

expect(result).toEqual(
expect.objectContaining({
content: expect.arrayContaining([
expect.objectContaining({
type: 'text',
text: expect.stringMatching(/3/),
}),
]),
}),
)
expect(result).toEqual(
expect.objectContaining({
content: expect.arrayContaining([
expect.objectContaining({
type: 'text',
text: expect.stringMatching(/3/),
}),
]),
}),
)
} catch (error: any) {
if (error.code === -32601) {
console.error('🚨 Tool call failed - tools capability not implemented!')
console.error('🚨 This means you haven\'t registered the "add" tool properly')
console.error('🚨 In src/tools.ts, use agent.server.registerTool() to create a simple "add" tool')
console.error('🚨 The tool should return "1 + 2 = 3" (hardcoded for this simple exercise)')
const enhancedError = new Error('🚨 "add" tool registration required. ' + (error.message || error))
enhancedError.stack = error.stack
throw enhancedError
}
throw error
}
})
76 changes: 51 additions & 25 deletions exercises/02.tools/01.solution.simple/src/index.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -22,35 +22,61 @@ afterAll(async () => {
})

test('Tool Definition', async () => {
const list = await client.listTools()
const [firstTool] = list.tools
invariant(firstTool, '🚨 No tools found')
try {
const list = await client.listTools()
const [firstTool] = list.tools
invariant(firstTool, '🚨 No tools found')

expect(firstTool).toEqual(
expect.objectContaining({
name: expect.stringMatching(/^add$/i),
description: expect.stringMatching(/add/i),
inputSchema: expect.objectContaining({
type: 'object',
expect(firstTool).toEqual(
expect.objectContaining({
name: expect.stringMatching(/^add$/i),
description: expect.stringMatching(/add/i),
inputSchema: expect.objectContaining({
type: 'object',
}),
}),
}),
)
)
} catch (error: any) {
if (error.code === -32601) {
console.error('🚨 Tools capability not implemented!')
console.error('🚨 This exercise requires registering tools with the MCP server')
console.error('🚨 You need to: 1) Add tools: {} to server capabilities, 2) Register an "add" tool in initializeTools()')
console.error('🚨 Check src/tools.ts and make sure you implement the "add" tool')
const enhancedError = new Error('🚨 Tools capability required. Register an "add" tool that hardcodes 1 + 2 = 3. ' + (error.message || error))
enhancedError.stack = error.stack
throw enhancedError
}
throw error
}
})

test('Tool Call', async () => {
const result = await client.callTool({
name: 'add',
arguments: {},
})
try {
const result = await client.callTool({
name: 'add',
arguments: {},
})

expect(result).toEqual(
expect.objectContaining({
content: expect.arrayContaining([
expect.objectContaining({
type: 'text',
text: expect.stringMatching(/3/),
}),
]),
}),
)
expect(result).toEqual(
expect.objectContaining({
content: expect.arrayContaining([
expect.objectContaining({
type: 'text',
text: expect.stringMatching(/3/),
}),
]),
}),
)
} catch (error: any) {
if (error.code === -32601) {
console.error('🚨 Tool call failed - tools capability not implemented!')
console.error('🚨 This means you haven\'t registered the "add" tool properly')
console.error('🚨 In src/tools.ts, use agent.server.registerTool() to create a simple "add" tool')
console.error('🚨 The tool should return "1 + 2 = 3" (hardcoded for this simple exercise)')
const enhancedError = new Error('🚨 "add" tool registration required. ' + (error.message || error))
enhancedError.stack = error.stack
throw enhancedError
}
throw error
}
})
81 changes: 70 additions & 11 deletions exercises/02.tools/02.problem.args/src/index.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -26,20 +26,47 @@ test('Tool Definition', async () => {
const [firstTool] = list.tools
invariant(firstTool, '🚨 No tools found')

expect(firstTool).toEqual(
expect.objectContaining({
name: expect.stringMatching(/^add$/i),
description: expect.stringMatching(/^add two numbers$/i),
inputSchema: expect.objectContaining({
type: 'object',
properties: expect.objectContaining({
firstNumber: expect.objectContaining({
type: 'number',
description: expect.stringMatching(/first/i),
try {
expect(firstTool).toEqual(
expect.objectContaining({
name: expect.stringMatching(/^add$/i),
description: expect.stringMatching(/^add two numbers$/i),
inputSchema: expect.objectContaining({
type: 'object',
properties: expect.objectContaining({
firstNumber: expect.objectContaining({
type: 'number',
description: expect.stringMatching(/first/i),
}),
secondNumber: expect.objectContaining({
type: 'number',
description: expect.stringMatching(/second/i),
}),
}),
required: expect.arrayContaining(['firstNumber', 'secondNumber']),
}),
}),
}),
)
} catch (error: any) {
console.error('🚨 Tool schema mismatch!')
console.error('🚨 This exercise requires updating the "add" tool to accept dynamic arguments')
console.error('🚨 Current tool schema:', JSON.stringify(firstTool, null, 2))
console.error('🚨 You need to: 1) Add proper inputSchema with firstNumber and secondNumber parameters')
console.error('🚨 2) Update the tool description to "add two numbers"')
console.error('🚨 3) Make the tool calculate firstNumber + secondNumber instead of hardcoding 1 + 2')
const enhancedError = new Error('🚨 Tool schema update required. Add firstNumber and secondNumber parameters to the "add" tool. ' + (error.message || error))
enhancedError.stack = error.stack
throw enhancedError
}

// 🚨 Proactive check: Ensure the tool schema includes both required arguments
invariant(
firstTool.inputSchema?.properties?.firstNumber,
'🚨 Tool must have firstNumber parameter defined'
)
invariant(
firstTool.inputSchema?.properties?.secondNumber,
'🚨 Tool must have secondNumber parameter defined'
)
})

Expand All @@ -63,3 +90,35 @@ test('Tool Call', async () => {
}),
)
})

test('Tool Call with Different Numbers', async () => {
try {
const result = await client.callTool({
name: 'add',
arguments: {
firstNumber: 5,
secondNumber: 7,
},
})

expect(result).toEqual(
expect.objectContaining({
content: expect.arrayContaining([
expect.objectContaining({
type: 'text',
text: expect.stringMatching(/12/),
}),
]),
}),
)
} catch (error: any) {
console.error('🚨 Tool call with different numbers failed!')
console.error('🚨 This suggests the tool implementation is still hardcoded')
console.error('🚨 The tool should calculate firstNumber + secondNumber = 5 + 7 = 12')
console.error('🚨 But it\'s probably still returning hardcoded "1 + 2 = 3"')
console.error('🚨 Update the tool implementation to use the dynamic arguments from the input schema')
const enhancedError = new Error('🚨 Dynamic tool calculation required. Tool should calculate arguments, not return hardcoded values. ' + (error.message || error))
enhancedError.stack = error.stack
throw enhancedError
}
})
Loading