@loguro/mcp 1.1.0 → 1.2.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/dist/index.js +293 -5
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -19560,6 +19560,263 @@ class StdioServerTransport {
|
|
|
19560
19560
|
import { existsSync, readFileSync } from "node:fs";
|
|
19561
19561
|
import { homedir } from "node:os";
|
|
19562
19562
|
import { join } from "node:path";
|
|
19563
|
+
|
|
19564
|
+
// src/docs-catalog.ts
|
|
19565
|
+
var DOCS_CATALOG = [
|
|
19566
|
+
{ path: "/docs/getting-started", title: "Getting Started", section: "General" },
|
|
19567
|
+
{ path: "/docs/query-syntax", title: "Query Syntax", section: "General" },
|
|
19568
|
+
{ path: "/docs/alerting", title: "Alerting", section: "General" },
|
|
19569
|
+
{ path: "/docs/integrations", title: "Integrations", section: "General" },
|
|
19570
|
+
{ path: "/docs/cli/install", title: "Install", section: "CLI" },
|
|
19571
|
+
{ path: "/docs/cli/getting-started", title: "Getting Started", section: "CLI" },
|
|
19572
|
+
{ path: "/docs/cli/auth", title: "Auth", section: "CLI" },
|
|
19573
|
+
{ path: "/docs/cli/project-link", title: "Project Link", section: "CLI" },
|
|
19574
|
+
{ path: "/docs/cli/commands", title: "Commands", section: "CLI" },
|
|
19575
|
+
{ path: "/docs/cli/querying", title: "Querying", section: "CLI" },
|
|
19576
|
+
{ path: "/docs/cli/query-syntax", title: "Query Syntax", section: "CLI" },
|
|
19577
|
+
{ path: "/docs/cli/investigate", title: "Investigate", section: "CLI" },
|
|
19578
|
+
{ path: "/docs/cli/visualizations", title: "Visualizations", section: "CLI" },
|
|
19579
|
+
{ path: "/docs/cli/replay", title: "Replay", section: "CLI" },
|
|
19580
|
+
{ path: "/docs/cli/alerts", title: "Alerts", section: "CLI" },
|
|
19581
|
+
{ path: "/docs/cli/integrations", title: "Integrations", section: "CLI" },
|
|
19582
|
+
{ path: "/docs/cli/share", title: "Share", section: "CLI" },
|
|
19583
|
+
{ path: "/docs/cli/account", title: "Account", section: "CLI" },
|
|
19584
|
+
{ path: "/docs/commands/count", title: "--count", section: "Commands" },
|
|
19585
|
+
{ path: "/docs/commands/top", title: "--top", section: "Commands" },
|
|
19586
|
+
{ path: "/docs/commands/unique", title: "--unique", section: "Commands" },
|
|
19587
|
+
{ path: "/docs/commands/rate", title: "--rate", section: "Commands" },
|
|
19588
|
+
{ path: "/docs/commands/diff", title: "--diff", section: "Commands" },
|
|
19589
|
+
{ path: "/docs/commands/downloads", title: "--downloads", section: "Commands" },
|
|
19590
|
+
{ path: "/docs/commands/replay", title: "--replay", section: "Commands" },
|
|
19591
|
+
{ path: "/docs/commands/live", title: "--live", section: "Commands" },
|
|
19592
|
+
{ path: "/docs/commands/group", title: "--group", section: "Commands" },
|
|
19593
|
+
{ path: "/docs/commands/alerts", title: "--alerts", section: "Commands" },
|
|
19594
|
+
{ path: "/docs/commands/views", title: "--views", section: "Commands" },
|
|
19595
|
+
{ path: "/docs/commands/keys", title: "--keys", section: "Commands" },
|
|
19596
|
+
{ path: "/docs/commands/channels", title: "--channels", section: "Commands" },
|
|
19597
|
+
{ path: "/docs/commands/embed-status", title: "--embed::status", section: "Commands" },
|
|
19598
|
+
{ path: "/docs/commands/billing", title: "--billing", section: "Commands" },
|
|
19599
|
+
{ path: "/docs/commands/usage", title: "--usage", section: "Commands" },
|
|
19600
|
+
{ path: "/docs/commands/integrations-config", title: "--integrations::config", section: "Commands" },
|
|
19601
|
+
{ path: "/docs/commands/send", title: "--send", section: "Commands" },
|
|
19602
|
+
{ path: "/docs/commands/tasks", title: "--task", section: "Commands" },
|
|
19603
|
+
{ path: "/docs/commands/slow", title: "--slow", section: "Commands" },
|
|
19604
|
+
{ path: "/docs/commands/sample", title: "--sample", section: "Commands" },
|
|
19605
|
+
{ path: "/docs/commands/memory", title: "--memory", section: "Commands" },
|
|
19606
|
+
{ path: "/docs/commands/chart", title: "--chart", section: "Commands" },
|
|
19607
|
+
{ path: "/docs/commands/timeline", title: "--timeline", section: "Commands" },
|
|
19608
|
+
{ path: "/docs/commands/notifications", title: "--notifications", section: "Commands" },
|
|
19609
|
+
{ path: "/docs/commands/severity", title: "--severity", section: "Commands" },
|
|
19610
|
+
{ path: "/docs/commands/separate-message", title: "--separate::message", section: "Commands" },
|
|
19611
|
+
{ path: "/docs/commands/no-group", title: "--no-group", section: "Commands" },
|
|
19612
|
+
{ path: "/docs/commands/hashtag", title: "#view", section: "Commands" },
|
|
19613
|
+
{ path: "/docs/commands/investigate", title: "--investigate", section: "Commands" },
|
|
19614
|
+
{ path: "/docs/commands/explain", title: "--explain", section: "Commands" },
|
|
19615
|
+
{ path: "/docs/commands/notes", title: "--notes", section: "Commands" },
|
|
19616
|
+
{ path: "/docs/commands/share", title: "--share:md", section: "Commands" },
|
|
19617
|
+
{ path: "/docs/commands/slack", title: "--slack", section: "Commands" },
|
|
19618
|
+
{ path: "/docs/commands/trace", title: "--trace:full", section: "Commands" },
|
|
19619
|
+
{ path: "/docs/features/saved-views", title: "Saved Views", section: "Features" },
|
|
19620
|
+
{ path: "/docs/features/log-export", title: "Log Export", section: "Features" },
|
|
19621
|
+
{ path: "/docs/features/embed-widgets", title: "Embed Widgets", section: "Features" },
|
|
19622
|
+
{ path: "/docs/features/replay", title: "Replay", section: "Features" },
|
|
19623
|
+
{ path: "/docs/features/issue-tracker", title: "Issue Tracker", section: "Features" },
|
|
19624
|
+
{ path: "/docs/features/messaging", title: "Messaging", section: "Features" },
|
|
19625
|
+
{ path: "/docs/features/heartbeat", title: "Heartbeat", section: "Features" },
|
|
19626
|
+
{ path: "/docs/features/memory", title: "Memory", section: "Features" },
|
|
19627
|
+
{ path: "/docs/mcp/setup", title: "Setup", section: "MCP" },
|
|
19628
|
+
{ path: "/docs/mcp/auth", title: "Auth", section: "MCP" },
|
|
19629
|
+
{ path: "/docs/mcp/config", title: "Config", section: "MCP" },
|
|
19630
|
+
{ path: "/docs/mcp/tools", title: "Tools", section: "MCP" },
|
|
19631
|
+
{ path: "/docs/mcp/clients", title: "Clients", section: "MCP" },
|
|
19632
|
+
{ path: "/docs/mcp/vs-cli", title: "MCP vs CLI", section: "MCP" },
|
|
19633
|
+
{ path: "/docs/tui/getting-started", title: "Getting Started", section: "TUI" },
|
|
19634
|
+
{ path: "/docs/tui/views", title: "Views", section: "TUI" },
|
|
19635
|
+
{ path: "/docs/tui/keymap", title: "Keymap", section: "TUI" },
|
|
19636
|
+
{ path: "/docs/tui/search", title: "Search", section: "TUI" },
|
|
19637
|
+
{ path: "/docs/tui/alerts", title: "Alerts", section: "TUI" },
|
|
19638
|
+
{ path: "/docs/tui/saved-views", title: "Saved Views", section: "TUI" },
|
|
19639
|
+
{ path: "/docs/tui/docs-browser", title: "Docs Browser", section: "TUI" },
|
|
19640
|
+
{ path: "/docs/tui/health-badge", title: "Health Badge", section: "TUI" },
|
|
19641
|
+
{ path: "/docs/tui/troubleshooting", title: "Troubleshooting", section: "TUI" },
|
|
19642
|
+
{ path: "/docs/web-analytics/getting-started", title: "Getting Started", section: "Web Analytics" },
|
|
19643
|
+
{ path: "/docs/web-analytics/install", title: "Install", section: "Web Analytics" },
|
|
19644
|
+
{ path: "/docs/web-analytics/events", title: "Events", section: "Web Analytics" },
|
|
19645
|
+
{ path: "/docs/web-analytics/pageviews", title: "Pageviews", section: "Web Analytics" },
|
|
19646
|
+
{ path: "/docs/web-analytics/identity", title: "Identity", section: "Web Analytics" },
|
|
19647
|
+
{ path: "/docs/web-analytics/privacy", title: "Privacy", section: "Web Analytics" },
|
|
19648
|
+
{ path: "/docs/web-analytics/api-reference", title: "API Reference", section: "Web Analytics" },
|
|
19649
|
+
{ path: "/docs/web-analytics/troubleshooting", title: "Troubleshooting", section: "Web Analytics" }
|
|
19650
|
+
];
|
|
19651
|
+
|
|
19652
|
+
// src/docs.ts
|
|
19653
|
+
var DOCS_BASE_URL = (process.env.LOGURO_DOCS_BASE_URL ?? "https://logu.ro").replace(/\/$/, "");
|
|
19654
|
+
var CACHE_TTL_MS = 15 * 60 * 1000;
|
|
19655
|
+
var FETCH_TIMEOUT_MS = 1e4;
|
|
19656
|
+
var USER_AGENT = `loguro-mcp-docs/1.0.0 (node/${process.version})`;
|
|
19657
|
+
var cache = new Map;
|
|
19658
|
+
var allFetchedAt = 0;
|
|
19659
|
+
function extractHeadings(md) {
|
|
19660
|
+
const out = [];
|
|
19661
|
+
for (const line of md.split(`
|
|
19662
|
+
`)) {
|
|
19663
|
+
const m = line.match(/^(#{1,6})\s+(.+?)\s*$/);
|
|
19664
|
+
if (m)
|
|
19665
|
+
out.push(m[2].trim());
|
|
19666
|
+
}
|
|
19667
|
+
return out;
|
|
19668
|
+
}
|
|
19669
|
+
function isFresh(entry) {
|
|
19670
|
+
return Date.now() - entry.fetchedAt < CACHE_TTL_MS;
|
|
19671
|
+
}
|
|
19672
|
+
async function fetchDoc(path, force = false) {
|
|
19673
|
+
const cached2 = cache.get(path);
|
|
19674
|
+
if (!force && cached2 && isFresh(cached2))
|
|
19675
|
+
return cached2;
|
|
19676
|
+
const url = `${DOCS_BASE_URL}${path}.md`;
|
|
19677
|
+
const res = await fetch(url, {
|
|
19678
|
+
headers: { "User-Agent": USER_AGENT, Accept: "text/markdown,text/plain,*/*" },
|
|
19679
|
+
signal: AbortSignal.timeout(FETCH_TIMEOUT_MS)
|
|
19680
|
+
});
|
|
19681
|
+
if (!res.ok) {
|
|
19682
|
+
throw new Error(`Failed to fetch ${url}: HTTP ${res.status}`);
|
|
19683
|
+
}
|
|
19684
|
+
const body = await res.text();
|
|
19685
|
+
const entry = {
|
|
19686
|
+
path,
|
|
19687
|
+
body,
|
|
19688
|
+
headings: extractHeadings(body),
|
|
19689
|
+
fetchedAt: Date.now()
|
|
19690
|
+
};
|
|
19691
|
+
cache.set(path, entry);
|
|
19692
|
+
return entry;
|
|
19693
|
+
}
|
|
19694
|
+
async function fetchAllDocs() {
|
|
19695
|
+
if (Date.now() - allFetchedAt < CACHE_TTL_MS)
|
|
19696
|
+
return;
|
|
19697
|
+
await Promise.all(DOCS_CATALOG.map((entry) => fetchDoc(entry.path).catch((err) => {
|
|
19698
|
+
process.stderr.write(`docs: failed to fetch ${entry.path}: ${err.message}
|
|
19699
|
+
`);
|
|
19700
|
+
})));
|
|
19701
|
+
allFetchedAt = Date.now();
|
|
19702
|
+
}
|
|
19703
|
+
function listDocs(section) {
|
|
19704
|
+
const filtered = section ? DOCS_CATALOG.filter((e) => e.section.toLowerCase() === section.toLowerCase()) : DOCS_CATALOG;
|
|
19705
|
+
return filtered.map((e) => {
|
|
19706
|
+
const cached2 = cache.get(e.path);
|
|
19707
|
+
return cached2 ? { ...e, headings: cached2.headings } : { ...e };
|
|
19708
|
+
});
|
|
19709
|
+
}
|
|
19710
|
+
function listSections() {
|
|
19711
|
+
const counts = new Map;
|
|
19712
|
+
for (const e of DOCS_CATALOG)
|
|
19713
|
+
counts.set(e.section, (counts.get(e.section) ?? 0) + 1);
|
|
19714
|
+
return [...counts.entries()].map(([section, count]) => ({ section, count }));
|
|
19715
|
+
}
|
|
19716
|
+
function tokens(s) {
|
|
19717
|
+
return s.toLowerCase().split(/\s+/).filter(Boolean);
|
|
19718
|
+
}
|
|
19719
|
+
function countOccurrences(haystack, needle) {
|
|
19720
|
+
if (!needle)
|
|
19721
|
+
return 0;
|
|
19722
|
+
let count = 0;
|
|
19723
|
+
let i = 0;
|
|
19724
|
+
const lc = haystack.toLowerCase();
|
|
19725
|
+
while ((i = lc.indexOf(needle, i)) !== -1) {
|
|
19726
|
+
count++;
|
|
19727
|
+
i += needle.length;
|
|
19728
|
+
}
|
|
19729
|
+
return count;
|
|
19730
|
+
}
|
|
19731
|
+
function buildSnippet(body, query, max = 280) {
|
|
19732
|
+
const lc = body.toLowerCase();
|
|
19733
|
+
const idx = lc.indexOf(query.toLowerCase());
|
|
19734
|
+
if (idx === -1) {
|
|
19735
|
+
return body.slice(0, max).trim() + (body.length > max ? "…" : "");
|
|
19736
|
+
}
|
|
19737
|
+
const start = Math.max(0, idx - 80);
|
|
19738
|
+
const end = Math.min(body.length, idx + query.length + 200);
|
|
19739
|
+
const prefix = start > 0 ? "…" : "";
|
|
19740
|
+
const suffix = end < body.length ? "…" : "";
|
|
19741
|
+
return prefix + body.slice(start, end).replace(/\s+/g, " ").trim() + suffix;
|
|
19742
|
+
}
|
|
19743
|
+
async function searchDocs(query, limit = 5) {
|
|
19744
|
+
await fetchAllDocs();
|
|
19745
|
+
const q = query.trim().toLowerCase();
|
|
19746
|
+
const qTokens = tokens(q);
|
|
19747
|
+
if (!q)
|
|
19748
|
+
return [];
|
|
19749
|
+
const hits = [];
|
|
19750
|
+
for (const entry of DOCS_CATALOG) {
|
|
19751
|
+
const cached2 = cache.get(entry.path);
|
|
19752
|
+
const titleLc = entry.title.toLowerCase();
|
|
19753
|
+
const sectionLc = entry.section.toLowerCase();
|
|
19754
|
+
const matchedIn = new Set;
|
|
19755
|
+
let score = 0;
|
|
19756
|
+
const matchedHeadings = [];
|
|
19757
|
+
if (titleLc.includes(q)) {
|
|
19758
|
+
score += 50;
|
|
19759
|
+
matchedIn.add("title");
|
|
19760
|
+
} else {
|
|
19761
|
+
for (const t of qTokens)
|
|
19762
|
+
if (titleLc.includes(t)) {
|
|
19763
|
+
score += 15;
|
|
19764
|
+
matchedIn.add("title");
|
|
19765
|
+
}
|
|
19766
|
+
}
|
|
19767
|
+
if (sectionLc.includes(q)) {
|
|
19768
|
+
score += 10;
|
|
19769
|
+
matchedIn.add("section");
|
|
19770
|
+
}
|
|
19771
|
+
if (cached2) {
|
|
19772
|
+
for (const h of cached2.headings) {
|
|
19773
|
+
const hLc = h.toLowerCase();
|
|
19774
|
+
if (hLc.includes(q)) {
|
|
19775
|
+
score += 20;
|
|
19776
|
+
matchedIn.add("heading");
|
|
19777
|
+
matchedHeadings.push(h);
|
|
19778
|
+
} else {
|
|
19779
|
+
for (const t of qTokens) {
|
|
19780
|
+
if (hLc.includes(t)) {
|
|
19781
|
+
score += 5;
|
|
19782
|
+
matchedIn.add("heading");
|
|
19783
|
+
if (!matchedHeadings.includes(h))
|
|
19784
|
+
matchedHeadings.push(h);
|
|
19785
|
+
}
|
|
19786
|
+
}
|
|
19787
|
+
}
|
|
19788
|
+
}
|
|
19789
|
+
const bodyOccurrences = countOccurrences(cached2.body, q);
|
|
19790
|
+
if (bodyOccurrences > 0) {
|
|
19791
|
+
score += Math.min(bodyOccurrences, 10);
|
|
19792
|
+
matchedIn.add("body");
|
|
19793
|
+
} else {
|
|
19794
|
+
for (const t of qTokens) {
|
|
19795
|
+
const occ = countOccurrences(cached2.body, t);
|
|
19796
|
+
if (occ > 0) {
|
|
19797
|
+
score += Math.min(occ, 5) * 0.5;
|
|
19798
|
+
matchedIn.add("body");
|
|
19799
|
+
}
|
|
19800
|
+
}
|
|
19801
|
+
}
|
|
19802
|
+
}
|
|
19803
|
+
if (score > 0) {
|
|
19804
|
+
hits.push({
|
|
19805
|
+
path: entry.path,
|
|
19806
|
+
title: entry.title,
|
|
19807
|
+
section: entry.section,
|
|
19808
|
+
score,
|
|
19809
|
+
matchedIn: [...matchedIn],
|
|
19810
|
+
snippet: cached2 ? buildSnippet(cached2.body, q) : "",
|
|
19811
|
+
matchedHeadings
|
|
19812
|
+
});
|
|
19813
|
+
}
|
|
19814
|
+
}
|
|
19815
|
+
hits.sort((a, b) => b.score - a.score);
|
|
19816
|
+
return hits.slice(0, limit);
|
|
19817
|
+
}
|
|
19818
|
+
|
|
19819
|
+
// src/index.ts
|
|
19563
19820
|
function loadCliAuth() {
|
|
19564
19821
|
const xdg = process.env.XDG_CONFIG_HOME;
|
|
19565
19822
|
const base = xdg && xdg.length > 0 ? xdg : join(homedir(), ".config");
|
|
@@ -19589,7 +19846,7 @@ if (!TOKEN) {
|
|
|
19589
19846
|
process.stderr.write("Error: no PAT found. Run `loguro login` first, or set LOGURO_TOKEN env var.\n");
|
|
19590
19847
|
process.exit(1);
|
|
19591
19848
|
}
|
|
19592
|
-
var
|
|
19849
|
+
var USER_AGENT2 = `loguro-mcp/1.0.0 (node/${process.version})`;
|
|
19593
19850
|
var REQUEST_TIMEOUT_MS = 15000;
|
|
19594
19851
|
function buildQS(params) {
|
|
19595
19852
|
const qs = new URLSearchParams;
|
|
@@ -19610,7 +19867,7 @@ async function logsRequest(project, params) {
|
|
|
19610
19867
|
const res = await fetch(url, {
|
|
19611
19868
|
headers: {
|
|
19612
19869
|
Authorization: `Bearer ${TOKEN}`,
|
|
19613
|
-
"User-Agent":
|
|
19870
|
+
"User-Agent": USER_AGENT2,
|
|
19614
19871
|
Accept: "application/json"
|
|
19615
19872
|
},
|
|
19616
19873
|
signal: AbortSignal.timeout(REQUEST_TIMEOUT_MS)
|
|
@@ -19630,7 +19887,7 @@ async function logsSubRequest(project, subPath, params, method = "GET") {
|
|
|
19630
19887
|
method,
|
|
19631
19888
|
headers: {
|
|
19632
19889
|
Authorization: `Bearer ${TOKEN}`,
|
|
19633
|
-
"User-Agent":
|
|
19890
|
+
"User-Agent": USER_AGENT2,
|
|
19634
19891
|
Accept: "application/json"
|
|
19635
19892
|
},
|
|
19636
19893
|
signal: AbortSignal.timeout(REQUEST_TIMEOUT_MS)
|
|
@@ -19647,7 +19904,7 @@ async function apiRequest(method, path, body) {
|
|
|
19647
19904
|
method,
|
|
19648
19905
|
headers: {
|
|
19649
19906
|
Authorization: `Bearer ${TOKEN}`,
|
|
19650
|
-
"User-Agent":
|
|
19907
|
+
"User-Agent": USER_AGENT2,
|
|
19651
19908
|
Accept: "application/json",
|
|
19652
19909
|
...body !== undefined ? { "Content-Type": "application/json" } : {}
|
|
19653
19910
|
},
|
|
@@ -20314,7 +20571,7 @@ server.tool("check_investigated", "Batch check which fingerprints have cached AI
|
|
|
20314
20571
|
method: "POST",
|
|
20315
20572
|
headers: {
|
|
20316
20573
|
Authorization: `Bearer ${TOKEN}`,
|
|
20317
|
-
"User-Agent":
|
|
20574
|
+
"User-Agent": USER_AGENT2,
|
|
20318
20575
|
Accept: "application/json",
|
|
20319
20576
|
"Content-Type": "application/json"
|
|
20320
20577
|
},
|
|
@@ -20327,5 +20584,36 @@ server.tool("check_investigated", "Batch check which fingerprints have cached AI
|
|
|
20327
20584
|
const data = await res.json();
|
|
20328
20585
|
return jsonResult(data, `Cached investigations: ${data.investigated?.length ?? 0}/${fingerprints.length}`);
|
|
20329
20586
|
});
|
|
20587
|
+
server.tool("list_docs", "Browse the Loguro documentation catalog. Returns titles + paths grouped by section. Call without args to see everything; pass `section` to filter. Use `read_doc` to fetch full content of a page.", {
|
|
20588
|
+
section: exports_external.string().optional().describe("Filter by section: General, CLI, Commands, Features, MCP, TUI, Web Analytics")
|
|
20589
|
+
}, async ({ section }) => {
|
|
20590
|
+
const docs = listDocs(section);
|
|
20591
|
+
const sections = listSections();
|
|
20592
|
+
const grouped = {};
|
|
20593
|
+
for (const d of docs) {
|
|
20594
|
+
if (!grouped[d.section])
|
|
20595
|
+
grouped[d.section] = [];
|
|
20596
|
+
grouped[d.section].push({ path: d.path, title: d.title, headings: d.headings });
|
|
20597
|
+
}
|
|
20598
|
+
const summary = section ? `${docs.length} page(s) in section "${section}"` : `${docs.length} pages across ${sections.length} sections: ${sections.map((s) => `${s.section} (${s.count})`).join(", ")}`;
|
|
20599
|
+
return jsonResult({ sections, docs: grouped }, summary);
|
|
20600
|
+
});
|
|
20601
|
+
server.tool("search_docs", "Search Loguro documentation by keyword. Fetches all docs on first call (cached 15min), then scores matches across title, section, headings, and body. Returns top hits with snippets. Use this when you don't know which page covers a topic.", {
|
|
20602
|
+
query: exports_external.string().min(1).describe("Search terms — natural words, not regex. E.g. 'how do alerts work', 'PAT token', 'context filter'."),
|
|
20603
|
+
limit: exports_external.number().min(1).max(20).default(5).describe("Max results (default 5)")
|
|
20604
|
+
}, async ({ query, limit }) => {
|
|
20605
|
+
const hits = await searchDocs(query, limit);
|
|
20606
|
+
const summary = hits.length === 0 ? `No matches for "${query}"` : `Top ${hits.length} hit(s) for "${query}" — best: ${hits[0].title} (${hits[0].section}) score=${hits[0].score}`;
|
|
20607
|
+
return jsonResult({ query, hits }, summary);
|
|
20608
|
+
});
|
|
20609
|
+
server.tool("read_doc", "Fetch the full markdown body of a documentation page by its path (e.g. '/docs/cli/alerts'). Use after `search_docs` or `list_docs` to read a specific page end-to-end.", {
|
|
20610
|
+
path: exports_external.string().describe("Doc path starting with /docs/ — e.g. /docs/mcp/setup"),
|
|
20611
|
+
refresh: exports_external.boolean().default(false).describe("Bypass the 15min cache and refetch from logu.ro")
|
|
20612
|
+
}, async ({ path, refresh }) => {
|
|
20613
|
+
const normalized = path.startsWith("/") ? path : "/" + path;
|
|
20614
|
+
const doc2 = await fetchDoc(normalized, refresh);
|
|
20615
|
+
const summary = `${normalized} (${doc2.body.length} chars, ${doc2.headings.length} heading(s))`;
|
|
20616
|
+
return jsonResult({ path: normalized, headings: doc2.headings, body: doc2.body, fetchedAt: new Date(doc2.fetchedAt).toISOString() }, summary);
|
|
20617
|
+
});
|
|
20330
20618
|
var transport = new StdioServerTransport;
|
|
20331
20619
|
await server.connect(transport);
|
package/package.json
CHANGED