sc-elections-mcp 0.5.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 +187 -0
- package/dist/api/ethics-client.d.ts +45 -0
- package/dist/api/ethics-client.js +662 -0
- package/dist/api/ethics-client.js.map +1 -0
- package/dist/api/vrems-client.d.ts +18 -0
- package/dist/api/vrems-client.js +93 -0
- package/dist/api/vrems-client.js.map +1 -0
- package/dist/index.d.ts +2 -0
- package/dist/index.js +30 -0
- package/dist/index.js.map +1 -0
- package/dist/parsers/candidate-detail.d.ts +12 -0
- package/dist/parsers/candidate-detail.js +112 -0
- package/dist/parsers/candidate-detail.js.map +1 -0
- package/dist/parsers/candidate-search.d.ts +6 -0
- package/dist/parsers/candidate-search.js +39 -0
- package/dist/parsers/candidate-search.js.map +1 -0
- package/dist/parsers/csv-export.d.ts +5 -0
- package/dist/parsers/csv-export.js +81 -0
- package/dist/parsers/csv-export.js.map +1 -0
- package/dist/tools/campaign.d.ts +2 -0
- package/dist/tools/campaign.js +191 -0
- package/dist/tools/campaign.js.map +1 -0
- package/dist/tools/cross-search.d.ts +26 -0
- package/dist/tools/cross-search.js +219 -0
- package/dist/tools/cross-search.js.map +1 -0
- package/dist/tools/overlap.d.ts +25 -0
- package/dist/tools/overlap.js +201 -0
- package/dist/tools/overlap.js.map +1 -0
- package/dist/tools/search.d.ts +2 -0
- package/dist/tools/search.js +146 -0
- package/dist/tools/search.js.map +1 -0
- package/dist/tools/sei.d.ts +2 -0
- package/dist/tools/sei.js +99 -0
- package/dist/tools/sei.js.map +1 -0
- package/dist/tools/vrems.d.ts +2 -0
- package/dist/tools/vrems.js +138 -0
- package/dist/tools/vrems.js.map +1 -0
- package/dist/types.d.ts +430 -0
- package/dist/types.js +5 -0
- package/dist/types.js.map +1 -0
- package/package.json +46 -0
|
@@ -0,0 +1,201 @@
|
|
|
1
|
+
import { z } from 'zod';
|
|
2
|
+
import { cachedGetCampaignSummary, resolveCampaignContext, resolveCandidateName, getContributions, searchFilersByOffice, groupFilersByPerson } from '../api/ethics-client.js';
|
|
3
|
+
async function fetchCandidateContributions(candidateFilerId, campaignId, officeHint) {
|
|
4
|
+
try {
|
|
5
|
+
const summary = await cachedGetCampaignSummary(candidateFilerId);
|
|
6
|
+
// Resolve candidate name when summary.name is null
|
|
7
|
+
let candidateNameOverride;
|
|
8
|
+
if (!summary.name) {
|
|
9
|
+
candidateNameOverride = await resolveCandidateName(candidateFilerId);
|
|
10
|
+
}
|
|
11
|
+
const resolved = resolveCampaignContext(summary, candidateFilerId, campaignId, officeHint, candidateNameOverride);
|
|
12
|
+
if ('error' in resolved) {
|
|
13
|
+
return { candidateFilerId, candidateName: 'Unknown', officeName: 'Unknown', contributions: [], error: resolved.error };
|
|
14
|
+
}
|
|
15
|
+
const contributions = await getContributions(resolved.resolvedCampaignId, candidateFilerId);
|
|
16
|
+
return {
|
|
17
|
+
candidateFilerId,
|
|
18
|
+
candidateName: resolved.context.candidateName,
|
|
19
|
+
officeName: resolved.context.officeName,
|
|
20
|
+
contributions,
|
|
21
|
+
};
|
|
22
|
+
}
|
|
23
|
+
catch (err) {
|
|
24
|
+
return {
|
|
25
|
+
candidateFilerId,
|
|
26
|
+
candidateName: 'Unknown',
|
|
27
|
+
officeName: 'Unknown',
|
|
28
|
+
contributions: [],
|
|
29
|
+
error: err instanceof Error ? err.message : String(err),
|
|
30
|
+
};
|
|
31
|
+
}
|
|
32
|
+
}
|
|
33
|
+
const SUFFIXES = /\b(jr|sr|ii|iii|iv|v|md|dds|esq|phd|cpa)\.?$/i;
|
|
34
|
+
export function normalizeDonorName(name) {
|
|
35
|
+
let n = name.trim().toLowerCase().replace(/\s+/g, ' ');
|
|
36
|
+
// Remove periods from initials
|
|
37
|
+
n = n.replace(/\./g, '');
|
|
38
|
+
// Remove common suffixes
|
|
39
|
+
n = n.replace(SUFFIXES, '').trim();
|
|
40
|
+
// Normalize "Last, First" → "first last" for consistent matching
|
|
41
|
+
if (n.includes(',')) {
|
|
42
|
+
const [last, ...rest] = n.split(',');
|
|
43
|
+
n = `${rest.join(' ').trim()} ${last.trim()}`.trim();
|
|
44
|
+
}
|
|
45
|
+
return n;
|
|
46
|
+
}
|
|
47
|
+
/** @internal — exported for testing */
|
|
48
|
+
export function computeOverlap(primary, comparisons, exactMatch = false) {
|
|
49
|
+
const toKey = exactMatch
|
|
50
|
+
? (name) => name.trim().toLowerCase()
|
|
51
|
+
: normalizeDonorName;
|
|
52
|
+
const primaryDonors = new Map();
|
|
53
|
+
for (const c of primary.contributions) {
|
|
54
|
+
const key = toKey(c.paidBy);
|
|
55
|
+
const existing = primaryDonors.get(key);
|
|
56
|
+
if (existing) {
|
|
57
|
+
existing.amount += c.credit;
|
|
58
|
+
existing.count++;
|
|
59
|
+
}
|
|
60
|
+
else {
|
|
61
|
+
primaryDonors.set(key, { display: c.paidBy.trim(), amount: c.credit, count: 1 });
|
|
62
|
+
}
|
|
63
|
+
}
|
|
64
|
+
const comparisonMaps = comparisons.map(comp => {
|
|
65
|
+
const m = new Map();
|
|
66
|
+
for (const c of comp.contributions) {
|
|
67
|
+
const key = toKey(c.paidBy);
|
|
68
|
+
const existing = m.get(key);
|
|
69
|
+
if (existing) {
|
|
70
|
+
existing.amount += c.credit;
|
|
71
|
+
existing.count++;
|
|
72
|
+
}
|
|
73
|
+
else {
|
|
74
|
+
m.set(key, { display: c.paidBy.trim(), amount: c.credit, count: 1 });
|
|
75
|
+
}
|
|
76
|
+
}
|
|
77
|
+
return m;
|
|
78
|
+
});
|
|
79
|
+
const overlapping = [];
|
|
80
|
+
for (const [key, primaryData] of primaryDonors) {
|
|
81
|
+
const breakdown = [];
|
|
82
|
+
let appearsInComparison = false;
|
|
83
|
+
breakdown.push({
|
|
84
|
+
candidateName: primary.candidateName,
|
|
85
|
+
officeName: primary.officeName,
|
|
86
|
+
amount: primaryData.amount,
|
|
87
|
+
count: primaryData.count,
|
|
88
|
+
});
|
|
89
|
+
for (let i = 0; i < comparisons.length; i++) {
|
|
90
|
+
const compData = comparisonMaps[i].get(key);
|
|
91
|
+
if (compData) {
|
|
92
|
+
appearsInComparison = true;
|
|
93
|
+
breakdown.push({
|
|
94
|
+
candidateName: comparisons[i].candidateName,
|
|
95
|
+
officeName: comparisons[i].officeName,
|
|
96
|
+
amount: compData.amount,
|
|
97
|
+
count: compData.count,
|
|
98
|
+
});
|
|
99
|
+
}
|
|
100
|
+
}
|
|
101
|
+
if (appearsInComparison) {
|
|
102
|
+
const totalGiven = breakdown.reduce((sum, b) => sum + b.amount, 0);
|
|
103
|
+
overlapping.push({ donorName: primaryData.display, totalGiven, candidateBreakdown: breakdown });
|
|
104
|
+
}
|
|
105
|
+
}
|
|
106
|
+
return overlapping.sort((a, b) => b.totalGiven - a.totalGiven);
|
|
107
|
+
}
|
|
108
|
+
export function registerOverlapTools(server) {
|
|
109
|
+
server.tool('find_donor_overlap', 'Find donors who contributed to multiple candidates. Two modes:\n1. Explicit: pass primary + comparison candidate IDs (up to 20)\n2. Office-based: pass primary + office name to auto-discover comparison candidates (max 25)\nFetches contributions in parallel and computes intersection. Name matching normalizes "Last, First" vs "First Last", strips suffixes (Jr, Sr, etc), and is case-insensitive.', {
|
|
110
|
+
primary_candidate_filer_id: z.number().describe('candidateFilerId of the primary candidate'),
|
|
111
|
+
primary_campaign_id: z.number().optional().describe('campaignId for primary — optional, auto-resolved'),
|
|
112
|
+
primary_office: z.string().optional().describe('Office hint for primary candidate'),
|
|
113
|
+
comparison_candidate_filer_ids: z.array(z.number()).max(20).optional().describe('Array of up to 20 candidateFilerId values to compare against. Omit if using office param.'),
|
|
114
|
+
office: z.string().optional().describe('Office name to auto-discover comparison candidates (e.g. "Kershaw County Council"). Uses list_filers_by_office internally.'),
|
|
115
|
+
active_since: z.number().optional().describe('When using office mode, only include candidates with filings since this year'),
|
|
116
|
+
min_total: z.number().optional().describe('Minimum total given across all candidates to include'),
|
|
117
|
+
limit: z.number().optional().describe('Max overlapping donors to return (default 50)'),
|
|
118
|
+
exact_match: z.boolean().optional().describe('If true, skip name normalization and match donors by exact (case-insensitive) name. Useful when normalization causes false-positive merges.'),
|
|
119
|
+
}, async ({ primary_candidate_filer_id, primary_campaign_id, primary_office, comparison_candidate_filer_ids, office, active_since, min_total, limit, exact_match, }) => {
|
|
120
|
+
try {
|
|
121
|
+
let comparisonIds = comparison_candidate_filer_ids || [];
|
|
122
|
+
// Office-based mode: auto-discover comparison candidates
|
|
123
|
+
if (office && comparisonIds.length === 0) {
|
|
124
|
+
const result = await searchFilersByOffice(office, active_since);
|
|
125
|
+
const grouped = groupFilersByPerson(result.filers);
|
|
126
|
+
// Exclude the primary candidate
|
|
127
|
+
const others = grouped.filter(g => g.candidateFilerId !== primary_candidate_filer_id);
|
|
128
|
+
if (others.length > 25) {
|
|
129
|
+
return {
|
|
130
|
+
content: [{
|
|
131
|
+
type: 'text',
|
|
132
|
+
text: `Office "${office}" has ${others.length} candidates — too many for automatic comparison (max 25). Use active_since to narrow, or pass specific comparison_candidate_filer_ids.`,
|
|
133
|
+
}],
|
|
134
|
+
isError: true,
|
|
135
|
+
};
|
|
136
|
+
}
|
|
137
|
+
comparisonIds = others.map(g => g.candidateFilerId);
|
|
138
|
+
}
|
|
139
|
+
if (comparisonIds.length === 0) {
|
|
140
|
+
return {
|
|
141
|
+
content: [{
|
|
142
|
+
type: 'text',
|
|
143
|
+
text: 'Provide either comparison_candidate_filer_ids or an office name to discover comparison candidates.',
|
|
144
|
+
}],
|
|
145
|
+
isError: true,
|
|
146
|
+
};
|
|
147
|
+
}
|
|
148
|
+
// Fetch primary and all comparisons in parallel
|
|
149
|
+
const [primaryResult, ...comparisonResults] = await Promise.all([
|
|
150
|
+
fetchCandidateContributions(primary_candidate_filer_id, primary_campaign_id, primary_office),
|
|
151
|
+
...comparisonIds.map(id => fetchCandidateContributions(id)),
|
|
152
|
+
]);
|
|
153
|
+
const errors = [];
|
|
154
|
+
if (primaryResult.error)
|
|
155
|
+
errors.push(`Primary (${primary_candidate_filer_id}): ${primaryResult.error}`);
|
|
156
|
+
for (const comp of comparisonResults) {
|
|
157
|
+
if (comp.error)
|
|
158
|
+
errors.push(`Comparison (${comp.candidateFilerId}): ${comp.error}`);
|
|
159
|
+
}
|
|
160
|
+
const validComparisons = comparisonResults.filter(c => !c.error);
|
|
161
|
+
if (validComparisons.length === 0) {
|
|
162
|
+
return {
|
|
163
|
+
content: [{
|
|
164
|
+
type: 'text',
|
|
165
|
+
text: `Could not fetch any comparison candidates. Errors:\n${errors.join('\n')}`,
|
|
166
|
+
}],
|
|
167
|
+
isError: true,
|
|
168
|
+
};
|
|
169
|
+
}
|
|
170
|
+
let overlap = computeOverlap(primaryResult, validComparisons, exact_match);
|
|
171
|
+
if (min_total)
|
|
172
|
+
overlap = overlap.filter(d => d.totalGiven >= min_total);
|
|
173
|
+
const effectiveLimit = limit ?? 50;
|
|
174
|
+
const totalOverlap = overlap.length;
|
|
175
|
+
const limited = effectiveLimit > 0 ? overlap.slice(0, effectiveLimit) : overlap;
|
|
176
|
+
const candidateSummary = [
|
|
177
|
+
`Primary: ${primaryResult.candidateName} — ${primaryResult.officeName} (${primaryResult.contributions.length} contributions)`,
|
|
178
|
+
...validComparisons.map(c => `Compare: ${c.candidateName} — ${c.officeName} (${c.contributions.length} contributions)`),
|
|
179
|
+
].join('\n');
|
|
180
|
+
const limitNote = effectiveLimit > 0 && totalOverlap > effectiveLimit
|
|
181
|
+
? `\nShowing ${effectiveLimit} of ${totalOverlap} overlapping donors. Use limit=0 for all.`
|
|
182
|
+
: '';
|
|
183
|
+
const errorNote = errors.length > 0 ? `\nWarnings:\n${errors.map(e => ` - ${e}`).join('\n')}` : '';
|
|
184
|
+
return {
|
|
185
|
+
content: [{
|
|
186
|
+
type: 'text',
|
|
187
|
+
text: totalOverlap === 0
|
|
188
|
+
? `${candidateSummary}\n\nNo overlapping donors found.${errorNote}`
|
|
189
|
+
: `${candidateSummary}\n\n${totalOverlap} overlapping donor(s):${limitNote}${errorNote}\n---\n${JSON.stringify(limited, null, 2)}`,
|
|
190
|
+
}],
|
|
191
|
+
};
|
|
192
|
+
}
|
|
193
|
+
catch (error) {
|
|
194
|
+
return {
|
|
195
|
+
content: [{ type: 'text', text: `Error: ${error instanceof Error ? error.message : String(error)}` }],
|
|
196
|
+
isError: true,
|
|
197
|
+
};
|
|
198
|
+
}
|
|
199
|
+
});
|
|
200
|
+
}
|
|
201
|
+
//# sourceMappingURL=overlap.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"overlap.js","sourceRoot":"","sources":["../../src/tools/overlap.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,146 @@
|
|
|
1
|
+
import { z } from 'zod';
|
|
2
|
+
import { searchFilers, getFilerProfile, searchFilersByOffice, groupFilersByPerson, cachedGetCampaignSummary, normalizeOfficeName, listOfficeNames } from '../api/ethics-client.js';
|
|
3
|
+
export function registerSearchTools(server) {
|
|
4
|
+
server.tool('search_filers', 'Search SC Ethics Commission for candidates and officials by name. Returns candidateFilerId and seiFilerId needed for other tools. Default limit 50 results (0 for all). WARNING: The API searches the combined "Last, First" field — multi-word queries like "John Smith" may fail. Search by last name only for best results. To find all filers for a specific office, use list_filers_by_office. To discover valid office name formats, use list_office_names.', {
|
|
5
|
+
name: z.string().describe('Name to search for (e.g. "mcmaster", "haley"). Use last name only for best results.'),
|
|
6
|
+
limit: z.number().optional().describe('Max results to return (default 50, 0 for all). Common names can return 200+ results.'),
|
|
7
|
+
}, async ({ name, limit }) => {
|
|
8
|
+
try {
|
|
9
|
+
const results = await searchFilers(name);
|
|
10
|
+
const effectiveLimit = limit === undefined ? 50 : limit;
|
|
11
|
+
const totalCount = results.length;
|
|
12
|
+
const limited = effectiveLimit > 0 ? results.slice(0, effectiveLimit) : results;
|
|
13
|
+
const limitNote = effectiveLimit > 0 && totalCount > effectiveLimit
|
|
14
|
+
? `Showing ${effectiveLimit} of ${totalCount} results. Use limit=0 for all.\n`
|
|
15
|
+
: '';
|
|
16
|
+
return {
|
|
17
|
+
content: [{
|
|
18
|
+
type: 'text',
|
|
19
|
+
text: results.length === 0
|
|
20
|
+
? `No filers found matching "${name}"`
|
|
21
|
+
: `${limitNote}${JSON.stringify(limited, null, 2)}`,
|
|
22
|
+
}],
|
|
23
|
+
};
|
|
24
|
+
}
|
|
25
|
+
catch (error) {
|
|
26
|
+
return {
|
|
27
|
+
content: [{ type: 'text', text: `Error: ${error instanceof Error ? error.message : String(error)}` }],
|
|
28
|
+
isError: true,
|
|
29
|
+
};
|
|
30
|
+
}
|
|
31
|
+
});
|
|
32
|
+
server.tool('list_filers_by_office', 'Find all candidates/officials who have filed with the SC Ethics Commission for a specific office. Searches the entire filer database by sweeping all 26 letters and filtering by office name. Returns grouped results — one entry per person with an offices[] sub-array showing all their filings. May take 10-15 seconds on first call (cached 30 min after). With recent_only=true, enriches results with campaignId, balance, and status — no need to call get_campaign_summary separately.', {
|
|
33
|
+
office: z.string().describe('Office name to search for (partial match, e.g. "Greenville County Council", "Governor", "Sheriff")'),
|
|
34
|
+
recent_only: z.boolean().optional().describe('If true, only return filers with submissions in the last 2 years and enrich with campaign data. Default: false.'),
|
|
35
|
+
active_since: z.number().optional().describe('Only include filers with submissions on or after this year (e.g. 2022). More precise than recent_only.'),
|
|
36
|
+
}, async ({ office, recent_only, active_since }) => {
|
|
37
|
+
try {
|
|
38
|
+
const result = await searchFilersByOffice(office, active_since);
|
|
39
|
+
let { filers } = result;
|
|
40
|
+
if (recent_only) {
|
|
41
|
+
const cutoff = Date.now() - (2 * 365.25 * 24 * 60 * 60 * 1000);
|
|
42
|
+
filers = filers.filter(f => {
|
|
43
|
+
if (!f.lastSubmission)
|
|
44
|
+
return false;
|
|
45
|
+
const [month, day, year] = f.lastSubmission.split('/');
|
|
46
|
+
return new Date(+year, +month - 1, +day).getTime() >= cutoff;
|
|
47
|
+
});
|
|
48
|
+
}
|
|
49
|
+
// Group filers by person (dedup + merge offices)
|
|
50
|
+
const grouped = groupFilersByPerson(filers);
|
|
51
|
+
// Enrich with campaign data when recent_only
|
|
52
|
+
let enrichmentNote = '';
|
|
53
|
+
if (recent_only && grouped.length > 0) {
|
|
54
|
+
const ENRICH_CAP = 50;
|
|
55
|
+
const BATCH_SIZE = 6;
|
|
56
|
+
const toEnrich = grouped.slice(0, ENRICH_CAP);
|
|
57
|
+
const needle = office.toLowerCase();
|
|
58
|
+
for (let i = 0; i < toEnrich.length; i += BATCH_SIZE) {
|
|
59
|
+
const batch = toEnrich.slice(i, i + BATCH_SIZE);
|
|
60
|
+
await Promise.allSettled(batch.map(async (gf) => {
|
|
61
|
+
const summary = await cachedGetCampaignSummary(gf.candidateFilerId);
|
|
62
|
+
const allOffices = [
|
|
63
|
+
...summary.openReports.map(r => ({ ...r, status: 'open' })),
|
|
64
|
+
...summary.closedReports.map(r => ({ ...r, status: 'closed' })),
|
|
65
|
+
];
|
|
66
|
+
// Find best matching office: prefer open, then most recent
|
|
67
|
+
const matches = allOffices.filter(o => o.officeName.toLowerCase().includes(needle));
|
|
68
|
+
const match = matches.find(o => o.status === 'open') || matches[0];
|
|
69
|
+
gf.normalizedOffice = normalizeOfficeName(gf.offices[0]?.officeName || '');
|
|
70
|
+
if (match) {
|
|
71
|
+
gf.primaryOfficeName = match.officeName;
|
|
72
|
+
gf.campaignStatus = match.status;
|
|
73
|
+
gf.balance = match.balance;
|
|
74
|
+
gf.campaignId = match.officeId;
|
|
75
|
+
}
|
|
76
|
+
}));
|
|
77
|
+
}
|
|
78
|
+
if (grouped.length > ENRICH_CAP) {
|
|
79
|
+
enrichmentNote = `\nNote: Enriched ${ENRICH_CAP} of ${grouped.length} filers with campaign data. Use a more specific query for remaining.`;
|
|
80
|
+
}
|
|
81
|
+
}
|
|
82
|
+
const parts = [];
|
|
83
|
+
if (result.totalFailed > 0) {
|
|
84
|
+
parts.push(`Note: ${result.totalFailed} of 26 searches failed; results may be incomplete.`);
|
|
85
|
+
}
|
|
86
|
+
if (grouped.length === 0) {
|
|
87
|
+
parts.push(`No filers found for office matching "${office}"${recent_only ? ' (with recent_only filter)' : ''}`);
|
|
88
|
+
}
|
|
89
|
+
else {
|
|
90
|
+
if (recent_only) {
|
|
91
|
+
parts.push('=== ENRICHED RESULTS ===\nThese results include campaignId, balance, and campaign status for each filer.\nDo NOT call get_campaign_summary for these filers — the data is already included below.\n===');
|
|
92
|
+
}
|
|
93
|
+
parts.push(`${grouped.length} filer(s) found for "${office}"${recent_only ? ' (last 2 years)' : ''}:${enrichmentNote}`);
|
|
94
|
+
parts.push(JSON.stringify(grouped, null, 2));
|
|
95
|
+
}
|
|
96
|
+
return {
|
|
97
|
+
content: [{ type: 'text', text: parts.join('\n') }],
|
|
98
|
+
};
|
|
99
|
+
}
|
|
100
|
+
catch (error) {
|
|
101
|
+
return {
|
|
102
|
+
content: [{ type: 'text', text: `Error: ${error instanceof Error ? error.message : String(error)}` }],
|
|
103
|
+
isError: true,
|
|
104
|
+
};
|
|
105
|
+
}
|
|
106
|
+
});
|
|
107
|
+
server.tool('get_filer_profile', 'Get full profile for a filer including address, phone, positions held, and open/closed campaign offices. Use candidateFilerId and seiFilerId from search_filers. Returns campaignId (in openOffices/closedOffices) for campaign finance tools.', {
|
|
108
|
+
candidate_filer_id: z.number().describe('candidateFilerId from search_filers results'),
|
|
109
|
+
sei_filer_id: z.number().describe('seiFilerId from search_filers results'),
|
|
110
|
+
}, async ({ candidate_filer_id, sei_filer_id }) => {
|
|
111
|
+
try {
|
|
112
|
+
const profile = await getFilerProfile(candidate_filer_id, sei_filer_id);
|
|
113
|
+
return {
|
|
114
|
+
content: [{ type: 'text', text: JSON.stringify(profile, null, 2) }],
|
|
115
|
+
};
|
|
116
|
+
}
|
|
117
|
+
catch (error) {
|
|
118
|
+
return {
|
|
119
|
+
content: [{ type: 'text', text: `Error: ${error instanceof Error ? error.message : String(error)}` }],
|
|
120
|
+
isError: true,
|
|
121
|
+
};
|
|
122
|
+
}
|
|
123
|
+
});
|
|
124
|
+
server.tool('list_office_names', 'List distinct office names from the SC Ethics Commission filer database. Returns exact office name strings — use these with list_filers_by_office for precise matching. Optional keyword filter (e.g. "House", "Senate", "Greenville"). First call triggers a database sweep (~10-15 sec); subsequent calls are instant from cache. NOTE: These are filer-reported names and may differ slightly from campaign-level names used in get_contributions/get_expenditures office hints. Use for discovery and partial matching.', {
|
|
125
|
+
keyword: z.string().optional().describe('Filter office names containing this keyword (case-insensitive, e.g. "House", "Senate", "Greenville")'),
|
|
126
|
+
}, async ({ keyword }) => {
|
|
127
|
+
try {
|
|
128
|
+
const names = await listOfficeNames(keyword);
|
|
129
|
+
return {
|
|
130
|
+
content: [{
|
|
131
|
+
type: 'text',
|
|
132
|
+
text: names.length === 0
|
|
133
|
+
? `No office names found${keyword ? ` matching "${keyword}"` : ''}`
|
|
134
|
+
: `${names.length} office name(s)${keyword ? ` matching "${keyword}"` : ''}:\n${JSON.stringify(names, null, 2)}`,
|
|
135
|
+
}],
|
|
136
|
+
};
|
|
137
|
+
}
|
|
138
|
+
catch (error) {
|
|
139
|
+
return {
|
|
140
|
+
content: [{ type: 'text', text: `Error: ${error instanceof Error ? error.message : String(error)}` }],
|
|
141
|
+
isError: true,
|
|
142
|
+
};
|
|
143
|
+
}
|
|
144
|
+
});
|
|
145
|
+
}
|
|
146
|
+
//# sourceMappingURL=search.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"search.js","sourceRoot":"","sources":["../../src/tools/search.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,99 @@
|
|
|
1
|
+
import { z } from 'zod';
|
|
2
|
+
import { getSeiDetails } from '../api/ethics-client.js';
|
|
3
|
+
export function registerSeiTools(server) {
|
|
4
|
+
server.tool('get_sei_details', 'Get full SEI report: positions, business interests, income, gifts, travel, contracts, creditors, lobbyist contacts, property transactions. Use seiFilerId from search_filers. SEI reveals financial interests, not campaign spending. Returns most recent report by default.', {
|
|
5
|
+
sei_filer_id: z.number().describe('seiFilerId from search_filers results'),
|
|
6
|
+
report_year: z.number().optional().describe('Specific report year. Omit for most recent.'),
|
|
7
|
+
}, async ({ sei_filer_id, report_year }) => {
|
|
8
|
+
try {
|
|
9
|
+
const details = await getSeiDetails(sei_filer_id, report_year);
|
|
10
|
+
if (!details) {
|
|
11
|
+
return {
|
|
12
|
+
content: [{ type: 'text', text: 'No SEI report found for this filer' }],
|
|
13
|
+
};
|
|
14
|
+
}
|
|
15
|
+
// Build a readable summary with non-empty sections
|
|
16
|
+
const sections = [
|
|
17
|
+
`SEI Report for filer ${sei_filer_id} — Year: ${details.reportYear}, Submitted: ${details.dateSubmitted}`,
|
|
18
|
+
];
|
|
19
|
+
if (details.positions.length > 0) {
|
|
20
|
+
sections.push(`\nPositions (${details.positions.length}):`);
|
|
21
|
+
sections.push(JSON.stringify(details.positions, null, 2));
|
|
22
|
+
}
|
|
23
|
+
if (details.businessInterests.length > 0) {
|
|
24
|
+
sections.push(`\nBusiness Interests (${details.businessInterests.length}):`);
|
|
25
|
+
sections.push(JSON.stringify(details.businessInterests, null, 2));
|
|
26
|
+
}
|
|
27
|
+
if (details.privateIncome.length > 0) {
|
|
28
|
+
sections.push(`\nPrivate Income (${details.privateIncome.length}):`);
|
|
29
|
+
sections.push(JSON.stringify(details.privateIncome, null, 2));
|
|
30
|
+
}
|
|
31
|
+
if (details.governmentIncome.length > 0) {
|
|
32
|
+
sections.push(`\nGovernment Income (${details.governmentIncome.length}):`);
|
|
33
|
+
sections.push(JSON.stringify(details.governmentIncome, null, 2));
|
|
34
|
+
}
|
|
35
|
+
if (details.familyPrivateIncome.length > 0) {
|
|
36
|
+
sections.push(`\nFamily Private Income (${details.familyPrivateIncome.length}):`);
|
|
37
|
+
sections.push(JSON.stringify(details.familyPrivateIncome, null, 2));
|
|
38
|
+
}
|
|
39
|
+
if (details.familyGovernmentIncome.length > 0) {
|
|
40
|
+
sections.push(`\nFamily Government Income (${details.familyGovernmentIncome.length}):`);
|
|
41
|
+
sections.push(JSON.stringify(details.familyGovernmentIncome, null, 2));
|
|
42
|
+
}
|
|
43
|
+
if (details.gifts.length > 0) {
|
|
44
|
+
sections.push(`\nGifts (${details.gifts.length}):`);
|
|
45
|
+
sections.push(JSON.stringify(details.gifts, null, 2));
|
|
46
|
+
}
|
|
47
|
+
if (details.travel.length > 0) {
|
|
48
|
+
sections.push(`\nTravel (${details.travel.length}):`);
|
|
49
|
+
sections.push(JSON.stringify(details.travel, null, 2));
|
|
50
|
+
}
|
|
51
|
+
if (details.governmentContracts.length > 0) {
|
|
52
|
+
sections.push(`\nGovernment Contracts (${details.governmentContracts.length}):`);
|
|
53
|
+
sections.push(JSON.stringify(details.governmentContracts, null, 2));
|
|
54
|
+
}
|
|
55
|
+
if (details.creditors.length > 0) {
|
|
56
|
+
sections.push(`\nCreditors (${details.creditors.length}):`);
|
|
57
|
+
sections.push(JSON.stringify(details.creditors, null, 2));
|
|
58
|
+
}
|
|
59
|
+
if (details.lobbyistFamily.length > 0) {
|
|
60
|
+
sections.push(`\nLobbyist Family (${details.lobbyistFamily.length}):`);
|
|
61
|
+
sections.push(JSON.stringify(details.lobbyistFamily, null, 2));
|
|
62
|
+
}
|
|
63
|
+
if (details.lobbyistPurchases.length > 0) {
|
|
64
|
+
sections.push(`\nLobbyist Purchases (${details.lobbyistPurchases.length}):`);
|
|
65
|
+
sections.push(JSON.stringify(details.lobbyistPurchases, null, 2));
|
|
66
|
+
}
|
|
67
|
+
if (details.regulatedBusinessAssociations.length > 0) {
|
|
68
|
+
sections.push(`\nRegulated Business Associations (${details.regulatedBusinessAssociations.length}):`);
|
|
69
|
+
sections.push(JSON.stringify(details.regulatedBusinessAssociations, null, 2));
|
|
70
|
+
}
|
|
71
|
+
if (details.propertyTransactions.length > 0) {
|
|
72
|
+
sections.push(`\nProperty Transactions (${details.propertyTransactions.length}):`);
|
|
73
|
+
sections.push(JSON.stringify(details.propertyTransactions, null, 2));
|
|
74
|
+
}
|
|
75
|
+
if (details.propertyImprovements.length > 0) {
|
|
76
|
+
sections.push(`\nProperty Improvements (${details.propertyImprovements.length}):`);
|
|
77
|
+
sections.push(JSON.stringify(details.propertyImprovements, null, 2));
|
|
78
|
+
}
|
|
79
|
+
if (details.propertyConflicts.length > 0) {
|
|
80
|
+
sections.push(`\nProperty Conflicts (${details.propertyConflicts.length}):`);
|
|
81
|
+
sections.push(JSON.stringify(details.propertyConflicts, null, 2));
|
|
82
|
+
}
|
|
83
|
+
if (details.additionalInformation.length > 0) {
|
|
84
|
+
sections.push(`\nAdditional Information (${details.additionalInformation.length}):`);
|
|
85
|
+
sections.push(JSON.stringify(details.additionalInformation, null, 2));
|
|
86
|
+
}
|
|
87
|
+
return {
|
|
88
|
+
content: [{ type: 'text', text: sections.join('\n') }],
|
|
89
|
+
};
|
|
90
|
+
}
|
|
91
|
+
catch (error) {
|
|
92
|
+
return {
|
|
93
|
+
content: [{ type: 'text', text: `Error: ${error instanceof Error ? error.message : String(error)}` }],
|
|
94
|
+
isError: true,
|
|
95
|
+
};
|
|
96
|
+
}
|
|
97
|
+
});
|
|
98
|
+
}
|
|
99
|
+
//# sourceMappingURL=sei.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"sei.js","sourceRoot":"","sources":["../../src/tools/sei.ts"],"names":[],"mappings":"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"}
|