Skip to content

Commit 41b8c01

Browse files
Merge pull request #3 from chrisreddington/copilot/fix-2
Tech Debt: Consolidate hardcoded constants and eliminate duplicate difficulty styling
2 parents 07d69b9 + 4572dbb commit 41b8c01

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

55 files changed

+3951
-6094
lines changed

.vscode/mcp.json

Lines changed: 12 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,17 @@
1010
"args": [
1111
"@playwright/mcp@latest"
1212
]
13+
},
14+
"context7": {
15+
"type": "http",
16+
"url": "https://mcp.context7.com/mcp"
17+
},
18+
"sequentialthinking": {
19+
"command": "npx",
20+
"args": [
21+
"-y",
22+
"@modelcontextprotocol/server-sequential-thinking"
23+
]
1324
}
14-
}
25+
} }
1526
}

mcp-server/jest.config.cjs

Lines changed: 0 additions & 39 deletions
This file was deleted.

mcp-server/package.json

Lines changed: 7 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -10,19 +10,19 @@
1010
"start": "node dist/index.js",
1111
"clean": "rm -rf dist",
1212
"type-check": "tsc --noEmit",
13-
"test": "jest",
14-
"test:watch": "jest --watch",
15-
"test:coverage": "jest --coverage"
13+
"test": "vitest run",
14+
"test:watch": "vitest",
15+
"test:coverage": "vitest run --coverage",
16+
"test:ui": "vitest --ui"
1617
},
1718
"dependencies": {
1819
"@modelcontextprotocol/sdk": "^1.17.0",
1920
"@turn-based-mcp/shared": "file:../shared"
2021
},
2122
"devDependencies": {
22-
"@types/jest": "^30.0.0",
2323
"@types/node": "^24.1.0",
24-
"jest": "^30.0.5",
25-
"ts-jest": "^29.4.0",
26-
"typescript": "^5.5.0"
24+
"@vitest/ui": "^3.2.4",
25+
"typescript": "^5.5.0",
26+
"vitest": "^3.2.4"
2727
}
2828
}

mcp-server/src/handlers/elicitation-handlers.ts

Lines changed: 9 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,8 @@
33
* Provides structured ways to gather user preferences and decisions
44
*/
55

