beplus-mcp 0.40.0 → 0.41.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 +19 -0
- package/dist/index.js +82 -16
- package/dist/index.js.map +1 -1
- package/dist/remote-server.d.ts +24 -0
- package/dist/remote-server.js +28792 -0
- package/dist/remote-server.js.map +1 -0
- package/package.json +8 -1
package/README.md
CHANGED
|
@@ -12,6 +12,25 @@ Claude Code/Desktop/Cursor ──stdio──▶ beplus-mcp ──HTTPS (Beare
|
|
|
12
12
|
|
|
13
13
|
Você se autentica com um **Personal Access Token (PAT)** gerado no painel da BePlus. O MCP só age em nome da SUA conta.
|
|
14
14
|
|
|
15
|
+
## Jeito mais fácil: conector por URL (sem Node, sem token)
|
|
16
|
+
|
|
17
|
+
A API da BePlus serve as mesmas ferramentas por HTTP, com login pelo navegador (OAuth).
|
|
18
|
+
|
|
19
|
+
**Claude Code:**
|
|
20
|
+
|
|
21
|
+
```bash
|
|
22
|
+
claude mcp add --transport http --scope user beplus https://api.beplus.academy/api/v1/mcp
|
|
23
|
+
claude mcp login beplus
|
|
24
|
+
```
|
|
25
|
+
|
|
26
|
+
O navegador abre, você entra na BePlus e clica em **Autorizar acesso**. Reinicie o Claude Code.
|
|
27
|
+
|
|
28
|
+
**Claude Desktop e claude.ai:** Configurações > Conectores > Adicionar conector personalizado, cole
|
|
29
|
+
`https://api.beplus.academy/api/v1/mcp`, clique em Conectar e em Autorizar acesso.
|
|
30
|
+
|
|
31
|
+
No conector por URL as ferramentas rodam no servidor: arquivo de mídia vai por **URL pública**, não por caminho do
|
|
32
|
+
seu computador. Para subir arquivo local, use o pacote abaixo.
|
|
33
|
+
|
|
15
34
|
## 1. Gere um Personal Access Token
|
|
16
35
|
|
|
17
36
|
No app da BePlus → **Configurações da conta → Tokens de acesso** → *Criar token*. Copie o token (`pat_…`) — ele só aparece uma vez.
|
package/dist/index.js
CHANGED
|
@@ -3303,8 +3303,8 @@ var require_utils = __commonJS({
|
|
|
3303
3303
|
var HOST_DELIMS = { "@": "%40", "/": "%2F", "?": "%3F", "#": "%23", ":": "%3A" };
|
|
3304
3304
|
var HOST_DELIM_RE = /[@/?#:]/g;
|
|
3305
3305
|
var HOST_DELIM_NO_COLON_RE = /[@/?#]/g;
|
|
3306
|
-
function reescapeHostDelimiters(host,
|
|
3307
|
-
const re =
|
|
3306
|
+
function reescapeHostDelimiters(host, isIP2) {
|
|
3307
|
+
const re = isIP2 ? HOST_DELIM_NO_COLON_RE : HOST_DELIM_RE;
|
|
3308
3308
|
re.lastIndex = 0;
|
|
3309
3309
|
return host.replace(re, (ch) => HOST_DELIMS[ch]);
|
|
3310
3310
|
}
|
|
@@ -3786,7 +3786,7 @@ var require_fast_uri = __commonJS({
|
|
|
3786
3786
|
fragment: void 0
|
|
3787
3787
|
};
|
|
3788
3788
|
let malformedAuthorityOrPort = false;
|
|
3789
|
-
let
|
|
3789
|
+
let isIP2 = false;
|
|
3790
3790
|
if (options.reference === "suffix") {
|
|
3791
3791
|
if (options.scheme) {
|
|
3792
3792
|
uri = options.scheme + ":" + uri;
|
|
@@ -3816,9 +3816,9 @@ var require_fast_uri = __commonJS({
|
|
|
3816
3816
|
if (ipv4result === false) {
|
|
3817
3817
|
const ipv6result = normalizeIPv6(parsed.host);
|
|
3818
3818
|
parsed.host = ipv6result.host.toLowerCase();
|
|
3819
|
-
|
|
3819
|
+
isIP2 = ipv6result.isIPV6;
|
|
3820
3820
|
} else {
|
|
3821
|
-
|
|
3821
|
+
isIP2 = true;
|
|
3822
3822
|
}
|
|
3823
3823
|
}
|
|
3824
3824
|
if (parsed.scheme === void 0 && parsed.userinfo === void 0 && parsed.host === void 0 && parsed.port === void 0 && parsed.query === void 0 && !parsed.path) {
|
|
@@ -3835,7 +3835,7 @@ var require_fast_uri = __commonJS({
|
|
|
3835
3835
|
}
|
|
3836
3836
|
const schemeHandler = getSchemeHandler(options.scheme || parsed.scheme);
|
|
3837
3837
|
if (!options.unicodeSupport && (!schemeHandler || !schemeHandler.unicodeSupport)) {
|
|
3838
|
-
if (parsed.host && (options.domainHost || schemeHandler && schemeHandler.domainHost) &&
|
|
3838
|
+
if (parsed.host && (options.domainHost || schemeHandler && schemeHandler.domainHost) && isIP2 === false && nonSimpleDomain(parsed.host)) {
|
|
3839
3839
|
try {
|
|
3840
3840
|
parsed.host = URL.domainToASCII(parsed.host.toLowerCase());
|
|
3841
3841
|
} catch (e) {
|
|
@@ -3849,7 +3849,7 @@ var require_fast_uri = __commonJS({
|
|
|
3849
3849
|
parsed.scheme = unescape(parsed.scheme);
|
|
3850
3850
|
}
|
|
3851
3851
|
if (parsed.host !== void 0) {
|
|
3852
|
-
parsed.host = reescapeHostDelimiters(unescape(parsed.host),
|
|
3852
|
+
parsed.host = reescapeHostDelimiters(unescape(parsed.host), isIP2);
|
|
3853
3853
|
}
|
|
3854
3854
|
}
|
|
3855
3855
|
if (parsed.path) {
|
|
@@ -21749,6 +21749,69 @@ async function pollUntilDone(client, generationId, budgetMs, jitterSeed = 0) {
|
|
|
21749
21749
|
|
|
21750
21750
|
// src/media.ts
|
|
21751
21751
|
import { readFile as readFile2, stat as stat2 } from "fs/promises";
|
|
21752
|
+
|
|
21753
|
+
// src/remote.ts
|
|
21754
|
+
import { lookup } from "dns/promises";
|
|
21755
|
+
import { isIP } from "net";
|
|
21756
|
+
var remote = false;
|
|
21757
|
+
function refuseLocalPath(ref) {
|
|
21758
|
+
if (!remote) return;
|
|
21759
|
+
throw new ApiError(
|
|
21760
|
+
0,
|
|
21761
|
+
`"${ref}" \xE9 um caminho de arquivo, e esta conex\xE3o roda no servidor da BePlus, que n\xE3o enxerga o seu computador. Mande uma URL p\xFAblica (http/https) ou suba o arquivo pela plataforma e use o link dele.`
|
|
21762
|
+
);
|
|
21763
|
+
}
|
|
21764
|
+
var MAX_REDIRECTS = 5;
|
|
21765
|
+
function v4Private(ip) {
|
|
21766
|
+
const [a, b] = ip.split(".").map(Number);
|
|
21767
|
+
return a === 0 || a === 10 || a === 127 || a === 169 && b === 254 || a === 172 && b >= 16 && b <= 31 || a === 192 && b === 168 || a === 100 && b >= 64 && b <= 127 || a >= 224;
|
|
21768
|
+
}
|
|
21769
|
+
function privateAddress(ip) {
|
|
21770
|
+
if (isIP(ip) === 4) return v4Private(ip);
|
|
21771
|
+
const v6 = ip.toLowerCase();
|
|
21772
|
+
const dotted = /^::ffff:(\d+\.\d+\.\d+\.\d+)$/.exec(v6);
|
|
21773
|
+
if (dotted) return v4Private(dotted[1]);
|
|
21774
|
+
const hex = /^::ffff:([0-9a-f]{1,4}):([0-9a-f]{1,4})$/.exec(v6);
|
|
21775
|
+
if (hex) {
|
|
21776
|
+
const hi = parseInt(hex[1], 16);
|
|
21777
|
+
const lo = parseInt(hex[2], 16);
|
|
21778
|
+
return v4Private(`${hi >> 8}.${hi & 255}.${lo >> 8}.${lo & 255}`);
|
|
21779
|
+
}
|
|
21780
|
+
return v6 === "::" || v6 === "::1" || /^f[cd]/.test(v6) || /^fe[89ab]/.test(v6) || /^ff/.test(v6);
|
|
21781
|
+
}
|
|
21782
|
+
async function assertPublic(url) {
|
|
21783
|
+
if (url.protocol !== "http:" && url.protocol !== "https:") {
|
|
21784
|
+
throw new ApiError(0, `S\xF3 baixo endere\xE7o http ou https: ${url.href}`);
|
|
21785
|
+
}
|
|
21786
|
+
const host = url.hostname.replace(/^\[|\]$/g, "").toLowerCase();
|
|
21787
|
+
if (host === "localhost" || host.endsWith(".localhost") || host.endsWith(".internal") || host.endsWith(".local")) {
|
|
21788
|
+
throw new ApiError(0, `Endere\xE7o interno n\xE3o \xE9 aceito: ${url.host}`);
|
|
21789
|
+
}
|
|
21790
|
+
const addrs = isIP(host) ? [{ address: host }] : await lookup(host, { all: true }).catch(() => []);
|
|
21791
|
+
if (addrs.length === 0) throw new ApiError(0, `N\xE3o encontrei o endere\xE7o ${url.host}.`);
|
|
21792
|
+
if (addrs.some((a) => privateAddress(a.address))) {
|
|
21793
|
+
throw new ApiError(0, `Endere\xE7o de rede privada n\xE3o \xE9 aceito: ${url.host}`);
|
|
21794
|
+
}
|
|
21795
|
+
}
|
|
21796
|
+
async function safeFetch(input, init = {}) {
|
|
21797
|
+
if (!remote) return fetch(input, init);
|
|
21798
|
+
let url = new URL(input);
|
|
21799
|
+
for (let hop = 0; hop <= MAX_REDIRECTS; hop++) {
|
|
21800
|
+
await assertPublic(url);
|
|
21801
|
+
const res = await fetch(url, { ...init, redirect: "manual" });
|
|
21802
|
+
const location = res.headers.get("location");
|
|
21803
|
+
if (res.status >= 300 && res.status < 400 && location) {
|
|
21804
|
+
await res.body?.cancel().catch(() => {
|
|
21805
|
+
});
|
|
21806
|
+
url = new URL(location, url);
|
|
21807
|
+
continue;
|
|
21808
|
+
}
|
|
21809
|
+
return res;
|
|
21810
|
+
}
|
|
21811
|
+
throw new ApiError(0, `Redirecionamentos demais ao baixar ${input}.`);
|
|
21812
|
+
}
|
|
21813
|
+
|
|
21814
|
+
// src/media.ts
|
|
21752
21815
|
import { basename, extname, isAbsolute, resolve } from "path";
|
|
21753
21816
|
import { homedir as homedir2 } from "os";
|
|
21754
21817
|
import { fileURLToPath } from "url";
|
|
@@ -21836,6 +21899,7 @@ function isRemoteRef(ref) {
|
|
|
21836
21899
|
return /^https?:\/\//i.test(ref);
|
|
21837
21900
|
}
|
|
21838
21901
|
function toLocalPath(ref) {
|
|
21902
|
+
refuseLocalPath(ref);
|
|
21839
21903
|
if (ref.startsWith("file://")) return fileURLToPath(ref);
|
|
21840
21904
|
if (ref === "~") return homedir2();
|
|
21841
21905
|
if (ref.startsWith("~/")) return resolve(homedir2(), ref.slice(2));
|
|
@@ -21875,8 +21939,9 @@ async function loadRemote(url) {
|
|
|
21875
21939
|
let name = decodeURIComponent(basename(u.pathname)) || "arquivo";
|
|
21876
21940
|
let res;
|
|
21877
21941
|
try {
|
|
21878
|
-
res = await
|
|
21879
|
-
} catch {
|
|
21942
|
+
res = await safeFetch(url, { signal: AbortSignal.timeout(DOWNLOAD_TIMEOUT_MS) });
|
|
21943
|
+
} catch (e) {
|
|
21944
|
+
if (e instanceof ApiError) throw e;
|
|
21880
21945
|
throw new ApiError(0, `N\xE3o consegui baixar ${url} (rede ou tempo esgotado).`);
|
|
21881
21946
|
}
|
|
21882
21947
|
if (!res.ok) {
|
|
@@ -23218,6 +23283,7 @@ function isRemote(ref) {
|
|
|
23218
23283
|
return /^https?:\/\//i.test(ref);
|
|
23219
23284
|
}
|
|
23220
23285
|
function toLocalPath2(ref) {
|
|
23286
|
+
refuseLocalPath(ref);
|
|
23221
23287
|
if (ref.startsWith("file://")) return fileURLToPath2(ref);
|
|
23222
23288
|
if (ref === "~") return homedir3();
|
|
23223
23289
|
if (ref.startsWith("~/")) return resolve2(homedir3(), ref.slice(2));
|
|
@@ -23243,7 +23309,7 @@ async function readAt(ref, offset, len) {
|
|
|
23243
23309
|
const ctrl = new AbortController();
|
|
23244
23310
|
const timer = setTimeout(() => ctrl.abort(), FETCH_TIMEOUT_MS);
|
|
23245
23311
|
try {
|
|
23246
|
-
const res = await
|
|
23312
|
+
const res = await safeFetch(ref, {
|
|
23247
23313
|
headers: { Range: `bytes=${offset}-${offset + len - 1}` },
|
|
23248
23314
|
signal: ctrl.signal
|
|
23249
23315
|
});
|
|
@@ -23286,7 +23352,7 @@ async function readHead(ref, bytes) {
|
|
|
23286
23352
|
const ctrl = new AbortController();
|
|
23287
23353
|
const timer = setTimeout(() => ctrl.abort(), FETCH_TIMEOUT_MS);
|
|
23288
23354
|
try {
|
|
23289
|
-
const res = await
|
|
23355
|
+
const res = await safeFetch(ref, {
|
|
23290
23356
|
headers: { Range: `bytes=0-${bytes - 1}` },
|
|
23291
23357
|
signal: ctrl.signal
|
|
23292
23358
|
});
|
|
@@ -23430,7 +23496,7 @@ function probeMp4(b) {
|
|
|
23430
23496
|
}
|
|
23431
23497
|
async function fileSizeOf(ref) {
|
|
23432
23498
|
if (!isRemote(ref)) return (await stat3(toLocalPath2(ref))).size;
|
|
23433
|
-
const res = await
|
|
23499
|
+
const res = await safeFetch(ref, { method: "HEAD" });
|
|
23434
23500
|
return Number(res.headers.get("content-length") ?? 0);
|
|
23435
23501
|
}
|
|
23436
23502
|
var ProbeError = class extends Error {
|
|
@@ -26203,10 +26269,10 @@ function withExtension(name, file) {
|
|
|
26203
26269
|
return ext && extname3(clean).toLowerCase() !== ext.toLowerCase() ? `${clean}${ext}` : clean;
|
|
26204
26270
|
}
|
|
26205
26271
|
async function uploadMedia(cfg, source, name) {
|
|
26206
|
-
const
|
|
26207
|
-
const loaded =
|
|
26272
|
+
const remote2 = isRemoteRef(source);
|
|
26273
|
+
const loaded = remote2 ? await loadRemote(source) : await loadLocal(source);
|
|
26208
26274
|
const file = { ...loaded, name: withExtension(name, loaded) };
|
|
26209
|
-
const reused =
|
|
26275
|
+
const reused = remote2 && new URL(source).host === BEPLUS_STORAGE_HOST;
|
|
26210
26276
|
const url = reused ? source : await uploadBytes(cfg, file);
|
|
26211
26277
|
const kind = kindOfMime(file.mime);
|
|
26212
26278
|
let meta = null;
|
|
@@ -27757,7 +27823,7 @@ N\xF3s: ${Object.entries(ids).map(([k, v]) => `${k}=${v}`).join(" \xB7 ")}` : ""
|
|
|
27757
27823
|
import { createRequire } from "module";
|
|
27758
27824
|
var require2 = createRequire(import.meta.url);
|
|
27759
27825
|
function readVersion() {
|
|
27760
|
-
if ("0.
|
|
27826
|
+
if ("0.41.0") return "0.41.0";
|
|
27761
27827
|
try {
|
|
27762
27828
|
const pkg = require2("../package.json");
|
|
27763
27829
|
return pkg.version ?? "0.0.0-unknown";
|