@voidly/mcp-server 1.0.0 → 1.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.
Files changed (3) hide show
  1. package/README.md +49 -46
  2. package/dist/index.js +90 -0
  3. package/package.json +1 -1
package/README.md CHANGED
@@ -1,26 +1,20 @@
1
1
  # Voidly MCP Server
2
2
 
3
- Model Context Protocol (MCP) server for the **Voidly Global Censorship Index**. Enables AI systems like Claude, ChatGPT, and other MCP-compatible clients to query real-time internet censorship data.
3
+ Model Context Protocol (MCP) server for the **Voidly Global Censorship Index**. Enables AI systems to query real-time internet censorship data.
4
4
 
5
- ## Features
5
+ ## Data Scale
6
6
 
7
- - **Real-time censorship data** from 50+ countries
8
- - **OONI-powered measurements** - millions of data points
9
- - **Incident tracking** - active censorship events
10
- - **Zero configuration** - works out of the box
11
-
12
- ## Tools
13
-
14
- | Tool | Description |
15
- |------|-------------|
16
- | `get_censorship_index` | Global overview of all monitored countries |
17
- | `get_country_status` | Detailed status for a specific country |
18
- | `check_domain_blocked` | Check if a domain is blocked in a country |
19
- | `get_most_censored` | Ranked list of most censored countries |
20
- | `get_active_incidents` | Currently active censorship incidents |
7
+ - **11.7M** live OONI measurements
8
+ - **1B+** historical measurements (10-year archive)
9
+ - **120+** countries monitored
10
+ - Updated every 5 minutes
21
11
 
22
12
  ## Installation
23
13
 
14
+ ```bash
15
+ npx @voidly/mcp-server
16
+ ```
17
+
24
18
  ### Claude Desktop
25
19
 
26
20
  Add to `~/Library/Application Support/Claude/claude_desktop_config.json`:
@@ -29,37 +23,41 @@ Add to `~/Library/Application Support/Claude/claude_desktop_config.json`:
29
23
  {
30
24
  "mcpServers": {
31
25
  "voidly": {
32
- "command": "node",
33
- "args": ["/path/to/voidly/mcp-server/dist/index.js"]
26
+ "command": "npx",
27
+ "args": ["@voidly/mcp-server"]
34
28
  }
35
29
  }
36
30
  }
37
31
  ```
38
32
 
39
- ### Claude Code
33
+ ### Cursor / Windsurf / Cline
40
34
 
41
- Add to your `.claude/settings.json`:
35
+ Add to your MCP config:
42
36
 
43
37
  ```json
44
38
  {
45
39
  "mcpServers": {
46
40
  "voidly": {
47
- "command": "node",
48
- "args": ["/path/to/voidly/mcp-server/dist/index.js"]
41
+ "command": "npx",
42
+ "args": ["@voidly/mcp-server"]
49
43
  }
50
44
  }
51
45
  }
52
46
  ```
53
47
 
54
- ### NPX (Coming Soon)
48
+ ## Tools
55
49
 
56
- ```bash
57
- npx @voidly/mcp-server
58
- ```
50
+ | Tool | Description |
51
+ |------|-------------|
52
+ | `get_censorship_index` | Global overview of all monitored countries |
53
+ | `get_country_status` | Detailed status for a specific country |
54
+ | `check_domain_blocked` | Check if a domain is blocked in a country |
55
+ | `get_most_censored` | Ranked list of most censored countries |
56
+ | `get_active_incidents` | Currently active censorship incidents |
59
57
 
60
58
  ## Usage Examples
61
59
 
62
- Once configured, you can ask Claude:
60
+ Once configured, you can ask:
63
61
 
64
62
  - "What countries have the most internet censorship?"
65
63
  - "Is the internet censored in China?"
@@ -67,38 +65,43 @@ Once configured, you can ask Claude:
67
65
  - "Are there any active internet shutdowns?"
68
66
  - "Is Twitter blocked in Russia?"
69
67
 
68
+ ## Other AI Platforms
69
+
70
+ ### OpenAI / ChatGPT
71
+
72
+ MCP isn't supported by OpenAI yet. Use our **OpenAI Action** instead:
73
+
74
+ 1. Go to ChatGPT → Create GPT → Actions
75
+ 2. Import [`openai-action/openapi.yaml`](../openai-action/openapi.yaml)
76
+ 3. Your GPT can now query Voidly data
77
+
78
+ ### Direct API
79
+
80
+ Public endpoints (no auth):
81
+ - `https://api.voidly.ai/data/censorship-index.json`
82
+ - `https://api.voidly.ai/data/country/{code}`
83
+ - `https://api.voidly.ai/data/methodology`
84
+
70
85
  ## Data Sources
