grantsignal-mcp 1.2.0 → 1.3.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/dist/ai-scoring.d.ts +35 -0
- package/dist/ai-scoring.d.ts.map +1 -0
- package/dist/ai-scoring.js +123 -0
- package/dist/ai-scoring.js.map +1 -0
- package/dist/config.d.ts +10 -5
- package/dist/config.d.ts.map +1 -1
- package/dist/config.js +11 -5
- package/dist/config.js.map +1 -1
- package/dist/post-processing.d.ts +58 -0
- package/dist/post-processing.d.ts.map +1 -0
- package/dist/post-processing.js +194 -0
- package/dist/post-processing.js.map +1 -0
- package/dist/scoring.d.ts +171 -0
- package/dist/scoring.d.ts.map +1 -0
- package/dist/scoring.js +809 -0
- package/dist/scoring.js.map +1 -0
- package/dist/server.d.ts +2 -2
- package/dist/server.d.ts.map +1 -1
- package/dist/server.js +673 -84
- package/dist/server.js.map +1 -1
- package/dist/supabase-client.d.ts +28 -0
- package/dist/supabase-client.d.ts.map +1 -0
- package/dist/supabase-client.js +70 -0
- package/dist/supabase-client.js.map +1 -0
- package/package.json +1 -1
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* GrantSignal MCP Server — AI Scoring (Claude Haiku)
|
|
3
|
+
*
|
|
4
|
+
* Lightweight wrapper around the Anthropic API for AI-powered tools.
|
|
5
|
+
* Ported from convex/lib/aiScoring.ts.
|
|
6
|
+
*/
|
|
7
|
+
export interface AiScoringResult {
|
|
8
|
+
text: string;
|
|
9
|
+
tokenCount: number;
|
|
10
|
+
}
|
|
11
|
+
/**
|
|
12
|
+
* Call Claude Haiku with a system prompt and user message.
|
|
13
|
+
* Returns null on failure (never throws).
|
|
14
|
+
*
|
|
15
|
+
* @param apiKey - Anthropic API key (passed explicitly for Worker compatibility)
|
|
16
|
+
*/
|
|
17
|
+
export declare function callHaiku(apiKey: string, systemPrompt: string, userMessage: string, maxTokens?: number): Promise<AiScoringResult | null>;
|
|
18
|
+
/**
|
|
19
|
+
* Build a smart-match prompt for scoring grant candidates.
|
|
20
|
+
*/
|
|
21
|
+
export declare function buildSmartMatchPrompt(orgProfile: {
|
|
22
|
+
orgName?: string;
|
|
23
|
+
orgType?: string;
|
|
24
|
+
mission?: string;
|
|
25
|
+
focusAreas?: string[];
|
|
26
|
+
populationsServed?: string[];
|
|
27
|
+
city?: string;
|
|
28
|
+
state?: string;
|
|
29
|
+
budgetSize?: number;
|
|
30
|
+
certifications?: string[];
|
|
31
|
+
}): string;
|
|
32
|
+
export declare const SMART_MATCH_SYSTEM_PROMPT = "You are a grant matching expert. Given an organization profile and a list of grant opportunities, score each grant on how well it matches the organization.\n\nFor each grant, provide:\n1. A match score from 0-100\n2. A 1-2 sentence rationale\n\nReturn ONLY valid JSON in this format:\n{\n \"scores\": [\n { \"id\": \"GRANT-0\", \"score\": 85, \"rationale\": \"Strong match because...\" },\n { \"id\": \"GRANT-1\", \"score\": 42, \"rationale\": \"Weak match because...\" },\n ...\n ]\n}\n\nUse the exact GRANT-N identifier shown in brackets before each grant.\n\nScoring guidelines:\n- 90-100: Near-perfect match \u2014 org's mission, populations, and capacity directly align\n- 70-89: Strong match \u2014 most criteria align, minor gaps\n- 50-69: Moderate match \u2014 some alignment but significant gaps in focus or capacity\n- 30-49: Weak match \u2014 tangential relevance only\n- 0-29: Poor match \u2014 wrong sector, geography, or capacity\n\nConsider: mission alignment, geographic eligibility, organizational type eligibility, budget/capacity match, population served overlap, focus area relevance.\n\nBe critical and realistic. Most grants should NOT score above 80 unless there's a very clear match.";
|
|
33
|
+
export declare const OPPORTUNITY_ANALYSIS_SYSTEM_PROMPT = "You are a grant strategy expert with deep knowledge of government funding. Analyze the provided grant opportunity using the competitive intelligence data.\n\nProduce a strategic briefing with these sections:\n\n1. **Overview** \u2014 2-3 sentence summary of the opportunity, who it's for, and what it funds.\n2. **Who Wins These Grants** \u2014 Based on award history data, describe the typical winning organization (size, type, track record). Name specific past winners if available.\n3. **Competitive Landscape** \u2014 How competitive is this? Estimate the number of applicants and success rate based on award data and typical demand for this type of funding.\n4. **Key Requirements** \u2014 The most critical eligibility and application requirements. What disqualifies applicants?\n5. **Strategic Recommendations** \u2014 3-5 actionable tips for a strong application. What differentiates winners from losers?\n6. **Red Flags & Risks** \u2014 Anything to watch out for: tight timelines, matching requirements, complex reporting, political considerations.\n\nKeep it concise and actionable. Use bullet points. Avoid generic advice \u2014 be specific to THIS grant.\n\nReturn plain text (markdown formatting is fine). Do NOT return JSON.";
|
|
34
|
+
export declare const ORG_INTELLIGENCE_SYSTEM_PROMPT = "You are a nonprofit funding strategist analyzing an organization's complete data profile. Synthesize all available data into an actionable intelligence brief.\n\nProduce a strategic briefing with these sections:\n\n1. **Organization Snapshot** \u2014 Type, location, size, and primary mission based on available data.\n2. **Revenue & Financial Health** \u2014 Revenue trends, diversity of funding sources, government dependency ratio, assets, growth trajectory. Flag any concerns (declining revenue, high dependency on single source).\n3. **Government Funding Profile** \u2014 Total government funding received, key agencies, types of awards. What's their government funding niche?\n4. **Compliance & Risk Assessment** \u2014 Audit results, M/WBE status, lobbying activity. Any red flags or concerns for potential funders?\n5. **Competitive Positioning** \u2014 What makes this org stand out? What are their strengths vs. peers?\n6. **Strategic Recommendations** \u2014 3-5 specific, actionable recommendations: new funding sources to pursue, capabilities to develop, relationships to build, risks to mitigate.\n7. **Funding Gaps** \u2014 Based on their mission and current funding, what types of grants should they pursue that they're currently missing?\n\nBe analytical and specific. Reference actual numbers from the data. Avoid generic advice \u2014 make recommendations based on THIS organization's specific profile.\n\nReturn plain text (markdown formatting is fine). Do NOT return JSON.";
|
|
35
|
+
//# sourceMappingURL=ai-scoring.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"ai-scoring.d.ts","sourceRoot":"","sources":["../src/ai-scoring.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAKH,MAAM,WAAW,eAAe;IAC9B,IAAI,EAAE,MAAM,CAAC;IACb,UAAU,EAAE,MAAM,CAAC;CACpB;AAED;;;;;GAKG;AACH,wBAAsB,SAAS,CAC7B,MAAM,EAAE,MAAM,EACd,YAAY,EAAE,MAAM,EACpB,WAAW,EAAE,MAAM,EACnB,SAAS,SAAO,GACf,OAAO,CAAC,eAAe,GAAG,IAAI,CAAC,CAqCjC;AAED;;GAEG;AACH,wBAAgB,qBAAqB,CAAC,UAAU,EAAE;IAChD,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,UAAU,CAAC,EAAE,MAAM,EAAE,CAAC;IACtB,iBAAiB,CAAC,EAAE,MAAM,EAAE,CAAC;IAC7B,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,cAAc,CAAC,EAAE,MAAM,EAAE,CAAC;CAC3B,GAAG,MAAM,CAYT;AAED,eAAO,MAAM,yBAAyB,usCA0B8D,CAAC;AAErG,eAAO,MAAM,kCAAkC,2tCAasB,CAAC;AAEtE,eAAO,MAAM,8BAA8B,09CAc0B,CAAC"}
|
|
@@ -0,0 +1,123 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* GrantSignal MCP Server — AI Scoring (Claude Haiku)
|
|
3
|
+
*
|
|
4
|
+
* Lightweight wrapper around the Anthropic API for AI-powered tools.
|
|
5
|
+
* Ported from convex/lib/aiScoring.ts.
|
|
6
|
+
*/
|
|
7
|
+
const HAIKU_MODEL = "claude-haiku-4-5-20251001";
|
|
8
|
+
const API_URL = "https://api.anthropic.com/v1/messages";
|
|
9
|
+
/**
|
|
10
|
+
* Call Claude Haiku with a system prompt and user message.
|
|
11
|
+
* Returns null on failure (never throws).
|
|
12
|
+
*
|
|
13
|
+
* @param apiKey - Anthropic API key (passed explicitly for Worker compatibility)
|
|
14
|
+
*/
|
|
15
|
+
export async function callHaiku(apiKey, systemPrompt, userMessage, maxTokens = 1500) {
|
|
16
|
+
if (!apiKey) {
|
|
17
|
+
console.warn("[aiScoring] No API key — skipping AI scoring");
|
|
18
|
+
return null;
|
|
19
|
+
}
|
|
20
|
+
try {
|
|
21
|
+
const resp = await fetch(API_URL, {
|
|
22
|
+
method: "POST",
|
|
23
|
+
headers: {
|
|
24
|
+
"Content-Type": "application/json",
|
|
25
|
+
"x-api-key": apiKey,
|
|
26
|
+
"anthropic-version": "2023-06-01",
|
|
27
|
+
},
|
|
28
|
+
body: JSON.stringify({
|
|
29
|
+
model: HAIKU_MODEL,
|
|
30
|
+
max_tokens: maxTokens,
|
|
31
|
+
system: systemPrompt,
|
|
32
|
+
messages: [{ role: "user", content: userMessage }],
|
|
33
|
+
}),
|
|
34
|
+
});
|
|
35
|
+
if (!resp.ok) {
|
|
36
|
+
const err = await resp.text();
|
|
37
|
+
console.error(`[aiScoring] Haiku API error ${resp.status}: ${err.substring(0, 200)}`);
|
|
38
|
+
return null;
|
|
39
|
+
}
|
|
40
|
+
const data = await resp.json();
|
|
41
|
+
return {
|
|
42
|
+
text: data.content?.[0]?.text ?? "",
|
|
43
|
+
tokenCount: (data.usage?.input_tokens ?? 0) + (data.usage?.output_tokens ?? 0),
|
|
44
|
+
};
|
|
45
|
+
}
|
|
46
|
+
catch (err) {
|
|
47
|
+
console.error(`[aiScoring] Haiku call failed: ${err.message}`);
|
|
48
|
+
return null;
|
|
49
|
+
}
|
|
50
|
+
}
|
|
51
|
+
/**
|
|
52
|
+
* Build a smart-match prompt for scoring grant candidates.
|
|
53
|
+
*/
|
|
54
|
+
export function buildSmartMatchPrompt(orgProfile) {
|
|
55
|
+
const parts = [
|
|
56
|
+
`Organization: ${orgProfile.orgName || "Unknown"}`,
|
|
57
|
+
orgProfile.orgType ? `Type: ${orgProfile.orgType}` : null,
|
|
58
|
+
orgProfile.mission ? `Mission: ${orgProfile.mission}` : null,
|
|
59
|
+
orgProfile.focusAreas?.length ? `Focus Areas: ${orgProfile.focusAreas.join(", ")}` : null,
|
|
60
|
+
orgProfile.populationsServed?.length ? `Populations Served: ${orgProfile.populationsServed.join(", ")}` : null,
|
|
61
|
+
orgProfile.city || orgProfile.state ? `Location: ${[orgProfile.city, orgProfile.state].filter(Boolean).join(", ")}` : null,
|
|
62
|
+
orgProfile.budgetSize ? `Annual Budget: $${orgProfile.budgetSize.toLocaleString()}` : null,
|
|
63
|
+
orgProfile.certifications?.length ? `Certifications: ${orgProfile.certifications.join(", ")}` : null,
|
|
64
|
+
];
|
|
65
|
+
return parts.filter(Boolean).join("\n");
|
|
66
|
+
}
|
|
67
|
+
export const SMART_MATCH_SYSTEM_PROMPT = `You are a grant matching expert. Given an organization profile and a list of grant opportunities, score each grant on how well it matches the organization.
|
|
68
|
+
|
|
69
|
+
For each grant, provide:
|
|
70
|
+
1. A match score from 0-100
|
|
71
|
+
2. A 1-2 sentence rationale
|
|
72
|
+
|
|
73
|
+
Return ONLY valid JSON in this format:
|
|
74
|
+
{
|
|
75
|
+
"scores": [
|
|
76
|
+
{ "id": "GRANT-0", "score": 85, "rationale": "Strong match because..." },
|
|
77
|
+
{ "id": "GRANT-1", "score": 42, "rationale": "Weak match because..." },
|
|
78
|
+
...
|
|
79
|
+
]
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
Use the exact GRANT-N identifier shown in brackets before each grant.
|
|
83
|
+
|
|
84
|
+
Scoring guidelines:
|
|
85
|
+
- 90-100: Near-perfect match — org's mission, populations, and capacity directly align
|
|
86
|
+
- 70-89: Strong match — most criteria align, minor gaps
|
|
87
|
+
- 50-69: Moderate match — some alignment but significant gaps in focus or capacity
|
|
88
|
+
- 30-49: Weak match — tangential relevance only
|
|
89
|
+
- 0-29: Poor match — wrong sector, geography, or capacity
|
|
90
|
+
|
|
91
|
+
Consider: mission alignment, geographic eligibility, organizational type eligibility, budget/capacity match, population served overlap, focus area relevance.
|
|
92
|
+
|
|
93
|
+
Be critical and realistic. Most grants should NOT score above 80 unless there's a very clear match.`;
|
|
94
|
+
export const OPPORTUNITY_ANALYSIS_SYSTEM_PROMPT = `You are a grant strategy expert with deep knowledge of government funding. Analyze the provided grant opportunity using the competitive intelligence data.
|
|
95
|
+
|
|
96
|
+
Produce a strategic briefing with these sections:
|
|
97
|
+
|
|
98
|
+
1. **Overview** — 2-3 sentence summary of the opportunity, who it's for, and what it funds.
|
|
99
|
+
2. **Who Wins These Grants** — Based on award history data, describe the typical winning organization (size, type, track record). Name specific past winners if available.
|
|
100
|
+
3. **Competitive Landscape** — How competitive is this? Estimate the number of applicants and success rate based on award data and typical demand for this type of funding.
|
|
101
|
+
4. **Key Requirements** — The most critical eligibility and application requirements. What disqualifies applicants?
|
|
102
|
+
5. **Strategic Recommendations** — 3-5 actionable tips for a strong application. What differentiates winners from losers?
|
|
103
|
+
6. **Red Flags & Risks** — Anything to watch out for: tight timelines, matching requirements, complex reporting, political considerations.
|
|
104
|
+
|
|
105
|
+
Keep it concise and actionable. Use bullet points. Avoid generic advice — be specific to THIS grant.
|
|
106
|
+
|
|
107
|
+
Return plain text (markdown formatting is fine). Do NOT return JSON.`;
|
|
108
|
+
export const ORG_INTELLIGENCE_SYSTEM_PROMPT = `You are a nonprofit funding strategist analyzing an organization's complete data profile. Synthesize all available data into an actionable intelligence brief.
|
|
109
|
+
|
|
110
|
+
Produce a strategic briefing with these sections:
|
|
111
|
+
|
|
112
|
+
1. **Organization Snapshot** — Type, location, size, and primary mission based on available data.
|
|
113
|
+
2. **Revenue & Financial Health** — Revenue trends, diversity of funding sources, government dependency ratio, assets, growth trajectory. Flag any concerns (declining revenue, high dependency on single source).
|
|
114
|
+
3. **Government Funding Profile** — Total government funding received, key agencies, types of awards. What's their government funding niche?
|
|
115
|
+
4. **Compliance & Risk Assessment** — Audit results, M/WBE status, lobbying activity. Any red flags or concerns for potential funders?
|
|
116
|
+
5. **Competitive Positioning** — What makes this org stand out? What are their strengths vs. peers?
|
|
117
|
+
6. **Strategic Recommendations** — 3-5 specific, actionable recommendations: new funding sources to pursue, capabilities to develop, relationships to build, risks to mitigate.
|
|
118
|
+
7. **Funding Gaps** — Based on their mission and current funding, what types of grants should they pursue that they're currently missing?
|
|
119
|
+
|
|
120
|
+
Be analytical and specific. Reference actual numbers from the data. Avoid generic advice — make recommendations based on THIS organization's specific profile.
|
|
121
|
+
|
|
122
|
+
Return plain text (markdown formatting is fine). Do NOT return JSON.`;
|
|
123
|
+
//# sourceMappingURL=ai-scoring.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"ai-scoring.js","sourceRoot":"","sources":["../src/ai-scoring.ts"],"names":[],"mappings":"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"}
|
package/dist/config.d.ts
CHANGED
|
@@ -1,13 +1,18 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* GrantSignal MCP Server — Configuration
|
|
3
3
|
*
|
|
4
|
-
* Reads
|
|
5
|
-
* Falls back to the production Convex deployment.
|
|
4
|
+
* Reads Supabase credentials and optional API keys from environment variables.
|
|
6
5
|
*/
|
|
7
6
|
export declare const config: {
|
|
8
|
-
/**
|
|
7
|
+
/** Supabase project URL */
|
|
8
|
+
supabaseUrl: string;
|
|
9
|
+
/** Supabase service role key (full DB access) */
|
|
10
|
+
supabaseKey: string;
|
|
11
|
+
/** Anthropic API key for AI-powered tools */
|
|
12
|
+
anthropicApiKey: string;
|
|
13
|
+
/** Legacy: Convex API URL (kept for client.ts backward compat) */
|
|
9
14
|
apiUrl: string;
|
|
10
|
-
/**
|
|
11
|
-
apiKey: string
|
|
15
|
+
/** Legacy: API key for Convex (kept for client.ts backward compat) */
|
|
16
|
+
apiKey: string;
|
|
12
17
|
};
|
|
13
18
|
//# sourceMappingURL=config.d.ts.map
|
package/dist/config.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"config.d.ts","sourceRoot":"","sources":["../src/config.ts"],"names":[],"mappings":"AAAA
|
|
1
|
+
{"version":3,"file":"config.d.ts","sourceRoot":"","sources":["../src/config.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAEH,eAAO,MAAM,MAAM;IACjB,2BAA2B;;IAK3B,iDAAiD;;IAGjD,6CAA6C;;IAI7C,kEAAkE;;IAKlE,sEAAsE;;CAEvE,CAAC"}
|
package/dist/config.js
CHANGED
|
@@ -1,14 +1,20 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* GrantSignal MCP Server — Configuration
|
|
3
3
|
*
|
|
4
|
-
* Reads
|
|
5
|
-
* Falls back to the production Convex deployment.
|
|
4
|
+
* Reads Supabase credentials and optional API keys from environment variables.
|
|
6
5
|
*/
|
|
7
6
|
export const config = {
|
|
8
|
-
/**
|
|
7
|
+
/** Supabase project URL */
|
|
8
|
+
supabaseUrl: process.env.SUPABASE_URL ||
|
|
9
|
+
"https://ykbpdjxhxlzkmpezjvhx.supabase.co",
|
|
10
|
+
/** Supabase service role key (full DB access) */
|
|
11
|
+
supabaseKey: process.env.SUPABASE_SERVICE_ROLE_KEY || "",
|
|
12
|
+
/** Anthropic API key for AI-powered tools */
|
|
13
|
+
anthropicApiKey: process.env.ANTHROPIC_API_KEY || process.env.CLAUDE_API_KEY || "",
|
|
14
|
+
/** Legacy: Convex API URL (kept for client.ts backward compat) */
|
|
9
15
|
apiUrl: process.env.GRANTSIGNAL_API_URL ||
|
|
10
16
|
"https://wooden-coyote-415.convex.site",
|
|
11
|
-
/**
|
|
12
|
-
apiKey: process.env.GRANTSIGNAL_API_KEY ||
|
|
17
|
+
/** Legacy: API key for Convex (kept for client.ts backward compat) */
|
|
18
|
+
apiKey: process.env.GRANTSIGNAL_API_KEY || "",
|
|
13
19
|
};
|
|
14
20
|
//# sourceMappingURL=config.js.map
|
package/dist/config.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"config.js","sourceRoot":"","sources":["../src/config.ts"],"names":[],"mappings":"AAAA
|
|
1
|
+
{"version":3,"file":"config.js","sourceRoot":"","sources":["../src/config.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAEH,MAAM,CAAC,MAAM,MAAM,GAAG;IACpB,2BAA2B;IAC3B,WAAW,EACT,OAAO,CAAC,GAAG,CAAC,YAAY;QACxB,0CAA0C;IAE5C,iDAAiD;IACjD,WAAW,EAAE,OAAO,CAAC,GAAG,CAAC,yBAAyB,IAAI,EAAE;IAExD,6CAA6C;IAC7C,eAAe,EACb,OAAO,CAAC,GAAG,CAAC,iBAAiB,IAAI,OAAO,CAAC,GAAG,CAAC,cAAc,IAAI,EAAE;IAEnE,kEAAkE;IAClE,MAAM,EACJ,OAAO,CAAC,GAAG,CAAC,mBAAmB;QAC/B,uCAAuC;IAEzC,sEAAsE;IACtE,MAAM,EAAE,OAAO,CAAC,GAAG,CAAC,mBAAmB,IAAI,EAAE;CAC9C,CAAC"}
|
|
@@ -0,0 +1,58 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* GrantSignal MCP Server — Post-Processing Functions
|
|
3
|
+
*
|
|
4
|
+
* Shared data transformation functions applied after Supabase queries.
|
|
5
|
+
* Ported from convex/http.ts.
|
|
6
|
+
*/
|
|
7
|
+
import type { SupabaseConfig } from "./supabase-client.js";
|
|
8
|
+
export declare const NYC_AGENCY_ACRONYMS: Record<string, {
|
|
9
|
+
code: string;
|
|
10
|
+
name: string;
|
|
11
|
+
}>;
|
|
12
|
+
/**
|
|
13
|
+
* Resolve an agency search term to a Checkbook agency code.
|
|
14
|
+
* Accepts acronyms (DFTA), codes (125), or full names.
|
|
15
|
+
*/
|
|
16
|
+
export declare function resolveAgencyFilter(input: string): {
|
|
17
|
+
code: string;
|
|
18
|
+
name: string;
|
|
19
|
+
original: string;
|
|
20
|
+
};
|
|
21
|
+
/**
|
|
22
|
+
* Resolve a grantId (Convex document ID) or opportunityNumber to the convex_id.
|
|
23
|
+
* Uses PostgREST GET on grant_opportunities table.
|
|
24
|
+
*/
|
|
25
|
+
export declare function resolveGrantId(config: SupabaseConfig, body: {
|
|
26
|
+
grantId?: string;
|
|
27
|
+
opportunityNumber?: string;
|
|
28
|
+
}): Promise<string | null>;
|
|
29
|
+
/** Deduplicate results by opportunityNumber (keep most recent postedDate). */
|
|
30
|
+
export declare function deduplicateResults(results: any[]): any[];
|
|
31
|
+
/**
|
|
32
|
+
* Null out sentinel close dates (year >= 2099) — treat as open-ended.
|
|
33
|
+
* Marks records that had sentinel dates so they aren't removed by stale filters.
|
|
34
|
+
*/
|
|
35
|
+
export declare function filterSentinelDates(results: any[]): any[];
|
|
36
|
+
/**
|
|
37
|
+
* Post-process search results: remove stale/expired records.
|
|
38
|
+
*/
|
|
39
|
+
export declare function applyFreshnessFilter(results: any[], opts: {
|
|
40
|
+
status?: string;
|
|
41
|
+
includeHistorical?: boolean;
|
|
42
|
+
}): any[];
|
|
43
|
+
/** Filter out procurement/construction listings from grant results. */
|
|
44
|
+
export declare function excludeProcurement(results: any[]): {
|
|
45
|
+
grants: any[];
|
|
46
|
+
procurementCount: number;
|
|
47
|
+
};
|
|
48
|
+
/** Filter out low-quality records (generic page titles, placeholder data). */
|
|
49
|
+
export declare function filterLowQuality(results: any[]): any[];
|
|
50
|
+
/**
|
|
51
|
+
* Apply the full search post-processing pipeline.
|
|
52
|
+
* Used by grants_search, grants_funding_landscape, and grants_match.
|
|
53
|
+
*/
|
|
54
|
+
export declare function applySearchPipeline(results: any[], opts?: {
|
|
55
|
+
status?: string;
|
|
56
|
+
includeHistorical?: boolean;
|
|
57
|
+
}): any[];
|
|
58
|
+
//# sourceMappingURL=post-processing.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"post-processing.d.ts","sourceRoot":"","sources":["../src/post-processing.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAEH,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,sBAAsB,CAAC;AAK3D,eAAO,MAAM,mBAAmB,EAAE,MAAM,CAAC,MAAM,EAAE;IAAE,IAAI,EAAE,MAAM,CAAC;IAAC,IAAI,EAAE,MAAM,CAAA;CAAE,CAoB9E,CAAC;AAEF;;;GAGG;AACH,wBAAgB,mBAAmB,CAAC,KAAK,EAAE,MAAM,GAAG;IAAE,IAAI,EAAE,MAAM,CAAC;IAAC,IAAI,EAAE,MAAM,CAAC;IAAC,QAAQ,EAAE,MAAM,CAAA;CAAE,CAgBnG;AAID;;;GAGG;AACH,wBAAsB,cAAc,CAClC,MAAM,EAAE,cAAc,EACtB,IAAI,EAAE;IAAE,OAAO,CAAC,EAAE,MAAM,CAAC;IAAC,iBAAiB,CAAC,EAAE,MAAM,CAAA;CAAE,GACrD,OAAO,CAAC,MAAM,GAAG,IAAI,CAAC,CAwBxB;AAID,8EAA8E;AAC9E,wBAAgB,kBAAkB,CAAC,OAAO,EAAE,GAAG,EAAE,GAAG,GAAG,EAAE,CAiBxD;AAED;;;GAGG;AACH,wBAAgB,mBAAmB,CAAC,OAAO,EAAE,GAAG,EAAE,GAAG,GAAG,EAAE,CAWzD;AAED;;GAEG;AACH,wBAAgB,oBAAoB,CAClC,OAAO,EAAE,GAAG,EAAE,EACd,IAAI,EAAE;IAAE,MAAM,CAAC,EAAE,MAAM,CAAC;IAAC,iBAAiB,CAAC,EAAE,OAAO,CAAA;CAAE,GACrD,GAAG,EAAE,CAaP;AAmBD,uEAAuE;AACvE,wBAAgB,kBAAkB,CAAC,OAAO,EAAE,GAAG,EAAE,GAAG;IAAE,MAAM,EAAE,GAAG,EAAE,CAAC;IAAC,gBAAgB,EAAE,MAAM,CAAA;CAAE,CAe9F;AAED,8EAA8E;AAC9E,wBAAgB,gBAAgB,CAAC,OAAO,EAAE,GAAG,EAAE,GAAG,GAAG,EAAE,CActD;AAED;;;GAGG;AACH,wBAAgB,mBAAmB,CACjC,OAAO,EAAE,GAAG,EAAE,EACd,IAAI,GAAE;IAAE,MAAM,CAAC,EAAE,MAAM,CAAC;IAAC,iBAAiB,CAAC,EAAE,OAAO,CAAA;CAAO,GAC1D,GAAG,EAAE,CAOP"}
|
|
@@ -0,0 +1,194 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* GrantSignal MCP Server — Post-Processing Functions
|
|
3
|
+
*
|
|
4
|
+
* Shared data transformation functions applied after Supabase queries.
|
|
5
|
+
* Ported from convex/http.ts.
|
|
6
|
+
*/
|
|
7
|
+
import { supabaseGet } from "./supabase-client.js";
|
|
8
|
+
// ── NYC Agency Acronym Resolver ─────────────────────────────
|
|
9
|
+
export const NYC_AGENCY_ACRONYMS = {
|
|
10
|
+
DFTA: { code: "125", name: "Department for the Aging" },
|
|
11
|
+
DYCD: { code: "260", name: "Department of Youth and Community Development" },
|
|
12
|
+
DOHMH: { code: "816", name: "Department of Health and Mental Hygiene" },
|
|
13
|
+
ACS: { code: "068", name: "Administration for Children's Services" },
|
|
14
|
+
DHS: { code: "069", name: "Department of Homeless Services" },
|
|
15
|
+
HRA: { code: "071", name: "Human Resources Administration" },
|
|
16
|
+
DSS: { code: "071", name: "Department of Social Services" },
|
|
17
|
+
DOE: { code: "040", name: "Department of Education" },
|
|
18
|
+
NYPD: { code: "056", name: "New York City Police Department" },
|
|
19
|
+
FDNY: { code: "057", name: "Fire Department" },
|
|
20
|
+
HPD: { code: "806", name: "Department of Housing Preservation and Development" },
|
|
21
|
+
DOT: { code: "841", name: "Department of Transportation" },
|
|
22
|
+
DPR: { code: "846", name: "Department of Parks and Recreation" },
|
|
23
|
+
DCLA: { code: "126", name: "Department of Cultural Affairs" },
|
|
24
|
+
SBS: { code: "801", name: "Department of Small Business Services" },
|
|
25
|
+
DEP: { code: "826", name: "Department of Environmental Protection" },
|
|
26
|
+
DSNY: { code: "827", name: "Department of Sanitation" },
|
|
27
|
+
DOB: { code: "810", name: "Department of Buildings" },
|
|
28
|
+
MOCJ: { code: "098", name: "Mayor's Office of Criminal Justice" },
|
|
29
|
+
};
|
|
30
|
+
/**
|
|
31
|
+
* Resolve an agency search term to a Checkbook agency code.
|
|
32
|
+
* Accepts acronyms (DFTA), codes (125), or full names.
|
|
33
|
+
*/
|
|
34
|
+
export function resolveAgencyFilter(input) {
|
|
35
|
+
const upper = input.toUpperCase().trim();
|
|
36
|
+
// Check acronym map
|
|
37
|
+
if (NYC_AGENCY_ACRONYMS[upper]) {
|
|
38
|
+
return { ...NYC_AGENCY_ACRONYMS[upper], original: input };
|
|
39
|
+
}
|
|
40
|
+
// Already a numeric code? Return as-is
|
|
41
|
+
if (/^\d{2,3}$/.test(input.trim())) {
|
|
42
|
+
const entry = Object.values(NYC_AGENCY_ACRONYMS).find(a => a.code === input.trim());
|
|
43
|
+
return { code: input.trim(), name: entry?.name || input, original: input };
|
|
44
|
+
}
|
|
45
|
+
// Full name input — return original for ILIKE search
|
|
46
|
+
return { code: input, name: input, original: input };
|
|
47
|
+
}
|
|
48
|
+
// ── Grant ID Resolver ───────────────────────────────────────
|
|
49
|
+
/**
|
|
50
|
+
* Resolve a grantId (Convex document ID) or opportunityNumber to the convex_id.
|
|
51
|
+
* Uses PostgREST GET on grant_opportunities table.
|
|
52
|
+
*/
|
|
53
|
+
export async function resolveGrantId(config, body) {
|
|
54
|
+
if (body.grantId) {
|
|
55
|
+
// Convex document IDs are long base64-like strings.
|
|
56
|
+
const looksLikeConvexId = body.grantId.length > 20 && !body.grantId.includes("-");
|
|
57
|
+
if (looksLikeConvexId)
|
|
58
|
+
return body.grantId;
|
|
59
|
+
// Treat as opportunity number — lookup via Supabase
|
|
60
|
+
const rows = await supabaseGet(config, "grant_opportunities", `opportunity_number=eq.${encodeURIComponent(body.grantId)}&select=convex_id&limit=1`);
|
|
61
|
+
if (rows.length > 0 && rows[0].convex_id)
|
|
62
|
+
return rows[0].convex_id;
|
|
63
|
+
return null;
|
|
64
|
+
}
|
|
65
|
+
if (body.opportunityNumber) {
|
|
66
|
+
const rows = await supabaseGet(config, "grant_opportunities", `opportunity_number=eq.${encodeURIComponent(body.opportunityNumber)}&select=convex_id&limit=1`);
|
|
67
|
+
if (rows.length > 0 && rows[0].convex_id)
|
|
68
|
+
return rows[0].convex_id;
|
|
69
|
+
return null;
|
|
70
|
+
}
|
|
71
|
+
return null;
|
|
72
|
+
}
|
|
73
|
+
// ── Search Result Post-Processing ───────────────────────────
|
|
74
|
+
/** Deduplicate results by opportunityNumber (keep most recent postedDate). */
|
|
75
|
+
export function deduplicateResults(results) {
|
|
76
|
+
const dedupMap = new Map();
|
|
77
|
+
for (const r of results) {
|
|
78
|
+
const key = (r.opportunityNumber ?? "").toLowerCase().trim();
|
|
79
|
+
if (!key) {
|
|
80
|
+
const fallbackKey = `${(r.title ?? "").toLowerCase().trim()}|${(r.agency ?? "").toLowerCase().trim()}`;
|
|
81
|
+
if (!dedupMap.has(fallbackKey))
|
|
82
|
+
dedupMap.set(fallbackKey, r);
|
|
83
|
+
}
|
|
84
|
+
else if (!dedupMap.has(key)) {
|
|
85
|
+
dedupMap.set(key, r);
|
|
86
|
+
}
|
|
87
|
+
else {
|
|
88
|
+
const existing = dedupMap.get(key);
|
|
89
|
+
if ((r.postedDate ?? "") > (existing.postedDate ?? "")) {
|
|
90
|
+
dedupMap.set(key, r);
|
|
91
|
+
}
|
|
92
|
+
}
|
|
93
|
+
}
|
|
94
|
+
return Array.from(dedupMap.values());
|
|
95
|
+
}
|
|
96
|
+
/**
|
|
97
|
+
* Null out sentinel close dates (year >= 2099) — treat as open-ended.
|
|
98
|
+
* Marks records that had sentinel dates so they aren't removed by stale filters.
|
|
99
|
+
*/
|
|
100
|
+
export function filterSentinelDates(results) {
|
|
101
|
+
return results.map((r) => {
|
|
102
|
+
if (r.closeDate) {
|
|
103
|
+
const year = parseInt(r.closeDate.substring(0, 4), 10);
|
|
104
|
+
if (year >= 2099) {
|
|
105
|
+
r.closeDate = null;
|
|
106
|
+
r._rollingDeadline = true;
|
|
107
|
+
}
|
|
108
|
+
}
|
|
109
|
+
return r;
|
|
110
|
+
});
|
|
111
|
+
}
|
|
112
|
+
/**
|
|
113
|
+
* Post-process search results: remove stale/expired records.
|
|
114
|
+
*/
|
|
115
|
+
export function applyFreshnessFilter(results, opts) {
|
|
116
|
+
const today = new Date().toISOString().split("T")[0];
|
|
117
|
+
const twoYearsAgo = new Date();
|
|
118
|
+
twoYearsAgo.setFullYear(twoYearsAgo.getFullYear() - 2);
|
|
119
|
+
const staleCutoff = twoYearsAgo.toISOString().split("T")[0];
|
|
120
|
+
return results.filter((r) => {
|
|
121
|
+
if (opts.includeHistorical)
|
|
122
|
+
return true;
|
|
123
|
+
if (r.closeDate && r.closeDate < today)
|
|
124
|
+
return false;
|
|
125
|
+
if (r._rollingDeadline)
|
|
126
|
+
return true;
|
|
127
|
+
if (!r.closeDate && r.postedDate && r.postedDate < staleCutoff)
|
|
128
|
+
return false;
|
|
129
|
+
return true;
|
|
130
|
+
});
|
|
131
|
+
}
|
|
132
|
+
/** Categories that are procurement/construction, not grant solicitations. */
|
|
133
|
+
const PROCUREMENT_CATEGORIES = new Set([
|
|
134
|
+
"Construction/Construction Services",
|
|
135
|
+
"Construction Related Services",
|
|
136
|
+
"Goods",
|
|
137
|
+
"Goods and Services",
|
|
138
|
+
]);
|
|
139
|
+
/** Title patterns that indicate procurement bids, not grants. */
|
|
140
|
+
const PROCUREMENT_TITLE_PATTERNS = [
|
|
141
|
+
/^bid\s+(extension|cancellation|amendment)/i,
|
|
142
|
+
/^cancellation:/i,
|
|
143
|
+
/^correction:\s*bid/i,
|
|
144
|
+
/^requirements?\s+contract\s+for/i,
|
|
145
|
+
/^request\s+for\s+bid/i,
|
|
146
|
+
];
|
|
147
|
+
/** Filter out procurement/construction listings from grant results. */
|
|
148
|
+
export function excludeProcurement(results) {
|
|
149
|
+
let procurementCount = 0;
|
|
150
|
+
const grants = results.filter((r) => {
|
|
151
|
+
if (PROCUREMENT_CATEGORIES.has(r.categoryOfFunding)) {
|
|
152
|
+
procurementCount++;
|
|
153
|
+
return false;
|
|
154
|
+
}
|
|
155
|
+
const title = r.title ?? "";
|
|
156
|
+
if (PROCUREMENT_TITLE_PATTERNS.some((p) => p.test(title))) {
|
|
157
|
+
procurementCount++;
|
|
158
|
+
return false;
|
|
159
|
+
}
|
|
160
|
+
return true;
|
|
161
|
+
});
|
|
162
|
+
return { grants, procurementCount };
|
|
163
|
+
}
|
|
164
|
+
/** Filter out low-quality records (generic page titles, placeholder data). */
|
|
165
|
+
export function filterLowQuality(results) {
|
|
166
|
+
const genericTitles = new Set([
|
|
167
|
+
"program offices", "grants", "funding opportunities", "p-12 education",
|
|
168
|
+
"business and program accounts help", "about us", "contact us", "home",
|
|
169
|
+
"past opportunities", "find information about grants", "translation services",
|
|
170
|
+
"how to apply", "resources", "overview", "contact information",
|
|
171
|
+
"frequently asked questions", "application instructions",
|
|
172
|
+
]);
|
|
173
|
+
return results.filter((r) => {
|
|
174
|
+
const title = (r.title ?? "").toLowerCase().trim();
|
|
175
|
+
if (title.length < 15)
|
|
176
|
+
return false;
|
|
177
|
+
if (genericTitles.has(title))
|
|
178
|
+
return false;
|
|
179
|
+
return true;
|
|
180
|
+
});
|
|
181
|
+
}
|
|
182
|
+
/**
|
|
183
|
+
* Apply the full search post-processing pipeline.
|
|
184
|
+
* Used by grants_search, grants_funding_landscape, and grants_match.
|
|
185
|
+
*/
|
|
186
|
+
export function applySearchPipeline(results, opts = {}) {
|
|
187
|
+
let processed = deduplicateResults(results);
|
|
188
|
+
processed = filterSentinelDates(processed);
|
|
189
|
+
processed = applyFreshnessFilter(processed, opts);
|
|
190
|
+
const { grants } = excludeProcurement(processed);
|
|
191
|
+
processed = filterLowQuality(grants);
|
|
192
|
+
return processed;
|
|
193
|
+
}
|
|
194
|
+
//# sourceMappingURL=post-processing.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"post-processing.js","sourceRoot":"","sources":["../src/post-processing.ts"],"names":[],"mappings":"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"}
|