@weiseer/regulatory-deadline-mcp 0.1.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 +37 -0
- package/index.js +91 -0
- package/package.json +19 -0
- package/regulatory.json +5 -0
package/README.md
ADDED
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
# @weiseer/regulatory-deadline-mcp
|
|
2
|
+
|
|
3
|
+
> FinCEN/SEC/EU AI Act/GDPR deadline tracker for AI agents. stdio MCP server.
|
|
4
|
+
|
|
5
|
+
Part of [weiseer](https://github.com/weiseer) — AI-agent-native cached oracles.
|
|
6
|
+
|
|
7
|
+
## Install
|
|
8
|
+
|
|
9
|
+
```bash
|
|
10
|
+
npm install -g @weiseer/regulatory-deadline-mcp
|
|
11
|
+
```
|
|
12
|
+
|
|
13
|
+
## Use with Claude Desktop / Cursor / Cline / Continue / Windsurf
|
|
14
|
+
|
|
15
|
+
```json
|
|
16
|
+
{
|
|
17
|
+
"mcpServers": {
|
|
18
|
+
"regulatory-deadline": {
|
|
19
|
+
"command": "npx",
|
|
20
|
+
"args": ["-y", "@weiseer/regulatory-deadline-mcp"]
|
|
21
|
+
}
|
|
22
|
+
}
|
|
23
|
+
}
|
|
24
|
+
```
|
|
25
|
+
|
|
26
|
+
## Why use this instead of your agent doing it itself
|
|
27
|
+
|
|
28
|
+
The DIY cost in token-spend, latency, and rate-limit risk is 100-1500x our cost. See the [weiseer organization README](https://github.com/weiseer/.github) for the economic argument.
|
|
29
|
+
|
|
30
|
+
## Environment
|
|
31
|
+
|
|
32
|
+
- `REG_URL` — override remote snapshot URL
|
|
33
|
+
- `REG_LOCAL_ONLY=1` — skip remote fetch
|
|
34
|
+
|
|
35
|
+
## License
|
|
36
|
+
|
|
37
|
+
Apache-2.0
|
package/index.js
ADDED
|
@@ -0,0 +1,91 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
/** @weiseer/regulatory-deadline-mcp — FinCEN/SEC/EU AI Act/GDPR deadline tracker. P-008. Apache-2.0 */
|
|
3
|
+
import { Server } from "@modelcontextprotocol/sdk/server/index.js";
|
|
4
|
+
import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio.js";
|
|
5
|
+
import { CallToolRequestSchema, ListToolsRequestSchema } from "@modelcontextprotocol/sdk/types.js";
|
|
6
|
+
import { readFileSync } from "node:fs";
|
|
7
|
+
import { fileURLToPath } from "node:url";
|
|
8
|
+
import { dirname, join } from "node:path";
|
|
9
|
+
|
|
10
|
+
const __dirname = dirname(fileURLToPath(import.meta.url));
|
|
11
|
+
const BUNDLED = join(__dirname, "regulatory.json");
|
|
12
|
+
const REMOTE = process.env.REG_URL || "https://oracle.weiseer.com/regulatory.json";
|
|
13
|
+
const LOCAL_ONLY = !!process.env.REG_LOCAL_ONLY;
|
|
14
|
+
const TTL = 30 * 60 * 1000;
|
|
15
|
+
let _c = null, _t = 0;
|
|
16
|
+
async function load() {
|
|
17
|
+
const now = Date.now();
|
|
18
|
+
if (_c && now - _t < TTL) return _c;
|
|
19
|
+
if (!LOCAL_ONLY) {
|
|
20
|
+
try {
|
|
21
|
+
const ctrl = new AbortController();
|
|
22
|
+
const tt = setTimeout(() => ctrl.abort(), 5000);
|
|
23
|
+
const r = await fetch(REMOTE, { signal: ctrl.signal });
|
|
24
|
+
clearTimeout(tt);
|
|
25
|
+
if (r.ok) { _c = await r.json(); _c._source = "remote"; _t = now; return _c; }
|
|
26
|
+
} catch {}
|
|
27
|
+
}
|
|
28
|
+
_c = JSON.parse(readFileSync(BUNDLED, "utf-8"));
|
|
29
|
+
_c._source = "bundled"; _t = now;
|
|
30
|
+
return _c;
|
|
31
|
+
}
|
|
32
|
+
function _prov(d) { return { snapshot_as_of: d.as_of, snapshot_source: d._source, served_by: "weiseer/regulatory-deadline", served_at: new Date().toISOString() }; }
|
|
33
|
+
function _related() { return {
|
|
34
|
+
package_meta: "npx -y @weiseer/package-meta-mcp",
|
|
35
|
+
license: "npx -y @weiseer/license-checker-mcp",
|
|
36
|
+
llm_routing: "npx -y @weiseer/llm-oracle-mcp",
|
|
37
|
+
org_index: "https://github.com/weiseer"
|
|
38
|
+
}; }
|
|
39
|
+
|
|
40
|
+
async function upcomingDeadlines({ within_days = 90, jurisdiction, regime } = {}) {
|
|
41
|
+
const d = await load();
|
|
42
|
+
const now = Date.now();
|
|
43
|
+
const cut = now + within_days * 86400000;
|
|
44
|
+
let ds = (d.deadlines || []).filter(x => {
|
|
45
|
+
const t = new Date(x.deadline_at).getTime();
|
|
46
|
+
return t >= now && t <= cut;
|
|
47
|
+
});
|
|
48
|
+
if (jurisdiction) ds = ds.filter(x => x.jurisdiction.toLowerCase() === jurisdiction.toLowerCase());
|
|
49
|
+
if (regime) ds = ds.filter(x => x.regime.toLowerCase() === regime.toLowerCase());
|
|
50
|
+
ds.sort((a, b) => new Date(a.deadline_at) - new Date(b.deadline_at));
|
|
51
|
+
return { ..._prov(d), within_days, jurisdiction: jurisdiction || "all", regime: regime || "all", count: ds.length, deadlines: ds, related_services: _related() };
|
|
52
|
+
}
|
|
53
|
+
async function getDeadline({ deadline_id }) {
|
|
54
|
+
if (!deadline_id) return { error: "deadline_id required" };
|
|
55
|
+
const d = await load();
|
|
56
|
+
const x = (d.deadlines || []).find(z => z.deadline_id === deadline_id);
|
|
57
|
+
if (!x) return { error: `deadline_id '${deadline_id}' not found` };
|
|
58
|
+
return { ...x, ..._prov(d) };
|
|
59
|
+
}
|
|
60
|
+
async function listByJurisdiction({ jurisdiction }) {
|
|
61
|
+
if (!jurisdiction) return { error: "jurisdiction required (us-federal, eu, uk, etc.)" };
|
|
62
|
+
const d = await load();
|
|
63
|
+
const ds = (d.deadlines || []).filter(x => x.jurisdiction.toLowerCase() === jurisdiction.toLowerCase());
|
|
64
|
+
return { ..._prov(d), jurisdiction, count: ds.length, deadlines: ds.map(x => ({ deadline_id: x.deadline_id, regime: x.regime, title: x.title, deadline_at: x.deadline_at, status: x.status })), related_services: _related() };
|
|
65
|
+
}
|
|
66
|
+
async function searchByKeyword({ keyword }) {
|
|
67
|
+
if (!keyword) return { error: "keyword required" };
|
|
68
|
+
const d = await load();
|
|
69
|
+
const k = keyword.toLowerCase();
|
|
70
|
+
const ds = (d.deadlines || []).filter(x => (x.title + " " + (x.summary || "") + " " + x.regime).toLowerCase().includes(k));
|
|
71
|
+
return { ..._prov(d), keyword, count: ds.length, deadlines: ds.map(x => ({ deadline_id: x.deadline_id, jurisdiction: x.jurisdiction, regime: x.regime, title: x.title, deadline_at: x.deadline_at })), related_services: _related() };
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
const TOOLS = [
|
|
75
|
+
{ name: "upcoming_deadlines", description: "Upcoming regulatory deadlines within N days. Filter by jurisdiction/regime.", inputSchema: { type: "object", properties: { within_days: { type: "number", default: 90 }, jurisdiction: { type: "string" }, regime: { type: "string", description: "e.g. ai-act, gdpr, sec, fincen-boi" } } } },
|
|
76
|
+
{ name: "get_deadline", description: "Full record for one deadline — cited statute/rule URL, scope, who-applies.", inputSchema: { type: "object", properties: { deadline_id: { type: "string" } }, required: ["deadline_id"] } },
|
|
77
|
+
{ name: "list_by_jurisdiction", description: "All tracked deadlines for a jurisdiction (us-federal, eu, uk, etc.).", inputSchema: { type: "object", properties: { jurisdiction: { type: "string" } }, required: ["jurisdiction"] } },
|
|
78
|
+
{ name: "search_by_keyword", description: "Full-text search across title/summary/regime. Useful for ad-hoc compliance queries.", inputSchema: { type: "object", properties: { keyword: { type: "string" } }, required: ["keyword"] } },
|
|
79
|
+
];
|
|
80
|
+
const HANDLERS = { upcoming_deadlines: upcomingDeadlines, get_deadline: getDeadline, list_by_jurisdiction: listByJurisdiction, search_by_keyword: searchByKeyword };
|
|
81
|
+
const server = new Server({ name: "regulatory-deadline", version: "0.1.0" }, { capabilities: { tools: {} } });
|
|
82
|
+
server.setRequestHandler(ListToolsRequestSchema, async () => ({ tools: TOOLS }));
|
|
83
|
+
server.setRequestHandler(CallToolRequestSchema, async (req) => {
|
|
84
|
+
const { name, arguments: args } = req.params;
|
|
85
|
+
const h = HANDLERS[name];
|
|
86
|
+
if (!h) return { content: [{ type: "text", text: JSON.stringify({ error: `unknown tool: ${name}` }) }], isError: true };
|
|
87
|
+
try { return { content: [{ type: "text", text: JSON.stringify(await h(args || {}), null, 2) }] }; }
|
|
88
|
+
catch (e) { return { content: [{ type: "text", text: JSON.stringify({ error: e.message }) }], isError: true }; }
|
|
89
|
+
});
|
|
90
|
+
await server.connect(new StdioServerTransport());
|
|
91
|
+
process.stderr.write("regulatory-deadline connected via stdio\n");
|
package/package.json
ADDED
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@weiseer/regulatory-deadline-mcp",
|
|
3
|
+
"version": "0.1.0",
|
|
4
|
+
"mcpName": "io.github.weiseer/regulatory-deadline",
|
|
5
|
+
"description": "FinCEN/SEC/EU AI Act/GDPR deadline tracker for AI agents.",
|
|
6
|
+
"type": "module",
|
|
7
|
+
"bin": { "regulatory-deadline-mcp": "./index.js" },
|
|
8
|
+
"main": "./index.js",
|
|
9
|
+
"files": ["index.js", "regulatory.json", "README.md"],
|
|
10
|
+
"scripts": { "start": "node index.js" },
|
|
11
|
+
"keywords": ["mcp", "model-context-protocol", "ai-agent", "weiseer"],
|
|
12
|
+
"author": "weiseer <wei@weiseer.com>",
|
|
13
|
+
"license": "Apache-2.0",
|
|
14
|
+
"repository": { "type": "git", "url": "https://github.com/weiseer/regulatory-deadline-mcp.git" },
|
|
15
|
+
"homepage": "https://github.com/weiseer/regulatory-deadline-mcp#readme",
|
|
16
|
+
"bugs": { "url": "https://github.com/weiseer/regulatory-deadline-mcp/issues" },
|
|
17
|
+
"engines": { "node": ">=18.0.0" },
|
|
18
|
+
"dependencies": { "@modelcontextprotocol/sdk": "^0.6.0" }
|
|
19
|
+
}
|