#
tokens: 4345/50000 11/11 files
lines: on (toggle) GitHub
raw markdown copy reset
# Directory Structure

```
├── .gitignore
├── .npmignore
├── package-lock.json
├── package.json
├── README.md
├── src
│   ├── constants.ts
│   ├── index.ts
│   ├── tools
│   │   ├── index.ts
│   │   └── match.ts
│   ├── types.ts
│   └── utils.ts
└── tsconfig.json
```

# Files

--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------

```
 1 | # Dependencies
 2 | node_modules/
 3 | npm-debug.log*
 4 | yarn-debug.log*
 5 | yarn-error.log*
 6 | 
 7 | # Build output
 8 | dist/
 9 | build/
10 | 
11 | # IDE and editor files
12 | .idea/
13 | .vscode/
14 | *.swp
15 | *.swo
16 | .DS_Store
17 | 
18 | # Environment variables
19 | .env
20 | .env.local
21 | .env.*.local
22 | 
23 | # Logs
24 | logs/
25 | *.log 
```

--------------------------------------------------------------------------------
/.npmignore:
--------------------------------------------------------------------------------

```
 1 | # Source files
 2 | src/
 3 | *.ts
 4 | 
 5 | # Development files
 6 | .git/
 7 | .gitignore
 8 | .npmignore
 9 | .editorconfig
10 | .eslintrc
11 | .prettierrc
12 | tsconfig.json
13 | 
14 | # Test files
15 | __tests__/
16 | *.test.ts
17 | *.spec.ts
18 | 
19 | # Documentation
20 | docs/
21 | *.md
22 | !README.md
23 | 
24 | # Build files
25 | dist/*.map
26 | 
27 | # IDE files
28 | .idea/
29 | .vscode/
30 | *.swp
31 | *.swo
32 | 
33 | # OS files
34 | .DS_Store
35 | Thumbs.db 
```

--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------

```markdown
 1 | # TFT MCP Server
 2 | 
 3 | This is a Model Context Protocol (MCP) server for Team Fight Tactics (TFT) that provides access to TFT game data through various tools.
 4 | 
 5 | ## Features
 6 | 
 7 | - Get match history for a summoner
 8 | - Get detailed information about specific TFT matches
 9 | 
10 | ## Prerequisites
11 | 
12 | - Node.js (v14 or higher)
13 | - npm or yarn
14 | - Riot Games API Key (for accessing TFT data) - Get it from [Riot Games Developer Portal](https://developer.riotgames.com/)
15 |   - Note: For development, you can use a temporary API key that expires in 24 hours
16 |   - For production use, you'll need to apply for a permanent personal API key at [Riot's Application Portal](https://developer.riotgames.com/app-type)
17 | - Your Game Name, accessed from your Riot game console
18 | - Your Name Tagline, accessed from your Riot game console, which is usually followed/shown right after your Game Name. For example: `NA1`
19 | 
20 | ## Usage
21 | 
22 | 1. Configure the MCP server in your Claude Desktop config file:
23 | 
24 | ### MacOS
25 | 
26 | Location: `~/Library/Application Support/Claude/claude_desktop_config.json`
27 | 
28 | ### Windows
29 | 
30 | Location: `%APPDATA%/Claude/claude_desktop_config.json`
31 | 
32 | Add the following configuration:
33 | 
34 | ```json
35 | {
36 |   "mcpServers": {
37 |     "tft-mcp": {
38 |       "command": "npx",
39 |       "args": [
40 |         "mcp-server-tft",
41 |         "--apiKey",
42 |         "<YOUR_RIOT_API_KEY>",
43 |         "--gameName",
44 |         "<YOUR_GAME_NAME>",
45 |         "--tagLine",
46 |         "<YOUR_TAG_LINE>"
47 |       ]
48 |     }
49 |   }
50 | }
51 | ```
52 | 
53 | 2. The server will run on stdio and provide the following tools:
54 | 
55 | ### tft_match_history
56 | 
57 | Get TFT match history for the current player.
58 | 
59 | Parameters:
60 | 
61 | - `count` (optional): Number of matches to retrieve. Defaults to 20
62 | - `start` (optional): Start index for pagination. Defaults to 0
63 | 
64 | ### tft_match_details
65 | 
66 | Get detailed information about a specific TFT match.
67 | 
68 | Parameters:
69 | 
70 | - `matchId` (required): The match ID to get details for
71 | 
72 | ## Development
73 | 
74 | The project is written in TypeScript and uses the Model Context Protocol SDK. To modify the code:
75 | 
76 | 1. Make changes in the `src` directory
77 | 2. Run `npm run build` to compile
78 | 3. Run `npm start` with the required parameters to test changes
79 | 
80 | ## License
81 | 
82 | MIT
83 | 
```

