Localize mcp.php + add mcp-tool.php detail pages for all 19 MCP tools
- Replace all hardcoded English strings in mcp.php with dbnToolsT() calls - Add 44 MCP UI chrome translation keys to includes/i18n.php (en/no/uk/pl) - Generate includes/mcp-tool-translations.php with tool names, descriptions, and parameter docs translated into Norwegian, Ukrainian, and Polish via Azure OpenAI - Create mcp-tool.php: parameterized detail page (?tool=dbn.slug) with parameter table, example request/response JSON, and privacy section, all localized - Add "View details →" links on tool cards in mcp.php (shown on expand) - Add translations/mcp-chrome.php and scripts/generate-mcp-translations.php Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
+833
@@ -0,0 +1,833 @@
|
||||
<?php
|
||||
declare(strict_types=1);
|
||||
|
||||
require_once __DIR__ . '/includes/bootstrap.php';
|
||||
require_once __DIR__ . '/includes/DbnMcpRuntime.php';
|
||||
|
||||
$uiLang = dbnToolsCurrentLanguage();
|
||||
|
||||
// ── Load tool from ?tool= param ──────────────────────────────────────────────
|
||||
$requestedSlug = (string)($_GET['tool'] ?? '');
|
||||
$toolCatalog = DbnMcpRuntime::tools();
|
||||
$toolDef = null;
|
||||
foreach ($toolCatalog as $t) {
|
||||
if (($t['slug'] ?? '') === $requestedSlug) {
|
||||
$toolDef = $t;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if ($toolDef === null) {
|
||||
http_response_code(404);
|
||||
echo '<!doctype html><html><head><title>Tool not found</title></head><body><p>MCP tool not found. <a href="/mcp.php">Back to MCP setup</a></p></body></html>';
|
||||
exit;
|
||||
}
|
||||
|
||||
// ── Load translations ─────────────────────────────────────────────────────────
|
||||
$toolTranslations = [];
|
||||
$toolTransFile = __DIR__ . '/includes/mcp-tool-translations.php';
|
||||
if (file_exists($toolTransFile)) {
|
||||
$toolTranslations = (array)include $toolTransFile;
|
||||
}
|
||||
|
||||
function mcpToolT(string $slug, string $field, string $lang, array $trans): string
|
||||
{
|
||||
$fallback = $trans[$slug]['en'][$field] ?? '';
|
||||
return (string)($trans[$slug][$lang][$field] ?? $fallback);
|
||||
}
|
||||
|
||||
function mcpToolParamT(string $slug, string $param, string $lang, array $trans): string
|
||||
{
|
||||
$fallback = $trans[$slug]['en']['params'][$param] ?? '';
|
||||
return (string)($trans[$slug][$lang]['params'][$param] ?? $fallback);
|
||||
}
|
||||
|
||||
// ── Resolved display data ────────────────────────────────────────────────────
|
||||
$slug = (string)($toolDef['slug'] ?? '');
|
||||
$displayName = mcpToolT($slug, 'display_name', $uiLang, $toolTranslations) ?: (string)($toolDef['display_name'] ?? $slug);
|
||||
$description = mcpToolT($slug, 'description', $uiLang, $toolTranslations) ?: (string)($toolDef['description'] ?? '');
|
||||
$props = (array)($toolDef['config']['input_schema']['properties'] ?? []);
|
||||
$required = (array)($toolDef['config']['input_schema']['required'] ?? []);
|
||||
|
||||
$toolIcons = [
|
||||
'dbn.search_legal' => '🔍',
|
||||
'dbn.ask' => '💬',
|
||||
'dbn.summarize' => '📋',
|
||||
'dbn.timeline' => '📅',
|
||||
'dbn.redact' => '🔒',
|
||||
'dbn.translate' => '🌍',
|
||||
'dbn.legal_analysis' => '⚖️',
|
||||
'dbn.korrespond' => '✉️',
|
||||
'dbn.barnevernet_analyze' => '📄',
|
||||
'dbn.advocate_brief' => '🏛️',
|
||||
'dbn.deep_research' => '🔬',
|
||||
'dbn.discrepancy_find' => '🔄',
|
||||
'dbn.transcribe_audio' => '🎤',
|
||||
'dbn.corpus_stats' => '📊',
|
||||
'dbn.list_documents' => '📚',
|
||||
'dbn.get_document' => '📖',
|
||||
'dbn.citation_graph' => '🔗',
|
||||
'dbn.case_workbench_plan' => '🗂️',
|
||||
'dbn.save_to_case' => '💾',
|
||||
];
|
||||
$toolIcon = $toolIcons[$slug] ?? '🔧';
|
||||
|
||||
// ── Example requests (per tool) ───────────────────────────────────────────────
|
||||
$exampleRequests = [
|
||||
'dbn.search_legal' => <<<'JSON'
|
||||
{
|
||||
"query": "emergency care order requirements barnevernet",
|
||||
"language": "en",
|
||||
"limit": 5,
|
||||
"corpus_scope": "shared"
|
||||
}
|
||||
JSON,
|
||||
'dbn.ask' => <<<'JSON'
|
||||
{
|
||||
"question": "Can Barnevernet remove a child without a court hearing?",
|
||||
"language": "en",
|
||||
"use_case_context": false
|
||||
}
|
||||
JSON,
|
||||
'dbn.summarize' => <<<'JSON'
|
||||
{
|
||||
"text": "Paste the case document text here...",
|
||||
"language": "en",
|
||||
"use_legal_corpus": true,
|
||||
"use_case_context": false
|
||||
}
|
||||
JSON,
|
||||
'dbn.timeline' => <<<'JSON'
|
||||
{
|
||||
"text": "Paste case notes or decision letter here...",
|
||||
"language": "en",
|
||||
"focus": "all",
|
||||
"use_case_context": false
|
||||
}
|
||||
JSON,
|
||||
'dbn.redact' => <<<'JSON'
|
||||
{
|
||||
"text": "On 15.03.2024 caseworker Anna Hansen met with...",
|
||||
"language": "no",
|
||||
"mode": "standard",
|
||||
"output_format": "contextual"
|
||||
}
|
||||
JSON,
|
||||
'dbn.translate' => <<<'JSON'
|
||||
{
|
||||
"text": "Barnevernet fattet vedtak om omsorgsovertakelse...",
|
||||
"source_lang": "no",
|
||||
"target_lang": "en",
|
||||
"doc_type": "barnevernet"
|
||||
}
|
||||
JSON,
|
||||
'dbn.legal_analysis' => <<<'JSON'
|
||||
{
|
||||
"text": "Paste the document text to analyze here...",
|
||||
"language": "en",
|
||||
"doc_type": "auto"
|
||||
}
|
||||
JSON,
|
||||
'dbn.korrespond' => <<<'JSON'
|
||||
{
|
||||
"narrative": "Barnevernet issued an emergency placement order without notification.",
|
||||
"recipient_body": "Barnevernet",
|
||||
"goal": "Appeal the decision and request access to case documents.",
|
||||
"mode": "initiate",
|
||||
"language": "en"
|
||||
}
|
||||
JSON,
|
||||
'dbn.barnevernet_analyze' => <<<'JSON'
|
||||
{
|
||||
"document_text": "Paste the Barnevernet document text here...",
|
||||
"filename": "vedtak-omsorgsovertakelse.pdf",
|
||||
"advocate_role": "parent",
|
||||
"language": "en"
|
||||
}
|
||||
JSON,
|
||||
'dbn.advocate_brief' => <<<'JSON'
|
||||
{
|
||||
"query": "Grounds for challenging a care order under BVL §4-12",
|
||||
"advocate_role": "parent",
|
||||
"language": "en",
|
||||
"use_case_context": false
|
||||
}
|
||||
JSON,
|
||||
'dbn.deep_research' => <<<'JSON'
|
||||
{
|
||||
"query": "ECHR Article 8 violations in Norwegian child welfare cases",
|
||||
"language": "en",
|
||||
"use_case_context": false
|
||||
}
|
||||
JSON,
|
||||
'dbn.discrepancy_find' => <<<'JSON'
|
||||
{
|
||||
"document_a_text": "Text of the first document version...",
|
||||
"document_b_text": "Text of the second document version...",
|
||||
"filename_a": "report-2023.pdf",
|
||||
"filename_b": "report-2024.pdf",
|
||||
"language": "en"
|
||||
}
|
||||
JSON,
|
||||
'dbn.transcribe_audio' => <<<'JSON'
|
||||
{
|
||||
"audio_url": "https://example.com/meeting-recording.mp3",
|
||||
"language": "no",
|
||||
"diarize": true
|
||||
}
|
||||
JSON,
|
||||
'dbn.corpus_stats' => '{}',
|
||||
'dbn.list_documents' => <<<'JSON'
|
||||
{
|
||||
"category": "barnevernet",
|
||||
"limit": 20,
|
||||
"offset": 0
|
||||
}
|
||||
JSON,
|
||||
'dbn.get_document' => <<<'JSON'
|
||||
{
|
||||
"document_id": 42
|
||||
}
|
||||
JSON,
|
||||
'dbn.citation_graph' => <<<'JSON'
|
||||
{
|
||||
"doc_id": 42,
|
||||
"action": "cites",
|
||||
"depth": 2
|
||||
}
|
||||
JSON,
|
||||
'dbn.case_workbench_plan' => <<<'JSON'
|
||||
{
|
||||
"situation": "Barnevernet has scheduled a Fylkesnemnda hearing in 3 weeks. I need to prepare a response.",
|
||||
"goal": "Challenge the care order and request return of the child.",
|
||||
"deadline": "2024-06-15",
|
||||
"language": "en"
|
||||
}
|
||||
JSON,
|
||||
'dbn.save_to_case' => <<<'JSON'
|
||||
{
|
||||
"tool": "dbn.legal_analysis",
|
||||
"title": "Legal analysis of care order decision",
|
||||
"input_payload": { "text": "...", "language": "en" },
|
||||
"output_payload": { "issues": [...], "summary": "..." }
|
||||
}
|
||||
JSON,
|
||||
];
|
||||
|
||||
// ── Example responses (per tool) ──────────────────────────────────────────────
|
||||
$exampleResponses = [
|
||||
'dbn.search_legal' => <<<'JSON'
|
||||
{
|
||||
"ok": true,
|
||||
"results": [
|
||||
{
|
||||
"title": "BVL §4-12 — Vedtak om omsorgsovertakelse",
|
||||
"chunk_text": "§ 4-12. Vedtak om å overta omsorgen for et barn kan treffes dersom...",
|
||||
"score": 0.91,
|
||||
"source": "barnevernsloven"
|
||||
},
|
||||
{
|
||||
"title": "NOU 2012:5 — Bedre beskyttelse av barns utvikling",
|
||||
"chunk_text": "Utvalget vurderer at terskelen for akuttvedtak bør klargjøres...",
|
||||
"score": 0.84,
|
||||
"source": "nou"
|
||||
}
|
||||
],
|
||||
"total": 2
|
||||
}
|
||||
JSON,
|
||||
'dbn.ask' => <<<'JSON'
|
||||
{
|
||||
"ok": true,
|
||||
"answer": "Under Norwegian law, Barnevernet may issue an emergency care order (akuttvedtak) under BVL §4-6 without a prior court hearing if there is immediate risk of serious harm. However, the case must be reviewed by Fylkesnemnda within six weeks...",
|
||||
"sources": [
|
||||
{ "title": "BVL §4-6 — Midlertidige vedtak", "url": "/corpus/bvl-4-6" },
|
||||
{ "title": "Strand Lobben m.fl. mot Norge (EMD)", "url": "/corpus/echr-strand-lobben" }
|
||||
],
|
||||
"credits_used": 3
|
||||
}
|
||||
JSON,
|
||||
'dbn.summarize' => <<<'JSON'
|
||||
{
|
||||
"ok": true,
|
||||
"summary": "The document is a Barnevernet investigation report concerning a family with two children. Key findings include...",
|
||||
"key_points": [
|
||||
"Home visit conducted 12.03.2024 — no immediate danger found",
|
||||
"Tiltaksplan proposed with three support measures",
|
||||
"Next review scheduled for 15.06.2024"
|
||||
],
|
||||
"credits_used": 5
|
||||
}
|
||||
JSON,
|
||||
'dbn.timeline' => <<<'JSON'
|
||||
{
|
||||
"ok": true,
|
||||
"events": [
|
||||
{
|
||||
"date": "2024-03-12",
|
||||
"date_type": "ABSOLUTE",
|
||||
"confidence": "HIGH",
|
||||
"actor": "Barnevernet",
|
||||
"description": "Home visit conducted following anonymous report",
|
||||
"source_excerpt": "12.03.2024: hjemmebesøk ble gjennomført..."
|
||||
},
|
||||
{
|
||||
"date": "2024-06-15",
|
||||
"date_type": "ABSOLUTE",
|
||||
"confidence": "HIGH",
|
||||
"actor": "Fylkesnemnda",
|
||||
"description": "Scheduled hearing date",
|
||||
"source_excerpt": "Nemnda berammer møte til 15. juni 2024"
|
||||
}
|
||||
],
|
||||
"next_practical_step": "File your written submission before the 06.06.2024 deadline.",
|
||||
"credits_used": 4
|
||||
}
|
||||
JSON,
|
||||
'dbn.redact' => <<<'JSON'
|
||||
{
|
||||
"ok": true,
|
||||
"redacted_text": "On [DATE A] caseworker [PERSON A] met with [PERSON B] at [ADDRESS A]...",
|
||||
"replacements": [
|
||||
{ "original": "15.03.2024", "replacement": "[DATE A]" },
|
||||
{ "original": "Anna Hansen", "replacement": "[PERSON A]" },
|
||||
{ "original": "Ola Nordmann", "replacement": "[PERSON B]" }
|
||||
],
|
||||
"credits_used": 2
|
||||
}
|
||||
JSON,
|
||||
'dbn.translate' => <<<'JSON'
|
||||
{
|
||||
"ok": true,
|
||||
"source_lang": "no",
|
||||
"target_lang": "en",
|
||||
"translated_text": "Barnevernet issued a care order decision (vedtak om omsorgsovertakelse)...",
|
||||
"annotations": [
|
||||
{
|
||||
"term": "omsorgsovertakelse",
|
||||
"note": "Care order — formal transfer of parental responsibility to the state under BVL §4-12"
|
||||
},
|
||||
{
|
||||
"term": "Fylkesnemnda",
|
||||
"note": "County Social Welfare Board — the quasi-judicial body that reviews Barnevernet decisions"
|
||||
}
|
||||
],
|
||||
"credits_used": 6
|
||||
}
|
||||
JSON,
|
||||
'dbn.legal_analysis' => <<<'JSON'
|
||||
{
|
||||
"ok": true,
|
||||
"issues": [
|
||||
{
|
||||
"issue": "Procedural rights under forvaltningsloven §17",
|
||||
"analysis": "The parent was not given an opportunity to be heard before the decision was made, potentially violating fvl §17...",
|
||||
"legal_basis": ["forvaltningsloven §17", "BVL §6-3"],
|
||||
"sources": [{ "title": "fvl §17 — Plikten til å påse at saken er opplyst" }]
|
||||
}
|
||||
],
|
||||
"overall_assessment": "The document shows potential procedural violations that may form grounds for an appeal.",
|
||||
"credits_used": 8
|
||||
}
|
||||
JSON,
|
||||
'dbn.korrespond' => <<<'JSON'
|
||||
{
|
||||
"ok": true,
|
||||
"letter_no": "Til Barnevernet\nDato: 24.05.2024\n\nAnke på vedtak om omsorgsovertakelse...",
|
||||
"letter_en": "To Barnevernet\nDate: 24.05.2024\n\nAppeal against care order decision...",
|
||||
"cited_sources": ["BVL §4-12", "forvaltningsloven §28", "EMK artikkel 8"],
|
||||
"credits_used": 10
|
||||
}
|
||||
JSON,
|
||||
'dbn.barnevernet_analyze' => <<<'JSON'
|
||||
{
|
||||
"ok": true,
|
||||
"red_flags": [
|
||||
"Decision issued without notification to parent (fvl §16 violation)",
|
||||
"No tiltaksplan offered before escalating to care order (BVL §4-4)"
|
||||
],
|
||||
"legal_issues": [
|
||||
"Potential violation of proportionality principle — less intrusive measures not exhausted",
|
||||
"ECHR Art. 8 family life rights not addressed in reasoning"
|
||||
],
|
||||
"recommendations": [
|
||||
"File an appeal within 3 weeks citing fvl §28",
|
||||
"Request full case file under fvl §18",
|
||||
"Consult Fylkesnemnda procedural timeline"
|
||||
],
|
||||
"credits_used": 7
|
||||
}
|
||||
JSON,
|
||||
'dbn.advocate_brief' => <<<'JSON'
|
||||
{
|
||||
"ok": true,
|
||||
"brief": "On behalf of the parent, the following legal arguments support challenging the care order under BVL §4-12...",
|
||||
"legal_arguments": [
|
||||
"The threshold for care order under §4-12(a) requires 'serious deficiencies' — the report does not meet this standard",
|
||||
"Proportionality requires exhausting support measures (§4-4) before removal"
|
||||
],
|
||||
"sources": [
|
||||
{ "title": "BVL §4-12", "type": "statute" },
|
||||
{ "title": "Rt-2015-110", "type": "case_law" }
|
||||
],
|
||||
"credits_used": 9
|
||||
}
|
||||
JSON,
|
||||
'dbn.deep_research' => <<<'JSON'
|
||||
{
|
||||
"ok": true,
|
||||
"research_angles": [
|
||||
"Procedural safeguards under ECHR Art. 6 in child welfare proceedings",
|
||||
"Substantive requirements for care order threshold (BVL §4-12)",
|
||||
"Norwegian Supreme Court interpretation of best interests standard"
|
||||
],
|
||||
"brief": "Research synthesis: The European Court of Human Rights has found Norway in violation of Art. 8 in 14 cases since 2015, with the core issue being...",
|
||||
"citations": [
|
||||
"Strand Lobben m.fl. mot Norge, EMD-37283/13 (10.09.2019)",
|
||||
"Johansen mot Norge, EMD-17383/90 (07.08.1996)"
|
||||
],
|
||||
"credits_used": 15
|
||||
}
|
||||
JSON,
|
||||
'dbn.discrepancy_find' => <<<'JSON'
|
||||
{
|
||||
"ok": true,
|
||||
"discrepancies": [
|
||||
{
|
||||
"type": "deletion",
|
||||
"location": "Section 3, paragraph 2",
|
||||
"original": "The child expressed a wish to return home.",
|
||||
"modified": "[removed]",
|
||||
"significance": "HIGH — child's stated preference is a legally relevant factor under BVL §6-3"
|
||||
},
|
||||
{
|
||||
"type": "added_claim",
|
||||
"location": "Section 5",
|
||||
"original": "[absent]",
|
||||
"modified": "The parent failed to attend the scheduled meeting.",
|
||||
"significance": "MEDIUM — unverified claim added in the later version"
|
||||
}
|
||||
],
|
||||
"credits_used": 6
|
||||
}
|
||||
JSON,
|
||||
'dbn.transcribe_audio' => <<<'JSON'
|
||||
{
|
||||
"ok": true,
|
||||
"transcript": "Full transcript of the audio recording...",
|
||||
"segments": [
|
||||
{ "speaker": "A", "start": 0.0, "end": 4.2, "text": "God morgen, vi er samlet for å diskutere..." },
|
||||
{ "speaker": "B", "start": 4.5, "end": 9.1, "text": "Takk. Jeg ønsker å starte med å si at..." }
|
||||
],
|
||||
"language_detected": "no",
|
||||
"credits_used": 8
|
||||
}
|
||||
JSON,
|
||||
'dbn.corpus_stats' => <<<'JSON'
|
||||
{
|
||||
"ok": true,
|
||||
"documents": 2847,
|
||||
"chunks": 94231,
|
||||
"sources": {
|
||||
"statutes": 42,
|
||||
"tribunal_decisions": 1204,
|
||||
"echr_cases": 187,
|
||||
"government_reports": 1414
|
||||
},
|
||||
"last_updated": "2024-05-01"
|
||||
}
|
||||
JSON,
|
||||
'dbn.list_documents' => <<<'JSON'
|
||||
{
|
||||
"ok": true,
|
||||
"documents": [
|
||||
{ "id": 42, "title": "BVL §4-12 — Vedtak om omsorgsovertakelse", "category": "statute" },
|
||||
{ "id": 87, "title": "FNV-2023-142 — Fylkesnemnda for barnevern og sosiale saker", "category": "tribunal" },
|
||||
{ "id": 203, "title": "Strand Lobben m.fl. mot Norge (EMD-37283/13)", "category": "echr" }
|
||||
],
|
||||
"total": 847,
|
||||
"offset": 0
|
||||
}
|
||||
JSON,
|
||||
'dbn.get_document' => <<<'JSON'
|
||||
{
|
||||
"ok": true,
|
||||
"document": {
|
||||
"id": 42,
|
||||
"title": "BVL §4-12 — Vedtak om omsorgsovertakelse",
|
||||
"category": "statute",
|
||||
"chunks": [
|
||||
{ "chunk_id": 1, "text": "§ 4-12. Vedtak om å overta omsorgen for et barn kan treffes dersom..." },
|
||||
{ "chunk_id": 2, "text": "(a) det er alvorlige mangler ved den daglige omsorg som barnet får..." }
|
||||
]
|
||||
}
|
||||
}
|
||||
JSON,
|
||||
'dbn.citation_graph' => <<<'JSON'
|
||||
{
|
||||
"ok": true,
|
||||
"action": "cites",
|
||||
"root": { "id": 42, "title": "BVL §4-12" },
|
||||
"nodes": [
|
||||
{ "id": 42, "title": "BVL §4-12", "type": "statute" },
|
||||
{ "id": 15, "title": "BVL §4-4 — Hjelpetiltak", "type": "statute" },
|
||||
{ "id": 203, "title": "Strand Lobben m.fl. mot Norge", "type": "echr" }
|
||||
],
|
||||
"edges": [
|
||||
{ "from": 42, "to": 15, "type": "cites" },
|
||||
{ "from": 42, "to": 203, "type": "cites" }
|
||||
],
|
||||
"depth": 1
|
||||
}
|
||||
JSON,
|
||||
'dbn.case_workbench_plan' => <<<'JSON'
|
||||
{
|
||||
"ok": true,
|
||||
"plan": {
|
||||
"situation_summary": "Fylkesnemnda hearing scheduled in 3 weeks — care order challenge.",
|
||||
"steps": [
|
||||
"1. Request full case file under forvaltningsloven §18 — submit by 01.06.2024",
|
||||
"2. Run Legal Analysis tool on the original care order decision",
|
||||
"3. Create Advocate Brief (parent role) with the grounds for challenge",
|
||||
"4. Draft formal response letter using Korrespond (Fylkesnemnda preset)",
|
||||
"5. Compile timeline of all procedural dates"
|
||||
],
|
||||
"recommended_tools": ["dbn.legal_analysis", "dbn.advocate_brief", "dbn.korrespond", "dbn.timeline"],
|
||||
"deadline": "2024-06-15"
|
||||
},
|
||||
"credits_used": 3
|
||||
}
|
||||
JSON,
|
||||
'dbn.save_to_case' => <<<'JSON'
|
||||
{
|
||||
"ok": true,
|
||||
"saved": true,
|
||||
"case_entry_id": "entry_abc123",
|
||||
"title": "Legal analysis of care order decision",
|
||||
"saved_at": "2024-05-24T09:15:00Z"
|
||||
}
|
||||
JSON,
|
||||
];
|
||||
|
||||
$exReq = trim($exampleRequests[$slug] ?? '{}');
|
||||
$exResp = trim($exampleResponses[$slug] ?? '{"ok":true}');
|
||||
?>
|
||||
<!doctype html>
|
||||
<html lang="<?= htmlspecialchars($uiLang) ?>">
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1">
|
||||
<title><?= htmlspecialchars($displayName) ?> — <?= htmlspecialchars(dbnToolsT('mcp_page_title', $uiLang)) ?></title>
|
||||
<meta name="robots" content="noindex, nofollow">
|
||||
<link rel="preconnect" href="https://fonts.googleapis.com">
|
||||
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>
|
||||
<link rel="stylesheet" href="https://fonts.googleapis.com/css2?family=Crimson+Pro:wght@400;600;700&family=IBM+Plex+Sans:wght@400;500;600;700&display=swap">
|
||||
<link rel="stylesheet" href="assets/css/tools.css">
|
||||
<link rel="stylesheet" href="assets/css/dbn-tools-redesign.css">
|
||||
<style>
|
||||
.mcp-tool-breadcrumb {
|
||||
font-size: 0.85rem;
|
||||
color: var(--muted, #667085);
|
||||
margin-bottom: 1.5rem;
|
||||
}
|
||||
.mcp-tool-breadcrumb a {
|
||||
color: var(--dbn-blue, #00205b);
|
||||
text-decoration: none;
|
||||
}
|
||||
.mcp-tool-breadcrumb a:hover { text-decoration: underline; }
|
||||
.mcp-tool-hero {
|
||||
margin-bottom: 0.5rem;
|
||||
}
|
||||
.mcp-tool-hero__icon {
|
||||
font-size: 2rem;
|
||||
margin-bottom: 0.5rem;
|
||||
}
|
||||
.mcp-tool-hero__name {
|
||||
font-family: 'Crimson Pro', serif;
|
||||
font-size: clamp(1.5rem, 3vw, 2rem);
|
||||
font-weight: 700;
|
||||
color: var(--dbn-blue, #00205b);
|
||||
margin: 0 0 0.2rem;
|
||||
}
|
||||
.mcp-tool-hero__slug {
|
||||
font-family: 'IBM Plex Mono', 'Courier New', monospace;
|
||||
font-size: 0.82rem;
|
||||
color: var(--muted, #667085);
|
||||
margin-bottom: 0.75rem;
|
||||
}
|
||||
.mcp-tool-hero__desc {
|
||||
font-size: 1rem;
|
||||
color: var(--dbn-ink, #16130f);
|
||||
max-width: 640px;
|
||||
margin: 0;
|
||||
}
|
||||
/* Param table */
|
||||
.mcp-param-table {
|
||||
width: 100%;
|
||||
border-collapse: collapse;
|
||||
font-size: 0.875rem;
|
||||
margin-top: 0.75rem;
|
||||
}
|
||||
.mcp-param-table th {
|
||||
text-align: left;
|
||||
padding: 0.5rem 0.75rem;
|
||||
background: var(--dbn-paper, #f6f2ea);
|
||||
font-weight: 600;
|
||||
font-size: 0.78rem;
|
||||
text-transform: uppercase;
|
||||
letter-spacing: .04em;
|
||||
color: var(--muted, #667085);
|
||||
border-bottom: 2px solid var(--dbn-line, #e5e7eb);
|
||||
}
|
||||
.mcp-param-table td {
|
||||
padding: 0.6rem 0.75rem;
|
||||
border-bottom: 1px solid var(--dbn-line, #e5e7eb);
|
||||
vertical-align: top;
|
||||
}
|
||||
.mcp-param-table tr:last-child td { border-bottom: 0; }
|
||||
.mcp-param-name {
|
||||
font-family: 'IBM Plex Mono', monospace;
|
||||
font-size: 0.82rem;
|
||||
}
|
||||
.mcp-param-name--required {
|
||||
background: #ddd6fe;
|
||||
color: #5b21b6;
|
||||
padding: 0.15rem 0.4rem;
|
||||
border-radius: 4px;
|
||||
}
|
||||
.mcp-param-name--optional {
|
||||
background: #f3f4f6;
|
||||
color: #374151;
|
||||
padding: 0.15rem 0.4rem;
|
||||
border-radius: 4px;
|
||||
}
|
||||
.mcp-param-type {
|
||||
color: var(--muted, #667085);
|
||||
font-size: 0.8rem;
|
||||
}
|
||||
.mcp-param-enum {
|
||||
font-size: 0.75rem;
|
||||
color: var(--muted, #667085);
|
||||
font-family: monospace;
|
||||
}
|
||||
.mcp-req-yes {
|
||||
color: #065f46;
|
||||
font-weight: 600;
|
||||
}
|
||||
.mcp-req-no {
|
||||
color: var(--muted, #667085);
|
||||
}
|
||||
/* Code blocks (reuse mcp.php style) */
|
||||
.mcp-code-wrap {
|
||||
position: relative;
|
||||
}
|
||||
.mcp-code-wrap pre {
|
||||
background: #101828;
|
||||
color: #f9fafb;
|
||||
padding: 1rem;
|
||||
border-radius: 8px;
|
||||
font-size: 0.8rem;
|
||||
overflow-x: auto;
|
||||
margin: 0;
|
||||
line-height: 1.6;
|
||||
}
|
||||
.mcp-copy-btn {
|
||||
position: absolute;
|
||||
top: 0.5rem;
|
||||
right: 0.5rem;
|
||||
background: rgba(249,250,251,.12);
|
||||
border: 1px solid rgba(249,250,251,.2);
|
||||
color: #f9fafb;
|
||||
font-size: 0.75rem;
|
||||
padding: 0.3rem 0.6rem;
|
||||
border-radius: 5px;
|
||||
cursor: pointer;
|
||||
transition: background .15s;
|
||||
}
|
||||
.mcp-copy-btn:hover { background: rgba(249,250,251,.22); }
|
||||
.mcp-code-label {
|
||||
font-size: 0.78rem;
|
||||
font-weight: 600;
|
||||
color: var(--muted, #667085);
|
||||
text-transform: uppercase;
|
||||
letter-spacing: .04em;
|
||||
margin: 0 0 0.4rem;
|
||||
}
|
||||
.mcp-privacy {
|
||||
background: var(--dbn-paper, #f6f2ea);
|
||||
border-radius: 8px;
|
||||
padding: 1rem 1.25rem;
|
||||
font-size: 0.85rem;
|
||||
color: var(--dbn-ink, #16130f);
|
||||
}
|
||||
.mcp-privacy strong { color: var(--dbn-blue, #00205b); }
|
||||
.mcp-connect-link {
|
||||
display: inline-block;
|
||||
margin-top: 0.75rem;
|
||||
color: var(--dbn-blue, #00205b);
|
||||
font-weight: 600;
|
||||
font-size: 0.9rem;
|
||||
text-decoration: none;
|
||||
}
|
||||
.mcp-connect-link:hover { text-decoration: underline; }
|
||||
</style>
|
||||
</head>
|
||||
<body data-authenticated="<?= dbnToolsIsAuthenticated() ? 'true' : 'false' ?>" class="lt-app">
|
||||
<script>
|
||||
window.DBN_TOOLS_AUTHENTICATED = <?= dbnToolsIsAuthenticated() ? 'true' : 'false' ?>;
|
||||
window.DBN_TOOLS_LANG = <?= json_encode($uiLang, JSON_UNESCAPED_UNICODE) ?>;
|
||||
</script>
|
||||
|
||||
<?php include __DIR__ . '/includes/nav.php'; ?>
|
||||
|
||||
<div class="account-shell">
|
||||
|
||||
<!-- ── Breadcrumb ────────────────────────────────────────────── -->
|
||||
<div class="mcp-tool-breadcrumb">
|
||||
<a href="/mcp.php"><?= htmlspecialchars(dbnToolsT('mcp_tool_back', $uiLang)) ?></a>
|
||||
</div>
|
||||
|
||||
<!-- ── Hero ──────────────────────────────────────────────────── -->
|
||||
<section class="account-section">
|
||||
<div class="mcp-tool-hero">
|
||||
<div class="mcp-tool-hero__icon"><?= $toolIcon ?></div>
|
||||
<h1 class="mcp-tool-hero__name"><?= htmlspecialchars($displayName) ?></h1>
|
||||
<div class="mcp-tool-hero__slug"><?= htmlspecialchars($slug) ?></div>
|
||||
<p class="mcp-tool-hero__desc"><?= htmlspecialchars($description) ?></p>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<!-- ── Parameters ────────────────────────────────────────────── -->
|
||||
<section class="account-section">
|
||||
<p class="account-section__title"><?= htmlspecialchars(dbnToolsT('mcp_tool_params_title', $uiLang)) ?></p>
|
||||
|
||||
<?php if (empty($props)): ?>
|
||||
<p style="color:var(--muted,#667085); font-size:0.88rem;">
|
||||
<?= htmlspecialchars(dbnToolsT('mcp_tool_no_params', $uiLang)) ?>
|
||||
</p>
|
||||
<?php else: ?>
|
||||
<div style="overflow-x:auto;">
|
||||
<table class="mcp-param-table">
|
||||
<thead>
|
||||
<tr>
|
||||
<th><?= htmlspecialchars(dbnToolsT('mcp_tool_col_param', $uiLang)) ?></th>
|
||||
<th><?= htmlspecialchars(dbnToolsT('mcp_tool_col_type', $uiLang)) ?></th>
|
||||
<th><?= htmlspecialchars(dbnToolsT('mcp_tool_col_required', $uiLang)) ?></th>
|
||||
<th><?= htmlspecialchars(dbnToolsT('mcp_tool_col_desc', $uiLang)) ?></th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
<?php foreach ($props as $paramName => $paramDef):
|
||||
$isReq = in_array($paramName, $required, true);
|
||||
$paramType = (string)($paramDef['type'] ?? 'string');
|
||||
$enumVals = (array)($paramDef['enum'] ?? []);
|
||||
$paramDesc = mcpToolParamT($slug, $paramName, $uiLang, $toolTranslations);
|
||||
if ($paramDesc === '') {
|
||||
$paramDesc = (string)($paramDef['description'] ?? '');
|
||||
}
|
||||
?>
|
||||
<tr>
|
||||
<td>
|
||||
<span class="mcp-param-name <?= $isReq ? 'mcp-param-name--required' : 'mcp-param-name--optional' ?>">
|
||||
<?= htmlspecialchars($paramName) ?><?= $isReq ? '*' : '' ?>
|
||||
</span>
|
||||
</td>
|
||||
<td>
|
||||
<span class="mcp-param-type"><?= htmlspecialchars($paramType) ?></span>
|
||||
<?php if (!empty($enumVals)): ?>
|
||||
<br><span class="mcp-param-enum"><?= htmlspecialchars(implode(' | ', $enumVals)) ?></span>
|
||||
<?php endif; ?>
|
||||
</td>
|
||||
<td>
|
||||
<?php if ($isReq): ?>
|
||||
<span class="mcp-req-yes"><?= htmlspecialchars(dbnToolsT('mcp_tool_yes', $uiLang)) ?></span>
|
||||
<?php else: ?>
|
||||
<span class="mcp-req-no">—</span>
|
||||
<?php endif; ?>
|
||||
</td>
|
||||
<td><?= htmlspecialchars($paramDesc) ?></td>
|
||||
</tr>
|
||||
<?php endforeach; ?>
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
<p style="font-size:0.75rem; color:var(--muted,#667085); margin-top:0.5rem;">
|
||||
* <?= htmlspecialchars(dbnToolsT('mcp_tools_param_req_hint', $uiLang)) ?>
|
||||
</p>
|
||||
<?php endif; ?>
|
||||
</section>
|
||||
|
||||
<!-- ── Example request ───────────────────────────────────────── -->
|
||||
<section class="account-section">
|
||||
<p class="account-section__title"><?= htmlspecialchars(dbnToolsT('mcp_tool_example_req', $uiLang)) ?></p>
|
||||
<p class="mcp-code-label">POST /api/mcp/user/tools/<?= htmlspecialchars($slug) ?>/invoke</p>
|
||||
<div class="mcp-code-wrap">
|
||||
<button class="mcp-copy-btn" type="button" id="copyReqBtn">Copy</button>
|
||||
<pre><code id="exReqCode"><?= htmlspecialchars($exReq) ?></code></pre>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<!-- ── Example response ──────────────────────────────────────── -->
|
||||
<section class="account-section">
|
||||
<p class="account-section__title"><?= htmlspecialchars(dbnToolsT('mcp_tool_example_resp', $uiLang)) ?></p>
|
||||
<div class="mcp-code-wrap">
|
||||
<button class="mcp-copy-btn" type="button" id="copyRespBtn">Copy</button>
|
||||
<pre><code id="exRespCode"><?= htmlspecialchars($exResp) ?></code></pre>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<!-- ── Connect ───────────────────────────────────────────────── -->
|
||||
<section class="account-section">
|
||||
<p class="account-section__title"><?= htmlspecialchars(dbnToolsT('mcp_tool_connect_title', $uiLang)) ?></p>
|
||||
<p style="color:var(--muted,#667085); font-size:0.88rem; margin-top:0;">
|
||||
<?= htmlspecialchars(dbnToolsT('mcp_tool_connect_text', $uiLang)) ?>
|
||||
</p>
|
||||
<a href="/mcp.php" class="mcp-connect-link"><?= htmlspecialchars(dbnToolsT('mcp_tool_setup_link', $uiLang)) ?></a>
|
||||
</section>
|
||||
|
||||
<!-- ── Privacy ───────────────────────────────────────────────── -->
|
||||
<section class="account-section">
|
||||
<p class="account-section__title"><?= htmlspecialchars(dbnToolsT('mcp_privacy_title', $uiLang)) ?></p>
|
||||
<div class="mcp-privacy">
|
||||
<strong><?= htmlspecialchars(dbnToolsT('mcp_privacy_text', $uiLang)) ?></strong>
|
||||
</div>
|
||||
<p style="margin-top:0.75rem; font-size:0.82rem; color:var(--muted,#667085);">
|
||||
<?= htmlspecialchars(dbnToolsT('mcp_privacy_legal', $uiLang)) ?>
|
||||
</p>
|
||||
</section>
|
||||
|
||||
</div><!-- /.account-shell -->
|
||||
|
||||
<?php require_once __DIR__ . '/includes/footer.php'; ?>
|
||||
|
||||
<script>
|
||||
(function () {
|
||||
'use strict';
|
||||
function copyText(text, btn) {
|
||||
var orig = btn.textContent;
|
||||
if (navigator.clipboard) {
|
||||
navigator.clipboard.writeText(text).then(function () {
|
||||
btn.textContent = 'Copied!';
|
||||
setTimeout(function () { btn.textContent = orig; }, 1500);
|
||||
});
|
||||
} else {
|
||||
var ta = document.createElement('textarea');
|
||||
ta.value = text;
|
||||
ta.style.cssText = 'position:fixed;opacity:0';
|
||||
document.body.appendChild(ta);
|
||||
ta.select();
|
||||
document.execCommand('copy');
|
||||
document.body.removeChild(ta);
|
||||
btn.textContent = 'Copied!';
|
||||
setTimeout(function () { btn.textContent = orig; }, 1500);
|
||||
}
|
||||
}
|
||||
var reqBtn = document.getElementById('copyReqBtn');
|
||||
var respBtn = document.getElementById('copyRespBtn');
|
||||
var reqCode = document.getElementById('exReqCode');
|
||||
var respCode = document.getElementById('exRespCode');
|
||||
if (reqBtn && reqCode) reqBtn.addEventListener('click', function () { copyText(reqCode.textContent, reqBtn); });
|
||||
if (respBtn && respCode) respBtn.addEventListener('click', function () { copyText(respCode.textContent, respBtn); });
|
||||
}());
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
||||
Reference in New Issue
Block a user