@tuteliq/mcp 2.2.0 → 3.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 CHANGED
@@ -14,8 +14,9 @@
14
14
  </p>
15
15
 
16
16
  <p align="center">
17
- <a href="https://api.tuteliq.ai/docs">API Docs</a> •
18
- <a href="https://tuteliq.app">Dashboard</a> •
17
+ <a href="https://docs.tuteliq.ai">API Docs</a> •
18
+ <a href="https://tuteliq.ai">Dashboard</a> •
19
+ <a href="https://trust.tuteliq.ai">Trust</a> •
19
20
  <a href="https://discord.gg/7kbTeRYRXD">Discord</a>
20
21
  </p>
21
22
 
@@ -25,7 +26,7 @@
25
26
 
26
27
  Tuteliq MCP Server brings AI-powered child safety tools directly into Claude, Cursor, and other MCP-compatible AI assistants. Ask Claude to check messages for bullying, detect grooming patterns, or generate safety action plans.
27
28
 
28
- ## Available Tools (33)
29
+ ## Available Tools (35)
29
30
 
30
31
  ### Safety Detection
31
32
 
@@ -93,6 +94,13 @@ Tuteliq MCP Server brings AI-powered child safety tools directly into Claude, Cu
93
94
  | `get_breach` | Get details of a specific data breach |
94
95
  | `update_breach_status` | Update breach status and notification progress |
95
96
 
97
+ ### Verification
98
+
99
+ | Tool | Description |
100
+ |------|-------------|
101
+ | `verify_age` | Verify a user's age via document analysis, biometric estimation, or both. Methods: `document`, `biometric`, `combined`. Returns verified age range, confidence score, and minor status. Beta — requires Pro tier. 5 credits per call. |
102
+ | `verify_identity` | Confirm user identity with document authentication, face matching, and liveness detection. Returns match score, liveness result, and document authentication status. Beta — requires Business tier. 10 credits per call. |
103
+
96
104
  ---
97
105
 
98
106
  ## Installation
@@ -198,11 +206,18 @@ The message contains direct exclusionary language...
198
206
  ### Usage
199
207
  > "Show my monthly usage"
200
208
 
209
+ ### Age Verification
210
+ > "Verify the age of this user using their uploaded ID document"
211
+ > "Estimate this user's age from their selfie using biometric analysis"
212
+
213
+ ### Identity Verification
214
+ > "Verify this user's identity by matching their selfie against their ID document"
215
+
201
216
  ---
202
217
 
203
218
  ## Get an API Key
204
219
 