--------------------------------------------------------------------------------
/src/constants.ts:
--------------------------------------------------------------------------------

```typescript
1 | export const RIOT_ACCOUNT_API =
2 |   "https://americas.api.riotgames.com/riot/account/v1";
3 | export const RIOT_API_BASE = "https://americas.api.riotgames.com";
4 | 
```

--------------------------------------------------------------------------------
/src/types.ts:
--------------------------------------------------------------------------------

```typescript
 1 | export interface Arguments {
 2 |   apiKey: string;
 3 |   gameName: string;
 4 |   tagLine: string;
 5 |   [x: string]: unknown;
 6 | }
 7 | 
 8 | let _args: Arguments;
 9 | 
10 | export function setArgs(newArgs: Arguments) {
11 |   _args = newArgs;
12 | }
13 | 
14 | export function getArgs(): Arguments {
15 |   return _args;
16 | }
17 | 
```

--------------------------------------------------------------------------------
/tsconfig.json:
--------------------------------------------------------------------------------

```json
 1 | {
 2 |   "compilerOptions": {
 3 |     "target": "ES2020",
 4 |     "module": "NodeNext",
 5 |     "moduleResolution": "NodeNext",
 6 |     "esModuleInterop": true,
 7 |     "strict": true,
 8 |     "skipLibCheck": true,
 9 |     "forceConsistentCasingInFileNames": true,
10 |     "outDir": "./dist",
11 |     "rootDir": "./src"
12 |   },
13 |   "include": ["src/**/*"],
14 |   "exclude": ["node_modules", "dist"]
15 | }
16 | 
```

--------------------------------------------------------------------------------
/src/tools/index.ts:
--------------------------------------------------------------------------------

```typescript
 1 | import type { Tool } from "@modelcontextprotocol/sdk/types.js";
 2 | 
 3 | // Define tools using the Zod schemas
 4 | export const TFT_TOOLS: Tool[] = [
 5 |   {
 6 |     name: "tft_match_history",
 7 |     description: "Get TFT match history for the current player",
 8 |     inputSchema: {
 9 |       type: "object",
10 |       properties: {
11 |         count: {
12 |           type: "number",
13 |           default: 20,
14 |           description: "Number of matches to retrieve (default: 20)"
15 |         },
16 |         start: {
17 |           type: "number",
18 |           default: 0,
19 |           description: "Start index (default: 0)"
20 |         }
21 |       }
22 |     }
23 |   },
24 |   {
25 |     name: "tft_match_details",
26 |     description: "Get detailed information about a specific TFT match",
27 |     inputSchema: {
28 |       type: "object",
29 |       properties: {
30 |         matchId: {
31 |           type: "string",
32 |           description: "The match ID to get details for"
33 |         }
34 |       },
35 |       required: ["matchId"]
36 |     }
37 |   }
38 | ];
39 | 
```

--------------------------------------------------------------------------------
/package.json:
--------------------------------------------------------------------------------

```json
 1 | {
 2 |   "name": "mcp-server-tft",
 3 |   "version": "0.1.3",
 4 |   "description": "MCP Server for Team Fight Tactics (TFT)",
 5 |   "main": "dist/index.js",
 6 |   "type": "module",
 7 |   "bin": {
 8 |     "mcp-server-tft": "./dist/index.js"
 9 |   },
10 |   "scripts": {
11 |     "build": "tsc",
12 |     "start": "node dist/index.js",
13 |     "prepublishOnly": "npm run build"
14 |   },
15 |   "keywords": [
16 |     "tft",
17 |     "riot",
18 |     "riot-games",
19 |     "mcp",
20 |     "model-context-protocol",
21 |     "game-data"
22 |   ],
23 |   "author": "Your Name",
24 |   "license": "MIT",
25 |   "repository": {
26 |     "type": "git",
27 |     "url": "git+https://github.com/GeLi2001/tft-mcp-server.git"
28 |   },
29 |   "bugs": {
30 |     "url": "https://github.com/GeLi2001/tft-mcp-server/issues"
31 |   },
32 |   "homepage": "https://github.com/GeLi2001/tft-mcp-server#readme",
33 |   "dependencies": {
34 |     "@modelcontextprotocol/sdk": "^1.8.0",
35 |     "node-fetch": "^3.3.2",
36 |     "cheerio": "^1.0.0-rc.12",
37 |     "yargs": "^17.7.2",
38 |     "zod": "^3.23.8"
39 |   },
40 |   "devDependencies": {
41 |     "@types/node": "^20.11.19",
42 |     "@types/yargs": "^17.0.32",
43 |     "typescript": "^5.3.3"
44 |   },
45 |   "engines": {
46 |     "node": ">=14.0.0"
47 |   }
48 | }
49 | 
```

