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
497 changes: 271 additions & 226 deletions package-lock.json

Large diffs are not rendered by default.

4 changes: 2 additions & 2 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@
"start:dev": "tsup --watch --onSuccess \"node ./dist/index.js\""
},
"devDependencies": {
"@biomejs/biome": "2.4.13",
"@biomejs/biome": "2.5.4",
"@types/node": "^22.20.0",
"@types/sql.js": "^1.4.11",
"@vitest/coverage-v8": "^4.1.5",
Expand All @@ -50,7 +50,7 @@
"dependencies": {
"@anthropic-ai/mcpb": "^2.1.2",
"@modelcontextprotocol/sdk": "^1.29.0",
"cdb-converter": "^0.1.2",
"cdb-converter": "^0.2.0",
"sql-query-identifier": "^3.1.1",
"sql.js": "^1.14.1",
"zod": "^3.25.76"
Expand Down
17 changes: 9 additions & 8 deletions test/tools/get-player-info.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -20,13 +20,14 @@
// The official-release fixtures are databases, not played careers, so they
// have no active human player (GAM_user.game_i_active = 1). The tool should
// surface that as a graceful error rather than throwing.
it.each(
saveFixtures,
)("errors when there is no active player for %s", async (name, path) => {
const result = await mcp.callTool("pcm_get_player_info", {
savePath: path,
});
it.each(saveFixtures)(
"errors when there is no active player for %s",
async (name, path) => {

Check warning on line 25 in test/tools/get-player-info.test.ts

View workflow job for this annotation

GitHub Actions / test (22.x)

lint/correctness/noUnusedFunctionParameters

This parameter name is unused.

Check warning on line 25 in test/tools/get-player-info.test.ts

View workflow job for this annotation

GitHub Actions / test (26.x)

lint/correctness/noUnusedFunctionParameters

This parameter name is unused.

Check warning on line 25 in test/tools/get-player-info.test.ts

View workflow job for this annotation

GitHub Actions / test (24.x)

lint/correctness/noUnusedFunctionParameters

This parameter name is unused.
const result = await mcp.callTool("pcm_get_player_info", {
savePath: path,
});

expect(result.isError).toBe(true);
});
expect(result.isError).toBe(true);
},
);
});
21 changes: 11 additions & 10 deletions test/tools/get-table-schema.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -17,15 +17,16 @@
expect(mcp.registerTool).toHaveBeenCalledOnce();
});

it.each(
saveFixtures,
)("returns STA_race table schema for %s", async (name, path) => {
const result = await mcp.callTool("pcm_get_table_schema", {
savePath: path,
tableName: "STA_race",
});
it.each(saveFixtures)(
"returns STA_race table schema for %s",
async (name, path) => {

Check warning on line 22 in test/tools/get-table-schema.test.ts

View workflow job for this annotation

GitHub Actions / test (22.x)

lint/correctness/noUnusedFunctionParameters

This parameter name is unused.

Check warning on line 22 in test/tools/get-table-schema.test.ts

View workflow job for this annotation

GitHub Actions / test (26.x)

lint/correctness/noUnusedFunctionParameters

This parameter name is unused.

Check warning on line 22 in test/tools/get-table-schema.test.ts

View workflow job for this annotation

GitHub Actions / test (24.x)

lint/correctness/noUnusedFunctionParameters

This parameter name is unused.
const result = await mcp.callTool("pcm_get_table_schema", {
savePath: path,
tableName: "STA_race",
});

expect(result.structuredContent).toBeDefined();
expect(result.structuredContent).toMatchSnapshot();
});
expect(result.structuredContent).toBeDefined();
expect(result.structuredContent).toMatchSnapshot();
},
);
});
21 changes: 11 additions & 10 deletions test/tools/get-team-roster.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -17,17 +17,18 @@
expect(mcp.registerTool).toHaveBeenCalledOnce();
});

