@pipeworx/mcp-openstates 0.1.3 → 0.1.4
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/package.json +3 -3
- package/server.json +1 -1
- package/src/index.ts +30 -7
- package/src/server.ts +1 -1
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@pipeworx/mcp-openstates",
|
|
3
|
-
"version": "0.1.
|
|
3
|
+
"version": "0.1.4",
|
|
4
4
|
"description": "OpenStates MCP — bills, legislators, votes in all 50 US states",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "src/index.ts",
|
|
@@ -26,7 +26,7 @@
|
|
|
26
26
|
"@cloudflare/workers-types": "^4.20260405.1"
|
|
27
27
|
},
|
|
28
28
|
"pipeworx": {
|
|
29
|
-
"sourceHash": "v1-
|
|
30
|
-
"sourceCommit": "
|
|
29
|
+
"sourceHash": "v1-d9939703c0e177f41da0fbd131835af380ebc15e9c75b8fd58b9dbebd35552be",
|
|
30
|
+
"sourceCommit": "69152ffc15233d5998bfe6fe195c040cdb328366"
|
|
31
31
|
}
|
|
32
32
|
}
|
package/server.json
CHANGED
|
@@ -3,7 +3,7 @@
|
|
|
3
3
|
"name": "io.github.pipeworx-io/openstates",
|
|
4
4
|
"title": "Openstates",
|
|
5
5
|
"description": "OpenStates MCP — bills, legislators, votes in all 50 US states",
|
|
6
|
-
"version": "0.1.
|
|
6
|
+
"version": "0.1.4",
|
|
7
7
|
"websiteUrl": "https://pipeworx.io/packs/openstates",
|
|
8
8
|
"repository": {
|
|
9
9
|
"url": "https://github.com/pipeworx-io/mcp-openstates",
|
package/src/index.ts
CHANGED
|
@@ -997,8 +997,8 @@ export function resolveSessionCandidates(requested: string, sessions: OsSession[
|
|
|
997
997
|
return hits
|
|
998
998
|
.map((s, i) => ({ s, i }))
|
|
999
999
|
.sort((a, b) => {
|
|
1000
|
-
const pa = a.s
|
|
1001
|
-
const pb = b.s
|
|
1000
|
+
const pa = isSpecialSession(a.s) ? 1 : 0;
|
|
1001
|
+
const pb = isSpecialSession(b.s) ? 1 : 0;
|
|
1002
1002
|
if (pa !== pb) return pa - pb;
|
|
1003
1003
|
const da = a.s.start_date ?? '';
|
|
1004
1004
|
const db = b.s.start_date ?? '';
|
|
@@ -1009,6 +1009,14 @@ export function resolveSessionCandidates(requested: string, sessions: OsSession[
|
|
|
1009
1009
|
.slice(0, 4);
|
|
1010
1010
|
}
|
|
1011
1011
|
|
|
1012
|
+
// OpenStates does not always populate `classification` (Texas leaves it off and
|
|
1013
|
+
// names its specials "…Called Session"), so read the name too — otherwise the
|
|
1014
|
+
// newest special session outranks the regular one for the same year.
|
|
1015
|
+
function isSpecialSession(s: OsSession): boolean {
|
|
1016
|
+
if (s.classification) return s.classification !== 'primary';
|
|
1017
|
+
return /\b(special|called|extraordinary|extra)\b/i.test(s.name ?? '');
|
|
1018
|
+
}
|
|
1019
|
+
|
|
1012
1020
|
const TERRITORIES = new Set(['pr', 'gu', 'vi', 'as', 'mp']);
|
|
1013
1021
|
|
|
1014
1022
|
function jurisdictionPathId(jurisdiction: string): string {
|
|
@@ -1021,6 +1029,25 @@ function jurisdictionPathId(jurisdiction: string): string {
|
|
|
1021
1029
|
return j.startsWith('ocd-jurisdiction/') ? j : encodeURIComponent(j);
|
|
1022
1030
|
}
|
|
1023
1031
|
|
|
1032
|
+
// Session lists change a few times a year; the upstream free tier is small and
|
|
1033
|
+
// per-minute throttled, so keep them per isolate for an hour rather than
|
|
1034
|
+
// spending a request on every zero-row search.
|
|
1035
|
+
const SESSION_TTL_MS = 60 * 60 * 1000;
|
|
1036
|
+
const sessionCache = new Map<string, { at: number; data: { name?: string; legislative_sessions?: OsSession[] } }>();
|
|
1037
|
+
|
|
1038
|
+
async function jurisdictionSessions(apiKey: string, jurisdiction: string) {
|
|
1039
|
+
const key = jurisdictionPathId(jurisdiction);
|
|
1040
|
+
const hit = sessionCache.get(key);
|
|
1041
|
+
if (hit && Date.now() - hit.at < SESSION_TTL_MS) return hit.data;
|
|
1042
|
+
const data = await osFetch<{ name?: string; legislative_sessions?: OsSession[] }>(
|
|
1043
|
+
apiKey,
|
|
1044
|
+
`/jurisdictions/${key}`,
|
|
1045
|
+
new URLSearchParams({ include: 'legislative_sessions' }),
|
|
1046
|
+
);
|
|
1047
|
+
sessionCache.set(key, { at: Date.now(), data });
|
|
1048
|
+
return data;
|
|
1049
|
+
}
|
|
1050
|
+
|
|
1024
1051
|
/**
|
|
1025
1052
|
* Check a session value against the jurisdiction's real session list.
|
|
1026
1053
|
* exact → it IS a valid identifier (an empty result is genuine).
|
|
@@ -1033,11 +1060,7 @@ async function resolveSession(
|
|
|
1033
1060
|
jurisdiction: string,
|
|
1034
1061
|
session: string,
|
|
1035
1062
|
): Promise<{ exact?: string; candidates: OsSession[] }> {
|
|
1036
|
-
const data = await
|
|
1037
|
-
apiKey,
|
|
1038
|
-
`/jurisdictions/${jurisdictionPathId(jurisdiction)}`,
|
|
1039
|
-
new URLSearchParams({ include: 'legislative_sessions' }),
|
|
1040
|
-
);
|
|
1063
|
+
const data = await jurisdictionSessions(apiKey, jurisdiction);
|
|
1041
1064
|
const sessions = (data.legislative_sessions ?? []).filter((s) => s && s.identifier);
|
|
1042
1065
|
const norm = session.trim().toLowerCase();
|
|
1043
1066
|
const exact = sessions.find(
|
package/src/server.ts
CHANGED
|
@@ -9,7 +9,7 @@ import { CallToolRequestSchema, ListToolsRequestSchema } from '@modelcontextprot
|
|
|
9
9
|
import pack from './index.js';
|
|
10
10
|
|
|
11
11
|
const server = new Server(
|
|
12
|
-
{ name: '@pipeworx/mcp-openstates', version: '0.1.
|
|
12
|
+
{ name: '@pipeworx/mcp-openstates', version: '0.1.4' },
|
|
13
13
|
{ capabilities: { tools: {} } },
|
|
14
14
|
);
|
|
15
15
|
|