--------------------------------------------------------------------------------
/src/utils.ts:
--------------------------------------------------------------------------------

```typescript
 1 | import fetch from "node-fetch";
 2 | import { RIOT_ACCOUNT_API } from "./constants.js";
 3 | import { getArgs } from "./types.js";
 4 | 
 5 | export let CURRENT_PUUID: string | null = null;
 6 | 
 7 | export async function fetchWithErrorHandling(url: string, options: any = {}) {
 8 |   try {
 9 |     const headers = {
10 |       "X-Riot-Token": getArgs().apiKey,
11 |       ...options.headers
12 |     };
13 | 
14 |     const response = await fetch(url, { ...options, headers });
15 |     if (!response.ok) {
16 |       throw new Error(`HTTP error! status: ${response.status}`);
17 |     }
18 |     return response;
19 |   } catch (error) {
20 |     throw new Error(
21 |       `Failed to fetch: ${
22 |         error instanceof Error ? error.message : String(error)
23 |       }`
24 |     );
25 |   }
26 | }
27 | 
28 | export async function initializePUUID() {
29 |   try {
30 |     const args = getArgs();
31 |     const url = `${RIOT_ACCOUNT_API}/accounts/by-riot-id/${encodeURIComponent(
32 |       args.gameName
33 |     )}/${encodeURIComponent(args.tagLine)}`;
34 |     const response = await fetchWithErrorHandling(url);
35 |     const data = (await response.json()) as { puuid: string };
36 |     CURRENT_PUUID = data.puuid;
37 |   } catch (error) {
38 |     console.error("Failed to initialize PUUID:", error);
39 |     process.exit(1);
40 |   }
41 | }
42 | 
```

--------------------------------------------------------------------------------
/src/tools/match.ts:
--------------------------------------------------------------------------------

```typescript
 1 | import { RIOT_API_BASE } from "../constants.js";
 2 | import { CURRENT_PUUID, fetchWithErrorHandling } from "../utils.js";
 3 | 
 4 | // Tool handlers
 5 | export async function handleTftMatchHistory(params: any) {
 6 |   const { count = 20, start = 0 } = params;
 7 |   const url = `${RIOT_API_BASE}/tft/match/v1/matches/by-puuid/${CURRENT_PUUID}/ids?start=${start}&count=${count}`;
 8 | 
 9 |   try {
10 |     const response = await fetchWithErrorHandling(url);
11 |     const matchIds = await response.json();
12 |     return {
13 |       content: [
14 |         {
15 |           type: "text",
16 |           text: JSON.stringify({ matchIds }, null, 2)
17 |         }
18 |       ],
19 |       isError: false
20 |     };
21 |   } catch (error) {
22 |     return {
23 |       content: [
24 |         {
25 |           type: "text",
26 |           text: JSON.stringify(
27 |             {
28 |               error: error instanceof Error ? error.message : String(error)
29 |             },
30 |             null,
31 |             2
32 |           )
33 |         }
34 |       ],
35 |       isError: true
36 |     };
37 |   }
38 | }
39 | 
40 | export async function handleTftMatchDetails(params: any) {
41 |   const { matchId } = params;
42 |   const url = `${RIOT_API_BASE}/tft/match/v1/matches/${matchId}`;
43 | 
44 |   try {
45 |     const response = await fetchWithErrorHandling(url);
46 |     const data = await response.json();
47 |     return {
48 |       content: [
49 |         {
50 |           type: "text",
51 |           text: JSON.stringify(data, null, 2)
52 |         }
53 |       ],
54 |       isError: false
55 |     };
56 |   } catch (error) {
57 |     return {
58 |       content: [
59 |         {
60 |           type: "text",
61 |           text: JSON.stringify(
62 |             {
63 |               error: error instanceof Error ? error.message : String(error)
64 |             },
65 |             null,
66 |             2
67 |           )
68 |         }
69 |       ],
70 |       isError: true
71 |     };
72 |   }
73 | }
74 | 
```

