@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 +40 -5
- package/dist/index.js +361 -1
- package/dist/server.d.ts +2 -0
- package/dist/server.d.ts.map +1 -0
- package/dist/server.js +29 -0
- package/dist/src/formatters.d.ts +8 -0
- package/dist/src/formatters.d.ts.map +1 -0
- package/dist/src/formatters.js +108 -0
- package/dist/src/index.d.ts +4 -0
- package/dist/src/index.d.ts.map +1 -0
- package/dist/src/index.js +39 -0
- package/dist/src/tools/admin.d.ts +4 -0
- package/dist/src/tools/admin.d.ts.map +1 -0
- package/dist/src/tools/admin.js +206 -0
- package/dist/src/tools/analysis.d.ts +4 -0
- package/dist/src/tools/analysis.d.ts.map +1 -0
- package/dist/src/tools/analysis.js +179 -0
- package/dist/src/tools/detection.d.ts +4 -0
- package/dist/src/tools/detection.d.ts.map +1 -0
- package/dist/src/tools/detection.js +170 -0
- package/dist/src/tools/fraud.d.ts +4 -0
- package/dist/src/tools/fraud.d.ts.map +1 -0
- package/dist/src/tools/fraud.js +109 -0
- package/dist/src/tools/media.d.ts +4 -0
- package/dist/src/tools/media.d.ts.map +1 -0
- package/dist/src/tools/media.js +172 -0
- package/dist/src/transport.d.ts +7 -0
- package/dist/src/transport.d.ts.map +1 -0
- package/dist/src/transport.js +60 -0
- package/dist-ui/action-plan.html +176 -0
- package/dist-ui/detection-result.html +176 -0
- package/dist-ui/emotions-result.html +176 -0
- package/dist-ui/media-result.html +176 -0
- package/dist-ui/multi-result.html +176 -0
- package/dist-ui/report-result.html +176 -0
- package/package.json +31 -10
package/README.md
CHANGED
|
@@ -14,8 +14,9 @@
|
|
|
14
14
|
</p>
|
|
15
15
|
|
|
16
16
|
<p align="center">
|
|
17
|
-
<a href="https://
|
|
18
|
-
<a href="https://tuteliq.
|
|
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 (
|
|
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.
|
|
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**: [
|
|
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.
|
|
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}` }],
|
package/dist/server.d.ts
ADDED
|
@@ -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 @@
|
|
|
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"}
|