6+
import { DIFFICULTIES, GAME_TYPES, DEFAULT_PLAYER_NAME, DEFAULT_AI_DIFFICULTY } from '@turn-based-mcp/shared'
7+
68
export interface ElicitationResult {
79
action: "accept" | "decline" | "cancel"
810
content?: Record<string, any>
@@ -22,7 +24,7 @@ export async function elicitGameCreationPreferences(
2224
properties: {
2325
difficulty: {
2426
type: "string",
25-
enum: ["easy", "medium", "hard"],
27+
enum: DIFFICULTIES,
2628
title: "AI Difficulty Level",
2729
description: "How challenging should the AI opponent be?"
2830
},
@@ -37,7 +39,7 @@ export async function elicitGameCreationPreferences(
3739
type: "string",
3840
title: "Player Name",
3941
description: "What should we call you in the game?",
40-
default: "Player"
42+
default: DEFAULT_PLAYER_NAME
4143
}
4244
},
4345
required: ["difficulty"]
@@ -47,7 +49,7 @@ export async function elicitGameCreationPreferences(
4749
properties: {
4850
difficulty: {
4951
type: "string",
50-
enum: ["easy", "medium", "hard"],
52+
enum: DIFFICULTIES,
5153
title: "AI Difficulty Level",
5254
description: "How smart should the AI be at pattern recognition?"
5355
},
@@ -63,7 +65,7 @@ export async function elicitGameCreationPreferences(
6365
type: "string",
6466
title: "Player Name",
6567
description: "What should we call you?",
66-
default: "Player"
68+
default: DEFAULT_PLAYER_NAME
6769
}
6870
},
6971
required: ["difficulty"]
@@ -90,8 +92,8 @@ export async function elicitGameCreationPreferences(
9092
return {
9193
action: "accept",
9294
content: {
93-
difficulty: existingArgs?.aiDifficulty || "medium",
94-
playerName: existingArgs?.playerName || "Player",
95+
difficulty: existingArgs?.aiDifficulty || DEFAULT_AI_DIFFICULTY,
96+
playerName: existingArgs?.playerName || DEFAULT_PLAYER_NAME,
9597
...(gameType === 'rock-paper-scissors' && { maxRounds: 3 }),
9698
...(gameType === 'tic-tac-toe' && { playerSymbol: "X" })
9799
}
@@ -186,7 +188,7 @@ export async function elicitGameCompletionFeedback(
186188
},
187189
gameTypeForNext: {
188190
type: "string",
189-
enum: ["same", "tic-tac-toe", "rock-paper-scissors"],
191+
enum: ["same", ...GAME_TYPES],
190192
enumNames: ["Same Game", "Tic-Tac-Toe", "Rock Paper Scissors"],
191193
title: "If playing again, which game?",
192194
description: "Choose the game type for your next match"

mcp-server/src/handlers/game-operations.ts

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@ import { TicTacToeAI } from '../ai/tic-tac-toe-ai.js'
66
import { RockPaperScissorsAI } from '../ai/rock-paper-scissors-ai.js'
77
import { TicTacToeGame, RockPaperScissorsGame } from '@turn-based-mcp/shared'
88
import { getGameViaAPI, submitMoveViaAPI, createGameViaAPI } from '../utils/http-client.js'
9+
import { DEFAULT_PLAYER_NAME, DEFAULT_AI_DIFFICULTY } from '@turn-based-mcp/shared'
910

1011
// Initialize AI and game instances
1112
const ticTacToeAI = new TicTacToeAI()
@@ -316,9 +317,9 @@ export async function waitForPlayerMove(
316317
*/
317318
export async function createGame(
318319
gameType: string,
319-
playerName: string = 'Player',
320+
playerName: string = DEFAULT_PLAYER_NAME,
320321
gameId?: string,
321-
aiDifficulty: string = 'medium',
322+
aiDifficulty: string = DEFAULT_AI_DIFFICULTY,
322323
gameSpecificOptions?: Record<string, any>
323324
) {
324325
// Check if game already exists (for games that support custom IDs)

mcp-server/src/handlers/prompt-handlers.ts

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@
44
*/
55

66
import type { Prompt, PromptMessage } from '@modelcontextprotocol/sdk/types.js'
7+
import { GAME_TYPES, DIFFICULTIES } from '@turn-based-mcp/shared'
78

89
export interface PromptDefinition {
910
name: string
@@ -87,12 +88,12 @@ export const STRATEGY_PROMPTS: PromptDefinition[] = [
8788
arguments: [
8889
{
8990
name: 'gameType',
90-
description: 'Game type (tic-tac-toe, rock-paper-scissors)',
91+
description: `Game type (${GAME_TYPES?.join(', ') || 'tic-tac-toe, rock-paper-scissors'})`,
9192
required: false
9293
},
9394
{
9495
name: 'difficulty',
95-
description: 'AI difficulty level (easy, medium, hard)',
96+
description: `AI difficulty level (${DIFFICULTIES?.join(', ') || 'easy, medium, hard'})`,
9697
required: false
9798
}
9899
],
@@ -296,15 +297,15 @@ function getSpecificStrategyGuide(gameType: string, difficulty: string): string
296297
function getGameTypeStrategies(gameType: string): string {
297298
// Return strategies for all difficulties of a specific game
298299
return `Please provide comprehensive strategies for ${gameType.toUpperCase()} across all difficulty levels:\n\n` +
299-
['easy', 'medium', 'hard'].map(diff =>
300+
DIFFICULTIES.map(diff =>
300301
`For ${diff.toUpperCase()} difficulty: ${getSpecificStrategyGuide(gameType, diff)}\n`
301302
).join('\n')
302303
}
303304

304305
function getDifficultyStrategies(difficulty: string): string {
305306
// Return strategies for a specific difficulty across all games
306307
return `Please provide strategies for ${difficulty.toUpperCase()} difficulty across all games:\n\n` +
307-
['tic-tac-toe', 'rock-paper-scissors'].map(game =>
308+
GAME_TYPES.map(game =>
308309
`For ${game.replace(/-/g, ' ').toUpperCase()}: ${getSpecificStrategyGuide(game, difficulty)}\n`
309310
).join('\n')
310311
}

mcp-server/src/handlers/resource-handlers.ts

Lines changed: 3 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -3,8 +3,7 @@
33
*/
44

55
import { getGamesByType, getGameViaAPI } from '../utils/http-client.js'
6-
7-
const SUPPORTED_GAME_TYPES = ['tic-tac-toe', 'rock-paper-scissors']
6+
import { GAME_TYPES, isSupportedGameType } from '@turn-based-mcp/shared'
87

98
/**
109
* List all available game resources
@@ -13,7 +12,7 @@ export async function listResources() {
1312
try {
1413
const resources = []
1514

16-
for (const gameType of SUPPORTED_GAME_TYPES) {
15+
for (const gameType of GAME_TYPES) {
1716
try {
1817
// Get all games of this type
1918
const games = await getGamesByType(gameType)
@@ -63,7 +62,7 @@ export async function readResource(uri: string) {
6362
const [, gameType, gameId] = match
6463

6564
// Validate game type
66-
if (!SUPPORTED_GAME_TYPES.includes(gameType)) {
65+
if (!isSupportedGameType(gameType)) {
6766
throw new Error(`Invalid game type: ${gameType}`)
6867
}
6968

mcp-server/src/handlers/tool-handlers.ts

Lines changed: 9 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@
44

55
import { playGame, analyzeGame, waitForPlayerMove, createGame } from './game-operations.js'
66
import { elicitGameCreationPreferences } from './elicitation-handlers.js'
7+
import { GAME_TYPES, DIFFICULTIES, isSupportedGameType, DEFAULT_PLAYER_NAME, DEFAULT_AI_DIFFICULTY } from '@turn-based-mcp/shared'
78

89
export const TOOL_DEFINITIONS = [
910
{
@@ -18,7 +19,7 @@ export const TOOL_DEFINITIONS = [
1819
},
1920
gameType: {
2021
type: 'string',
21-
enum: ['tic-tac-toe', 'rock-paper-scissors'],
22+
enum: GAME_TYPES,
2223
description: 'Type of game to play',
2324
},
2425
},
@@ -37,7 +38,7 @@ export const TOOL_DEFINITIONS = [
3738
},
3839
gameType: {
3940
type: 'string',
40-
enum: ['tic-tac-toe', 'rock-paper-scissors'],
41+
enum: GAME_TYPES,
4142
description: 'Type of game to analyze',
4243
},
4344
},
@@ -56,7 +57,7 @@ export const TOOL_DEFINITIONS = [
5657
},
5758
gameType: {
5859
type: 'string',
59-
enum: ['tic-tac-toe', 'rock-paper-scissors'],
60+
enum: GAME_TYPES,
6061
description: 'Type of game to monitor',
6162
},
6263
timeoutSeconds: {
@@ -81,7 +82,7 @@ export const TOOL_DEFINITIONS = [
8182
properties: {
8283
gameType: {
8384
type: 'string',
84-
enum: ['tic-tac-toe', 'rock-paper-scissors'],
85+
enum: GAME_TYPES,
8586
description: 'Type of game to create'
8687
},
8788
gameId: {
@@ -108,7 +109,7 @@ export async function handleToolCall(name: string, args: any, server?: any) {
108109
if (!playGameType) {
109110
throw new Error('gameType is required')
110111
}
111-
if (!['tic-tac-toe', 'rock-paper-scissors'].includes(playGameType)) {
112+
if (!isSupportedGameType(playGameType)) {
112113
throw new Error(`Unsupported game type: ${playGameType}`)
113114
}
114115
return await playGame(playGameType, playGameId)
@@ -143,7 +144,7 @@ export async function handleToolCall(name: string, args: any, server?: any) {
143144
if (!genericGameType) {
144145
throw new Error('gameType is required')
145146
}
146-
if (!['tic-tac-toe', 'rock-paper-scissors'].includes(genericGameType)) {
147+
if (!isSupportedGameType(genericGameType)) {
147148
throw new Error(`Unsupported game type: ${genericGameType}`)
148149
}
149150
return await createGameWithElicitation(genericGameType, genericGameId, server)
@@ -162,7 +163,7 @@ export async function handleToolCall(name: string, args: any, server?: any) {
162163
async function createGameWithElicitation(gameType: string, gameId?: string, server?: any) {
163164
if (!server) {
164165
// Fallback to regular creation if no server for elicitation
165-
return await createGame(gameType, 'Player', gameId, 'medium')
166+
return await createGame(gameType, DEFAULT_PLAYER_NAME, gameId, DEFAULT_AI_DIFFICULTY)
166167
}
167168

168169
try {
@@ -228,5 +229,5 @@ async function createGameWithElicitation(gameType: string, gameId?: string, serv
228229
}
229230

230231
// Fallback to regular creation
231-
return await createGame(gameType, 'Player', gameId, 'medium')
232+
return await createGame(gameType, DEFAULT_PLAYER_NAME, gameId, DEFAULT_AI_DIFFICULTY)
232233
}

0 commit comments

Comments
 (0)