--------------------------------------------------------------------------------
/src/index.ts:
--------------------------------------------------------------------------------

```typescript
  1 | #!/usr/bin/env node
  2 | 
  3 | import { Server } from "@modelcontextprotocol/sdk/server/index.js";
  4 | import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio.js";
  5 | import {
  6 |   CallToolRequestSchema,
  7 |   ErrorCode,
  8 |   ListToolsRequestSchema,
  9 |   McpError
 10 | } from "@modelcontextprotocol/sdk/types.js";
 11 | import yargs from "yargs";
 12 | import { hideBin } from "yargs/helpers";
 13 | import { TFT_TOOLS } from "./tools/index.js";
 14 | import { handleTftMatchDetails, handleTftMatchHistory } from "./tools/match.js";
 15 | import { setArgs } from "./types.js";
 16 | import { initializePUUID } from "./utils.js";
 17 | 
 18 | // Parse command line arguments
 19 | interface Arguments {
 20 |   apiKey: string;
 21 |   gameName: string;
 22 |   tagLine: string;
 23 |   [x: string]: unknown;
 24 | }
 25 | 
 26 | const getArgs = async (): Promise<Arguments> => {
 27 |   return yargs(hideBin(process.argv))
 28 |     .option("apiKey", {
 29 |       alias: "k",
 30 |       type: "string",
 31 |       description: "Riot API Key",
 32 |       demandOption: true
 33 |     })
 34 |     .option("gameName", {
 35 |       alias: "n",
 36 |       type: "string",
 37 |       description: "Summoner Name",
 38 |       demandOption: true
 39 |     })
 40 |     .option("tagLine", {
 41 |       alias: "t",
 42 |       type: "string",
 43 |       description: "Name Tagline",
 44 |       demandOption: true
 45 |     })
 46 |     .help()
 47 |     .parseAsync();
 48 | };
 49 | 
 50 | // Server setup
 51 | const server = new Server(
 52 |   {
 53 |     name: "tft",
 54 |     version: "0.1.0"
 55 |   },
 56 |   {
 57 |     capabilities: {
 58 |       tools: {}
 59 |     }
 60 |   }
 61 | );
 62 | 
 63 | // Set up request handlers
 64 | server.setRequestHandler(ListToolsRequestSchema, async () => ({
 65 |   tools: TFT_TOOLS
 66 | }));
 67 | 
 68 | server.setRequestHandler(CallToolRequestSchema, async (request) => {
 69 |   try {
 70 |     switch (request.params.name) {
 71 |       case "tft_match_history": {
 72 |         return await handleTftMatchHistory(request.params.arguments);
 73 |       }
 74 |       case "tft_match_details": {
 75 |         return await handleTftMatchDetails(request.params.arguments);
 76 |       }
 77 |       default:
 78 |         throw new McpError(
 79 |           ErrorCode.MethodNotFound,
 80 |           `Unknown tool: ${request.params.name}`
 81 |         );
 82 |     }
 83 |   } catch (error) {
 84 |     return {
 85 |       content: [
 86 |         {
 87 |           type: "text",
 88 |           text: `Error: ${
 89 |             error instanceof Error ? error.message : String(error)
 90 |           }`
 91 |         }
 92 |       ],
 93 |       isError: true
 94 |     };
 95 |   }
 96 | });
 97 | 
 98 | // Modify runServer to initialize args and PUUID first
 99 | async function runServer() {
100 |   const parsedArgs = await getArgs();
101 |   setArgs(parsedArgs);
102 |   await initializePUUID();
103 |   const transport = new StdioServerTransport();
104 |   await server.connect(transport);
105 |   console.error("TFT MCP Server running on stdio");
106 | }
107 | 
108 | runServer().catch((error) => {
109 |   console.error("Fatal error running server:", error);
110 |   process.exit(1);
111 | });
112 | 
```