npb-mcp-server 0.1.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/README.md +301 -0
- package/dist/constants/teams.d.ts +14 -0
- package/dist/constants/teams.d.ts.map +1 -0
- package/dist/constants/teams.js +104 -0
- package/dist/constants/teams.js.map +1 -0
- package/dist/constants/teams.test.d.ts +2 -0
- package/dist/constants/teams.test.d.ts.map +1 -0
- package/dist/constants/teams.test.js +93 -0
- package/dist/constants/teams.test.js.map +1 -0
- package/dist/index.d.ts +3 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +268 -0
- package/dist/index.js.map +1 -0
- package/dist/scrapers/players.d.ts +14 -0
- package/dist/scrapers/players.d.ts.map +1 -0
- package/dist/scrapers/players.js +151 -0
- package/dist/scrapers/players.js.map +1 -0
- package/dist/tools/get-team-players.d.ts +13 -0
- package/dist/tools/get-team-players.d.ts.map +1 -0
- package/dist/tools/get-team-players.js +28 -0
- package/dist/tools/get-team-players.js.map +1 -0
- package/dist/tools/list-teams.d.ts +13 -0
- package/dist/tools/list-teams.d.ts.map +1 -0
- package/dist/tools/list-teams.js +22 -0
- package/dist/tools/list-teams.js.map +1 -0
- package/dist/tools/list-teams.test.d.ts +2 -0
- package/dist/tools/list-teams.test.d.ts.map +1 -0
- package/dist/tools/list-teams.test.js +46 -0
- package/dist/tools/list-teams.test.js.map +1 -0
- package/dist/tools/search-players.d.ts +16 -0
- package/dist/tools/search-players.d.ts.map +1 -0
- package/dist/tools/search-players.js +41 -0
- package/dist/tools/search-players.js.map +1 -0
- package/dist/types/npb.d.ts +51 -0
- package/dist/types/npb.d.ts.map +1 -0
- package/dist/types/npb.js +2 -0
- package/dist/types/npb.js.map +1 -0
- package/dist/utils/cache.d.ts +37 -0
- package/dist/utils/cache.d.ts.map +1 -0
- package/dist/utils/cache.js +75 -0
- package/dist/utils/cache.js.map +1 -0
- package/dist/utils/cache.test.d.ts +2 -0
- package/dist/utils/cache.test.d.ts.map +1 -0
- package/dist/utils/cache.test.js +62 -0
- package/dist/utils/cache.test.js.map +1 -0
- package/dist/utils/http.d.ts +9 -0
- package/dist/utils/http.d.ts.map +1 -0
- package/dist/utils/http.js +50 -0
- package/dist/utils/http.js.map +1 -0
- package/package.json +72 -0
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
import { TEAMS } from '../constants/teams.js';
|
|
2
|
+
import { getAllPlayers } from '../scrapers/players.js';
|
|
3
|
+
/**
|
|
4
|
+
* search_players ツールの実装
|
|
5
|
+
* 選手名やその他の条件で選手を検索
|
|
6
|
+
*/
|
|
7
|
+
export async function searchPlayers(args) {
|
|
8
|
+
const { name, team_id, position, number } = args;
|
|
9
|
+
// 対象の球団を決定
|
|
10
|
+
const targetTeams = team_id ? TEAMS.filter((t) => t.id === team_id) : TEAMS;
|
|
11
|
+
// すべての選手を取得
|
|
12
|
+
const rostersMap = await getAllPlayers(targetTeams);
|
|
13
|
+
let allPlayers = [];
|
|
14
|
+
for (const roster of rostersMap.values()) {
|
|
15
|
+
allPlayers = allPlayers.concat(roster.players);
|
|
16
|
+
}
|
|
17
|
+
// フィルタリング
|
|
18
|
+
let results = allPlayers;
|
|
19
|
+
if (name) {
|
|
20
|
+
const searchName = name.toLowerCase();
|
|
21
|
+
results = results.filter((p) => p.name.toLowerCase().includes(searchName));
|
|
22
|
+
}
|
|
23
|
+
if (position) {
|
|
24
|
+
results = results.filter((p) => p.position === position);
|
|
25
|
+
}
|
|
26
|
+
if (number) {
|
|
27
|
+
results = results.filter((p) => p.number === number);
|
|
28
|
+
}
|
|
29
|
+
return {
|
|
30
|
+
content: [
|
|
31
|
+
{
|
|
32
|
+
type: 'text',
|
|
33
|
+
text: JSON.stringify({
|
|
34
|
+
resultCount: results.length,
|
|
35
|
+
players: results,
|
|
36
|
+
}, null, 2),
|
|
37
|
+
},
|
|
38
|
+
],
|
|
39
|
+
};
|
|
40
|
+
}
|
|
41
|
+
//# sourceMappingURL=search-players.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"search-players.js","sourceRoot":"","sources":["../../src/tools/search-players.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,KAAK,EAAE,MAAM,uBAAuB,CAAC;AAC9C,OAAO,EAAE,aAAa,EAAE,MAAM,wBAAwB,CAAC;AAGvD;;;GAGG;AACH,MAAM,CAAC,KAAK,UAAU,aAAa,CAAC,IAKnC;IACC,MAAM,EAAE,IAAI,EAAE,OAAO,EAAE,QAAQ,EAAE,MAAM,EAAE,GAAG,IAAI,CAAC;IAEjD,WAAW;IACX,MAAM,WAAW,GAAG,OAAO,CAAC,CAAC,CAAC,KAAK,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,EAAE,KAAK,OAAO,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC;IAE5E,YAAY;IACZ,MAAM,UAAU,GAAG,MAAM,aAAa,CAAC,WAAW,CAAC,CAAC;IACpD,IAAI,UAAU,GAAa,EAAE,CAAC;IAE9B,KAAK,MAAM,MAAM,IAAI,UAAU,CAAC,MAAM,EAAE,EAAE,CAAC;QACzC,UAAU,GAAG,UAAU,CAAC,MAAM,CAAC,MAAM,CAAC,OAAO,CAAC,CAAC;IACjD,CAAC;IAED,UAAU;IACV,IAAI,OAAO,GAAG,UAAU,CAAC;IAEzB,IAAI,IAAI,EAAE,CAAC;QACT,MAAM,UAAU,GAAG,IAAI,CAAC,WAAW,EAAE,CAAC;QACtC,OAAO,GAAG,OAAO,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,IAAI,CAAC,WAAW,EAAE,CAAC,QAAQ,CAAC,UAAU,CAAC,CAAC,CAAC;IAC7E,CAAC;IAED,IAAI,QAAQ,EAAE,CAAC;QACb,OAAO,GAAG,OAAO,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,QAAQ,KAAK,QAAQ,CAAC,CAAC;IAC3D,CAAC;IAED,IAAI,MAAM,EAAE,CAAC;QACX,OAAO,GAAG,OAAO,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,MAAM,KAAK,MAAM,CAAC,CAAC;IACvD,CAAC;IAED,OAAO;QACL,OAAO,EAAE;YACP;gBACE,IAAI,EAAE,MAAM;gBACZ,IAAI,EAAE,IAAI,CAAC,SAAS,CAClB;oBACE,WAAW,EAAE,OAAO,CAAC,MAAM;oBAC3B,OAAO,EAAE,OAAO;iBACjB,EACD,IAAI,EACJ,CAAC,CACF;aACF;SACF;KACF,CAAC;AACJ,CAAC"}
|
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* NPB球団のリーグ
|
|
3
|
+
*/
|
|
4
|
+
export type League = 'central' | 'pacific';
|
|
5
|
+
/**
|
|
6
|
+
* 選手のポジション
|
|
7
|
+
*/
|
|
8
|
+
export type Position = 'pitcher' | 'catcher' | 'infielder' | 'outfielder';
|
|
9
|
+
/**
|
|
10
|
+
* 選手の投打
|
|
11
|
+
*/
|
|
12
|
+
export type Hand = '右' | '左' | '両';
|
|
13
|
+
/**
|
|
14
|
+
* 選手の分類
|
|
15
|
+
*/
|
|
16
|
+
export type PlayerCategory = 'registered' | 'development';
|
|
17
|
+
/**
|
|
18
|
+
* NPB球団情報
|
|
19
|
+
*/
|
|
20
|
+
export interface Team {
|
|
21
|
+
id: string;
|
|
22
|
+
name: string;
|
|
23
|
+
fullName: string;
|
|
24
|
+
league: League;
|
|
25
|
+
rosterUrl: string;
|
|
26
|
+
}
|
|
27
|
+
/**
|
|
28
|
+
* 選手情報
|
|
29
|
+
*/
|
|
30
|
+
export interface Player {
|
|
31
|
+
number: string;
|
|
32
|
+
name: string;
|
|
33
|
+
birthDate: string;
|
|
34
|
+
height: number;
|
|
35
|
+
weight: number;
|
|
36
|
+
pitchingHand: Hand;
|
|
37
|
+
battingHand: Hand;
|
|
38
|
+
position: Position;
|
|
39
|
+
category: PlayerCategory;
|
|
40
|
+
note?: string;
|
|
41
|
+
teamId: string;
|
|
42
|
+
}
|
|
43
|
+
/**
|
|
44
|
+
* 球団別選手一覧
|
|
45
|
+
*/
|
|
46
|
+
export interface TeamRoster {
|
|
47
|
+
team: Team;
|
|
48
|
+
players: Player[];
|
|
49
|
+
lastUpdated: Date;
|
|
50
|
+
}
|
|
51
|
+
//# sourceMappingURL=npb.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"npb.d.ts","sourceRoot":"","sources":["../../src/types/npb.ts"],"names":[],"mappings":"AAAA;;GAEG;AACH,MAAM,MAAM,MAAM,GAAG,SAAS,GAAG,SAAS,CAAC;AAE3C;;GAEG;AACH,MAAM,MAAM,QAAQ,GAAG,SAAS,GAAG,SAAS,GAAG,WAAW,GAAG,YAAY,CAAC;AAE1E;;GAEG;AACH,MAAM,MAAM,IAAI,GAAG,GAAG,GAAG,GAAG,GAAG,GAAG,CAAC;AAEnC;;GAEG;AACH,MAAM,MAAM,cAAc,GAAG,YAAY,GAAG,aAAa,CAAC;AAE1D;;GAEG;AACH,MAAM,WAAW,IAAI;IACnB,EAAE,EAAE,MAAM,CAAC;IACX,IAAI,EAAE,MAAM,CAAC;IACb,QAAQ,EAAE,MAAM,CAAC;IACjB,MAAM,EAAE,MAAM,CAAC;IACf,SAAS,EAAE,MAAM,CAAC;CACnB;AAED;;GAEG;AACH,MAAM,WAAW,MAAM;IACrB,MAAM,EAAE,MAAM,CAAC;IACf,IAAI,EAAE,MAAM,CAAC;IACb,SAAS,EAAE,MAAM,CAAC;IAClB,MAAM,EAAE,MAAM,CAAC;IACf,MAAM,EAAE,MAAM,CAAC;IACf,YAAY,EAAE,IAAI,CAAC;IACnB,WAAW,EAAE,IAAI,CAAC;IAClB,QAAQ,EAAE,QAAQ,CAAC;IACnB,QAAQ,EAAE,cAAc,CAAC;IACzB,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,MAAM,EAAE,MAAM,CAAC;CAChB;AAED;;GAEG;AACH,MAAM,WAAW,UAAU;IACzB,IAAI,EAAE,IAAI,CAAC;IACX,OAAO,EAAE,MAAM,EAAE,CAAC;IAClB,WAAW,EAAE,IAAI,CAAC;CACnB"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"npb.js","sourceRoot":"","sources":["../../src/types/npb.ts"],"names":[],"mappings":""}
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* シンプルなインメモリキャッシュ
|
|
3
|
+
*/
|
|
4
|
+
export declare class Cache {
|
|
5
|
+
private store;
|
|
6
|
+
private defaultTTL;
|
|
7
|
+
/**
|
|
8
|
+
* @param defaultTTL デフォルトのTTL(ミリ秒)、デフォルトは1時間
|
|
9
|
+
*/
|
|
10
|
+
constructor(defaultTTL?: number);
|
|
11
|
+
/**
|
|
12
|
+
* キャッシュからデータを取得
|
|
13
|
+
*/
|
|
14
|
+
get<T>(key: string): T | null;
|
|
15
|
+
/**
|
|
16
|
+
* キャッシュにデータを保存
|
|
17
|
+
*/
|
|
18
|
+
set<T>(key: string, data: T, ttl?: number): void;
|
|
19
|
+
/**
|
|
20
|
+
* キャッシュからデータを削除
|
|
21
|
+
*/
|
|
22
|
+
delete(key: string): boolean;
|
|
23
|
+
/**
|
|
24
|
+
* すべてのキャッシュをクリア
|
|
25
|
+
*/
|
|
26
|
+
clear(): void;
|
|
27
|
+
/**
|
|
28
|
+
* 期限切れのエントリーを削除
|
|
29
|
+
*/
|
|
30
|
+
cleanup(): void;
|
|
31
|
+
/**
|
|
32
|
+
* キャッシュサイズを取得
|
|
33
|
+
*/
|
|
34
|
+
size(): number;
|
|
35
|
+
}
|
|
36
|
+
export declare const globalCache: Cache;
|
|
37
|
+
//# sourceMappingURL=cache.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"cache.d.ts","sourceRoot":"","sources":["../../src/utils/cache.ts"],"names":[],"mappings":"AASA;;GAEG;AACH,qBAAa,KAAK;IAChB,OAAO,CAAC,KAAK,CAAmC;IAChD,OAAO,CAAC,UAAU,CAAS;IAE3B;;OAEG;gBACS,UAAU,GAAE,MAAgB;IAKxC;;OAEG;IACH,GAAG,CAAC,CAAC,EAAE,GAAG,EAAE,MAAM,GAAG,CAAC,GAAG,IAAI;IAmB7B;;OAEG;IACH,GAAG,CAAC,CAAC,EAAE,GAAG,EAAE,MAAM,EAAE,IAAI,EAAE,CAAC,EAAE,GAAG,CAAC,EAAE,MAAM,GAAG,IAAI;IAUhD;;OAEG;IACH,MAAM,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO;IAI5B;;OAEG;IACH,KAAK,IAAI,IAAI;IAIb;;OAEG;IACH,OAAO,IAAI,IAAI;IAWf;;OAEG;IACH,IAAI,IAAI,MAAM;CAGf;AAGD,eAAO,MAAM,WAAW,OAAc,CAAC"}
|
|
@@ -0,0 +1,75 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* シンプルなインメモリキャッシュ
|
|
3
|
+
*/
|
|
4
|
+
export class Cache {
|
|
5
|
+
store;
|
|
6
|
+
defaultTTL;
|
|
7
|
+
/**
|
|
8
|
+
* @param defaultTTL デフォルトのTTL(ミリ秒)、デフォルトは1時間
|
|
9
|
+
*/
|
|
10
|
+
constructor(defaultTTL = 3600000) {
|
|
11
|
+
this.store = new Map();
|
|
12
|
+
this.defaultTTL = defaultTTL;
|
|
13
|
+
}
|
|
14
|
+
/**
|
|
15
|
+
* キャッシュからデータを取得
|
|
16
|
+
*/
|
|
17
|
+
get(key) {
|
|
18
|
+
const entry = this.store.get(key);
|
|
19
|
+
if (!entry) {
|
|
20
|
+
return null;
|
|
21
|
+
}
|
|
22
|
+
const now = Date.now();
|
|
23
|
+
const age = now - entry.timestamp;
|
|
24
|
+
// TTLを超えている場合は削除して null を返す
|
|
25
|
+
if (age > entry.ttl) {
|
|
26
|
+
this.store.delete(key);
|
|
27
|
+
return null;
|
|
28
|
+
}
|
|
29
|
+
return entry.data;
|
|
30
|
+
}
|
|
31
|
+
/**
|
|
32
|
+
* キャッシュにデータを保存
|
|
33
|
+
*/
|
|
34
|
+
set(key, data, ttl) {
|
|
35
|
+
const entry = {
|
|
36
|
+
data,
|
|
37
|
+
timestamp: Date.now(),
|
|
38
|
+
ttl: ttl ?? this.defaultTTL,
|
|
39
|
+
};
|
|
40
|
+
this.store.set(key, entry);
|
|
41
|
+
}
|
|
42
|
+
/**
|
|
43
|
+
* キャッシュからデータを削除
|
|
44
|
+
*/
|
|
45
|
+
delete(key) {
|
|
46
|
+
return this.store.delete(key);
|
|
47
|
+
}
|
|
48
|
+
/**
|
|
49
|
+
* すべてのキャッシュをクリア
|
|
50
|
+
*/
|
|
51
|
+
clear() {
|
|
52
|
+
this.store.clear();
|
|
53
|
+
}
|
|
54
|
+
/**
|
|
55
|
+
* 期限切れのエントリーを削除
|
|
56
|
+
*/
|
|
57
|
+
cleanup() {
|
|
58
|
+
const now = Date.now();
|
|
59
|
+
for (const [key, entry] of this.store.entries()) {
|
|
60
|
+
const age = now - entry.timestamp;
|
|
61
|
+
if (age > entry.ttl) {
|
|
62
|
+
this.store.delete(key);
|
|
63
|
+
}
|
|
64
|
+
}
|
|
65
|
+
}
|
|
66
|
+
/**
|
|
67
|
+
* キャッシュサイズを取得
|
|
68
|
+
*/
|
|
69
|
+
size() {
|
|
70
|
+
return this.store.size;
|
|
71
|
+
}
|
|
72
|
+
}
|
|
73
|
+
// グローバルキャッシュインスタンス
|
|
74
|
+
export const globalCache = new Cache();
|
|
75
|
+
//# sourceMappingURL=cache.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"cache.js","sourceRoot":"","sources":["../../src/utils/cache.ts"],"names":[],"mappings":"AASA;;GAEG;AACH,MAAM,OAAO,KAAK;IACR,KAAK,CAAmC;IACxC,UAAU,CAAS;IAE3B;;OAEG;IACH,YAAY,aAAqB,OAAO;QACtC,IAAI,CAAC,KAAK,GAAG,IAAI,GAAG,EAAE,CAAC;QACvB,IAAI,CAAC,UAAU,GAAG,UAAU,CAAC;IAC/B,CAAC;IAED;;OAEG;IACH,GAAG,CAAI,GAAW;QAChB,MAAM,KAAK,GAAG,IAAI,CAAC,KAAK,CAAC,GAAG,CAAC,GAAG,CAAC,CAAC;QAElC,IAAI,CAAC,KAAK,EAAE,CAAC;YACX,OAAO,IAAI,CAAC;QACd,CAAC;QAED,MAAM,GAAG,GAAG,IAAI,CAAC,GAAG,EAAE,CAAC;QACvB,MAAM,GAAG,GAAG,GAAG,GAAG,KAAK,CAAC,SAAS,CAAC;QAElC,4BAA4B;QAC5B,IAAI,GAAG,GAAG,KAAK,CAAC,GAAG,EAAE,CAAC;YACpB,IAAI,CAAC,KAAK,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC;YACvB,OAAO,IAAI,CAAC;QACd,CAAC;QAED,OAAO,KAAK,CAAC,IAAS,CAAC;IACzB,CAAC;IAED;;OAEG;IACH,GAAG,CAAI,GAAW,EAAE,IAAO,EAAE,GAAY;QACvC,MAAM,KAAK,GAAkB;YAC3B,IAAI;YACJ,SAAS,EAAE,IAAI,CAAC,GAAG,EAAE;YACrB,GAAG,EAAE,GAAG,IAAI,IAAI,CAAC,UAAU;SAC5B,CAAC;QAEF,IAAI,CAAC,KAAK,CAAC,GAAG,CAAC,GAAG,EAAE,KAAK,CAAC,CAAC;IAC7B,CAAC;IAED;;OAEG;IACH,MAAM,CAAC,GAAW;QAChB,OAAO,IAAI,CAAC,KAAK,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC;IAChC,CAAC;IAED;;OAEG;IACH,KAAK;QACH,IAAI,CAAC,KAAK,CAAC,KAAK,EAAE,CAAC;IACrB,CAAC;IAED;;OAEG;IACH,OAAO;QACL,MAAM,GAAG,GAAG,IAAI,CAAC,GAAG,EAAE,CAAC;QAEvB,KAAK,MAAM,CAAC,GAAG,EAAE,KAAK,CAAC,IAAI,IAAI,CAAC,KAAK,CAAC,OAAO,EAAE,EAAE,CAAC;YAChD,MAAM,GAAG,GAAG,GAAG,GAAG,KAAK,CAAC,SAAS,CAAC;YAClC,IAAI,GAAG,GAAG,KAAK,CAAC,GAAG,EAAE,CAAC;gBACpB,IAAI,CAAC,KAAK,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC;YACzB,CAAC;QACH,CAAC;IACH,CAAC;IAED;;OAEG;IACH,IAAI;QACF,OAAO,IAAI,CAAC,KAAK,CAAC,IAAI,CAAC;IACzB,CAAC;CACF;AAED,mBAAmB;AACnB,MAAM,CAAC,MAAM,WAAW,GAAG,IAAI,KAAK,EAAE,CAAC"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"cache.test.d.ts","sourceRoot":"","sources":["../../src/utils/cache.test.ts"],"names":[],"mappings":""}
|
|
@@ -0,0 +1,62 @@
|
|
|
1
|
+
import { describe, it, expect, beforeEach } from 'vitest';
|
|
2
|
+
import { Cache } from './cache.js';
|
|
3
|
+
describe('Cache', () => {
|
|
4
|
+
let cache;
|
|
5
|
+
beforeEach(() => {
|
|
6
|
+
cache = new Cache(1000); // 1秒のTTL
|
|
7
|
+
});
|
|
8
|
+
it('データを保存して取得できる', () => {
|
|
9
|
+
cache.set('key1', 'value1');
|
|
10
|
+
expect(cache.get('key1')).toBe('value1');
|
|
11
|
+
});
|
|
12
|
+
it('存在しないキーはnullを返す', () => {
|
|
13
|
+
expect(cache.get('nonexistent')).toBeNull();
|
|
14
|
+
});
|
|
15
|
+
it('TTLが切れたデータはnullを返す', async () => {
|
|
16
|
+
cache.set('key1', 'value1', 100); // 100msのTTL
|
|
17
|
+
expect(cache.get('key1')).toBe('value1');
|
|
18
|
+
// 150ms待つ
|
|
19
|
+
await new Promise((resolve) => setTimeout(resolve, 150));
|
|
20
|
+
expect(cache.get('key1')).toBeNull();
|
|
21
|
+
});
|
|
22
|
+
it('データを削除できる', () => {
|
|
23
|
+
cache.set('key1', 'value1');
|
|
24
|
+
expect(cache.delete('key1')).toBe(true);
|
|
25
|
+
expect(cache.get('key1')).toBeNull();
|
|
26
|
+
});
|
|
27
|
+
it('存在しないキーの削除はfalseを返す', () => {
|
|
28
|
+
expect(cache.delete('nonexistent')).toBe(false);
|
|
29
|
+
});
|
|
30
|
+
it('すべてのデータをクリアできる', () => {
|
|
31
|
+
cache.set('key1', 'value1');
|
|
32
|
+
cache.set('key2', 'value2');
|
|
33
|
+
cache.clear();
|
|
34
|
+
expect(cache.get('key1')).toBeNull();
|
|
35
|
+
expect(cache.get('key2')).toBeNull();
|
|
36
|
+
expect(cache.size()).toBe(0);
|
|
37
|
+
});
|
|
38
|
+
it('キャッシュサイズを取得できる', () => {
|
|
39
|
+
expect(cache.size()).toBe(0);
|
|
40
|
+
cache.set('key1', 'value1');
|
|
41
|
+
cache.set('key2', 'value2');
|
|
42
|
+
expect(cache.size()).toBe(2);
|
|
43
|
+
});
|
|
44
|
+
it('期限切れエントリーをクリーンアップできる', async () => {
|
|
45
|
+
cache.set('key1', 'value1', 100); // 100msのTTL
|
|
46
|
+
cache.set('key2', 'value2', 5000); // 5秒のTTL
|
|
47
|
+
expect(cache.size()).toBe(2);
|
|
48
|
+
// 150ms待つ
|
|
49
|
+
await new Promise((resolve) => setTimeout(resolve, 150));
|
|
50
|
+
cache.cleanup();
|
|
51
|
+
expect(cache.size()).toBe(1);
|
|
52
|
+
expect(cache.get('key1')).toBeNull();
|
|
53
|
+
expect(cache.get('key2')).toBe('value2');
|
|
54
|
+
});
|
|
55
|
+
it('複雑なオブジェクトを保存できる', () => {
|
|
56
|
+
const obj = { name: 'test', values: [1, 2, 3] };
|
|
57
|
+
cache.set('obj', obj);
|
|
58
|
+
const retrieved = cache.get('obj');
|
|
59
|
+
expect(retrieved).toEqual(obj);
|
|
60
|
+
});
|
|
61
|
+
});
|
|
62
|
+
//# sourceMappingURL=cache.test.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"cache.test.js","sourceRoot":"","sources":["../../src/utils/cache.test.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"http.d.ts","sourceRoot":"","sources":["../../src/utils/http.ts"],"names":[],"mappings":"AAWA;;GAEG;AACH,wBAAsB,SAAS,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,CAAC,CAmB5D;AAED;;GAEG;AACH,wBAAsB,iBAAiB,CAAC,IAAI,EAAE,MAAM,EAAE,GAAG,OAAO,CAAC,GAAG,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC,CAepF"}
|
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
import fetch from 'node-fetch';
|
|
2
|
+
/**
|
|
3
|
+
* HTTPクライアント設定
|
|
4
|
+
*/
|
|
5
|
+
const DEFAULT_HEADERS = {
|
|
6
|
+
'User-Agent': 'NPB-MCP-Server/0.1.0',
|
|
7
|
+
Accept: 'text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8',
|
|
8
|
+
'Accept-Language': 'ja,en;q=0.9',
|
|
9
|
+
};
|
|
10
|
+
/**
|
|
11
|
+
* URLからHTMLを取得
|
|
12
|
+
*/
|
|
13
|
+
export async function fetchHTML(url) {
|
|
14
|
+
try {
|
|
15
|
+
const response = await fetch(url, {
|
|
16
|
+
headers: DEFAULT_HEADERS,
|
|
17
|
+
redirect: 'follow',
|
|
18
|
+
});
|
|
19
|
+
if (!response.ok) {
|
|
20
|
+
throw new Error(`HTTP error! status: ${response.status}`);
|
|
21
|
+
}
|
|
22
|
+
const html = await response.text();
|
|
23
|
+
return html;
|
|
24
|
+
}
|
|
25
|
+
catch (error) {
|
|
26
|
+
if (error instanceof Error) {
|
|
27
|
+
throw new Error(`Failed to fetch ${url}: ${error.message}`);
|
|
28
|
+
}
|
|
29
|
+
throw error;
|
|
30
|
+
}
|
|
31
|
+
}
|
|
32
|
+
/**
|
|
33
|
+
* 複数のURLから並列でHTMLを取得
|
|
34
|
+
*/
|
|
35
|
+
export async function fetchMultipleHTML(urls) {
|
|
36
|
+
const results = new Map();
|
|
37
|
+
const promises = urls.map(async (url) => {
|
|
38
|
+
try {
|
|
39
|
+
const html = await fetchHTML(url);
|
|
40
|
+
results.set(url, html);
|
|
41
|
+
}
|
|
42
|
+
catch (error) {
|
|
43
|
+
console.error(`Error fetching ${url}:`, error);
|
|
44
|
+
// エラーの場合は結果に含めない
|
|
45
|
+
}
|
|
46
|
+
});
|
|
47
|
+
await Promise.all(promises);
|
|
48
|
+
return results;
|
|
49
|
+
}
|
|
50
|
+
//# sourceMappingURL=http.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"http.js","sourceRoot":"","sources":["../../src/utils/http.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,MAAM,YAAY,CAAC;AAE/B;;GAEG;AACH,MAAM,eAAe,GAAG;IACtB,YAAY,EAAE,sBAAsB;IACpC,MAAM,EAAE,iEAAiE;IACzE,iBAAiB,EAAE,aAAa;CACjC,CAAC;AAEF;;GAEG;AACH,MAAM,CAAC,KAAK,UAAU,SAAS,CAAC,GAAW;IACzC,IAAI,CAAC;QACH,MAAM,QAAQ,GAAG,MAAM,KAAK,CAAC,GAAG,EAAE;YAChC,OAAO,EAAE,eAAe;YACxB,QAAQ,EAAE,QAAQ;SACnB,CAAC,CAAC;QAEH,IAAI,CAAC,QAAQ,CAAC,EAAE,EAAE,CAAC;YACjB,MAAM,IAAI,KAAK,CAAC,uBAAuB,QAAQ,CAAC,MAAM,EAAE,CAAC,CAAC;QAC5D,CAAC;QAED,MAAM,IAAI,GAAG,MAAM,QAAQ,CAAC,IAAI,EAAE,CAAC;QACnC,OAAO,IAAI,CAAC;IACd,CAAC;IAAC,OAAO,KAAK,EAAE,CAAC;QACf,IAAI,KAAK,YAAY,KAAK,EAAE,CAAC;YAC3B,MAAM,IAAI,KAAK,CAAC,mBAAmB,GAAG,KAAK,KAAK,CAAC,OAAO,EAAE,CAAC,CAAC;QAC9D,CAAC;QACD,MAAM,KAAK,CAAC;IACd,CAAC;AACH,CAAC;AAED;;GAEG;AACH,MAAM,CAAC,KAAK,UAAU,iBAAiB,CAAC,IAAc;IACpD,MAAM,OAAO,GAAG,IAAI,GAAG,EAAkB,CAAC;IAE1C,MAAM,QAAQ,GAAG,IAAI,CAAC,GAAG,CAAC,KAAK,EAAE,GAAG,EAAE,EAAE;QACtC,IAAI,CAAC;YACH,MAAM,IAAI,GAAG,MAAM,SAAS,CAAC,GAAG,CAAC,CAAC;YAClC,OAAO,CAAC,GAAG,CAAC,GAAG,EAAE,IAAI,CAAC,CAAC;QACzB,CAAC;QAAC,OAAO,KAAK,EAAE,CAAC;YACf,OAAO,CAAC,KAAK,CAAC,kBAAkB,GAAG,GAAG,EAAE,KAAK,CAAC,CAAC;YAC/C,iBAAiB;QACnB,CAAC;IACH,CAAC,CAAC,CAAC;IAEH,MAAM,OAAO,CAAC,GAAG,CAAC,QAAQ,CAAC,CAAC;IAC5B,OAAO,OAAO,CAAC;AACjB,CAAC"}
|
package/package.json
ADDED
|
@@ -0,0 +1,72 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "npb-mcp-server",
|
|
3
|
+
"version": "0.1.0",
|
|
4
|
+
"description": "MCP Server for NPB (Nippon Professional Baseball) player and team information",
|
|
5
|
+
"type": "module",
|
|
6
|
+
"main": "dist/index.js",
|
|
7
|
+
"bin": {
|
|
8
|
+
"npb-mcp-server": "dist/index.js"
|
|
9
|
+
},
|
|
10
|
+
"scripts": {
|
|
11
|
+
"build": "tsc",
|
|
12
|
+
"dev": "tsc --watch",
|
|
13
|
+
"start": "node dist/index.js",
|
|
14
|
+
"start:http": "MCP_TRANSPORT=http node dist/index.js",
|
|
15
|
+
"test": "vitest run",
|
|
16
|
+
"test:watch": "vitest",
|
|
17
|
+
"test:coverage": "vitest run --coverage",
|
|
18
|
+
"lint": "eslint . --ext .ts,.tsx",
|
|
19
|
+
"lint:fix": "eslint . --ext .ts,.tsx --fix",
|
|
20
|
+
"format": "prettier --write \"src/**/*.{ts,tsx,json,md}\"",
|
|
21
|
+
"format:check": "prettier --check \"src/**/*.{ts,tsx,json,md}\"",
|
|
22
|
+
"fix": "run-s format lint:fix",
|
|
23
|
+
"check": "run-p lint format:check test",
|
|
24
|
+
"prepare": "npm run build",
|
|
25
|
+
"release:patch": "npm version patch && git push --follow-tags",
|
|
26
|
+
"release:minor": "npm version minor && git push --follow-tags",
|
|
27
|
+
"release:major": "npm version major && git push --follow-tags"
|
|
28
|
+
},
|
|
29
|
+
"keywords": [
|
|
30
|
+
"mcp",
|
|
31
|
+
"npb",
|
|
32
|
+
"baseball",
|
|
33
|
+
"japan",
|
|
34
|
+
"model-context-protocol",
|
|
35
|
+
"scraping"
|
|
36
|
+
],
|
|
37
|
+
"author": "MITSUBOSHI <yuya.mitsuboshi@gmail.com> (https://github.com/MITSUBOSHI)",
|
|
38
|
+
"license": "MIT",
|
|
39
|
+
"repository": {
|
|
40
|
+
"type": "git",
|
|
41
|
+
"url": "git+https://github.com/MITSUBOSHI/npb-mcp-server.git"
|
|
42
|
+
},
|
|
43
|
+
"homepage": "https://github.com/MITSUBOSHI/npb-mcp-server#readme",
|
|
44
|
+
"bugs": {
|
|
45
|
+
"url": "https://github.com/MITSUBOSHI/npb-mcp-server/issues"
|
|
46
|
+
},
|
|
47
|
+
"files": [
|
|
48
|
+
"dist",
|
|
49
|
+
"README.md"
|
|
50
|
+
],
|
|
51
|
+
"dependencies": {
|
|
52
|
+
"@modelcontextprotocol/sdk": "^1.0.4",
|
|
53
|
+
"cheerio": "^1.0.0",
|
|
54
|
+
"hono": "^4.6.14",
|
|
55
|
+
"@hono/node-server": "^1.13.7",
|
|
56
|
+
"node-fetch": "^3.3.2"
|
|
57
|
+
},
|
|
58
|
+
"devDependencies": {
|
|
59
|
+
"@types/node": "^20.11.0",
|
|
60
|
+
"@typescript-eslint/eslint-plugin": "^8.21.0",
|
|
61
|
+
"@typescript-eslint/parser": "^8.21.0",
|
|
62
|
+
"@vitest/coverage-v8": "^2.1.8",
|
|
63
|
+
"eslint": "^9.18.0",
|
|
64
|
+
"eslint-config-prettier": "^9.1.0",
|
|
65
|
+
"eslint-plugin-prettier": "^5.2.1",
|
|
66
|
+
"globals": "^15.13.0",
|
|
67
|
+
"npm-run-all": "^4.1.5",
|
|
68
|
+
"prettier": "^3.4.2",
|
|
69
|
+
"typescript": "^5.3.3",
|
|
70
|
+
"vitest": "^2.1.8"
|
|
71
|
+
}
|
|
72
|
+
}
|