205
- 1. Go to [tuteliq.app](https://tuteliq.app)
220
+ 1. Go to [tuteliq.ai](https://tuteliq.ai)
206
221
  2. Create an account
207
222
  3. Generate an API key
208
223
  4. Add it to your MCP config
@@ -232,7 +247,7 @@ Enable `PII_REDACTION_ENABLED=true` on your Tuteliq API to automatically strip e
232
247
 
233
248
  ## Support
234
249
 
235
- - **API Docs**: [api.tuteliq.ai/docs](https://api.tuteliq.ai/docs)
250
+ - **API Docs**: [docs.tuteliq.ai](https://docs.tuteliq.ai)
236
251
  - **Discord**: [discord.gg/7kbTeRYRXD](https://discord.gg/7kbTeRYRXD)
237
252
  - **Email**: support@tuteliq.ai
238
253
 
@@ -244,6 +259,26 @@ MIT License - see [LICENSE](LICENSE) for details.
244
259
 
245
260
  ---
246
261
 
262
+ ## Get Certified — Free
263
+
264
+ Tuteliq offers a **free certification program** for anyone who wants to deepen their understanding of online child safety. Complete a track, pass the quiz, and earn your official Tuteliq certificate — verified and shareable.
265
+
266
+ **Three tracks available:**
267
+
268
+ | Track | Who it's for | Duration |
269
+ |-------|-------------|----------|
270
+ | **Parents & Caregivers** | Parents, guardians, grandparents, teachers, coaches | ~90 min |
271
+ | **Young People (10–16)** | Young people who want to learn to spot manipulation | ~60 min |
272
+ | **Companies & Platforms** | Product managers, trust & safety teams, CTOs, compliance officers | ~120 min |
273
+
274
+ **Start here →** [tuteliq.ai/certify](https://tuteliq.ai/certify)
275
+
276
+ - 100% Free — no login required
277
+ - Verifiable certificate on completion
278
+ - Covers grooming recognition, sextortion, cyberbullying, regulatory obligations (KOSA, EU DSA), and more
279
+
280
+ ---
281
+
247
282
  ## The Mission: Why This Matters
248
283
 
249
284
  Before you decide to contribute or sponsor, read these numbers. They are not projections. They are not estimates from a pitch deck. They are verified statistics from the University of Edinburgh, UNICEF, NCMEC, and Interpol.
package/dist/index.js CHANGED
@@ -563,11 +563,175 @@ const tools = [
563
563
  required: ['id', 'status'],
564
564
  },
565
565
  },
566
+ // =========================================================================
567
+ // Fraud Detection Tools
568
+ // =========================================================================
569
+ {
570
+ name: 'detect_social_engineering',
571
+ description: 'Detect social engineering tactics such as pretexting, urgency fabrication, trust exploitation, and authority impersonation in text content.',
572
+ inputSchema: {
573
+ type: 'object',
574
+ properties: {
575
+ content: { type: 'string', description: 'Text content to analyze' },
576
+ context: { type: 'object', description: 'Optional analysis context' },
577
+ include_evidence: { type: 'boolean', description: 'Include supporting evidence excerpts' },
578
+ external_id: { type: 'string', description: 'External tracking ID' },
579
+ customer_id: { type: 'string', description: 'Customer identifier' },
580
+ },
581
+ required: ['content'],
582
+ },
583
+ },
584
+ {
585
+ name: 'detect_app_fraud',
586
+ description: 'Detect app-based fraud patterns such as fake investment platforms, phishing apps, subscription traps, and malicious download links.',
587
+ inputSchema: {
588
+ type: 'object',
589
+ properties: {
590
+ content: { type: 'string', description: 'Text content to analyze' },
591
+ context: { type: 'object', description: 'Optional analysis context' },
592
+ include_evidence: { type: 'boolean', description: 'Include supporting evidence excerpts' },
593
+ external_id: { type: 'string', description: 'External tracking ID' },
594
+ customer_id: { type: 'string', description: 'Customer identifier' },
595
+ },
596
+ required: ['content'],
597
+ },
598
+ },
599
+ {
600
+ name: 'detect_romance_scam',
601
+ description: 'Detect romance scam patterns such as love-bombing, financial requests, identity deception, and emotional manipulation in conversations.',
602
+ inputSchema: {
603
+ type: 'object',
604
+ properties: {
605
+ content: { type: 'string', description: 'Text content to analyze' },
606
+ context: { type: 'object', description: 'Optional analysis context' },
607
+ include_evidence: { type: 'boolean', description: 'Include supporting evidence excerpts' },
608
+ external_id: { type: 'string', description: 'External tracking ID' },
609
+ customer_id: { type: 'string', description: 'Customer identifier' },
610
+ },
611
+ required: ['content'],
612
+ },
613
+ },
614
+ {
615
+ name: 'detect_mule_recruitment',
616
+ description: 'Detect money mule recruitment tactics such as easy-money offers, bank account sharing requests, and laundering facilitation.',
617
+ inputSchema: {
618
+ type: 'object',
619
+ properties: {
620
+ content: { type: 'string', description: 'Text content to analyze' },
621
+ context: { type: 'object', description: 'Optional analysis context' },
622
+ include_evidence: { type: 'boolean', description: 'Include supporting evidence excerpts' },
623
+ external_id: { type: 'string', description: 'External tracking ID' },
624
+ customer_id: { type: 'string', description: 'Customer identifier' },
625
+ },
626
+ required: ['content'],
627
+ },
628
+ },
629
+ // =========================================================================
630
+ // Safety Extended Tools
631
+ // =========================================================================
632
+ {
633
+ name: 'detect_gambling_harm',
634
+ description: 'Detect gambling-related harm indicators such as chasing losses, borrowing to gamble, concealment behavior, and emotional distress from gambling.',
635
+ inputSchema: {
636
+ type: 'object',
637
+ properties: {
638
+ content: { type: 'string', description: 'Text content to analyze' },
639
+ context: { type: 'object', description: 'Optional analysis context' },
640
+ include_evidence: { type: 'boolean', description: 'Include supporting evidence excerpts' },
641
+ external_id: { type: 'string', description: 'External tracking ID' },
642
+ customer_id: { type: 'string', description: 'Customer identifier' },
643
+ },
644
+ required: ['content'],
645
+ },
646
+ },
647
+ {
648
+ name: 'detect_coercive_control',
649
+ description: 'Detect coercive control patterns such as isolation tactics, financial control, monitoring behavior, threats, and emotional manipulation.',
650
+ inputSchema: {
651
+ type: 'object',
652
+ properties: {
653
+ content: { type: 'string', description: 'Text content to analyze' },
654
+ context: { type: 'object', description: 'Optional analysis context' },
655
+ include_evidence: { type: 'boolean', description: 'Include supporting evidence excerpts' },
656
+ external_id: { type: 'string', description: 'External tracking ID' },
657
+ customer_id: { type: 'string', description: 'Customer identifier' },
658
+ },
659
+ required: ['content'],
660
+ },
661
+ },
662
+ {
663
+ name: 'detect_vulnerability_exploitation',
664
+ description: 'Detect exploitation of vulnerable individuals including targeting the elderly, disabled, financially distressed, or emotionally vulnerable.',
665
+ inputSchema: {
666
+ type: 'object',
667
+ properties: {
668
+ content: { type: 'string', description: 'Text content to analyze' },
669
+ context: { type: 'object', description: 'Optional analysis context' },
670
+ include_evidence: { type: 'boolean', description: 'Include supporting evidence excerpts' },
671
+ external_id: { type: 'string', description: 'External tracking ID' },
672
+ customer_id: { type: 'string', description: 'Customer identifier' },
673
+ },
674
+ required: ['content'],
675
+ },
676
+ },
677
+ {
678
+ name: 'detect_radicalisation',
679
+ description: 'Detect radicalisation indicators such as extremist rhetoric, us-vs-them framing, calls to action, conspiracy narratives, and ideological grooming.',
680
+ inputSchema: {
681
+ type: 'object',
682
+ properties: {
683
+ content: { type: 'string', description: 'Text content to analyze' },
684
+ context: { type: 'object', description: 'Optional analysis context' },
685
+ include_evidence: { type: 'boolean', description: 'Include supporting evidence excerpts' },
686
+ external_id: { type: 'string', description: 'External tracking ID' },
687
+ customer_id: { type: 'string', description: 'Customer identifier' },
688
+ },
689
+ required: ['content'],
690
+ },
691
+ },
692
+ // =========================================================================
693
+ // Multi-Endpoint Analysis
694
+ // =========================================================================
695
+ {
696
+ name: 'analyse_multi',
697
+ description: 'Run multiple detection endpoints on a single piece of text. Returns individual results per endpoint plus an aggregated summary with overall risk level.',
698
+ inputSchema: {
699
+ type: 'object',
700
+ properties: {
701
+ content: { type: 'string', description: 'Text content to analyze' },
702
+ endpoints: {
703
+ type: 'array',
704
+ items: { type: 'string' },
705
+ description: 'Detection endpoints to run (e.g., social_engineering, app_fraud, romance_scam, mule_recruitment, gambling_harm, coercive_control, vulnerability_exploitation, radicalisation)',
706
+ },
707
+ context: { type: 'object', description: 'Optional analysis context' },
708
+ include_evidence: { type: 'boolean', description: 'Include supporting evidence in individual results' },
709
+ external_id: { type: 'string', description: 'External tracking ID' },
710
+ customer_id: { type: 'string', description: 'Customer identifier' },
711
+ },
712
+ required: ['content', 'endpoints'],
713
+ },
714
+ },
715
+ // =========================================================================
716
+ // Video Analysis
717
+ // =========================================================================
718
+ {
719
+ name: 'analyze_video',
720
+ description: 'Analyze a video file for safety concerns. Extracts key frames and runs safety classification on each. Returns timestamped findings with severity scores. Supports mp4, mov, avi, webm, mkv.',
721
+ inputSchema: {
722
+ type: 'object',
723
+ properties: {
724
+ file_path: { type: 'string', description: 'Absolute path to the video file on disk' },
725
+ age_group: { type: 'string', description: 'Age group for calibrated analysis (e.g., "child", "teen", "adult")' },
726
+ },
727
+ required: ['file_path'],
728
+ },
729
+ },
566
730
  ];
567
731
  // Create MCP server
568
732
  const server = new index_js_1.Server({
569
733
  name: 'tuteliq-mcp',
570
- version: '2.1.0',
734
+ version: '2.2.0',
571
735
  }, {
572
736
  capabilities: {
573
737
  tools: {},
@@ -581,6 +745,88 @@ server.setRequestHandler(types_js_1.ListToolsRequestSchema, async () => {
581
745
  function filenameFromPath(filePath) {
582
746
  return filePath.split('/').pop() || filePath;
583
747
  }
748
+ // Format a DetectionResult as markdown
749
+ function formatDetectionResult(result) {
750
+ const detected = result.detected;
751
+ const levelEmoji = riskEmoji[result.level] || '⚪';
752
+ const label = result.endpoint
753
+ .split('_')
754
+ .map(w => w.charAt(0).toUpperCase() + w.slice(1))
755
+ .join(' ');
756
+ const header = detected
757
+ ? `## ${levelEmoji} ${label} Detected`
758
+ : `## ✅ No ${label} Detected`;
759
+ const categories = result.categories.length > 0
760
+ ? `**Categories:** ${result.categories.map(c => c.tag).join(', ')}`
761
+ : '';
762
+ const evidence = result.evidence && result.evidence.length > 0
763
+ ? `### Evidence\n${result.evidence.map(e => `- _"${e.text}"_ — **${e.tactic}** (weight: ${e.weight.toFixed(2)})`).join('\n')}`
764
+ : '';
765
+ const calibration = result.age_calibration?.applied
766
+ ? `**Age Calibration:** ${result.age_calibration.age_group} (${result.age_calibration.multiplier}x)`
767
+ : '';
768
+ return `${header}
769
+
770
+ **Risk Score:** ${(result.risk_score * 100).toFixed(0)}%
771
+ **Level:** ${result.level}
772
+ **Confidence:** ${(result.confidence * 100).toFixed(0)}%
773
+ ${categories}
774
+
775
+ ### Rationale
776
+ ${result.rationale}
777
+
778
+ ### Recommended Action
779
+ \`${result.recommended_action}\`
780
+
781
+ ${evidence}
782
+ ${calibration}`.trim();
783
+ }
784
+ // Format an AnalyseMultiResult as markdown
785
+ function formatMultiResult(result) {
786
+ const s = result.summary;
787
+ const overallEmoji = riskEmoji[s.overall_risk_level] || '⚪';
788
+ const summarySection = `## Multi-Endpoint Analysis
789
+
790
+ **Overall Risk:** ${overallEmoji} ${s.overall_risk_level}
791
+ **Endpoints Analyzed:** ${s.total_endpoints}
792
+ **Threats Detected:** ${s.detected_count}
793
+ **Highest Risk:** ${s.highest_risk.endpoint} (${(s.highest_risk.risk_score * 100).toFixed(0)}%)
794
+ ${result.cross_endpoint_modifier ? `**Cross-Endpoint Modifier:** ${result.cross_endpoint_modifier.toFixed(2)}x` : ''}`;
795
+ const perEndpoint = result.results
796
+ .map(r => {
797
+ const emoji = r.detected ? (riskEmoji[r.level] || '⚪') : '✅';
798
+ return `### ${emoji} ${r.endpoint}
799
+ **Detected:** ${r.detected ? 'Yes' : 'No'} | **Risk:** ${(r.risk_score * 100).toFixed(0)}% | **Level:** ${r.level}
800
+ ${r.categories.length > 0 ? `**Categories:** ${r.categories.map(c => c.tag).join(', ')}` : ''}
801
+ ${r.rationale}`;
802
+ })
803
+ .join('\n\n');
804
+ return `${summarySection}
805
+
806
+ ---
807
+
808
+ ${perEndpoint}`;
809
+ }
810
+ // Format a VideoAnalysisResult as markdown
811
+ function formatVideoResult(result) {
812
+ const emoji = severityEmoji[result.overall_severity] || '✅';
813
+ const findingsSection = result.safety_findings.length > 0
814
+ ? result.safety_findings
815
+ .map(f => {
816
+ const fEmoji = severityEmoji[f.severity <= 0.3 ? 'low' : f.severity <= 0.6 ? 'medium' : f.severity <= 0.85 ? 'high' : 'critical'] || '⚪';
817
+ return `- \`${f.timestamp.toFixed(1)}s\` (frame ${f.frame_index}) ${fEmoji} ${f.description}\n Categories: ${f.categories.join(', ')} | Severity: ${(f.severity * 100).toFixed(0)}%`;
818
+ })
819
+ .join('\n')
820
+ : '_No safety findings._';
821
+ return `## 🎬 Video Analysis
822
+
823
+ **Overall Severity:** ${emoji} ${result.overall_severity}
824
+ **Overall Risk Score:** ${(result.overall_risk_score * 100).toFixed(0)}%
825
+ **Frames Analyzed:** ${result.frames_analyzed}
826
+
827
+ ### Safety Findings
828
+ ${findingsSection}`;
829
+ }
584
830
  // Call tool handler
585
831
  server.setRequestHandler(types_js_1.CallToolRequestSchema, async (request) => {
586
832
  const { name, arguments: args = {} } = request.params;
@@ -1009,6 +1255,120 @@ ${result.recommendations ? `### Recommendation\n${result.recommendations.reason}
1009
1255
  const b = result.breach;
1010
1256
  return { content: [{ type: 'text', text: `## ✅ Breach Updated\n\n**ID:** ${b.id}\n**Status:** ${b.status}\n**Notification:** ${b.notification_status}` }] };
1011
1257
  }
1258
+ // =====================================================================
1259
+ // Fraud Detection
1260
+ // =====================================================================
1261
+ case 'detect_social_engineering': {
1262
+ const result = await client.detectSocialEngineering({
1263
+ content: args.content,
1264
+ context: args.context,
1265
+ includeEvidence: args.include_evidence,
1266
+ external_id: args.external_id,
1267
+ customer_id: args.customer_id,
1268
+ });
1269
+ return { content: [{ type: 'text', text: formatDetectionResult(result) }] };
1270
+ }
1271
+ case 'detect_app_fraud': {
1272
+ const result = await client.detectAppFraud({
1273
+ content: args.content,
1274
+ context: args.context,
1275
+ includeEvidence: args.include_evidence,
1276
+ external_id: args.external_id,
1277
+ customer_id: args.customer_id,
1278
+ });
1279
+ return { content: [{ type: 'text', text: formatDetectionResult(result) }] };
1280
+ }
1281
+ case 'detect_romance_scam': {
1282
+ const result = await client.detectRomanceScam({
1283
+ content: args.content,
1284
+ context: args.context,
1285
+ includeEvidence: args.include_evidence,
1286
+ external_id: args.external_id,
1287
+ customer_id: args.customer_id,
1288
+ });
1289
+ return { content: [{ type: 'text', text: formatDetectionResult(result) }] };
1290
+ }
1291
+ case 'detect_mule_recruitment': {
1292
+ const result = await client.detectMuleRecruitment({
1293
+ content: args.content,
1294
+ context: args.context,
1295
+ includeEvidence: args.include_evidence,
1296
+ external_id: args.external_id,
1297
+ customer_id: args.customer_id,
1298
+ });
1299
+ return { content: [{ type: 'text', text: formatDetectionResult(result) }] };
1300
+ }
1301
+ // =====================================================================
1302
+ // Safety Extended
1303
+ // =====================================================================
1304
+ case 'detect_gambling_harm': {
1305
+ const result = await client.detectGamblingHarm({
1306
+ content: args.content,
1307
+ context: args.context,
1308
+ includeEvidence: args.include_evidence,
1309
+ external_id: args.external_id,
1310
+ customer_id: args.customer_id,
1311
+ });
1312
+ return { content: [{ type: 'text', text: formatDetectionResult(result) }] };
1313
+ }
1314
+ case 'detect_coercive_control': {
1315
+ const result = await client.detectCoerciveControl({
1316
+ content: args.content,
1317
+ context: args.context,
1318
+ includeEvidence: args.include_evidence,
1319
+ external_id: args.external_id,
1320
+ customer_id: args.customer_id,
1321
+ });
1322
+ return { content: [{ type: 'text', text: formatDetectionResult(result) }] };
1323
+ }
1324
+ case 'detect_vulnerability_exploitation': {
1325
+ const result = await client.detectVulnerabilityExploitation({
1326
+ content: args.content,
1327
+ context: args.context,
1328
+ includeEvidence: args.include_evidence,
1329
+ external_id: args.external_id,
1330
+ customer_id: args.customer_id,
1331
+ });
1332
+ return { content: [{ type: 'text', text: formatDetectionResult(result) }] };
1333
+ }
1334
+ case 'detect_radicalisation': {
1335
+ const result = await client.detectRadicalisation({
1336
+ content: args.content,
1337
+ context: args.context,
1338
+ includeEvidence: args.include_evidence,
1339
+ external_id: args.external_id,
1340
+ customer_id: args.customer_id,
1341
+ });
1342
+ return { content: [{ type: 'text', text: formatDetectionResult(result) }] };
1343
+ }
1344
+ // =====================================================================
1345
+ // Multi-Endpoint Analysis
1346
+ // =====================================================================
1347
+ case 'analyse_multi': {
1348
+ const result = await client.analyseMulti({
1349
+ content: args.content,
1350
+ detections: args.endpoints,
1351
+ context: args.context,
1352
+ includeEvidence: args.include_evidence,
1353
+ external_id: args.external_id,
1354
+ customer_id: args.customer_id,
1355
+ });
1356
+ return { content: [{ type: 'text', text: formatMultiResult(result) }] };
1357
+ }
1358
+ // =====================================================================
1359
+ // Video Analysis
1360
+ // =====================================================================
1361
+ case 'analyze_video': {
1362
+ const filePath = args.file_path;
1363
+ const buffer = (0, fs_1.readFileSync)(filePath);
1364
+ const filename = filenameFromPath(filePath);
1365
+ const result = await client.analyzeVideo({
1366
+ file: buffer,
1367
+ filename,
1368
+ ageGroup: args.age_group,
1369
+ });
1370
+ return { content: [{ type: 'text', text: formatVideoResult(result) }] };
1371
+ }
1012
1372
  default:
1013
1373
  return {
1014
1374
  content: [{ type: 'text', text: `Unknown tool: ${name}` }],
@@ -0,0 +1,2 @@
1
+ export {};
2
+ //# sourceMappingURL=server.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"server.d.ts","sourceRoot":"","sources":["../server.ts"],"names":[],"mappings":""}
package/dist/server.js ADDED
@@ -0,0 +1,29 @@
1
+ "use strict";
2
+ var __importDefault = (this && this.__importDefault) || function (mod) {
3
+ return (mod && mod.__esModule) ? mod : { "default": mod };
4
+ };
5
+ Object.defineProperty(exports, "__esModule", { value: true });
6
+ const express_1 = __importDefault(require("express"));
7
+ const cors_1 = __importDefault(require("cors"));
8
+ const index_js_1 = require("./src/index.js");
9
+ const transport_js_1 = require("./src/transport.js");
10
+ const app = (0, express_1.default)();
11
+ const port = parseInt(process.env.PORT || '3001', 10);
12
+ app.use((0, cors_1.default)());
13
+ app.use(express_1.default.json());
14
+ const mcpServer = (0, index_js_1.createServer)();
15
+ const mcpHandler = (0, transport_js_1.createHttpHandler)(mcpServer);
16
+ app.all('/mcp', (req, res) => {
17
+ mcpHandler(req, res).catch((err) => {
18
+ console.error('MCP handler error:', err);
19
+ if (!res.headersSent) {
20
+ res.status(500).json({ error: 'Internal server error' });
21
+ }
22
+ });
23
+ });
24
+ app.get('/health', (_req, res) => {
25
+ res.json({ status: 'ok', version: '3.0.0' });
26
+ });
27
+ app.listen(port, () => {
28
+ console.error(`Tuteliq MCP App server running on http://localhost:${port}/mcp`);
29
+ });
@@ -0,0 +1,8 @@
1
+ import type { DetectionResult, AnalyseMultiResult, VideoAnalysisResult } from '@tuteliq/sdk';
2
+ export declare const severityEmoji: Record<string, string>;
3
+ export declare const riskEmoji: Record<string, string>;
4
+ export declare const trendEmoji: Record<string, string>;
5
+ export declare function formatDetectionResult(result: DetectionResult): string;
6
+ export declare function formatMultiResult(result: AnalyseMultiResult): string;
7
+ export declare function formatVideoResult(result: VideoAnalysisResult): string;
8
+ //# sourceMappingURL=formatters.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"formatters.d.ts","sourceRoot":"","sources":["../../src/formatters.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,eAAe,EAAE,kBAAkB,EAAE,mBAAmB,EAAE,MAAM,cAAc,CAAC;AAE7F,eAAO,MAAM,aAAa,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAKhD,CAAC;AAEF,eAAO,MAAM,SAAS,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAO5C,CAAC;AAEF,eAAO,MAAM,UAAU,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAI7C,CAAC;AAEF,wBAAgB,qBAAqB,CAAC,MAAM,EAAE,eAAe,GAAG,MAAM,CA4CrE;AAED,wBAAgB,iBAAiB,CAAC,MAAM,EAAE,kBAAkB,GAAG,MAAM,CA2BpE;AAED,wBAAgB,iBAAiB,CAAC,MAAM,EAAE,mBAAmB,GAAG,MAAM,CAoBrE"}
@@ -0,0 +1,108 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.trendEmoji = exports.riskEmoji = exports.severityEmoji = void 0;
4
+ exports.formatDetectionResult = formatDetectionResult;
5
+ exports.formatMultiResult = formatMultiResult;
6
+ exports.formatVideoResult = formatVideoResult;
7
+ exports.severityEmoji = {
8
+ low: '\u{1F7E1}',
9
+ medium: '\u{1F7E0}',
10
+ high: '\u{1F534}',
11
+ critical: '\u26D4',
12
+ };
13
+ exports.riskEmoji = {
14
+ safe: '\u2705',
15
+ none: '\u2705',
16
+ low: '\u{1F7E1}',
17
+ medium: '\u{1F7E0}',
18
+ high: '\u{1F534}',
19
+ critical: '\u26D4',
20
+ };
21
+ exports.trendEmoji = {
22
+ improving: '\u{1F4C8}',
23
+ stable: '\u27A1\uFE0F',
24
+ worsening: '\u{1F4C9}',
25
+ };
26
+ function formatDetectionResult(result) {
27
+ const detected = result.detected;
28
+ const levelEmoji = exports.riskEmoji[result.level] || '\u26AA';
29
+ const label = result.endpoint
30
+ .split('_')
31
+ .map(w => w.charAt(0).toUpperCase() + w.slice(1))
32
+ .join(' ');
33
+ const header = detected
34
+ ? `## ${levelEmoji} ${label} Detected`
35
+ : `## \u2705 No ${label} Detected`;
36
+ const categories = result.categories.length > 0
37
+ ? `**Categories:** ${result.categories.map(c => c.tag).join(', ')}`
38
+ : '';
39
+ const evidence = result.evidence && result.evidence.length > 0
40
+ ? `### Evidence\n${result.evidence.map(e => `- _"${e.text}"_ \u2014 **${e.tactic}** (weight: ${e.weight.toFixed(2)})`).join('\n')}`
41
+ : '';
42
+ const calibration = result.age_calibration?.applied
43
+ ? `**Age Calibration:** ${result.age_calibration.age_group} (${result.age_calibration.multiplier}x)`
44
+ : '';
45
+ const messageAnalysis = result.message_analysis && result.message_analysis.length > 0
46
+ ? `### Message Analysis\n${result.message_analysis.map(m => `- **Message ${m.message_index}** (risk: ${(m.risk_score * 100).toFixed(0)}%) — ${m.summary}${m.flags.length > 0 ? ` [${m.flags.join(', ')}]` : ''}`).join('\n')}`
47
+ : '';
48
+ return `${header}
49
+
50
+ **Risk Score:** ${(result.risk_score * 100).toFixed(0)}%
51
+ **Level:** ${result.level}
52
+ **Confidence:** ${(result.confidence * 100).toFixed(0)}%
53
+ ${categories}
54
+
55
+ ### Rationale
56
+ ${result.rationale}
57
+
58
+ ### Recommended Action
59
+ \`${result.recommended_action}\`
60
+
61
+ ${evidence}
62
+ ${messageAnalysis}
63
+ ${calibration}`.trim();
64
+ }
65
+ function formatMultiResult(result) {
66
+ const s = result.summary;
67
+ const overallEmoji = exports.riskEmoji[s.overall_risk_level] || '\u26AA';
68
+ const summarySection = `## Multi-Endpoint Analysis
69
+
70
+ **Overall Risk:** ${overallEmoji} ${s.overall_risk_level}
71
+ **Endpoints Analyzed:** ${s.total_endpoints}
72
+ **Threats Detected:** ${s.detected_count}
73
+ **Highest Risk:** ${s.highest_risk.endpoint} (${(s.highest_risk.risk_score * 100).toFixed(0)}%)
74
+ ${result.cross_endpoint_modifier ? `**Cross-Endpoint Modifier:** ${result.cross_endpoint_modifier.toFixed(2)}x` : ''}`;
75
+ const perEndpoint = result.results
76
+ .map(r => {
77
+ const emoji = r.detected ? (exports.riskEmoji[r.level] || '\u26AA') : '\u2705';
78
+ return `### ${emoji} ${r.endpoint}
79
+ **Detected:** ${r.detected ? 'Yes' : 'No'} | **Risk:** ${(r.risk_score * 100).toFixed(0)}% | **Level:** ${r.level}
80
+ ${r.categories.length > 0 ? `**Categories:** ${r.categories.map(c => c.tag).join(', ')}` : ''}
81
+ ${r.rationale}`;
82
+ })
83
+ .join('\n\n');
84
+ return `${summarySection}
85
+
86
+ ---
87
+
88
+ ${perEndpoint}`;
89
+ }
90
+ function formatVideoResult(result) {
91
+ const emoji = exports.severityEmoji[result.overall_severity] || '\u2705';
92
+ const findingsSection = result.safety_findings.length > 0
93
+ ? result.safety_findings
94
+ .map(f => {
95
+ const fEmoji = exports.severityEmoji[f.severity <= 0.3 ? 'low' : f.severity <= 0.6 ? 'medium' : f.severity <= 0.85 ? 'high' : 'critical'] || '\u26AA';
96
+ return `- \`${f.timestamp.toFixed(1)}s\` (frame ${f.frame_index}) ${fEmoji} ${f.description}\n Categories: ${f.categories.join(', ')} | Severity: ${(f.severity * 100).toFixed(0)}%`;
97
+ })
98
+ .join('\n')
99
+ : '_No safety findings._';
100
+ return `## \u{1F3AC} Video Analysis
101
+
102
+ **Overall Severity:** ${emoji} ${result.overall_severity}
103
+ **Overall Risk Score:** ${(result.overall_risk_score * 100).toFixed(0)}%
104
+ **Frames Analyzed:** ${result.frames_analyzed}
105
+
106
+ ### Safety Findings
107
+ ${findingsSection}`;
108
+ }
@@ -0,0 +1,4 @@
1
+ #!/usr/bin/env node
2
+ import { McpServer } from '@modelcontextprotocol/sdk/server/mcp.js';
3
+ export declare function createServer(): McpServer;
4
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/index.ts"],"names":[],"mappings":";AAEA,OAAO,EAAE,SAAS,EAAE,MAAM,yCAAyC,CAAC;AAUpE,wBAAgB,YAAY,IAAI,SAAS,CAsBxC"}