@thenavidm/threads-mcp-cli 1.1.1 → 2.0.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 +141 -88
- package/SKILL.md +9 -8
- package/dist/app.d.ts +9 -0
- package/dist/app.js +101 -0
- package/dist/app.js.map +1 -0
- package/dist/auth/login.js +2 -1
- package/dist/auth/login.js.map +1 -1
- package/dist/auth/refresh.d.ts +8 -0
- package/dist/auth/refresh.js +39 -0
- package/dist/auth/refresh.js.map +1 -0
- package/dist/doctor.d.ts +11 -4
- package/dist/doctor.js +64 -125
- package/dist/doctor.js.map +1 -1
- package/dist/{server.d.ts → guide.d.ts} +14 -17
- package/dist/{server.js → guide.js} +18 -122
- package/dist/guide.js.map +1 -0
- package/dist/index.d.ts +5 -8
- package/dist/index.js +9 -162
- package/dist/index.js.map +1 -1
- package/dist/npx.d.ts +2 -0
- package/dist/npx.js +14 -0
- package/dist/npx.js.map +1 -0
- package/dist/tools/accounts.d.ts +5 -18
- package/dist/tools/discover.d.ts +5 -46
- package/dist/tools/insights.d.ts +5 -36
- package/dist/tools/kit.d.ts +23 -49
- package/dist/tools/kit.js +64 -79
- package/dist/tools/kit.js.map +1 -1
- package/dist/tools/posts.d.ts +10 -161
- package/dist/tools/read.d.ts +3 -24
- package/dist/tools/replies.d.ts +8 -79
- package/package.json +13 -7
- package/dist/cli.d.ts +0 -59
- package/dist/cli.js +0 -444
- package/dist/cli.js.map +0 -1
- package/dist/safety.d.ts +0 -52
- package/dist/safety.js +0 -85
- package/dist/safety.js.map +0 -1
- package/dist/server.js.map +0 -1
- package/dist/transport/http.d.ts +0 -28
- package/dist/transport/http.js +0 -107
- package/dist/transport/http.js.map +0 -1
package/dist/safety.js
DELETED
|
@@ -1,85 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Decides whether a write is allowed to reach Threads.
|
|
3
|
-
*
|
|
4
|
-
* The hazard is specific and worth naming. A Threads post is public the instant
|
|
5
|
-
* it lands, and Threads has no edit endpoint: fixing a typo means deleting and
|
|
6
|
-
* republishing, which loses the replies and the likes and spends one of the
|
|
7
|
-
* hundred deletions the account gets each day. There is no unsend and no
|
|
8
|
-
* revision. None of that is dangerous when a person meant it.
|
|
9
|
-
*
|
|
10
|
-
* So: everything works, and the operations that reach other people need an
|
|
11
|
-
* explicit `confirm: true` the model has to set deliberately after reading a
|
|
12
|
-
* description that says why. That is a speed bump a careless call trips over
|
|
13
|
-
* and an intentional one clears in a single retry.
|
|
14
|
-
*
|
|
15
|
-
* Hiding a reply is not guarded. It is one call to undo and reversible from the
|
|
16
|
-
* app, and a confirmation on every hide would train the model to pass `confirm`
|
|
17
|
-
* reflexively, which is worse than not asking at all.
|
|
18
|
-
*
|
|
19
|
-
* THREADS_READ_ONLY=1 removes every write from the tool list entirely, for
|
|
20
|
-
* pointing an agent at an account it should only ever read.
|
|
21
|
-
*/
|
|
22
|
-
import { appendFileSync } from "node:fs";
|
|
23
|
-
import { WriteBlockedError } from "./api/errors.js";
|
|
24
|
-
export class WriteGuard {
|
|
25
|
-
config;
|
|
26
|
-
surface;
|
|
27
|
-
constructor(config, surface = "mcp") {
|
|
28
|
-
this.config = config;
|
|
29
|
-
this.surface = surface;
|
|
30
|
-
}
|
|
31
|
-
/** `--confirm` in a terminal, `confirm: true` in a tool call. */
|
|
32
|
-
get confirmFlag() {
|
|
33
|
-
return this.surface === "cli" ? "--confirm" : "confirm: true";
|
|
34
|
-
}
|
|
35
|
-
get readOnly() {
|
|
36
|
-
return this.config.readOnly;
|
|
37
|
-
}
|
|
38
|
-
check(tool, risk, confirm, summary) {
|
|
39
|
-
if (risk === "read")
|
|
40
|
-
return;
|
|
41
|
-
if (this.config.readOnly) {
|
|
42
|
-
this.audit(tool, summary, "blocked: read-only");
|
|
43
|
-
throw new WriteBlockedError(`${tool} is unavailable: this server is running with THREADS_READ_ONLY=1.`);
|
|
44
|
-
}
|
|
45
|
-
if (risk === "destructive") {
|
|
46
|
-
if (!this.config.allowDestructive) {
|
|
47
|
-
this.audit(tool, summary, "blocked: destructive disabled");
|
|
48
|
-
throw new WriteBlockedError(`${tool} is unavailable: this server is running with THREADS_ALLOW_DESTRUCTIVE=0.`);
|
|
49
|
-
}
|
|
50
|
-
if (confirm !== true) {
|
|
51
|
-
this.audit(tool, summary, "blocked: no confirm");
|
|
52
|
-
throw new WriteBlockedError(`${tool} is public or irreversible, so it will not run without ${this.confirmFlag}. About to: ${summary}. Call again with ${this.confirmFlag} if that is what was asked for.`);
|
|
53
|
-
}
|
|
54
|
-
}
|
|
55
|
-
this.audit(tool, summary, "allowed");
|
|
56
|
-
}
|
|
57
|
-
/** Append-only record of every attempted write, when THREADS_AUDIT_LOG is set. */
|
|
58
|
-
audit(tool, summary, outcome) {
|
|
59
|
-
if (!this.config.auditPath)
|
|
60
|
-
return;
|
|
61
|
-
const line = JSON.stringify({ at: new Date().toISOString(), tool, summary, outcome });
|
|
62
|
-
try {
|
|
63
|
-
appendFileSync(this.config.auditPath, `${line}\n`, { mode: 0o600 });
|
|
64
|
-
}
|
|
65
|
-
catch {
|
|
66
|
-
// A failing audit log must never take the tool call down with it.
|
|
67
|
-
}
|
|
68
|
-
}
|
|
69
|
-
}
|
|
70
|
-
/**
|
|
71
|
-
* MCP annotations for a risk level.
|
|
72
|
-
*
|
|
73
|
-
* Clients use these to decide what to auto-approve, so they have to be honest.
|
|
74
|
-
* `openWorldHint` is true for everything because every call leaves the machine,
|
|
75
|
-
* and `idempotentHint` is false for a post because calling it twice posts twice.
|
|
76
|
-
*/
|
|
77
|
-
export function annotationsFor(risk, options = {}) {
|
|
78
|
-
return {
|
|
79
|
-
readOnlyHint: risk === "read",
|
|
80
|
-
destructiveHint: risk === "destructive",
|
|
81
|
-
idempotentHint: options.idempotent ?? risk === "read",
|
|
82
|
-
openWorldHint: true,
|
|
83
|
-
};
|
|
84
|
-
}
|
|
85
|
-
//# sourceMappingURL=safety.js.map
|
package/dist/safety.js.map
DELETED
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"safety.js","sourceRoot":"","sources":["../src/safety.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;GAoBG;AAEH,OAAO,EAAE,cAAc,EAAE,MAAM,SAAS,CAAC;AAEzC,OAAO,EAAE,iBAAiB,EAAE,MAAM,iBAAiB,CAAC;AAapD,MAAM,OAAO,UAAU;IACJ,MAAM,CAAS;IACf,OAAO,CAAU;IAElC,YAAY,MAAc,EAAE,UAAmB,KAAK;QAClD,IAAI,CAAC,MAAM,GAAG,MAAM,CAAC;QACrB,IAAI,CAAC,OAAO,GAAG,OAAO,CAAC;IACzB,CAAC;IAED,iEAAiE;IACjE,IAAY,WAAW;QACrB,OAAO,IAAI,CAAC,OAAO,KAAK,KAAK,CAAC,CAAC,CAAC,WAAW,CAAC,CAAC,CAAC,eAAe,CAAC;IAChE,CAAC;IAED,IAAI,QAAQ;QACV,OAAO,IAAI,CAAC,MAAM,CAAC,QAAQ,CAAC;IAC9B,CAAC;IAED,KAAK,CAAC,IAAY,EAAE,IAAU,EAAE,OAA4B,EAAE,OAAe;QAC3E,IAAI,IAAI,KAAK,MAAM;YAAE,OAAO;QAE5B,IAAI,IAAI,CAAC,MAAM,CAAC,QAAQ,EAAE,CAAC;YACzB,IAAI,CAAC,KAAK,CAAC,IAAI,EAAE,OAAO,EAAE,oBAAoB,CAAC,CAAC;YAChD,MAAM,IAAI,iBAAiB,CACzB,GAAG,IAAI,mEAAmE,CAC3E,CAAC;QACJ,CAAC;QAED,IAAI,IAAI,KAAK,aAAa,EAAE,CAAC;YAC3B,IAAI,CAAC,IAAI,CAAC,MAAM,CAAC,gBAAgB,EAAE,CAAC;gBAClC,IAAI,CAAC,KAAK,CAAC,IAAI,EAAE,OAAO,EAAE,+BAA+B,CAAC,CAAC;gBAC3D,MAAM,IAAI,iBAAiB,CACzB,GAAG,IAAI,2EAA2E,CACnF,CAAC;YACJ,CAAC;YACD,IAAI,OAAO,KAAK,IAAI,EAAE,CAAC;gBACrB,IAAI,CAAC,KAAK,CAAC,IAAI,EAAE,OAAO,EAAE,qBAAqB,CAAC,CAAC;gBACjD,MAAM,IAAI,iBAAiB,CACzB,GAAG,IAAI,0DAA0D,IAAI,CAAC,WAAW,eAAe,OAAO,qBAAqB,IAAI,CAAC,WAAW,iCAAiC,CAC9K,CAAC;YACJ,CAAC;QACH,CAAC;QAED,IAAI,CAAC,KAAK,CAAC,IAAI,EAAE,OAAO,EAAE,SAAS,CAAC,CAAC;IACvC,CAAC;IAED,kFAAkF;IAC1E,KAAK,CAAC,IAAY,EAAE,OAAe,EAAE,OAAe;QAC1D,IAAI,CAAC,IAAI,CAAC,MAAM,CAAC,SAAS;YAAE,OAAO;QACnC,MAAM,IAAI,GAAG,IAAI,CAAC,SAAS,CAAC,EAAE,EAAE,EAAE,IAAI,IAAI,EAAE,CAAC,WAAW,EAAE,EAAE,IAAI,EAAE,OAAO,EAAE,OAAO,EAAE,CAAC,CAAC;QACtF,IAAI,CAAC;YACH,cAAc,CAAC,IAAI,CAAC,MAAM,CAAC,SAAS,EAAE,GAAG,IAAI,IAAI,EAAE,EAAE,IAAI,EAAE,KAAK,EAAE,CAAC,CAAC;QACtE,CAAC;QAAC,MAAM,CAAC;YACP,kEAAkE;QACpE,CAAC;IACH,CAAC;CACF;AAED;;;;;;GAMG;AACH,MAAM,UAAU,cAAc,CAC5B,IAAU,EACV,UAAoC,EAAE;IAEtC,OAAO;QACL,YAAY,EAAE,IAAI,KAAK,MAAM;QAC7B,eAAe,EAAE,IAAI,KAAK,aAAa;QACvC,cAAc,EAAE,OAAO,CAAC,UAAU,IAAI,IAAI,KAAK,MAAM;QACrD,aAAa,EAAE,IAAI;KACpB,CAAC;AACJ,CAAC"}
|
package/dist/server.js.map
DELETED
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"server.js","sourceRoot":"","sources":["../src/server.ts"],"names":[],"mappings":"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"}
|
package/dist/transport/http.d.ts
DELETED
|
@@ -1,28 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* HTTP transport, for running the server somewhere always on.
|
|
3
|
-
*
|
|
4
|
-
* Streamable HTTP, stateless: every request builds its own transport and tears
|
|
5
|
-
* it down. No session map means no session leak, which matters more here than
|
|
6
|
-
* the reconnect support a stateful server would buy.
|
|
7
|
-
*
|
|
8
|
-
* There is a second reason to run this way for Threads specifically. A token
|
|
9
|
-
* only stays alive if something refreshes it inside its 60-day window, and an
|
|
10
|
-
* MCP server launched over stdio only exists while a client has it open. A
|
|
11
|
-
* long-running HTTP instance refreshes on its own and never lets the window
|
|
12
|
-
* close.
|
|
13
|
-
*
|
|
14
|
-
* Bound to 127.0.0.1 by default. A Threads token can post as you, so a server
|
|
15
|
-
* that binds 0.0.0.0 without being asked is a mistake waiting to be made once;
|
|
16
|
-
* THREADS_HTTP_HOST is there for people who mean it.
|
|
17
|
-
*/
|
|
18
|
-
import type { BuiltServer } from "../server.js";
|
|
19
|
-
export type HttpOptions = {
|
|
20
|
-
port: number;
|
|
21
|
-
host: string;
|
|
22
|
-
/** When set, every request must send `Authorization: Bearer <token>`. */
|
|
23
|
-
token?: string;
|
|
24
|
-
};
|
|
25
|
-
export declare function httpOptionsFromEnv(argv?: string[]): HttpOptions;
|
|
26
|
-
export declare function startHttpServer(built: BuiltServer, options: HttpOptions): Promise<{
|
|
27
|
-
close: () => Promise<void>;
|
|
28
|
-
}>;
|
package/dist/transport/http.js
DELETED
|
@@ -1,107 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* HTTP transport, for running the server somewhere always on.
|
|
3
|
-
*
|
|
4
|
-
* Streamable HTTP, stateless: every request builds its own transport and tears
|
|
5
|
-
* it down. No session map means no session leak, which matters more here than
|
|
6
|
-
* the reconnect support a stateful server would buy.
|
|
7
|
-
*
|
|
8
|
-
* There is a second reason to run this way for Threads specifically. A token
|
|
9
|
-
* only stays alive if something refreshes it inside its 60-day window, and an
|
|
10
|
-
* MCP server launched over stdio only exists while a client has it open. A
|
|
11
|
-
* long-running HTTP instance refreshes on its own and never lets the window
|
|
12
|
-
* close.
|
|
13
|
-
*
|
|
14
|
-
* Bound to 127.0.0.1 by default. A Threads token can post as you, so a server
|
|
15
|
-
* that binds 0.0.0.0 without being asked is a mistake waiting to be made once;
|
|
16
|
-
* THREADS_HTTP_HOST is there for people who mean it.
|
|
17
|
-
*/
|
|
18
|
-
import { createServer } from "node:http";
|
|
19
|
-
import { StreamableHTTPServerTransport } from "@modelcontextprotocol/sdk/server/streamableHttp.js";
|
|
20
|
-
import { daysRemaining } from "../auth/tokens.js";
|
|
21
|
-
import { numericFlag } from "../config.js";
|
|
22
|
-
export function httpOptionsFromEnv(argv = []) {
|
|
23
|
-
// `--port` beats THREADS_HTTP_PORT, which beats the default. Both spellings
|
|
24
|
-
// of the flag are accepted; see numericFlag for why that is worth saying.
|
|
25
|
-
const fromEnv = Number(process.env.THREADS_HTTP_PORT);
|
|
26
|
-
const fallback = Number.isFinite(fromEnv) && fromEnv > 0 ? fromEnv : 8787;
|
|
27
|
-
const port = numericFlag(argv, "port", fallback);
|
|
28
|
-
return {
|
|
29
|
-
port,
|
|
30
|
-
host: process.env.THREADS_HTTP_HOST || "127.0.0.1",
|
|
31
|
-
token: process.env.THREADS_HTTP_TOKEN || undefined,
|
|
32
|
-
};
|
|
33
|
-
}
|
|
34
|
-
async function readBody(req) {
|
|
35
|
-
const chunks = [];
|
|
36
|
-
for await (const chunk of req)
|
|
37
|
-
chunks.push(chunk);
|
|
38
|
-
const raw = Buffer.concat(chunks).toString("utf8");
|
|
39
|
-
if (!raw)
|
|
40
|
-
return undefined;
|
|
41
|
-
try {
|
|
42
|
-
return JSON.parse(raw);
|
|
43
|
-
}
|
|
44
|
-
catch {
|
|
45
|
-
return undefined;
|
|
46
|
-
}
|
|
47
|
-
}
|
|
48
|
-
/** Constant-time-ish comparison, so the token cannot be guessed byte by byte. */
|
|
49
|
-
function tokenMatches(expected, provided) {
|
|
50
|
-
if (expected.length !== provided.length)
|
|
51
|
-
return false;
|
|
52
|
-
let diff = 0;
|
|
53
|
-
for (let i = 0; i < expected.length; i++)
|
|
54
|
-
diff |= expected.charCodeAt(i) ^ provided.charCodeAt(i);
|
|
55
|
-
return diff === 0;
|
|
56
|
-
}
|
|
57
|
-
async function handle(built, options, req, res) {
|
|
58
|
-
// Health needs no auth: it reports counts, never content.
|
|
59
|
-
if (req.method === "GET" && (req.url === "/health" || req.url === "/healthz")) {
|
|
60
|
-
res.writeHead(200, { "content-type": "application/json" });
|
|
61
|
-
res.end(JSON.stringify({
|
|
62
|
-
status: "ok",
|
|
63
|
-
tools: built.toolCount,
|
|
64
|
-
accounts: built.config.accounts.length,
|
|
65
|
-
read_only: built.config.readOnly,
|
|
66
|
-
tokens: built.config.accounts.map((a) => ({
|
|
67
|
-
username: a.username ?? null,
|
|
68
|
-
days_left: daysRemaining(a) ?? null,
|
|
69
|
-
})),
|
|
70
|
-
}));
|
|
71
|
-
return;
|
|
72
|
-
}
|
|
73
|
-
if (options.token) {
|
|
74
|
-
const header = req.headers.authorization ?? "";
|
|
75
|
-
const provided = header.startsWith("Bearer ") ? header.slice(7) : "";
|
|
76
|
-
if (!provided || !tokenMatches(options.token, provided)) {
|
|
77
|
-
res.writeHead(401, { "content-type": "application/json" });
|
|
78
|
-
res.end(JSON.stringify({ error: "unauthorized" }));
|
|
79
|
-
return;
|
|
80
|
-
}
|
|
81
|
-
}
|
|
82
|
-
const transport = new StreamableHTTPServerTransport({ sessionIdGenerator: undefined });
|
|
83
|
-
res.on("close", () => void transport.close());
|
|
84
|
-
await built.server.connect(transport);
|
|
85
|
-
await transport.handleRequest(req, res, await readBody(req));
|
|
86
|
-
}
|
|
87
|
-
export async function startHttpServer(built, options) {
|
|
88
|
-
const http = createServer((req, res) => {
|
|
89
|
-
void handle(built, options, req, res).catch((error) => {
|
|
90
|
-
if (!res.headersSent)
|
|
91
|
-
res.writeHead(500, { "content-type": "application/json" });
|
|
92
|
-
res.end(JSON.stringify({
|
|
93
|
-
jsonrpc: "2.0",
|
|
94
|
-
error: { code: -32603, message: error?.message ?? "internal error" },
|
|
95
|
-
id: null,
|
|
96
|
-
}));
|
|
97
|
-
});
|
|
98
|
-
});
|
|
99
|
-
await new Promise((resolve) => http.listen(options.port, options.host, resolve));
|
|
100
|
-
process.stderr.write(`[threads-mcp] HTTP on http://${options.host}:${options.port} (${built.toolCount} tools, ${built.config.accounts.length} account(s))${options.token ? "" : "\n[threads-mcp] No THREADS_HTTP_TOKEN set: this endpoint is unauthenticated."}\n`);
|
|
101
|
-
return {
|
|
102
|
-
close: () => new Promise((resolve) => {
|
|
103
|
-
http.close(() => resolve());
|
|
104
|
-
}),
|
|
105
|
-
};
|
|
106
|
-
}
|
|
107
|
-
//# sourceMappingURL=http.js.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"http.js","sourceRoot":"","sources":["../../src/transport/http.ts"],"names":[],"mappings":"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"}
|