71
86
 
72
87
  - **Primary**: OONI (Open Observatory of Network Interference)
73
- - **Update Frequency**: Every 6 hours
74
- - **Countries Monitored**: 50+
88
+ - **Secondary**: Voidly probe network
75
89
  - **License**: CC BY 4.0
76
90
 
77
- ## API Endpoints Used
78
-
79
- - `https://censorship.voidly.ai/v1/censorship-index`
80
- - `https://censorship.voidly.ai/v1/censorship-index/:country`
81
- - `https://censorship.voidly.ai/v1/censorship-index/incidents`
82
-
83
91
  ## Development
84
92
 
85
93
  ```bash
86
- # Install dependencies
87
94
  npm install
88
-
89
- # Build
90
95
  npm run build
91
-
92
- # Run in development
93
96
  npm run dev
94
97
  ```
95
98
 
96
- ## License
99
+ ## Links
97
100
 
98
- MIT
101
+ - [Voidly Censorship Index](https://voidly.ai/censorship-index)
102
+ - [npm Package](https://www.npmjs.com/package/@voidly/mcp-server)
103
+ - [OpenAI Action Spec](../openai-action/)
99
104
 
100
- ## Links
105
+ ## License
101
106
 
102
- - [Voidly Global Censorship Index](https://voidly.ai/censorship-index)
103
- - [API Documentation](https://voidly.ai/api-docs)
104
- - [Hugging Face Dataset](https://huggingface.co/datasets/emperor-mew/global-censorship-index)
107
+ MIT
package/dist/index.js CHANGED
@@ -187,6 +187,72 @@ async function getActiveIncidents() {
187
187
  result += `URL: https://voidly.ai/censorship-index\n`;
188
188
  return result;
189
189
  }
190
+ async function verifyClaim(claim, requireEvidence = false) {
191
+ const data = await fetchJson(`${VOIDLY_API}/v1/verify-claim?claim=${encodeURIComponent(claim)}&require_evidence=${requireEvidence}`);
192
+ let result = `# Claim Verification\n\n`;
193
+ result += `**Claim:** "${data.claim}"\n\n`;
194
+ // Verdict with emoji
195
+ const verdictEmoji = {
196
+ confirmed: '✅',
197
+ likely: '🟡',
198
+ unconfirmed: '❓',
199
+ no_data: '⚪',
200
+ insufficient_data: '⚠️',
201
+ };
202
+ result += `## Verdict: ${verdictEmoji[data.verdict] || ''} ${data.verdict.toUpperCase()}\n\n`;
203
+ result += `**Confidence:** ${(data.confidence * 100).toFixed(0)}%\n`;
204
+ result += `**Reason:** ${data.reason}\n\n`;
205
+ // Parsed components
206
+ result += `## Parsed Claim\n`;
207
+ if (data.parsed.country) {
208
+ result += `- Country: ${data.parsed.country} (${data.parsed.country_code})\n`;
209
+ }
210
+ if (data.parsed.service) {
211
+ result += `- Service: ${data.parsed.service}\n`;
212
+ }
213
+ if (data.parsed.date) {
214
+ result += `- Date: ${data.parsed.date}\n`;
215
+ }
216
+ if (data.parsed.date_range) {
217
+ result += `- Date Range: ${data.parsed.date_range.start} to ${data.parsed.date_range.end}\n`;
218
+ }
219
+ result += '\n';
220
+ // Matching incidents
221
+ if (data.incidents && data.incidents.length > 0) {
222
+ result += `## Supporting Incidents\n\n`;
223
+ data.incidents.forEach((inc, i) => {
224
+ result += `### ${i + 1}. ${inc.title}\n`;
225
+ result += `- ID: ${inc.id}\n`;
226
+ result += `- Status: ${inc.status}\n`;
227
+ result += `- Severity: ${inc.severity}\n`;
228
+ result += `- Confidence: ${(inc.confidence * 100).toFixed(0)}%\n`;
229
+ result += `- Started: ${inc.startTime.slice(0, 10)}\n`;
230
+ result += `- Permalink: ${inc.permalink}\n\n`;
231
+ });
232
+ }
233
+ // Evidence if requested
234
+ if (data.evidence && data.evidence.length > 0) {
235
+ result += `## Evidence Chain\n\n`;
236
+ data.evidence.forEach((ev, i) => {
237
+ result += `${i + 1}. **${ev.source.toUpperCase()}** (${ev.kind})\n`;
238
+ result += ` - Observed: ${ev.observedAt.slice(0, 10)}\n`;
239
+ result += ` - Confidence: ${(ev.confidence * 100).toFixed(0)}%\n`;
240
+ if (ev.permalink) {
241
+ result += ` - Verify: ${ev.permalink}\n`;
242
+ }
243
+ result += '\n';
244
+ });
245
+ }
246
+ // Citation
247
+ if (data.citation) {
248
+ result += `## Citation\n\n`;
249
+ result += `${data.citation}\n\n`;
250
+ }
251
+ result += `## Source\n`;
252
+ result += `Data: Voidly Research Claim Verification API\n`;
253
+ result += `License: CC BY 4.0\n`;
254
+ return result;
255
+ }
190
256
  // Create MCP server
191
257
  const server = new Server({
192
258
  name: 'voidly-censorship-index',
@@ -264,6 +330,24 @@ server.setRequestHandler(ListToolsRequestSchema, async () => ({
264
330
  required: [],
265
331
  },
266
332
  },
333
+ {
334
+ name: 'verify_claim',
335
+ description: 'Verify a censorship claim with evidence. Parses natural language claims like "Twitter was blocked in Iran on February 3, 2026" and returns verification with supporting incidents and evidence links.',
336
+ inputSchema: {
337
+ type: 'object',
338
+ properties: {
339
+ claim: {
340
+ type: 'string',
341
+ description: 'Natural language censorship claim to verify (e.g., "Is YouTube blocked in China?", "Twitter was blocked in Iran on February 3, 2026")',
342
+ },
343
+ require_evidence: {
344
+ type: 'boolean',
345
+ description: 'Whether to include detailed evidence chain with source links (default: false)',
346
+ },
347
+ },
348
+ required: ['claim'],
349
+ },
350
+ },
267
351
  ],
268
352
  }));
269
353
  server.setRequestHandler(CallToolRequestSchema, async (request) => {
@@ -293,6 +377,12 @@ server.setRequestHandler(CallToolRequestSchema, async (request) => {
293
377
  case 'get_active_incidents':
294
378
  result = await getActiveIncidents();
295
379
  break;
380
+ case 'verify_claim':
381
+ if (!args?.claim) {
382
+ throw new Error('claim is required');
383
+ }
384
+ result = await verifyClaim(args.claim, args?.require_evidence || false);
385
+ break;
296
386
  default:
297
387
  throw new Error(`Unknown tool: ${name}`);
298
388
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@voidly/mcp-server",
3
- "version": "1.0.0",
3
+ "version": "1.1.0",
4
4
  "description": "MCP server for Voidly Global Censorship Index - enables AI systems to query real-time censorship data",
5
5
  "type": "module",
6
6
  "main": "dist/index.js",