it.each(
saveFixtures,
)("returns the roster for a given team for %s", async (name, path) => {
const result = await mcp.callTool("pcm_get_team_roster", {
savePath: path,
teamId: 1,
});
it.each(saveFixtures)(
"returns the roster for a given team for %s",
async (name, path) => {

Check warning on line 22 in test/tools/get-team-roster.test.ts

View workflow job for this annotation

GitHub Actions / test (22.x)

lint/correctness/noUnusedFunctionParameters

This parameter name is unused.

Check warning on line 22 in test/tools/get-team-roster.test.ts

View workflow job for this annotation

GitHub Actions / test (26.x)

lint/correctness/noUnusedFunctionParameters

This parameter name is unused.

Check warning on line 22 in test/tools/get-team-roster.test.ts

View workflow job for this annotation

GitHub Actions / test (24.x)

lint/correctness/noUnusedFunctionParameters

This parameter name is unused.
const result = await mcp.callTool("pcm_get_team_roster", {
savePath: path,
teamId: 1,
});

expect(result.structuredContent).toBeDefined();
expect(result.structuredContent).toMatchSnapshot();
});
expect(result.structuredContent).toBeDefined();
expect(result.structuredContent).toMatchSnapshot();
},
);

it("returns an error for an unknown team", async () => {
const result = await mcp.callTool("pcm_get_team_roster", {
Expand Down
58 changes: 30 additions & 28 deletions test/tools/query-save.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -20,34 +20,36 @@ describe("querySave", () => {
expect(mcp.registerTool).toHaveBeenCalledOnce();
});

it.each(
saveFixtures,
)("runs a read-only SELECT against %s", async (_name, path) => {
const result = await mcp.callTool("pcm_query_save", {
savePath: path,
query: "SELECT COUNT(*) AS n FROM STA_race",
});

expect(result.isError).toBeUndefined();
expect(result.structuredContent).toMatchObject({ rowCount: 1 });
});

it.each(
saveFixtures,
)("rejects a WITH … DELETE CTE for %s", async (_name, path) => {
const result = await mcp.callTool("pcm_query_save", {
savePath: path,
query: "WITH x AS (SELECT 1) DELETE FROM STA_race",
});

expect(result.isError).toBe(true);
expect(result.content).toEqual([
{
type: "text",
text: "Only read-only SELECT (or WITH … SELECT) queries are allowed.",
},
]);
});
it.each(saveFixtures)(
"runs a read-only SELECT against %s",
async (_name, path) => {
const result = await mcp.callTool("pcm_query_save", {
savePath: path,
query: "SELECT COUNT(*) AS n FROM STA_race",
});

expect(result.isError).toBeUndefined();
expect(result.structuredContent).toMatchObject({ rowCount: 1 });
},
);

it.each(saveFixtures)(
"rejects a WITH … DELETE CTE for %s",
async (_name, path) => {
const result = await mcp.callTool("pcm_query_save", {
savePath: path,
query: "WITH x AS (SELECT 1) DELETE FROM STA_race",
});

expect(result.isError).toBe(true);
expect(result.content).toEqual([
{
type: "text",
text: "Only read-only SELECT (or WITH … SELECT) queries are allowed.",
},
]);
},
);

describe("assertReadOnlyQuery", () => {
describe("allowed queries", () => {
Expand Down
23 changes: 12 additions & 11 deletions test/tools/search-cyclist.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -17,17 +17,18 @@
expect(mcp.registerTool).toHaveBeenCalledOnce();
});

it.each(
saveFixtures,
)("finds cyclists by last name for %s", async (name, path) => {
const result = await mcp.callTool("pcm_search_cyclist", {
savePath: path,
lastName: "van der",
});

expect(result.structuredContent).toBeDefined();
expect(result.structuredContent).toMatchSnapshot();
});
it.each(saveFixtures)(
"finds cyclists by last name for %s",
async (name, path) => {

Check warning on line 22 in test/tools/search-cyclist.test.ts

View workflow job for this annotation

GitHub Actions / test (22.x)

lint/correctness/noUnusedFunctionParameters

This parameter name is unused.

Check warning on line 22 in test/tools/search-cyclist.test.ts

View workflow job for this annotation

GitHub Actions / test (26.x)

lint/correctness/noUnusedFunctionParameters

This parameter name is unused.

Check warning on line 22 in test/tools/search-cyclist.test.ts

View workflow job for this annotation

GitHub Actions / test (24.x)

lint/correctness/noUnusedFunctionParameters

This parameter name is unused.
const result = await mcp.callTool("pcm_search_cyclist", {
savePath: path,
lastName: "van der",
});

expect(result.structuredContent).toBeDefined();
expect(result.structuredContent).toMatchSnapshot();
},
);

it("caps results at 10 and flags truncation for a broad search", async () => {
const result = await mcp.callTool("pcm_search_cyclist", {
Expand Down
Loading
Loading