@iola_adm/iola-cli 0.1.72 → 0.1.74
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 +3 -0
- package/package.json +1 -1
- package/skills/education/SKILL.md +22 -0
- package/src/cli.js +206 -34
package/README.md
CHANGED
|
@@ -129,6 +129,9 @@ iola version --check
|
|
|
129
129
|
- subagents, skill bundles, layered settings, usage/budget accounting и trajectory export;
|
|
130
130
|
- полноценный локальный MCP server по stdio/http: tools, resources и prompts;
|
|
131
131
|
- MCP-мост для локальной модели: встроенный `iola-local` доступен как `mcp:iola-local:TOOL`;
|
|
132
|
+
- вопросы по открытым данным сначала идут в публичный remote MCP `https://apiiola.yasg.ru/mcp`
|
|
133
|
+
через `layer_suggest`, `layer_query`, `layer_get` и `layer_answer_context`, а локальная БД/API
|
|
134
|
+
остаются fallback;
|
|
132
135
|
- дополнительные stdio MCP-серверы можно добавить в `~/.iola/config.json` в раздел `mcp.servers`;
|
|
133
136
|
- браузерный runtime через Playwright: чтение страниц, скриншоты, PDF, клики, ввод и eval;
|
|
134
137
|
- управляемые локальные файловые операции с режимами `locked`, `read-only`, `workspace-write`, `full-access`;
|
package/package.json
CHANGED
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: education
|
|
3
|
+
description: Вопросы по образовательным учреждениям Йошкар-Олы: школы, детские сады, руководители, контакты, адреса и лицензии.
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
Используй MCP tools слоя данных, а не прямую догадку модели.
|
|
7
|
+
|
|
8
|
+
Основные слои:
|
|
9
|
+
|
|
10
|
+
- `schools` — муниципальные школы, лицеи и гимназии.
|
|
11
|
+
- `kindergartens` — муниципальные детские сады.
|
|
12
|
+
|
|
13
|
+
Для поиска используй:
|
|
14
|
+
|
|
15
|
+
- `mcp:iola-local:layer.list` — список доступных слоев.
|
|
16
|
+
- `mcp:iola-local:layer.schema` — схема слоя.
|
|
17
|
+
- `mcp:iola-local:layer.query` — поиск по слою.
|
|
18
|
+
- `mcp:iola-local:layer.get` — точная карточка записи.
|
|
19
|
+
|
|
20
|
+
Если вопрос можно ответить точным совпадением по руководителю, ИНН, названию или адресу, отвечай только по найденной записи и указывай источник: слой, название и ИНН.
|
|
21
|
+
|
|
22
|
+
Если совпадений нет или их несколько, прямо скажи, что данных недостаточно или нужно уточнение. Не выдумывай школы, детские сады, руководителей, адреса, телефоны, лицензии и сайты.
|
package/src/cli.js
CHANGED
|
@@ -180,7 +180,7 @@ const DEFAULT_AI_CONFIG = {
|
|
|
180
180
|
suggestions: true,
|
|
181
181
|
},
|
|
182
182
|
skills: {
|
|
183
|
-
enabled: ["open-data", "reports", "local-model", "local-files", "browser-agent"],
|
|
183
|
+
enabled: ["education", "open-data", "reports", "local-model", "local-files", "browser-agent"],
|
|
184
184
|
},
|
|
185
185
|
daemon: {
|
|
186
186
|
host: "127.0.0.1",
|
|
@@ -236,11 +236,19 @@ const AGENTS = {
|
|
|
236
236
|
const DATASETS = {
|
|
237
237
|
schools: {
|
|
238
238
|
title: "Школы",
|
|
239
|
+
category: "Образование",
|
|
239
240
|
endpoint: "schools",
|
|
241
|
+
aliases: ["школ", "лицей", "гимнази"],
|
|
242
|
+
searchFields: ["name", "address", "head", "inn"],
|
|
243
|
+
personFields: ["head"],
|
|
240
244
|
},
|
|
241
245
|
kindergartens: {
|
|
242
246
|
title: "Детские сады",
|
|
247
|
+
category: "Образование",
|
|
243
248
|
endpoint: "kindergartens",
|
|
249
|
+
aliases: ["сад", "детсад", "детский сад", "доу", "мбдоу"],
|
|
250
|
+
searchFields: ["name", "address", "head", "inn"],
|
|
251
|
+
personFields: ["head"],
|
|
244
252
|
},
|
|
245
253
|
};
|
|
246
254
|
const SLASH_COMMANDS = [
|
|
@@ -6467,34 +6475,52 @@ function emitEvent(options, type, data) {
|
|
|
6467
6475
|
|
|
6468
6476
|
async function buildDataContext(question) {
|
|
6469
6477
|
await assertPermission("externalApi");
|
|
6470
|
-
const apiBaseUrl = await getApiBaseUrl();
|
|
6471
|
-
const mcpBaseUrl = await getMcpBaseUrl();
|
|
6472
|
-
const [layers, schools, kindergartens] = await Promise.all([
|
|
6473
|
-
fetchJson(`${mcpBaseUrl}/mcp-version`),
|
|
6474
|
-
fetchAllApiItems(`${apiBaseUrl}/schools`),
|
|
6475
|
-
fetchAllApiItems(`${apiBaseUrl}/kindergartens`),
|
|
6476
|
-
]);
|
|
6477
6478
|
const queryTerms = extractSearchTerms(question);
|
|
6478
6479
|
const patterns = extractStructuredPatterns(question);
|
|
6479
|
-
|
|
6480
|
-
|
|
6481
|
-
|
|
6482
|
-
|
|
6483
|
-
|
|
6484
|
-
|
|
6485
|
-
|
|
6486
|
-
|
|
6480
|
+
try {
|
|
6481
|
+
const context = await callPublicMcpTool("layer_answer_context", { question, limit: 8 });
|
|
6482
|
+
const layerMap = Object.fromEntries((context.results || []).map((result) => [result.layer?.id || result.layer, result.items || []]));
|
|
6483
|
+
return {
|
|
6484
|
+
source: "remote-mcp",
|
|
6485
|
+
contract_version: context.contract_version,
|
|
6486
|
+
layers: context.layers || [],
|
|
6487
|
+
facts: context.facts || [],
|
|
6488
|
+
sources: context.sources || [],
|
|
6489
|
+
answer_guidance: context.answer_guidance || "",
|
|
6490
|
+
query: {
|
|
6491
|
+
text: question,
|
|
6492
|
+
terms: queryTerms,
|
|
6493
|
+
patterns,
|
|
6494
|
+
},
|
|
6495
|
+
schools: layerMap.schools || [],
|
|
6496
|
+
kindergartens: layerMap.kindergartens || [],
|
|
6497
|
+
};
|
|
6498
|
+
} catch (error) {
|
|
6499
|
+
const layers = await callMcpTool("layer.list", { category: "Образование" });
|
|
6500
|
+
const targetLayerIds = resolveTargetLayerIds(patterns);
|
|
6501
|
+
const layerResults = await Promise.all(targetLayerIds.map((layer) =>
|
|
6502
|
+
callMcpTool("layer.query", { layer, query: question, terms: queryTerms, patterns, limit: 8 })));
|
|
6503
|
+
const layerMap = Object.fromEntries(layerResults.map((result) => [result.layer, result.items || []]));
|
|
6487
6504
|
|
|
6488
|
-
|
|
6489
|
-
|
|
6490
|
-
|
|
6491
|
-
|
|
6492
|
-
|
|
6493
|
-
|
|
6494
|
-
|
|
6495
|
-
|
|
6496
|
-
|
|
6497
|
-
|
|
6505
|
+
return {
|
|
6506
|
+
source: "local-fallback",
|
|
6507
|
+
fallback_error: error instanceof Error ? error.message : String(error),
|
|
6508
|
+
layers,
|
|
6509
|
+
query: {
|
|
6510
|
+
text: question,
|
|
6511
|
+
terms: queryTerms,
|
|
6512
|
+
patterns,
|
|
6513
|
+
},
|
|
6514
|
+
schools: layerMap.schools || [],
|
|
6515
|
+
kindergartens: layerMap.kindergartens || [],
|
|
6516
|
+
};
|
|
6517
|
+
}
|
|
6518
|
+
}
|
|
6519
|
+
|
|
6520
|
+
function resolveTargetLayerIds(patterns = {}) {
|
|
6521
|
+
const knownLayers = Object.keys(DATASETS);
|
|
6522
|
+
if (patterns.targetLayers?.length) return patterns.targetLayers.filter((layer) => DATASETS[layer]);
|
|
6523
|
+
return knownLayers;
|
|
6498
6524
|
}
|
|
6499
6525
|
|
|
6500
6526
|
async function fetchAllApiItems(endpoint, limit = 500, maxItems = 5000) {
|
|
@@ -6509,6 +6535,36 @@ async function fetchAllApiItems(endpoint, limit = 500, maxItems = 5000) {
|
|
|
6509
6535
|
return all;
|
|
6510
6536
|
}
|
|
6511
6537
|
|
|
6538
|
+
async function queryLayer(layer, args = {}) {
|
|
6539
|
+
const meta = DATASETS[layer];
|
|
6540
|
+
if (!meta) throw new Error(`Неизвестный слой: ${layer}`);
|
|
6541
|
+
const endpoint = `${await getApiBaseUrl()}/${meta.endpoint}`;
|
|
6542
|
+
const items = await fetchAllApiItems(endpoint);
|
|
6543
|
+
const terms = args.terms || extractSearchTerms(args.query || "");
|
|
6544
|
+
const patterns = args.patterns || extractStructuredPatterns(args.query || "");
|
|
6545
|
+
const limit = Number(args.limit || 20);
|
|
6546
|
+
return {
|
|
6547
|
+
layer,
|
|
6548
|
+
schema: layerSchema(layer),
|
|
6549
|
+
items: findRelevantItems(normalizeItems(items), terms, patterns, layer).slice(0, limit).map(selectPublicSummary),
|
|
6550
|
+
};
|
|
6551
|
+
}
|
|
6552
|
+
|
|
6553
|
+
function layerSchema(layer) {
|
|
6554
|
+
const meta = DATASETS[layer];
|
|
6555
|
+
if (!meta) throw new Error(`Неизвестный слой: ${layer}`);
|
|
6556
|
+
return {
|
|
6557
|
+
id: layer,
|
|
6558
|
+
title: meta.title,
|
|
6559
|
+
category: meta.category,
|
|
6560
|
+
endpoint: meta.endpoint,
|
|
6561
|
+
aliases: meta.aliases || [],
|
|
6562
|
+
searchFields: meta.searchFields || [],
|
|
6563
|
+
personFields: meta.personFields || [],
|
|
6564
|
+
sourceFields: ["layer", "name", "inn"],
|
|
6565
|
+
};
|
|
6566
|
+
}
|
|
6567
|
+
|
|
6512
6568
|
function emptyDataContext(question) {
|
|
6513
6569
|
return {
|
|
6514
6570
|
enabled: false,
|
|
@@ -6844,6 +6900,7 @@ async function showMcpInfo(args) {
|
|
|
6844
6900
|
server_name: info.server_name,
|
|
6845
6901
|
server_version: info.server_version,
|
|
6846
6902
|
skill_version: info.skill_version,
|
|
6903
|
+
contract_version: info.contract_version || "-",
|
|
6847
6904
|
npm_package: info.npm_package,
|
|
6848
6905
|
mcp_endpoint: info.mcp_endpoint,
|
|
6849
6906
|
layers: info.data_layers.map((layer) => layer.id).join(", "),
|
|
@@ -6894,9 +6951,9 @@ async function listDataset(dataset, args) {
|
|
|
6894
6951
|
|
|
6895
6952
|
const data = options.local
|
|
6896
6953
|
? searchLocalRecords(options.search || options._.join(" ") || "", { dataset, limit: Number(options.limit || 20), fts: options.fts })
|
|
6897
|
-
:
|
|
6954
|
+
: await listDatasetViaRemoteMcp(dataset, options, params);
|
|
6898
6955
|
const items = data;
|
|
6899
|
-
const filtered = applyDatasetFilters(items, options);
|
|
6956
|
+
const filtered = applyDatasetFilters(items, options.local ? options : { ...options, search: "" });
|
|
6900
6957
|
const limited = filtered.slice(0, Number(options.limit || 20));
|
|
6901
6958
|
const summarized = limited.map(selectPublicSummary);
|
|
6902
6959
|
const projected = projectColumns(summarized, options.columns);
|
|
@@ -6918,13 +6975,34 @@ async function listDataset(dataset, args) {
|
|
|
6918
6975
|
printDatasetTable(projected, options.columns);
|
|
6919
6976
|
}
|
|
6920
6977
|
|
|
6978
|
+
async function listDatasetViaRemoteMcp(dataset, options, params) {
|
|
6979
|
+
try {
|
|
6980
|
+
const limit = Number(options.limit || 20);
|
|
6981
|
+
const offset = Number(options.offset || 0);
|
|
6982
|
+
const query = options.search || options._.join(" ") || "";
|
|
6983
|
+
const result = await callPublicMcpTool("layer_query", {
|
|
6984
|
+
layer: dataset,
|
|
6985
|
+
query,
|
|
6986
|
+
limit: offset + limit,
|
|
6987
|
+
});
|
|
6988
|
+
return normalizeItems(result.items || []).slice(offset, offset + limit);
|
|
6989
|
+
} catch (error) {
|
|
6990
|
+
if (options.debug) {
|
|
6991
|
+
console.error(`remote MCP fallback to API: ${error instanceof Error ? error.message : String(error)}`);
|
|
6992
|
+
}
|
|
6993
|
+
return normalizeItems(await fetchJsonMaybeCached(`${await getApiBaseUrl()}/${DATASETS[dataset].endpoint}?${params}`, options));
|
|
6994
|
+
}
|
|
6995
|
+
}
|
|
6996
|
+
|
|
6921
6997
|
async function getDatasetItem(dataset, options) {
|
|
6922
6998
|
if (!options.inn) {
|
|
6923
6999
|
throw new Error(`INN is required. Example: iola ${dataset} get --inn 1215067180`);
|
|
6924
7000
|
}
|
|
6925
7001
|
|
|
6926
|
-
const
|
|
6927
|
-
|
|
7002
|
+
const result = options.local
|
|
7003
|
+
? { found: true, item: searchLocalRecords(options.inn, { dataset, limit: 1, fts: false })[0] }
|
|
7004
|
+
: await callPublicMcpTool("layer_get", { layer: dataset, inn: options.inn });
|
|
7005
|
+
const item = result?.item;
|
|
6928
7006
|
|
|
6929
7007
|
if (!item) {
|
|
6930
7008
|
throw new Error(`Record was not found in ${dataset}: inn=${options.inn}`);
|
|
@@ -6953,13 +7031,13 @@ async function searchAll(args) {
|
|
|
6953
7031
|
searchLocalRecords(query, { dataset: "kindergartens", limit, fts: options.fts }),
|
|
6954
7032
|
]
|
|
6955
7033
|
: await Promise.all([
|
|
6956
|
-
|
|
6957
|
-
|
|
7034
|
+
callPublicMcpTool("layer_query", { layer: "schools", query, limit }),
|
|
7035
|
+
callPublicMcpTool("layer_query", { layer: "kindergartens", query, limit }),
|
|
6958
7036
|
]);
|
|
6959
7037
|
|
|
6960
7038
|
const result = {
|
|
6961
|
-
schools: projectColumns(filterItems(normalizeItems(schools), query).slice(0, limit).map(selectPublicSummary), options.columns),
|
|
6962
|
-
kindergartens: projectColumns(filterItems(normalizeItems(kindergartens), query).slice(0, limit).map(selectPublicSummary), options.columns),
|
|
7039
|
+
schools: projectColumns((options.local ? filterItems(normalizeItems(schools.items || schools), query) : normalizeItems(schools.items || schools)).slice(0, limit).map(selectPublicSummary), options.columns),
|
|
7040
|
+
kindergartens: projectColumns((options.local ? filterItems(normalizeItems(kindergartens.items || kindergartens), query) : normalizeItems(kindergartens.items || kindergartens)).slice(0, limit).map(selectPublicSummary), options.columns),
|
|
6963
7041
|
};
|
|
6964
7042
|
|
|
6965
7043
|
if (options.json || options.format === "json") {
|
|
@@ -7843,6 +7921,12 @@ function mcpTools() {
|
|
|
7843
7921
|
const schema = (properties = {}) => ({ type: "object", properties, additionalProperties: false });
|
|
7844
7922
|
return [
|
|
7845
7923
|
{ name: "status", description: "Статус локальной БД, sync и активного AI-профиля.", inputSchema: schema() },
|
|
7924
|
+
{ name: "layer.list", description: "Список слоев данных и их схем.", inputSchema: schema({ category: { type: "string" } }) },
|
|
7925
|
+
{ name: "layer.schema", description: "Схема слоя данных.", inputSchema: schema({ layer: { type: "string" } }) },
|
|
7926
|
+
{ name: "layer.suggest", description: "Подобрать слой данных по вопросу пользователя через публичный MCP.", inputSchema: schema({ query: { type: "string" }, limit: { type: "number" } }) },
|
|
7927
|
+
{ name: "layer.query", description: "Поиск по слою данных через общий retrieval.", inputSchema: schema({ layer: { type: "string" }, query: { type: "string" }, terms: { type: "array" }, patterns: { type: "object" }, limit: { type: "number" } }) },
|
|
7928
|
+
{ name: "layer.get", description: "Получить запись слоя по ИНН или названию.", inputSchema: schema({ layer: { type: "string" }, query: { type: "string" }, inn: { type: "string" } }) },
|
|
7929
|
+
{ name: "layer.answer_context", description: "RAG-контекст с фактами и источниками через публичный MCP.", inputSchema: schema({ question: { type: "string" }, layer: { type: "string" }, limit: { type: "number" } }) },
|
|
7846
7930
|
{ name: "search", description: "Поиск по локальным открытым данным Йошкар-Олы.", inputSchema: schema({ query: { type: "string" }, dataset: { type: "string" }, limit: { type: "number" } }) },
|
|
7847
7931
|
{ name: "card", description: "Карточка объекта по названию или ИНН.", inputSchema: schema({ query: { type: "string" } }) },
|
|
7848
7932
|
{ name: "quality", description: "Проверки качества данных.", inputSchema: schema({ scope: { type: "string" } }) },
|
|
@@ -7860,6 +7944,7 @@ function mcpTools() {
|
|
|
7860
7944
|
function mcpResources() {
|
|
7861
7945
|
return [
|
|
7862
7946
|
{ uri: "iola://status", name: "Статус CLI", mimeType: "application/json" },
|
|
7947
|
+
{ uri: "iola://layers", name: "Слои данных", mimeType: "application/json" },
|
|
7863
7948
|
{ uri: "iola://sync", name: "Статус синхронизации", mimeType: "application/json" },
|
|
7864
7949
|
{ uri: "iola://settings", name: "Эффективные настройки", mimeType: "application/json" },
|
|
7865
7950
|
{ uri: "iola://skills", name: "Skills", mimeType: "application/json" },
|
|
@@ -7877,6 +7962,41 @@ function mcpPrompts() {
|
|
|
7877
7962
|
}
|
|
7878
7963
|
|
|
7879
7964
|
async function callMcpTool(name, args = {}) {
|
|
7965
|
+
if (name === "layer.list") {
|
|
7966
|
+
try {
|
|
7967
|
+
const result = await callPublicMcpTool("layer_list", { category: args.category || undefined });
|
|
7968
|
+
return result.items || result;
|
|
7969
|
+
} catch {
|
|
7970
|
+
return Object.entries(DATASETS)
|
|
7971
|
+
.map(([id, meta]) => layerSchema(id))
|
|
7972
|
+
.filter((layer) => !args.category || layer.category === args.category);
|
|
7973
|
+
}
|
|
7974
|
+
}
|
|
7975
|
+
if (name === "layer.schema") {
|
|
7976
|
+
try {
|
|
7977
|
+
return await callPublicMcpTool("layer_schema", { layer: args.layer });
|
|
7978
|
+
} catch {
|
|
7979
|
+
return layerSchema(args.layer);
|
|
7980
|
+
}
|
|
7981
|
+
}
|
|
7982
|
+
if (name === "layer.suggest") return callPublicMcpTool("layer_suggest", { query: args.query || "", limit: Number(args.limit || 5) });
|
|
7983
|
+
if (name === "layer.query") {
|
|
7984
|
+
try {
|
|
7985
|
+
const result = await callPublicMcpTool("layer_query", { layer: args.layer, query: args.query || "", limit: Number(args.limit || 20) });
|
|
7986
|
+
return { layer: result.layer?.id || args.layer, schema: result.layer, items: result.items || [] };
|
|
7987
|
+
} catch {
|
|
7988
|
+
return queryLayer(args.layer, args);
|
|
7989
|
+
}
|
|
7990
|
+
}
|
|
7991
|
+
if (name === "layer.get") {
|
|
7992
|
+
try {
|
|
7993
|
+
return await callPublicMcpTool("layer_get", { layer: args.layer, query: args.query || "", inn: args.inn || "" });
|
|
7994
|
+
} catch {
|
|
7995
|
+
const result = await queryLayer(args.layer, { query: args.inn || args.query || "", terms: [args.inn || args.query || ""], limit: 1 });
|
|
7996
|
+
return result.items[0] || null;
|
|
7997
|
+
}
|
|
7998
|
+
}
|
|
7999
|
+
if (name === "layer.answer_context") return callPublicMcpTool("layer_answer_context", { question: args.question || "", layer: args.layer || "", limit: Number(args.limit || 5) });
|
|
7880
8000
|
if (name === "index.search") return searchDocs(args.query || "", Number(args.limit || 20));
|
|
7881
8001
|
if (name === "report") {
|
|
7882
8002
|
const output = args.output || `${args.name || "education-contacts"}.${args.format || "xlsx"}`;
|
|
@@ -7896,6 +8016,7 @@ async function callMcpTool(name, args = {}) {
|
|
|
7896
8016
|
|
|
7897
8017
|
async function readMcpResource(uri) {
|
|
7898
8018
|
if (uri === "iola://status") return JSON.stringify({ db: getDbStatus(), sync: getSyncStatus() }, null, 2);
|
|
8019
|
+
if (uri === "iola://layers") return JSON.stringify(Object.fromEntries(Object.keys(DATASETS).map((id) => [id, layerSchema(id)])), null, 2);
|
|
7899
8020
|
if (uri === "iola://sync") return JSON.stringify(getSyncStatus(), null, 2);
|
|
7900
8021
|
if (uri === "iola://settings") return JSON.stringify(await loadConfig(), null, 2);
|
|
7901
8022
|
if (uri === "iola://skills") return JSON.stringify(listSkills(await loadConfig()), null, 2);
|
|
@@ -9044,6 +9165,9 @@ function sanitizeConfig(config) {
|
|
|
9044
9165
|
}
|
|
9045
9166
|
}
|
|
9046
9167
|
}
|
|
9168
|
+
if (Array.isArray(next.skills?.enabled) && next.skills.enabled.includes("open-data") && !next.skills.enabled.includes("education")) {
|
|
9169
|
+
next.skills.enabled = ["education", ...next.skills.enabled];
|
|
9170
|
+
}
|
|
9047
9171
|
return next;
|
|
9048
9172
|
}
|
|
9049
9173
|
|
|
@@ -9275,6 +9399,54 @@ async function fetchJson(url) {
|
|
|
9275
9399
|
return response.json();
|
|
9276
9400
|
}
|
|
9277
9401
|
|
|
9402
|
+
function parseJsonOrSse(text) {
|
|
9403
|
+
const trimmed = String(text || "").trim();
|
|
9404
|
+
if (!trimmed) return null;
|
|
9405
|
+
if (trimmed.startsWith("{") || trimmed.startsWith("[")) return JSON.parse(trimmed);
|
|
9406
|
+
const dataLines = [];
|
|
9407
|
+
for (const line of trimmed.split(/\r?\n/)) {
|
|
9408
|
+
if (line.startsWith("data:")) dataLines.push(line.slice(5).trim());
|
|
9409
|
+
}
|
|
9410
|
+
if (!dataLines.length) throw new Error(`Unexpected MCP response: ${trimmed.slice(0, 300)}`);
|
|
9411
|
+
return JSON.parse(dataLines.join("\n"));
|
|
9412
|
+
}
|
|
9413
|
+
|
|
9414
|
+
async function publicMcpRequest(method, params = undefined) {
|
|
9415
|
+
const baseUrl = await getMcpBaseUrl();
|
|
9416
|
+
const body = { jsonrpc: "2.0", id: 1, method };
|
|
9417
|
+
if (params !== undefined) body.params = params;
|
|
9418
|
+
const response = await fetch(`${baseUrl}/mcp`, {
|
|
9419
|
+
method: "POST",
|
|
9420
|
+
headers: {
|
|
9421
|
+
accept: "application/json, text/event-stream",
|
|
9422
|
+
"content-type": "application/json",
|
|
9423
|
+
},
|
|
9424
|
+
body: JSON.stringify(body),
|
|
9425
|
+
});
|
|
9426
|
+
const text = await response.text();
|
|
9427
|
+
if (!response.ok) {
|
|
9428
|
+
throw new Error(`MCP ${method} failed: ${response.status} ${response.statusText}: ${text.slice(0, 300)}`);
|
|
9429
|
+
}
|
|
9430
|
+
const payload = parseJsonOrSse(text);
|
|
9431
|
+
if (payload?.error) throw new Error(payload.error.message || JSON.stringify(payload.error));
|
|
9432
|
+
return payload?.result;
|
|
9433
|
+
}
|
|
9434
|
+
|
|
9435
|
+
async function callPublicMcpTool(name, args = {}) {
|
|
9436
|
+
const result = await publicMcpRequest("tools/call", { name, arguments: args });
|
|
9437
|
+
if (result?.structuredContent) return result.structuredContent;
|
|
9438
|
+
if (result?.structured_content) return result.structured_content;
|
|
9439
|
+
const text = result?.content?.find?.((item) => item.type === "text")?.text;
|
|
9440
|
+
if (text) {
|
|
9441
|
+
try {
|
|
9442
|
+
return JSON.parse(text);
|
|
9443
|
+
} catch {
|
|
9444
|
+
return text;
|
|
9445
|
+
}
|
|
9446
|
+
}
|
|
9447
|
+
return result;
|
|
9448
|
+
}
|
|
9449
|
+
|
|
9278
9450
|
function printJson(value) {
|
|
9279
9451
|
console.log(JSON.stringify(value, null, 2));
|
|
9280
9452
|
}
|