Function bodies 451 total
fuzzyMatchList function · typescript · L217-L252 (36 LOC)src/mcp/backfill-server-core.ts
function fuzzyMatchList(input: string | undefined, validOptions: string[]): string[] {
if (!input || !input.trim()) return [];
// Split on commas, semicolons, or " and "
const parts = input
.split(/[,;]|\s+and\s+/i)
.map((s) => s.trim())
.filter(Boolean);
const matched: string[] = [];
for (const part of parts) {
const lower = part.toLowerCase();
// Exact match first
const exact = validOptions.find((opt) => opt.toLowerCase() === lower);
if (exact) {
matched.push(exact);
continue;
}
// Prefix match
const prefix = validOptions.find((opt) => opt.toLowerCase().startsWith(lower));
if (prefix) {
matched.push(prefix);
continue;
}
// Contains match
const contains = validOptions.find((opt) => opt.toLowerCase().includes(lower));
if (contains) {
matched.push(contains);
continue;
}
// Keep original if no match found
matched.push(part);
}
return [...new Set(matched)];
}deriveProgram function · typescript · L264-L276 (13 LOC)src/mcp/backfill-server-core.ts
function deriveProgram(speciesType: string): string {
switch (speciesType) {
case "Fish":
case "Invert":
return "fish";
case "Plant":
return "plant";
case "Coral":
return "coral";
default:
return "fish";
}
}matchSpecies function · typescript · L278-L408 (131 LOC)src/mcp/backfill-server-core.ts
async function matchSpecies(
commonName: string | undefined,
latinName: string | undefined
): Promise<SpeciesMatch | null> {
if (!commonName && !latinName) return null;
// Try exact latin name match first
if (latinName && latinName.trim()) {
const byLatin = await query<{
common_name_id: number;
scientific_name_id: number;
group_id: number;
common_name: string;
scientific_name: string;
base_points: number | null;
program_class: string | null;
}>(
`SELECT
cn.common_name_id,
scin.scientific_name_id,
sng.group_id,
cn.common_name,
scin.scientific_name,
sng.base_points,
sng.program_class
FROM species_scientific_name scin
JOIN species_name_group sng ON scin.group_id = sng.group_id
LEFT JOIN species_common_name cn ON cn.group_id = sng.group_id
WHERE LOWER(scin.scientific_name) = LOWER(?)
LIMIT 1`,
[latinName.trim()]
);
if (byLatihandleParseCsv function · typescript · L429-L470 (42 LOC)src/mcp/backfill-server-core.ts
async function handleParseCsv(args: ParseCsvArgs) {
const { file_path, preview_limit } = args;
const { rows, columns } = await parseCsvFile(file_path);
const displayRows = preview_limit ? rows.slice(0, preview_limit) : rows;
// Per-row field presence diagnostics
const diagnostics = displayRows.map((row, index) => {
const missing: string[] = [];
const present: string[] = [];
for (const col of columns) {
if (!row[col] || !row[col].trim()) {
missing.push(col);
} else {
present.push(col);
}
}
return { row_index: index, present_count: present.length, missing_fields: missing };
});
return {
content: [
{
type: "text" as const,
text: JSON.stringify(
{
success: true,
file_path,
total_rows: rows.length,
columns,
column_count: columns.length,
displayed_rows: displayRows.length,
rows: displayRows,
handleValidateImport function · typescript · L472-L613 (142 LOC)src/mcp/backfill-server-core.ts
async function handleValidateImport(args: ValidateImportArgs) {
const { file_path, member_id, admin_id, default_points } = args;
const { rows } = await parseCsvFile(file_path);
// Resolve member if member_id provided
let resolvedMember: { id: number; display_name: string } | null = null;
if (member_id) {
const members = await query<{ id: number; display_name: string }>(
"SELECT id, display_name FROM members WHERE id = ?",
[member_id]
);
if (members.length > 0) {
resolvedMember = members[0];
}
}
const validations: RowValidation[] = [];
let readyCount = 0;
let attentionCount = 0;
for (let i = 0; i < rows.length; i++) {
const row = rows[i];
const warnings: string[] = [];
// Member resolution
let rowMemberId: number | null = resolvedMember?.id ?? null;
let rowMemberName: string | null = resolvedMember?.display_name ?? null;
if (!rowMemberId && row.member_name) {
const memberMatches = await query<{ id: handleSearchMember function · typescript · L874-L929 (56 LOC)src/mcp/backfill-server-core.ts
async function handleSearchMember(args: SearchMemberArgs) {
const { name, email } = args;
const conditions: string[] = [];
const params: string[] = [];
if (name) {
conditions.push("LOWER(display_name) LIKE LOWER(?)");
params.push(`%${name.trim()}%`);
}
if (email) {
conditions.push("LOWER(contact_email) LIKE LOWER(?)");
params.push(`%${email.trim()}%`);
}
if (conditions.length === 0) {
throw new Error("Provide at least name or email");
}
const results = await query<{
id: number;
display_name: string;
contact_email: string;
is_admin: number;
}>(
`SELECT id, display_name, contact_email, is_admin
FROM members
WHERE ${conditions.join(" OR ")}
ORDER BY display_name
LIMIT 20`,
params
);
return {
content: [
{
type: "text" as const,
text: JSON.stringify(
{
success: true,
count: results.length,
members: results.map((m) => ({
handleSearchSpecies function · typescript · L931-L999 (69 LOC)src/mcp/backfill-server-core.ts
async function handleSearchSpecies(args: SearchSpeciesArgs) {
const { query: searchQuery, species_type } = args;
if (!searchQuery || searchQuery.trim().length < 2) {
throw new Error("Query must be at least 2 characters");
}
const pattern = `%${searchQuery.trim()}%`;
const typeCondition = species_type
? "AND sng.species_type = ?"
: "";
const typeParams = species_type ? [species_type] : [];
const results = await query<{
group_id: number;
common_name_id: number;
scientific_name_id: number;
common_name: string;
scientific_name: string;
program_class: string;
species_type: string;
base_points: number | null;
}>(
`SELECT DISTINCT
sng.group_id,
cn.common_name_id,
scin.scientific_name_id,
cn.common_name,
scin.scientific_name,
sng.program_class,
sng.species_type,
sng.base_points
FROM species_name_group sng
LEFT JOIN species_common_name cn ON cn.group_id = sng.group_id
Repobility · severity-and-effort ranking · https://repobility.com
handleListCsvFiles function · typescript · L1001-L1038 (38 LOC)src/mcp/backfill-server-core.ts
async function handleListCsvFiles(args: ListCsvFilesArgs) {
const { directory_path } = args;
const entries = await readdir(directory_path);
const csvFiles: Array<{ name: string; path: string; size: number }> = [];
for (const entry of entries) {
if (extname(entry).toLowerCase() === ".csv") {
const fullPath = join(directory_path, entry);
const stats = await stat(fullPath);
csvFiles.push({
name: entry,
path: fullPath,
size: stats.size,
});
}
}
csvFiles.sort((a, b) => a.name.localeCompare(b.name));
return {
content: [
{
type: "text" as const,
text: JSON.stringify(
{
success: true,
directory: directory_path,
count: csvFiles.length,
files: csvFiles,
},
null,
2
),
},
],
};
}createSpeciesServer function · typescript · L38-L54 (17 LOC)src/mcp/http-server.ts
function createSpeciesServer(): Server {
const server = new Server(
{
name: "species-database",
version: "1.0.0",
},
{
capabilities: {
resources: {},
tools: {},
},
}
);
initializeSpeciesServer(server);
return server;
}createMemberServer function · typescript · L59-L75 (17 LOC)src/mcp/http-server.ts
function createMemberServer(): Server {
const server = new Server(
{
name: "member-management",
version: "1.0.0",
},
{
capabilities: {
resources: {},
tools: {},
},
}
);
initializeMemberServer(server);
return server;
}createBackfillServer function · typescript · L80-L96 (17 LOC)src/mcp/http-server.ts
function createBackfillServer(): Server {
const server = new Server(
{
name: "backfill",
version: "1.0.0",
},
{
capabilities: {
resources: {},
tools: {},
},
}
);
initializeBackfillServer(server);
return server;
}createMcpHandler function · typescript · L101-L166 (66 LOC)src/mcp/http-server.ts
function createMcpHandler(
serverName: string,
transports: Record<string, StreamableHTTPServerTransport>,
createServer: () => Server
) {
return async (req: Request, res: Response) => {
const sessionId = req.headers["mcp-session-id"] as string | undefined;
try {
let transport: StreamableHTTPServerTransport;
if (sessionId && transports[sessionId]) {
// Reuse existing transport for this session
transport = transports[sessionId];
await transport.handleRequest(req, res, req.body);
} else if (!sessionId && isInitializeRequest(req.body)) {
// New initialization request - create new transport and session
logger.info(`${serverName} MCP client initializing new session [${domain}]`);
transport = new StreamableHTTPServerTransport({
sessionIdGenerator: () => randomUUID(),
onsessioninitialized: (sid) => {
logger.info(`${serverName} session initialized: ${sid}`);
transportsstartMcpHttpServer function · typescript · L171-L249 (79 LOC)src/mcp/http-server.ts
export async function startMcpHttpServer(): Promise<void> {
if (!config.mcp?.enabled) {
logger.info("MCP HTTP server disabled in config");
return;
}
const mcpPort = config.mcp.port || 3001;
const mcpHost = config.mcp.host || "127.0.0.1";
const app = express();
app.use(express.json());
// Health check endpoint
app.get("/health", (_req, res) => {
res.json({
status: "ok",
domain,
database: dbName,
databasePath: dbPath,
servers: ["species", "members", "backfill"],
});
});
// Species MCP Server - POST for main communication
const speciesHandler = createMcpHandler(
"Species",
speciesTransports,
createSpeciesServer
);
app.post("/mcp/species", speciesHandler);
app.get("/mcp/species", speciesHandler); // Also support GET for SSE
// Member Management MCP Server - POST for main communication
const memberHandler = createMcpHandler(
"Members",
memberTransports,
createMemberServer
);
app.pstopMcpHttpServer function · typescript · L254-L297 (44 LOC)src/mcp/http-server.ts
export async function stopMcpHttpServer(): Promise<void> {
// Close all active transports
for (const sessionId in speciesTransports) {
try {
await speciesTransports[sessionId].close();
delete speciesTransports[sessionId];
} catch (error) {
logger.error(`Error closing species transport ${sessionId}:`, error);
}
}
for (const sessionId in memberTransports) {
try {
await memberTransports[sessionId].close();
delete memberTransports[sessionId];
} catch (error) {
logger.error(`Error closing member transport ${sessionId}:`, error);
}
}
for (const sessionId in backfillTransports) {
try {
await backfillTransports[sessionId].close();
delete backfillTransports[sessionId];
} catch (error) {
logger.error(`Error closing backfill transport ${sessionId}:`, error);
}
}
// Close HTTP server
if (serverInstance) {
return new Promise((resolve, reject) => {
serverInstance?.close((err) => {handleListMembers function · typescript · L353-L412 (60 LOC)src/mcp/member-server-core.ts
async function handleListMembers(args: ListMembersArgs) {
const { query: searchQuery, is_admin, has_submissions, limit = 100, offset = 0 } = args;
const conditions: string[] = ["1=1"];
const params: (string | number)[] = [];
if (is_admin !== undefined) {
conditions.push("m.is_admin = ?");
params.push(is_admin ? 1 : 0);
}
if (searchQuery && typeof searchQuery === 'string' && searchQuery.trim().length >= 2) {
const searchPattern = `%${searchQuery.trim().toLowerCase()}%`;
conditions.push("(LOWER(m.display_name) LIKE ? OR LOWER(m.contact_email) LIKE ?)");
params.push(searchPattern, searchPattern);
}
let sql = `
SELECT m.*, COUNT(s.id) as submission_count
FROM members m
LEFT JOIN submissions s ON m.id = s.member_id AND s.approved_on IS NOT NULL
WHERE ${conditions.join(" AND ")}
GROUP BY m.id
`;
if (has_submissions !== undefined) {
sql += has_submissions ? " HAVING submission_count > 0" : " HAVING submission_count = 0";
}If a scraper extracted this row, it came from Repobility (https://repobility.com)
handleGetMemberDetail function · typescript · L414-L506 (93 LOC)src/mcp/member-server-core.ts
async function handleGetMemberDetail(args: GetMemberDetailArgs) {
const { member_id } = args;
const members = await query<Member>("SELECT * FROM members WHERE id = ?", [member_id]);
if (members.length === 0) {
throw new Error(`Member ${member_id} not found`);
}
const member = members[0];
// Get submission counts
const submissions = await query<{ count: number }>(
"SELECT COUNT(*) as count FROM submissions WHERE member_id = ?",
[member_id]
);
const approvedSubmissions = await query<{ count: number }>(
"SELECT COUNT(*) as count FROM submissions WHERE member_id = ? AND approved_on IS NOT NULL",
[member_id]
);
const totalPoints = await query<{ total: number }>(
`
SELECT SUM(
points +
IFNULL(article_points, 0) +
(IFNULL(first_time_species, 0) * 5) +
(IFNULL(flowered, 0) * points) +
(IFNULL(sexual_reproduction, 0) * points)
) as total
FROM submissions
WHERE member_id = ? AND approved_on IS NOT NhandleMergeMembers function · typescript · L508-L635 (128 LOC)src/mcp/member-server-core.ts
async function handleMergeMembers(args: MergeMembersArgs) {
const { from_member_id, to_member_id, preview } = args;
if (from_member_id === to_member_id) {
throw new Error("Cannot merge a member into itself");
}
// Get both members
const fromMembers = await query<Member>("SELECT * FROM members WHERE id = ?", [from_member_id]);
const toMembers = await query<Member>("SELECT * FROM members WHERE id = ?", [to_member_id]);
if (fromMembers.length === 0) {
throw new Error(`Source member ${from_member_id} not found`);
}
if (toMembers.length === 0) {
throw new Error(`Destination member ${to_member_id} not found`);
}
const fromMember = fromMembers[0];
const toMember = toMembers[0];
// Get counts for preview
const submissionCount = await query<{ count: number }>(
"SELECT COUNT(*) as count FROM submissions WHERE member_id = ?",
[from_member_id]
);
const awardCount = await query<{ count: number }>(
"SELECT COUNT(*) as count FROM awards WHhandleUpdateMember function · typescript · L637-L687 (51 LOC)src/mcp/member-server-core.ts
async function handleUpdateMember(args: UpdateMemberArgs) {
const { member_id, contact_email, display_name } = args;
const updates: string[] = [];
const values: (string | number)[] = [];
if (contact_email !== undefined && typeof contact_email === 'string') {
updates.push("contact_email = ?");
values.push(contact_email.trim());
}
if (display_name !== undefined && typeof display_name === 'string') {
updates.push("display_name = ?");
values.push(display_name.trim());
}
if (updates.length === 0) {
throw new Error("No fields to update");
}
values.push(member_id);
await withTransaction(async (db) => {
const stmt = await db.prepare(`
UPDATE members
SET ${updates.join(", ")}
WHERE id = ?
`);
await stmt.run(...values);
await stmt.finalize();
});
// Fetch updated member
const updated = await query<Member>("SELECT * FROM members WHERE id = ?", [member_id]);
return {
content: [
{
type: "texhandleDeleteMember function · typescript · L689-L747 (59 LOC)src/mcp/member-server-core.ts
async function handleDeleteMember(args: DeleteMemberArgs) {
const { member_id, force } = args;
// Check if member exists
const members = await query<Member>("SELECT * FROM members WHERE id = ?", [member_id]);
if (members.length === 0) {
throw new Error(`Member ${member_id} not found`);
}
// Check for approved submissions
const approvedSubmissions = await query<{ count: number }>(
"SELECT COUNT(*) as count FROM submissions WHERE member_id = ? AND approved_on IS NOT NULL",
[member_id]
);
const approvedCount = approvedSubmissions[0]?.count || 0;
if (approvedCount > 0 && !force) {
throw new Error(
`Member has ${approvedCount} approved submissions. Use force: true to delete anyway.`
);
}
// Get submission count before delete
const allSubmissions = await query<{ count: number }>(
"SELECT COUNT(*) as count FROM submissions WHERE member_id = ?",
[member_id]
);
const submissionCount = allSubmissions[0]?.count || 0;
await whandleSetAdminStatus function · typescript · L749-L781 (33 LOC)src/mcp/member-server-core.ts
async function handleSetAdminStatus(args: SetAdminStatusArgs) {
const { member_id, is_admin } = args;
const members = await query<Member>("SELECT * FROM members WHERE id = ?", [member_id]);
if (members.length === 0) {
throw new Error(`Member ${member_id} not found`);
}
await withTransaction(async (db) => {
const stmt = await db.prepare("UPDATE members SET is_admin = ? WHERE id = ?");
await stmt.run(is_admin ? 1 : 0, member_id);
await stmt.finalize();
});
return {
content: [
{
type: "text" as const,
text: JSON.stringify(
{
success: true,
member_id,
display_name: members[0].display_name,
is_admin,
message: `Admin status ${is_admin ? "granted" : "revoked"}`,
},
null,
2
),
},
],
};
}formatSpeciesGroup function · typescript · L204-L214 (11 LOC)src/mcp/species-server-core.ts
async function formatSpeciesGroup(group: SpeciesNameGroup): Promise<{
group_id: number;
program_class: string;
canonical_genus: string;
canonical_species_name: string;
species_type: string;
base_points: number | null;
is_cares_species: boolean;
external_references: string[];
image_links: string[];
}> {handleCreateSpeciesGroup function · typescript · L1112-L1147 (36 LOC)src/mcp/species-server-core.ts
async function handleCreateSpeciesGroup(args: CreateSpeciesGroupArgs) {
const {
program_class,
canonical_genus,
canonical_species_name,
species_type,
base_points,
is_cares_species,
} = args;
const group_id = await createSpeciesGroup({
programClass: program_class,
speciesType: species_type,
canonicalGenus: canonical_genus,
canonicalSpeciesName: canonical_species_name,
basePoints: base_points,
isCaresSpecies: is_cares_species,
});
return {
content: [
{
type: "text" as const,
text: JSON.stringify(
{
success: true,
group_id,
message: "Species group created successfully",
},
null,
2
),
},
],
};
}handleUpdateSpeciesGroup function · typescript · L1149-L1178 (30 LOC)src/mcp/species-server-core.ts
async function handleUpdateSpeciesGroup(args: UpdateSpeciesGroupArgs) {
const { group_id, program_class, base_points, is_cares_species, external_references, image_links } = args;
const changes = await updateSpeciesGroup(group_id, {
programClass: program_class,
basePoints: base_points,
isCaresSpecies: is_cares_species,
externalReferences: external_references,
imageLinks: image_links,
});
return {
content: [
{
type: "text" as const,
text: JSON.stringify(
{
success: true,
group_id,
changes,
updated_fields: Object.keys(args).filter((k) => k !== "group_id"),
message: changes > 0 ? "Species group updated successfully" : "Species group not found",
},
null,
2
),
},
],
};
}Repobility · code-quality intelligence platform · https://repobility.com
handleDeleteSpeciesGroup function · typescript · L1180-L1202 (23 LOC)src/mcp/species-server-core.ts
async function handleDeleteSpeciesGroup(args: DeleteSpeciesGroupArgs) {
const { group_id, force } = args;
const changes = await deleteSpeciesGroup(group_id, force);
return {
content: [
{
type: "text" as const,
text: JSON.stringify(
{
success: true,
group_id,
changes,
message: changes > 0 ? "Species group deleted successfully" : "Species group not found",
},
null,
2
),
},
],
};
}handleAddSpeciesSynonym function · typescript · L1204-L1226 (23 LOC)src/mcp/species-server-core.ts
async function handleAddSpeciesSynonym(args: AddSpeciesSynonymArgs) {
const { group_id, common_name, scientific_name } = args;
const name_id = await addSynonym(group_id, common_name, scientific_name);
return {
content: [
{
type: "text" as const,
text: JSON.stringify(
{
success: true,
name_id,
group_id,
message: "Synonym added successfully",
},
null,
2
),
},
],
};
}handleUpdateSpeciesSynonym function · typescript · L1228-L1253 (26 LOC)src/mcp/species-server-core.ts
async function handleUpdateSpeciesSynonym(args: UpdateSpeciesSynonymArgs) {
const { name_id, common_name, scientific_name } = args;
const changes = await updateSynonym(name_id, {
commonName: common_name,
scientificName: scientific_name,
});
return {
content: [
{
type: "text" as const,
text: JSON.stringify(
{
success: true,
name_id,
changes,
message: changes > 0 ? "Synonym updated successfully" : "Synonym not found",
},
null,
2
),
},
],
};
}handleDeleteSpeciesSynonym function · typescript · L1255-L1277 (23 LOC)src/mcp/species-server-core.ts
async function handleDeleteSpeciesSynonym(args: DeleteSpeciesSynonymArgs) {
const { name_id, force } = args;
const changes = await deleteSynonym(name_id, force);
return {
content: [
{
type: "text" as const,
text: JSON.stringify(
{
success: true,
name_id,
changes,
message: changes > 0 ? "Synonym deleted successfully" : "Synonym not found",
},
null,
2
),
},
],
};
}handleListCommonNamesByText function · typescript · L1279-L1301 (23 LOC)src/mcp/species-server-core.ts
async function handleListCommonNamesByText(args: ListCommonNamesByTextArgs) {
const { common_name, limit } = args;
const results = await getCommonNamesByText(common_name, limit);
return {
content: [
{
type: "text" as const,
text: JSON.stringify(
{
success: true,
common_name,
count: results.length,
results,
},
null,
2
),
},
],
};
}handleDeleteCommonNameById function · typescript · L1303-L1325 (23 LOC)src/mcp/species-server-core.ts
async function handleDeleteCommonNameById(args: DeleteCommonNameByIdArgs) {
const { common_name_id } = args;
const changes = await deleteCommonName(common_name_id);
return {
content: [
{
type: "text" as const,
text: JSON.stringify(
{
success: true,
common_name_id,
changes,
message: changes > 0 ? "Common name deleted successfully" : "Common name not found",
},
null,
2
),
},
],
};
}handleBulkDeleteCommonNames function · typescript · L1327-L1362 (36 LOC)src/mcp/species-server-core.ts
async function handleBulkDeleteCommonNames(args: BulkDeleteCommonNamesArgs) {
const { common_name, common_name_ids, preview = false } = args;
// Validate that we have either common_name or common_name_ids
if (!common_name && !common_name_ids) {
throw new Error("Must provide either 'common_name' or 'common_name_ids'");
}
if (common_name && common_name_ids) {
throw new Error("Cannot provide both 'common_name' and 'common_name_ids'");
}
const options = common_name ? { commonName: common_name } : { commonNameIds: common_name_ids! };
const result = await bulkDeleteCommonNames(options, preview);
return {
content: [
{
type: "text" as const,
text: JSON.stringify(
{
success: true,
preview,
count: result.count,
...(result.preview && { preview_results: result.preview }),
message: preview
? `Preview: Would delete ${result.count} common name(s)`
:handleMergeSpeciesGroups function · typescript · L1364-L1457 (94 LOC)src/mcp/species-server-core.ts
async function handleMergeSpeciesGroups(args: MergeSpeciesGroupsArgs) {
const { canonical_group_id, defunct_group_id, preview } = args;
if (canonical_group_id === defunct_group_id) {
throw new Error("Cannot merge a species with itself");
}
// Get both groups
const groups = await query<SpeciesNameGroup>(
"SELECT * FROM species_name_group WHERE group_id IN (?, ?)",
[canonical_group_id, defunct_group_id]
);
if (groups.length !== 2) {
throw new Error("One or both species groups not found");
}
const canonical = groups.find((g) => g.group_id === canonical_group_id);
const defunct = groups.find((g) => g.group_id === defunct_group_id);
// Get synonyms to move (from both split tables)
const commonNamesToMove = await query<{ common_name_id: number; common_name: string }>(
"SELECT * FROM species_common_name WHERE group_id = ?",
[defunct_group_id]
);
const scientificNamesToMove = await query<{ scientific_name_id: number; scientific_name: strAll rows above produced by Repobility · https://repobility.com
handleSearchSpecies function · typescript · L1459-L1528 (70 LOC)src/mcp/species-server-core.ts
async function handleSearchSpecies(args: SearchSpeciesArgs) {
const {
query: searchQuery,
species_type,
program_class,
has_base_points,
is_cares_species,
sort_by = "name",
limit = 100,
offset = 0,
count_only = false,
} = args;
const filters: SpeciesAdminFilters = {
species_type,
program_class,
has_base_points,
is_cares_species,
search: searchQuery,
};
const result = await getSpeciesForAdmin(filters, sort_by as "name" | "points" | "class" | undefined, limit, offset);
// If count_only is true, return just the count
if (count_only) {
return {
content: [
{
type: "text" as const,
text: JSON.stringify(
{
success: true,
total_count: result.total_count,
count_only: true,
},
null,
2
),
},
],
};
}
return {
content: [
{
type: "text" as const,
handleGetSpeciesDetail function · typescript · L1530-L1554 (25 LOC)src/mcp/species-server-core.ts
async function handleGetSpeciesDetail(args: GetSpeciesDetailArgs) {
const { group_id } = args;
const speciesDetail = await getSpeciesDetail(group_id);
if (!speciesDetail) {
throw new Error(`Species group ${group_id} not found`);
}
return {
content: [
{
type: "text" as const,
text: JSON.stringify(
{
success: true,
species: speciesDetail,
},
null,
2
),
},
],
};
}handleSetBasePoints function · typescript · L1556-L1657 (102 LOC)src/mcp/species-server-core.ts
async function handleSetBasePoints(args: SetBasePointsArgs) {
const { group_id, group_ids, species_type, program_class, base_points, preview } = args;
// Determine which species to update
let targetGroupIds: number[] = [];
if (group_id) {
targetGroupIds = [group_id];
} else if (group_ids && group_ids.length > 0) {
targetGroupIds = group_ids;
} else if (species_type || program_class) {
// Query to get group_ids matching filters
const filters: SpeciesAdminFilters = { species_type, program_class };
const result = await getSpeciesForAdmin(filters, "name", 10000, 0);
targetGroupIds = result.species.map((s) => s.group_id);
} else {
throw new Error("Must provide group_id, group_ids, or species_type/program_class filter");
}
if (targetGroupIds.length === 0) {
return {
content: [
{
type: "text" as const,
text: JSON.stringify(
{
success: true,
updated_count: 0,
handleToggleCaresStatus function · typescript · L1659-L1684 (26 LOC)src/mcp/species-server-core.ts
async function handleToggleCaresStatus(args: ToggleCaresStatusArgs) {
const { group_id, is_cares_species } = args;
const changes = await updateSpeciesGroup(group_id, {
isCaresSpecies: is_cares_species,
});
return {
content: [
{
type: "text" as const,
text: JSON.stringify(
{
success: true,
group_id,
changes,
is_cares_species,
message: changes > 0 ? "CARES status updated" : "Species group not found",
},
null,
2
),
},
],
};
}handleUpdateCanonicalName function · typescript · L1686-L1779 (94 LOC)src/mcp/species-server-core.ts
async function handleUpdateCanonicalName(args: UpdateCanonicalNameArgs) {
const {
group_id,
new_canonical_genus,
new_canonical_species_name,
preserve_old_as_synonym = true,
} = args;
if (!new_canonical_genus && !new_canonical_species_name) {
throw new Error("At least one new field must be provided");
}
const groups = await query<SpeciesNameGroup>(
"SELECT * FROM species_name_group WHERE group_id = ?",
[group_id]
);
if (groups.length === 0) {
throw new Error(`Species group ${group_id} not found`);
}
const oldGroup = groups[0];
const oldCanonicalName = `${oldGroup.canonical_genus} ${oldGroup.canonical_species_name}`;
await withTransaction(async (db) => {
// Update canonical name
const updates: string[] = [];
const values: (string | number)[] = [];
if (new_canonical_genus) {
updates.push("canonical_genus = ?");
values.push(new_canonical_genus.trim());
}
if (new_canonical_species_name) {
uhandleSyncIucnData function · typescript · L1785-L1928 (144 LOC)src/mcp/species-server-core.ts
async function handleSyncIucnData(args: SyncIucnDataArgs) {
const { group_id, group_ids, sync_missing, days_old, limit = 10, preview = false } = args;
const database = db(true); // Write access for IUCN data updates
let targetSpecies: { group_id: number; canonical_genus: string; canonical_species_name: string }[] = [];
// Determine which species to sync
if (group_id) {
const species = await query<{ group_id: number; canonical_genus: string; canonical_species_name: string }>(
"SELECT group_id, canonical_genus, canonical_species_name FROM species_name_group WHERE group_id = ?",
[group_id]
);
if (species.length === 0) {
throw new Error(`Species group ${group_id} not found`);
}
targetSpecies = species;
} else if (group_ids && group_ids.length > 0) {
targetSpecies = await query<{ group_id: number; canonical_genus: string; canonical_species_name: string }>(
`SELECT group_id, canonical_genus, canonical_species_name FROM species_namhandleGetIucnSyncLog function · typescript · L1930-L1952 (23 LOC)src/mcp/species-server-core.ts
async function handleGetIucnSyncLog(args: GetIucnSyncLogArgs) {
const { group_id, limit = 100 } = args;
const database = db();
const log = await getIucnSyncLog(database, group_id, limit);
return {
content: [
{
type: "text" as const,
text: JSON.stringify(
{
success: true,
total_entries: log.length,
log_entries: log,
},
null,
2
),
},
],
};
}handleGetSpeciesMissingIucn function · typescript · L1954-L1974 (21 LOC)src/mcp/species-server-core.ts
async function handleGetSpeciesMissingIucn() {
const database = db();
const missing = await getSpeciesWithMissingIucn(database);
return {
content: [
{
type: "text" as const,
text: JSON.stringify(
{
success: true,
total_count: missing.length,
species: missing,
},
null,
2
),
},
],
};
}Repobility · severity-and-effort ranking · https://repobility.com
handleGetSpeciesNeedingResync function · typescript · L1976-L1999 (24 LOC)src/mcp/species-server-core.ts
async function handleGetSpeciesNeedingResync(args: GetSpeciesNeedingResyncArgs) {
const { days_old = 365 } = args;
const database = db();
const needingResync = await getSpeciesNeedingResync(database, days_old);
return {
content: [
{
type: "text" as const,
text: JSON.stringify(
{
success: true,
total_count: needingResync.length,
days_old_threshold: days_old,
species: needingResync,
},
null,
2
),
},
],
};
}handleGetIucnSyncStats function · typescript · L2001-L2020 (20 LOC)src/mcp/species-server-core.ts
async function handleGetIucnSyncStats() {
const database = db();
const stats = await getIucnSyncStats(database);
return {
content: [
{
type: "text" as const,
text: JSON.stringify(
{
success: true,
stats,
},
null,
2
),
},
],
};
}handleGetCanonicalRecommendations function · typescript · L2026-L2064 (39 LOC)src/mcp/species-server-core.ts
async function handleGetCanonicalRecommendations(args: GetCanonicalRecommendationsArgs) {
const { group_id, status, limit } = args;
const database = db();
const recommendations = await getCanonicalRecommendations(database, {
groupId: group_id,
status,
limit,
});
return {
content: [
{
type: "text" as const,
text: JSON.stringify(
{
success: true,
total_count: recommendations.length,
recommendations: recommendations.map((rec) => ({
id: rec.id,
group_id: rec.group_id,
current_name: `${rec.current_canonical_genus} ${rec.current_canonical_species}`,
suggested_name: `${rec.suggested_canonical_genus} ${rec.suggested_canonical_species}`,
iucn_taxon_id: rec.iucn_taxon_id,
iucn_url: rec.iucn_url,
reason: rec.reason,
status: rec.status,
created_at: rec.created_at,
rhandleAcceptCanonicalRecommendation function · typescript · L2066-L2090 (25 LOC)src/mcp/species-server-core.ts
async function handleAcceptCanonicalRecommendation(args: AcceptCanonicalRecommendationArgs) {
const { recommendation_id, reviewed_by } = args;
const database = db(true); // Write access
const success = await acceptCanonicalRecommendation(database, recommendation_id, reviewed_by);
return {
content: [
{
type: "text" as const,
text: JSON.stringify(
{
success,
recommendation_id,
reviewed_by,
message: "Canonical name recommendation accepted and applied successfully",
},
null,
2
),
},
],
};
}handleRejectCanonicalRecommendation function · typescript · L2092-L2116 (25 LOC)src/mcp/species-server-core.ts
async function handleRejectCanonicalRecommendation(args: RejectCanonicalRecommendationArgs) {
const { recommendation_id, reviewed_by } = args;
const database = db(true); // Write access
const success = await rejectCanonicalRecommendation(database, recommendation_id, reviewed_by);
return {
content: [
{
type: "text" as const,
text: JSON.stringify(
{
success,
recommendation_id,
reviewed_by,
message: "Canonical name recommendation rejected successfully",
},
null,
2
),
},
],
};
}getUploadRateLimiters function · typescript · L173-L179 (7 LOC)src/middleware/rateLimiter.ts
export function getUploadRateLimiters() {
return [
strictUploadLimiter, // First check unauthenticated limits
uploadRateLimiter, // Then check per-minute limits
dailyUploadLimiter, // Finally check daily limits
];
}onSubmissionSend function · typescript · L27-L47 (21 LOC)src/notifications.ts
export async function onSubmissionSend(sub: Submission, member: MemberRecord) {
if (EMAILS_DISABLED) {
logger.info("Email disabled - would have sent submission confirmation", { submissionId: sub.id });
return;
}
const admins = await getAdminEmails();
return transporter.sendMail({
from: fromEmail,
to: member.contact_email,
cc: admins,
bcc: DEBUG_EMAIL,
subject: `Submission Confirmation - ${sub.species_common_name}`,
html: renderOnSubmission({
domain: config.server.domain,
submission: sub,
member,
}),
});
}sendChangesRequest function · typescript · L49-L65 (17 LOC)src/notifications.ts
export async function sendChangesRequest(sub: Submission, contact_email: string, content: string) {
if (EMAILS_DISABLED) {
logger.info("Email disabled - would have sent changes request", { submissionId: sub.id });
return;
}
const admins = await getAdminEmails();
return transporter.sendMail({
from: fromEmail,
to: contact_email,
cc: admins,
bcc: DEBUG_EMAIL,
subject: `Changes Requested - ${sub.species_common_name}`,
text: content,
});
}If a scraper extracted this row, it came from Repobility (https://repobility.com)
onChangesRequested function · typescript · L68-L94 (27 LOC)src/notifications.ts
export async function onChangesRequested(
submission: Submission,
member: MemberRecord,
reason: string
) {
if (EMAILS_DISABLED) {
logger.info("Email disabled - would have sent changes requested", { submissionId: submission.id });
return;
}
const admins = await getAdminEmails();
return transporter.sendMail({
from: fromEmail,
to: member.contact_email,
cc: admins,
bcc: DEBUG_EMAIL,
subject: `Changes Requested - ${submission.species_common_name}`,
html: renderOnChangesRequested({
domain: config.server.domain,
submission,
member,
reason,
programContactEmail: config.email.adminsEmail,
}),
});
}onSubmissionApprove function · typescript · L97-L114 (18 LOC)src/notifications.ts
export async function onSubmissionApprove(sub: Submission, member: MemberRecord) {
if (EMAILS_DISABLED) {
logger.info("Email disabled - would have sent submission approval", { submissionId: sub.id });
return;
}
return transporter.sendMail({
from: fromEmail,
to: member.contact_email,
bcc: DEBUG_EMAIL,
subject: `Submission Approved! - ${sub.species_common_name}`,
html: renderOnApprove({
domain: config.server.domain,
submission: sub,
member,
}),
});
}sendResetEmail function · typescript · L117-L134 (18 LOC)src/notifications.ts
export async function sendResetEmail(email: string, display_name: string, code: string) {
if (EMAILS_DISABLED) {
logger.info("Email disabled - would have sent password reset", { email });
return;
}
return transporter.sendMail({
from: fromEmail,
to: email,
subject: "Reset Password",
html: renderResetEmail({
domain: config.server.domain,
display_name,
code,
programContactEmail: config.email.adminsEmail,
}),
});
}