2d2502a037
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
321 lines
14 KiB
PHP
321 lines
14 KiB
PHP
<?php
|
|
declare(strict_types=1);
|
|
|
|
/**
|
|
* Public, indexable overview of the Do Better Norge MCP server.
|
|
* Unlike mcp.php (token mint, gated) and mcp-tool.php (per-tool detail), this is
|
|
* the marketing front door: anyone can read it; it links into /mcp.php to connect.
|
|
* Tool catalog is rendered live from DbnMcpRuntime::tools() so it never drifts.
|
|
*/
|
|
|
|
require_once __DIR__ . '/includes/bootstrap.php';
|
|
require_once __DIR__ . '/includes/DbnMcpRuntime.php';
|
|
|
|
$uiLang = dbnToolsCurrentLanguage();
|
|
$toolCatalog = DbnMcpRuntime::tools();
|
|
$toolCount = count($toolCatalog);
|
|
|
|
$endpointUrl = 'https://mcp.dobetternorge.no/mcp';
|
|
$healthUrl = 'https://mcp.dobetternorge.no/healthz';
|
|
$host = 'mcp.dobetternorge.no';
|
|
|
|
$toolIcons = [
|
|
'dbn.search_legal' => '🔍',
|
|
'dbn.corpus_search' => '🧭',
|
|
'dbn.corpus_stats' => '📊',
|
|
'dbn.list_documents' => '📚',
|
|
'dbn.get_document' => '📖',
|
|
'dbn.citation_graph' => '🔗',
|
|
'dbn.korrespond' => '✉️',
|
|
'dbn.korrespond_refine' => '✨',
|
|
'dbn.advocate_brief' => '🏛️',
|
|
'dbn.deep_research' => '🔬',
|
|
'dbn.ask' => '💬',
|
|
'dbn.summarize' => '📋',
|
|
'dbn.legal_analysis' => '⚖️',
|
|
'dbn.timeline' => '📅',
|
|
'dbn.barnevernet_analyze' => '📄',
|
|
'dbn.discrepancy_find' => '🔄',
|
|
'dbn.extract_text' => '📑',
|
|
'dbn.transcribe_audio' => '🎤',
|
|
'dbn.translate' => '🌍',
|
|
'dbn.redact' => '🔒',
|
|
'dbn.case_workbench_plan' => '🗂️',
|
|
'dbn.save_to_case' => '💾',
|
|
];
|
|
|
|
// Presentation groups (ordered). Any tool not listed falls into "More tools".
|
|
$toolGroups = [
|
|
'Search & retrieval' => ['dbn.search_legal', 'dbn.corpus_search', 'dbn.corpus_stats', 'dbn.list_documents', 'dbn.get_document', 'dbn.citation_graph'],
|
|
'Drafting & correspondence' => ['dbn.korrespond', 'dbn.korrespond_refine', 'dbn.advocate_brief', 'dbn.deep_research'],
|
|
'Analysis' => ['dbn.ask', 'dbn.summarize', 'dbn.legal_analysis', 'dbn.timeline', 'dbn.barnevernet_analyze', 'dbn.discrepancy_find'],
|
|
'Documents, media & privacy'=> ['dbn.extract_text', 'dbn.transcribe_audio', 'dbn.translate', 'dbn.redact'],
|
|
'Case workbench' => ['dbn.case_workbench_plan', 'dbn.save_to_case'],
|
|
];
|
|
|
|
// Index tools by slug for grouped rendering.
|
|
$bySlug = [];
|
|
foreach ($toolCatalog as $t) {
|
|
$bySlug[(string)($t['slug'] ?? '')] = $t;
|
|
}
|
|
$grouped = [];
|
|
$claimed = [];
|
|
foreach ($toolGroups as $groupName => $slugs) {
|
|
$bucket = [];
|
|
foreach ($slugs as $s) {
|
|
if (isset($bySlug[$s])) {
|
|
$bucket[] = $bySlug[$s];
|
|
$claimed[$s] = true;
|
|
}
|
|
}
|
|
if ($bucket) {
|
|
$grouped[$groupName] = $bucket;
|
|
}
|
|
}
|
|
$leftover = [];
|
|
foreach ($toolCatalog as $t) {
|
|
if (empty($claimed[(string)($t['slug'] ?? '')])) {
|
|
$leftover[] = $t;
|
|
}
|
|
}
|
|
if ($leftover) {
|
|
$grouped['More tools'] = $leftover;
|
|
}
|
|
?>
|
|
<!doctype html>
|
|
<html lang="<?= htmlspecialchars($uiLang) ?>">
|
|
<head>
|
|
<meta charset="utf-8">
|
|
<meta name="viewport" content="width=device-width, initial-scale=1">
|
|
<title>MCP server — Norwegian legal tools | Do Better Norge</title>
|
|
<meta name="description" content="The Do Better Norge legal toolkit as a Model Context Protocol (MCP) server. Connect Claude, n8n, Cursor or any MCP client to <?= (int)$toolCount ?> source-grounded Norwegian family-law and public-law tools.">
|
|
<link rel="canonical" href="https://tools.dobetternorge.no/mcp-about.php">
|
|
<meta property="og:title" content="Do Better Norge — Norwegian legal tools as an MCP server">
|
|
<meta property="og:description" content="<?= (int)$toolCount ?> source-grounded Norwegian family-law and public-law tools, callable from any MCP client.">
|
|
<meta property="og:type" content="website">
|
|
<meta property="og:url" content="https://tools.dobetternorge.no/mcp-about.php">
|
|
<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-hero {
|
|
padding: 2.75rem 1.5rem 2.25rem;
|
|
text-align: center;
|
|
border-bottom: 1px solid var(--dbn-line, rgba(22,19,15,.16));
|
|
margin-bottom: 2rem;
|
|
}
|
|
.mcp-hero__badge {
|
|
display: inline-flex;
|
|
align-items: center;
|
|
gap: 0.4rem;
|
|
background: #ede9fe;
|
|
color: #5b21b6;
|
|
font-size: 0.75rem;
|
|
font-weight: 600;
|
|
letter-spacing: .04em;
|
|
text-transform: uppercase;
|
|
padding: 0.3rem 0.75rem;
|
|
border-radius: 999px;
|
|
margin-bottom: 1rem;
|
|
}
|
|
.mcp-hero h1 {
|
|
font-family: 'Crimson Pro', serif;
|
|
font-size: clamp(1.8rem, 4vw, 2.6rem);
|
|
font-weight: 700;
|
|
color: var(--dbn-blue, #00205b);
|
|
margin: 0 0 0.7rem;
|
|
}
|
|
.mcp-hero p {
|
|
color: var(--muted, #667085);
|
|
font-size: 1.02rem;
|
|
max-width: 620px;
|
|
margin: 0 auto 1.4rem;
|
|
line-height: 1.6;
|
|
}
|
|
.mcp-hero__cta {
|
|
display: inline-flex;
|
|
align-items: center;
|
|
gap: 0.4rem;
|
|
background: var(--dbn-blue, #00205b);
|
|
color: #fff;
|
|
text-decoration: none;
|
|
font-weight: 600;
|
|
font-size: 0.92rem;
|
|
padding: 0.7rem 1.4rem;
|
|
border-radius: 8px;
|
|
transition: background .15s;
|
|
}
|
|
.mcp-hero__cta:hover { background: #001a4a; }
|
|
.mcp-conn {
|
|
border: 1px solid var(--dbn-line, rgba(22,19,15,.16));
|
|
border-radius: 12px;
|
|
background: #fff;
|
|
padding: 1.25rem 1.4rem;
|
|
margin-bottom: 2rem;
|
|
}
|
|
.mcp-conn__row {
|
|
display: flex;
|
|
gap: 1rem;
|
|
padding: 0.5rem 0;
|
|
border-bottom: 1px solid var(--dbn-line, #eef0f4);
|
|
font-size: 0.9rem;
|
|
}
|
|
.mcp-conn__row:last-child { border-bottom: 0; }
|
|
.mcp-conn__label { width: 130px; flex-shrink: 0; color: var(--muted, #667085); }
|
|
.mcp-conn__val {
|
|
font-family: 'IBM Plex Mono', 'Courier New', monospace;
|
|
font-size: 0.84rem;
|
|
color: var(--dbn-ink, #16130f);
|
|
word-break: break-all;
|
|
}
|
|
.mcp-group { margin-bottom: 1.75rem; }
|
|
.mcp-group__title {
|
|
font-size: 0.78rem;
|
|
text-transform: uppercase;
|
|
letter-spacing: .06em;
|
|
color: var(--muted, #667085);
|
|
font-weight: 600;
|
|
margin: 0 0 0.75rem;
|
|
}
|
|
.mcp-tool-grid {
|
|
display: grid;
|
|
grid-template-columns: repeat(auto-fill, minmax(250px, 1fr));
|
|
gap: 0.75rem;
|
|
}
|
|
.mcp-tool-card {
|
|
display: flex;
|
|
gap: 0.7rem;
|
|
border: 1px solid var(--dbn-line, rgba(22,19,15,.16));
|
|
border-radius: 10px;
|
|
padding: 0.85rem 1rem;
|
|
background: #fff;
|
|
text-decoration: none;
|
|
transition: border-color .15s, box-shadow .15s;
|
|
}
|
|
.mcp-tool-card:hover {
|
|
border-color: var(--dbn-blue, #00205b);
|
|
box-shadow: 0 4px 12px rgba(0,32,91,.08);
|
|
}
|
|
.mcp-tool-card__icon { font-size: 1.25rem; line-height: 1.4; flex-shrink: 0; }
|
|
.mcp-tool-card__name { font-weight: 600; font-size: 0.88rem; color: var(--dbn-blue, #00205b); margin-bottom: 0.15rem; }
|
|
.mcp-tool-card__slug {
|
|
font-family: 'IBM Plex Mono', 'Courier New', monospace;
|
|
font-size: 0.71rem; color: var(--muted, #667085); margin-bottom: 0.3rem;
|
|
}
|
|
.mcp-tool-card__desc {
|
|
font-size: 0.82rem; color: var(--dbn-ink, #16130f); line-height: 1.45;
|
|
display: -webkit-box; -webkit-line-clamp: 2; -webkit-box-orient: vertical; overflow: hidden;
|
|
}
|
|
.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); }
|
|
</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">
|
|
|
|
<!-- ── Hero ─────────────────────────────────────────────────── -->
|
|
<div class="mcp-hero">
|
|
<div class="mcp-hero__badge">Model Context Protocol</div>
|
|
<h1>Norwegian family-law & public-law tools, as an MCP server.</h1>
|
|
<p>
|
|
The Do Better Norge legal toolkit is exposed as a Model Context Protocol server. Any MCP
|
|
client — Claude, an n8n agent, Cursor or your own SDK — can search the legal corpus
|
|
(family law, child-welfare, procurement, health, labour, tax, ECHR case law and more),
|
|
draft correspondence to authorities, analyze Barnevernet documents and more, all grounded
|
|
in the live DBN legal sources.
|
|
</p>
|
|
<a class="mcp-hero__cta" href="/mcp.php">Mint a token & connect →</a>
|
|
</div>
|
|
|
|
<!-- ── Connection ───────────────────────────────────────────── -->
|
|
<section class="account-section">
|
|
<p class="account-section__title">Server endpoint</p>
|
|
<p style="color:var(--muted,#667085); font-size:0.88rem; margin-top:0;">
|
|
A live Streamable-HTTP bridge in front of the DBN tool runtime. Tools are registered
|
|
dynamically per session, so the catalog always reflects the server. Access is gated by a
|
|
member token (Plus/Pro), so each call runs in the token-holder's own tenant.
|
|
</p>
|
|
<div class="mcp-conn">
|
|
<div class="mcp-conn__row"><span class="mcp-conn__label">Host</span><span class="mcp-conn__val"><?= htmlspecialchars($host) ?></span></div>
|
|
<div class="mcp-conn__row"><span class="mcp-conn__label">Endpoint</span><span class="mcp-conn__val"><?= htmlspecialchars($endpointUrl) ?></span></div>
|
|
<div class="mcp-conn__row"><span class="mcp-conn__label">Transport</span><span class="mcp-conn__val">Streamable HTTP (MCP)</span></div>
|
|
<div class="mcp-conn__row"><span class="mcp-conn__label">Auth</span><span class="mcp-conn__val">Bearer token (Plus/Pro member)</span></div>
|
|
<div class="mcp-conn__row"><span class="mcp-conn__label">Health</span><span class="mcp-conn__val"><?= htmlspecialchars($healthUrl) ?></span></div>
|
|
<div class="mcp-conn__row"><span class="mcp-conn__label">Tools</span><span class="mcp-conn__val"><?= (int)$toolCount ?> registered</span></div>
|
|
</div>
|
|
</section>
|
|
|
|
<!-- ── Tool catalog ─────────────────────────────────────────── -->
|
|
<section class="account-section">
|
|
<p class="account-section__title"><?= (int)$toolCount ?> tools available</p>
|
|
<p style="color:var(--muted,#667085); font-size:0.88rem; margin-top:0; margin-bottom:1.25rem;">
|
|
Every tool returns source-grounded output with citations where applicable. This is
|
|
informational legal assistance, not legal advice.
|
|
</p>
|
|
|
|
<?php foreach ($grouped as $groupName => $tools): ?>
|
|
<div class="mcp-group">
|
|
<p class="mcp-group__title"><?= htmlspecialchars($groupName) ?></p>
|
|
<div class="mcp-tool-grid">
|
|
<?php foreach ($tools as $tool):
|
|
$slug = (string)($tool['slug'] ?? '');
|
|
$name = (string)($tool['display_name'] ?? $slug);
|
|
$desc = (string)($tool['description'] ?? '');
|
|
$icon = $toolIcons[$slug] ?? '🔧';
|
|
$detailUrl = '/mcp-tool.php?tool=' . urlencode($slug) . ($uiLang !== 'en' ? '&lang=' . urlencode($uiLang) : '');
|
|
?>
|
|
<a class="mcp-tool-card" href="<?= htmlspecialchars($detailUrl) ?>">
|
|
<span class="mcp-tool-card__icon" aria-hidden="true"><?= $icon ?></span>
|
|
<span>
|
|
<span class="mcp-tool-card__name"><?= htmlspecialchars($name) ?></span>
|
|
<span class="mcp-tool-card__slug"><?= htmlspecialchars($slug) ?></span>
|
|
<span class="mcp-tool-card__desc"><?= htmlspecialchars($desc) ?></span>
|
|
</span>
|
|
</a>
|
|
<?php endforeach; ?>
|
|
</div>
|
|
</div>
|
|
<?php endforeach; ?>
|
|
</section>
|
|
|
|
<!-- ── Connect ──────────────────────────────────────────────── -->
|
|
<section class="account-section">
|
|
<p class="account-section__title">Connect from your client</p>
|
|
<p style="color:var(--muted,#667085); font-size:0.88rem; margin-top:0;">
|
|
Plus and Pro members mint a personal MCP token, then point Claude Desktop, Claude Code,
|
|
Cursor, VS Code or any Streamable-HTTP MCP client at the endpoint above. The server
|
|
registers all <?= (int)$toolCount ?> <code>dbn.*</code> tools per session.
|
|
</p>
|
|
<a href="/mcp.php" class="mcp-hero__cta" style="margin-top:0.5rem;">Open MCP setup →</a>
|
|
</section>
|
|
|
|
<!-- ── Privacy ──────────────────────────────────────────────── -->
|
|
<section class="account-section">
|
|
<p class="account-section__title">Privacy</p>
|
|
<div class="mcp-privacy">
|
|
<strong>Default privacy is process-and-forget.</strong> Tool calls are not persisted to a
|
|
case record unless you explicitly call <code>dbn.save_to_case</code>.
|
|
</div>
|
|
</section>
|
|
|
|
</div><!-- /.account-shell -->
|
|
|
|
<?php require_once __DIR__ . '/includes/footer.php'; ?>
|
|
</body>
|
|
</html>
|