@thenavidm/threads-mcp-cli 1.1.2 → 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/dist/index.js CHANGED
@@ -1,167 +1,14 @@
1
1
  #!/usr/bin/env node
2
2
  /**
3
- * Entry point.
3
+ * Both binaries. `threads-mcp` with no arguments serves MCP over stdio,
4
+ * `--http` serves it over HTTP, and any command runs one tool from the shell.
4
5
  *
5
- * `threads-mcp` stdio, which is what MCP clients launch
6
- * `threads-mcp login` run OAuth and store a 60-day token
7
- * `threads-mcp refresh` extend every stored token now
8
- * `threads-mcp doctor` check the setup and say what is wrong
9
- * `threads-mcp --http` HTTP, for running it somewhere always on
10
- *
11
- * `threads-cli` the same tools as shell commands
12
- */
13
- import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio.js";
14
- import { buildServer, VERSION } from "./server.js";
15
- import { loadConfig } from "./config.js";
16
- import { accountsFromStore } from "./auth/store.js";
17
- import { httpOptionsFromEnv, startHttpServer } from "./transport/http.js";
18
- import { daysRemaining } from "./auth/tokens.js";
19
- import { runCli, isCliCommand } from "./cli.js";
20
- const HELP = `threads-mcp ${VERSION}
21
-
22
- threads-mcp Run over stdio. This is what an MCP client launches.
23
- threads-mcp login Authorise a Threads profile and store a 60-day token.
24
- threads-mcp refresh Extend every stored token by another 60 days.
25
- threads-mcp doctor Check the setup and report what is wrong.
26
- threads-mcp --http [--port=N] Run over HTTP, for a machine that is always on.
27
- threads-mcp --version Print the version.
28
-
29
- threads-cli List every tool as a shell command.
30
- threads-cli <command> --help What one command takes.
31
- threads-cli schema <command> The JSON schema an MCP client sees.
32
-
33
- Credentials, in priority order:
34
- THREADS_ACCOUNTS JSON array, for several profiles at once:
35
- [{"access_token":"THQ...","username":"you"}]
36
- THREADS_ACCESS_TOKEN a long-lived token for one profile
37
- THREADS_USER_ID numeric profile id. Resolved from the token when absent
38
- THREADS_USERNAME username, for matching and display. Also resolved
39
- the token store written by \`login\`, and the only source this
40
- server can keep refreshed on its own
41
-
42
- For \`login\` only:
43
- THREADS_APP_ID Threads app id from developers.facebook.com
44
- THREADS_APP_SECRET Threads app secret
45
-
46
- Options:
47
- THREADS_DEFAULT_ACCOUNT which username acts when a tool names none
48
- THREADS_READ_ONLY=1 hide every write from the tool list
49
- THREADS_ALLOW_DESTRUCTIVE=0 keep writes, block posting and deleting
50
- THREADS_TOKEN_STORE where tokens are kept, default ~/.threads-mcp/tokens.json
51
- THREADS_PERSIST_TOKENS=0 stop writing refreshed tokens back to the store
52
- THREADS_REFRESH_WINDOW_DAYS refresh this many days before expiry, default 20
53
- THREADS_CONTAINER_TIMEOUT_MS how long to wait for media, default 120000
54
- THREADS_REQUEST_TIMEOUT_MS per-request deadline, default 30000
55
- THREADS_MIN_REQUEST_INTERVAL_MS spacing between requests, default 120
56
- THREADS_MAX_RETRIES retries on 5xx and quota codes, default 3
57
- THREADS_AUDIT_LOG append-only log of every attempted write
58
- THREADS_GRAPH_HOST override the Graph host, default graph.threads.net
59
- THREADS_USER_AGENT override the User-Agent sent to Meta
60
- THREADS_HTTP_PORT / _HOST / _TOKEN for --http
61
-
62
- https://github.com/thenavidm/threads-mcp-cli
63
- `;
64
- /**
65
- * One entry point, two programs. `threads-mcp` is the server and must stay
66
- * silent on stdout; `threads-cli` is the one a person types. Running the CLI
67
- * binary with no arguments is someone asking what they can type, so it lists
68
- * the commands rather than hanging on a transport that will never speak.
6
+ * Node's compile cache goes on before the app loads, so every launch after the
7
+ * first skips compiling it again. Node before 22.8 has no compile cache and
8
+ * starts as before; NODE_DISABLE_COMPILE_CACHE=1 turns it off.
69
9
  */
70
- function invokedAsCli() {
71
- const name = (process.argv[1] ?? "").split("/").pop() ?? "";
72
- return name.startsWith("threads-cli");
73
- }
74
- async function main() {
75
- const argv = process.argv.slice(2);
76
- const command = argv[0];
77
- if (invokedAsCli() && argv.length === 0) {
78
- process.exitCode = await runCli(["tools"]);
79
- return;
80
- }
81
- // Checked before --help and --version so `<tool> --help` reaches the tool.
82
- // A bare `--help` starts with a dash, so it falls through to the block below.
83
- if (isCliCommand(argv)) {
84
- process.exitCode = await runCli(argv);
85
- return;
86
- }
87
- // An unknown word used to fall through and start the server, which then sat
88
- // waiting on stdin: a typo looked like a hang, and scripts saw exit code 0.
89
- //
90
- // `doctor`, `login` and `refresh` belong to the entry point rather than the
91
- // tool list, and they are the first things someone types when nothing works.
92
- // Rejecting them as unknown commands sent them to the server binary to
93
- // diagnose the CLI.
94
- const ENTRY_COMMANDS = new Set(["doctor", "login", "refresh", "help"]);
95
- if (invokedAsCli() &&
96
- command !== undefined &&
97
- !command.startsWith("-") &&
98
- !ENTRY_COMMANDS.has(command)) {
99
- process.stderr.write(`${JSON.stringify({ error: `Unknown command '${command}'. Run \`threads-cli\` to list them.` }, null, 2)}\n`);
100
- process.exitCode = 1;
101
- return;
102
- }
103
- if (argv.includes("--help") || argv.includes("-h") || command === "help") {
104
- process.stdout.write(HELP);
105
- return;
106
- }
107
- if (argv.includes("--version") || argv.includes("-v")) {
108
- process.stdout.write(`${VERSION}\n`);
109
- return;
110
- }
111
- if (command === "login") {
112
- const { runLogin } = await import("./auth/login.js");
113
- process.exitCode = await runLogin(argv.slice(1));
114
- return;
115
- }
116
- if (command === "doctor") {
117
- const { runDoctor } = await import("./doctor.js");
118
- process.exitCode = await runDoctor();
119
- return;
120
- }
121
- if (command === "refresh") {
122
- const { runRefresh } = await import("./doctor.js");
123
- process.exitCode = await runRefresh();
124
- return;
125
- }
126
- // The store is read here rather than inside loadConfig so that the config
127
- // module stays free of filesystem access and remains trivially testable.
128
- const stored = accountsFromStore(loadConfig().storePath);
129
- const config = loadConfig(stored);
130
- const built = buildServer(config);
131
- // Warn, never block. A network check at startup would delay the handshake,
132
- // and the failure is more actionable on the tool call that hits it.
133
- if (config.accounts.length === 0) {
134
- process.stderr.write("[threads-mcp] No credentials configured. Every tool will report the missing setup. Run `threads-mcp login`.\n");
135
- }
136
- else {
137
- const soon = config.accounts.filter((a) => {
138
- const days = daysRemaining(a);
139
- return days !== undefined && days <= 7;
140
- });
141
- if (soon.length) {
142
- process.stderr.write(`[threads-mcp] ${soon.length} token(s) expire within a week and will be refreshed automatically on the next call. An expired Threads token cannot be recovered.\n`);
143
- }
144
- }
145
- const shutdown = async (close) => {
146
- if (close)
147
- await close().catch(() => undefined);
148
- process.exit(0);
149
- };
150
- if (argv.includes("--http")) {
151
- const { close } = await startHttpServer(built, httpOptionsFromEnv(argv));
152
- process.on("SIGTERM", () => void shutdown(close));
153
- process.on("SIGINT", () => void shutdown(close));
154
- return;
155
- }
156
- const transport = new StdioServerTransport();
157
- await built.server.connect(transport);
158
- // Handled so `docker stop` and a client shutting down return promptly rather
159
- // than waiting out a grace period.
160
- process.on("SIGTERM", () => void shutdown());
161
- process.on("SIGINT", () => void shutdown());
162
- }
163
- main().catch((error) => {
164
- process.stderr.write(`[threads-mcp] ${error.message}\n`);
165
- process.exit(1);
166
- });
10
+ import * as nodeModule from "node:module";
11
+ nodeModule.enableCompileCache?.();
12
+ const { app } = await import("./app.js");
13
+ await app.main();
167
14
  //# sourceMappingURL=index.js.map
package/dist/index.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":";AACA;;;;;;;GAOG;AAEH,OAAO,KAAK,UAAU,MAAM,aAAa,CAAC;AAE1C,UAAU,CAAC,kBAAkB,EAAE,EAAE,CAAC;AAClC,MAAM,EAAE,GAAG,EAAE,GAAG,MAAM,MAAM,CAAC,UAAU,CAAC,CAAC;AACzC,MAAM,GAAG,CAAC,IAAI,EAAE,CAAC"}
@@ -5,23 +5,10 @@
5
5
  * tools rather than footnotes: the 60-day token clock, and the daily publishing
6
6
  * quota. Both fail silently and both are cheap to check.
7
7
  */
8
- import { z } from "zod";
9
8
  import { clamp } from "./kit.js";
10
- export declare const listAccounts: import("./kit.js").ToolSpec<{
11
- fast: z.ZodOptional<z.ZodBoolean>;
12
- }>;
13
- export declare const whoami: import("./kit.js").ToolSpec<{
14
- account: z.ZodOptional<z.ZodString>;
15
- }>;
16
- export declare const getPublishingLimit: import("./kit.js").ToolSpec<{
17
- account: z.ZodOptional<z.ZodString>;
18
- }>;
19
- export declare const refreshToken: import("./kit.js").ToolSpec<{
20
- account: z.ZodOptional<z.ZodString>;
21
- }>;
22
- export declare const ACCOUNT_TOOLS: (import("./kit.js").ToolSpec<{
23
- fast: z.ZodOptional<z.ZodBoolean>;
24
- }> | import("./kit.js").ToolSpec<{
25
- account: z.ZodOptional<z.ZodString>;
26
- }>)[];
9
+ export declare const listAccounts: import("@thenavidm/slipway").Tool<import("./kit.js").ToolContext>;
10
+ export declare const whoami: import("@thenavidm/slipway").Tool<import("./kit.js").ToolContext>;
11
+ export declare const getPublishingLimit: import("@thenavidm/slipway").Tool<import("./kit.js").ToolContext>;
12
+ export declare const refreshToken: import("@thenavidm/slipway").Tool<import("./kit.js").ToolContext>;
13
+ export declare const ACCOUNT_TOOLS: import("@thenavidm/slipway").Tool<import("./kit.js").ToolContext>[];
27
14
  export { clamp };
@@ -8,49 +8,8 @@
8
8
  * indistinguishable from a niche query. So these tools say which mode they are
9
9
  * in rather than letting a model draw a conclusion from a filtered corpus.
10
10
  */
11
- import { z } from "zod";
12
- export declare const searchKeyword: import("./kit.js").ToolSpec<{
13
- account: z.ZodOptional<z.ZodString>;
14
- limit: z.ZodOptional<z.ZodNumber>;
15
- cursor: z.ZodOptional<z.ZodString>;
16
- q: z.ZodString;
17
- search_type: z.ZodOptional<z.ZodEnum<["TOP", "RECENT"]>>;
18
- media_type: z.ZodOptional<z.ZodEnum<["TEXT_POST", "IMAGE", "VIDEO", "CAROUSEL_ALBUM", "REPOST_FACADE"]>>;
19
- since: z.ZodOptional<z.ZodString>;
20
- until: z.ZodOptional<z.ZodString>;
21
- }>;
22
- export declare const searchTopicTag: import("./kit.js").ToolSpec<{
23
- account: z.ZodOptional<z.ZodString>;
24
- limit: z.ZodOptional<z.ZodNumber>;
25
- cursor: z.ZodOptional<z.ZodString>;
26
- tag: z.ZodString;
27
- search_type: z.ZodOptional<z.ZodEnum<["TOP", "RECENT"]>>;
28
- }>;
29
- export declare const lookupProfile: import("./kit.js").ToolSpec<{
30
- account: z.ZodOptional<z.ZodString>;
31
- username: z.ZodString;
32
- }>;
33
- export declare const listAllowlistedCountries: import("./kit.js").ToolSpec<{
34
- account: z.ZodOptional<z.ZodString>;
35
- }>;
36
- export declare const DISCOVER_TOOLS: (import("./kit.js").ToolSpec<{
37
- account: z.ZodOptional<z.ZodString>;
38
- limit: z.ZodOptional<z.ZodNumber>;
39
- cursor: z.ZodOptional<z.ZodString>;
40
- q: z.ZodString;
41
- search_type: z.ZodOptional<z.ZodEnum<["TOP", "RECENT"]>>;
42
- media_type: z.ZodOptional<z.ZodEnum<["TEXT_POST", "IMAGE", "VIDEO", "CAROUSEL_ALBUM", "REPOST_FACADE"]>>;
43
- since: z.ZodOptional<z.ZodString>;
44
- until: z.ZodOptional<z.ZodString>;
45
- }> | import("./kit.js").ToolSpec<{
46
- account: z.ZodOptional<z.ZodString>;
47
- limit: z.ZodOptional<z.ZodNumber>;
48
- cursor: z.ZodOptional<z.ZodString>;
49
- tag: z.ZodString;
50
- search_type: z.ZodOptional<z.ZodEnum<["TOP", "RECENT"]>>;
51
- }> | import("./kit.js").ToolSpec<{
52
- account: z.ZodOptional<z.ZodString>;
53
- username: z.ZodString;
54
- }> | import("./kit.js").ToolSpec<{
55
- account: z.ZodOptional<z.ZodString>;
56
- }>)[];
11
+ export declare const searchKeyword: import("@thenavidm/slipway").Tool<import("./kit.js").ToolContext>;
12
+ export declare const searchTopicTag: import("@thenavidm/slipway").Tool<import("./kit.js").ToolContext>;
13
+ export declare const lookupProfile: import("@thenavidm/slipway").Tool<import("./kit.js").ToolContext>;
14
+ export declare const listAllowlistedCountries: import("@thenavidm/slipway").Tool<import("./kit.js").ToolContext>;
15
+ export declare const DISCOVER_TOOLS: import("@thenavidm/slipway").Tool<import("./kit.js").ToolContext>[];
@@ -17,39 +17,8 @@
17
17
  * views tells you which ones worked. That means a fetch per post, so it is
18
18
  * bounded and says what it sampled.
19
19
  */
20
- import { z } from "zod";
21
- export declare const getPostInsights: import("./kit.js").ToolSpec<{
22
- account: z.ZodOptional<z.ZodString>;
23
- id: z.ZodString;
24
- }>;
25
- export declare const getAccountInsights: import("./kit.js").ToolSpec<{
26
- account: z.ZodOptional<z.ZodString>;
27
- since: z.ZodOptional<z.ZodString>;
28
- until: z.ZodOptional<z.ZodString>;
29
- metrics: z.ZodOptional<z.ZodArray<z.ZodEnum<["views", "likes", "replies", "reposts", "quotes", "clicks", "followers_count"]>, "many">>;
30
- }>;
31
- export declare const getFollowerDemographics: import("./kit.js").ToolSpec<{
32
- account: z.ZodOptional<z.ZodString>;
33
- breakdown: z.ZodEnum<["country", "city", "age", "gender"]>;
34
- }>;
35
- export declare const getTopPosts: import("./kit.js").ToolSpec<{
36
- account: z.ZodOptional<z.ZodString>;
37
- sample: z.ZodOptional<z.ZodNumber>;
38
- sort_by: z.ZodOptional<z.ZodEnum<["engagement_rate", "views", "likes", "replies", "reposts", "quotes"]>>;
39
- }>;
40
- export declare const INSIGHT_TOOLS: (import("./kit.js").ToolSpec<{
41
- account: z.ZodOptional<z.ZodString>;
42
- id: z.ZodString;
43
- }> | import("./kit.js").ToolSpec<{
44
- account: z.ZodOptional<z.ZodString>;
45
- since: z.ZodOptional<z.ZodString>;
46
- until: z.ZodOptional<z.ZodString>;
47
- metrics: z.ZodOptional<z.ZodArray<z.ZodEnum<["views", "likes", "replies", "reposts", "quotes", "clicks", "followers_count"]>, "many">>;
48
- }> | import("./kit.js").ToolSpec<{
49
- account: z.ZodOptional<z.ZodString>;
50
- breakdown: z.ZodEnum<["country", "city", "age", "gender"]>;
51
- }> | import("./kit.js").ToolSpec<{
52
- account: z.ZodOptional<z.ZodString>;
53
- sample: z.ZodOptional<z.ZodNumber>;
54
- sort_by: z.ZodOptional<z.ZodEnum<["engagement_rate", "views", "likes", "replies", "reposts", "quotes"]>>;
55
- }>)[];
20
+ export declare const getPostInsights: import("@thenavidm/slipway").Tool<import("./kit.js").ToolContext>;
21
+ export declare const getAccountInsights: import("@thenavidm/slipway").Tool<import("./kit.js").ToolContext>;
22
+ export declare const getFollowerDemographics: import("@thenavidm/slipway").Tool<import("./kit.js").ToolContext>;
23
+ export declare const getTopPosts: import("@thenavidm/slipway").Tool<import("./kit.js").ToolContext>;
24
+ export declare const INSIGHT_TOOLS: import("@thenavidm/slipway").Tool<import("./kit.js").ToolContext>[];
@@ -1,51 +1,29 @@
1
1
  /**
2
- * Shared plumbing every tool uses.
2
+ * Shared plumbing every tool uses, now on Slipway.
3
3
  *
4
- * Registering thirty tools by hand is thirty chances to forget an annotation,
5
- * leak a stack trace, or return a shape the model cannot read. This wraps all
6
- * of it once so a tool module only describes what it actually does.
4
+ * Tool modules keep describing themselves with a Zod shape, a risk and a
5
+ * handler. This adapter turns each into a Slipway tool, so the MCP server, the
6
+ * CLI, the write guard, annotations and errors all come from the framework
7
+ * instead of a copy kept in this repo.
7
8
  */
8
- import type { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
9
- import { z, type ZodRawShape } from "zod";
9
+ import { z, type Risk, type SlipwayError, type Tool } from "@thenavidm/slipway";
10
10
  import type { ThreadsClient } from "../api/client.js";
11
+ import { ThreadsError } from "../api/errors.js";
11
12
  import type { Account, Config } from "../config.js";
12
- import { type Risk, type WriteGuard } from "../safety.js";
13
13
  export type ToolContext = {
14
14
  client: ThreadsClient;
15
15
  config: Config;
16
- guard: WriteGuard;
17
16
  /** Resolve which profile this call acts as. */
18
17
  account: (hint?: string) => Account;
19
18
  };
20
- export type ToolResult = {
21
- content: {
22
- type: "text";
23
- text: string;
24
- }[];
25
- isError?: boolean;
26
- };
27
- /**
28
- * A tool returns either a pre-rendered string or a value to serialise.
29
- *
30
- * The reading tools return the tagged format from `format/posts.ts`, which is
31
- * already text. The writing tools return a small object, an id and a permalink,
32
- * where JSON is clearer than tags. Both go through here so neither has to think
33
- * about the MCP content envelope.
34
- */
35
- export declare function ok(data: unknown): ToolResult;
36
- /**
37
- * Errors come back as a normal result with `isError`, not a thrown exception.
38
- *
39
- * A thrown MCP error reaches the model as a protocol failure with no structure.
40
- * A result it can read tells it what went wrong and usually how to fix it,
41
- * which is the difference between a correct retry and a give-up.
42
- */
43
- export declare function fail(error: unknown): ToolResult;
44
19
  /** The optional argument that picks a profile, on every account-scoped tool. */
45
20
  export declare const accountArg: {
46
21
  account: z.ZodOptional<z.ZodString>;
47
22
  };
48
- /** The confirmation argument required by every public or irreversible tool. */
23
+ /**
24
+ * Kept so tool modules read the same, but never sent: Slipway adds `confirm`
25
+ * to every irreversible tool itself, with one description everywhere.
26
+ */
49
27
  export declare const confirmArg: {
50
28
  confirm: z.ZodOptional<z.ZodBoolean>;
51
29
  };
@@ -54,7 +32,8 @@ export declare const pageArgs: {
54
32
  limit: z.ZodOptional<z.ZodNumber>;
55
33
  cursor: z.ZodOptional<z.ZodString>;
56
34
  };
57
- export type ToolSpec<S extends ZodRawShape> = {
35
+ type Shape = Record<string, z.ZodType>;
36
+ export type ToolSpec<S extends Shape> = {
58
37
  name: string;
59
38
  /** One line, imperative. Shown in tool pickers. */
60
39
  title: string;
@@ -67,24 +46,19 @@ export type ToolSpec<S extends ZodRawShape> = {
67
46
  /** One line for the audit log and the confirm message, when this is a write. */
68
47
  summary?: (args: z.infer<z.ZodObject<S>>) => string;
69
48
  };
70
- export declare function defineTool<S extends ZodRawShape>(spec: ToolSpec<S>): ToolSpec<S>;
49
+ export type AnyToolSpec = Tool<ToolContext>;
71
50
  /**
72
- * A tool of any shape, for the one place tools are held together in a list.
73
- *
74
- * `ToolSpec` is generic over its schema, so a list of tools with different
75
- * schemas has no single type: each handler takes a different argument shape and
76
- * function parameters are contravariant. The type safety that matters lives
77
- * inside each `defineTool` call, where schema and handler are checked against
78
- * each other. This only loosens the seam where they are collected.
51
+ * Meta answers almost every failure with HTTP 400, an expired token and a
52
+ * spent quota included, and puts what happened in `code` and `error_subcode`.
53
+ * `api/errors.ts` already sorts them into classes, so the exit code and error
54
+ * code follow the class, not the status, and Meta's own fields ride along in
55
+ * `details` for the model to read.
79
56
  */
80
- export type AnyToolSpec = Omit<ToolSpec<ZodRawShape>, "handler" | "summary"> & {
81
- handler: (args: never, ctx: ToolContext) => Promise<unknown>;
82
- summary?: (args: never) => string;
83
- };
84
- /** Register one tool against the server, with guarding and error handling applied. */
85
- export declare function register(server: McpServer, contextFor: (extra: unknown) => ToolContext, spec: AnyToolSpec): void;
86
- export declare function makeContext(client: ThreadsClient, config: Config, guard: WriteGuard): ToolContext;
57
+ export declare function toSlipway(error: ThreadsError): SlipwayError;
58
+ export declare function defineTool<S extends Shape>(spec: ToolSpec<S>): Tool<ToolContext>;
59
+ export declare function makeContext(client: ThreadsClient, config: Config): ToolContext;
87
60
  /** Clamp a caller-supplied limit into a range Threads will accept. */
88
61
  export declare function clamp(value: number | undefined, fallback: number, max?: number): number;
89
62
  /** Trim a summary to one readable line for the audit log. */
90
63
  export declare function snippet(text: string | undefined, length?: number): string;
64
+ export {};
package/dist/tools/kit.js CHANGED
@@ -1,39 +1,15 @@
1
1
  /**
2
- * Shared plumbing every tool uses.
2
+ * Shared plumbing every tool uses, now on Slipway.
3
3
  *
4
- * Registering thirty tools by hand is thirty chances to forget an annotation,
5
- * leak a stack trace, or return a shape the model cannot read. This wraps all
6
- * of it once so a tool module only describes what it actually does.
4
+ * Tool modules keep describing themselves with a Zod shape, a risk and a
5
+ * handler. This adapter turns each into a Slipway tool, so the MCP server, the
6
+ * CLI, the write guard, annotations and errors all come from the framework
7
+ * instead of a copy kept in this repo.
7
8
  */
8
- import { z } from "zod";
9
- import { ThreadsError } from "../api/errors.js";
9
+ import { ApiError, AuthError, NotFoundError as SlipwayNotFound, RateLimitError as SlipwayRateLimit, RefusedError, TimeoutError as SlipwayTimeout, toolkit, UsageError, z, } from "@thenavidm/slipway";
10
+ import { AuthenticationError, NotFoundError, PermissionError, RateLimitError, TextTooLongError, ThreadsError, TimeoutError, ValidationError, WriteBlockedError, } from "../api/errors.js";
10
11
  import { selectAccount } from "../config.js";
11
- import { annotationsFor } from "../safety.js";
12
- /**
13
- * A tool returns either a pre-rendered string or a value to serialise.
14
- *
15
- * The reading tools return the tagged format from `format/posts.ts`, which is
16
- * already text. The writing tools return a small object, an id and a permalink,
17
- * where JSON is clearer than tags. Both go through here so neither has to think
18
- * about the MCP content envelope.
19
- */
20
- export function ok(data) {
21
- const text = typeof data === "string" ? data : JSON.stringify(data, null, 2);
22
- return { content: [{ type: "text", text }] };
23
- }
24
- /**
25
- * Errors come back as a normal result with `isError`, not a thrown exception.
26
- *
27
- * A thrown MCP error reaches the model as a protocol failure with no structure.
28
- * A result it can read tells it what went wrong and usually how to fix it,
29
- * which is the difference between a correct retry and a give-up.
30
- */
31
- export function fail(error) {
32
- const payload = error instanceof ThreadsError
33
- ? error.toJSON()
34
- : { error: error?.message ?? String(error) };
35
- return { content: [{ type: "text", text: JSON.stringify(payload, null, 2) }], isError: true };
36
- }
12
+ const kit = toolkit();
37
13
  /** The optional argument that picks a profile, on every account-scoped tool. */
38
14
  export const accountArg = {
39
15
  account: z
@@ -41,67 +17,76 @@ export const accountArg = {
41
17
  .optional()
42
18
  .describe("Which connected Threads profile to act as, by username (for example 'thenavidm'). Defaults to the first connected profile. Call list_accounts to see them."),
43
19
  };
44
- /** The confirmation argument required by every public or irreversible tool. */
20
+ /**
21
+ * Kept so tool modules read the same, but never sent: Slipway adds `confirm`
22
+ * to every irreversible tool itself, with one description everywhere.
23
+ */
45
24
  export const confirmArg = {
46
- confirm: z
47
- .boolean()
48
- .optional()
49
- .describe("Must be true for this to run. The result is public immediately or cannot be undone, so it is refused without an explicit confirmation. Threads has no edit endpoint and no unsend."),
25
+ confirm: z.boolean().optional(),
50
26
  };
51
27
  /** Cursor and limit, on every paginating tool. */
52
28
  export const pageArgs = {
53
- limit: z
54
- .number()
55
- .int()
56
- .min(1)
57
- .max(100)
58
- .optional()
59
- .describe("How many to return, 1-100."),
29
+ limit: z.number().int().min(1).max(100).optional().describe("How many to return, 1-100."),
60
30
  cursor: z
61
31
  .string()
62
32
  .optional()
63
33
  .describe("Continue from a previous page. Pass the `cursor` attribute from the last result."),
64
34
  };
65
- export function defineTool(spec) {
66
- return spec;
35
+ /**
36
+ * Meta answers almost every failure with HTTP 400, an expired token and a
37
+ * spent quota included, and puts what happened in `code` and `error_subcode`.
38
+ * `api/errors.ts` already sorts them into classes, so the exit code and error
39
+ * code follow the class, not the status, and Meta's own fields ride along in
40
+ * `details` for the model to read.
41
+ */
42
+ export function toSlipway(error) {
43
+ const details = Object.fromEntries(Object.entries({
44
+ endpoint: error.endpoint,
45
+ meta_code: error.code || undefined,
46
+ meta_subcode: error.subcode || undefined,
47
+ meta_type: error.type || undefined,
48
+ detail: error.detail || undefined,
49
+ trace_id: error.traceId || undefined,
50
+ }).filter(([, value]) => value !== undefined));
51
+ const options = { ...(error.status ? { status: error.status } : {}), details, cause: error };
52
+ if (error instanceof AuthenticationError || error instanceof PermissionError)
53
+ return new AuthError(error.message, options);
54
+ if (error instanceof NotFoundError)
55
+ return new SlipwayNotFound(error.message, options);
56
+ if (error instanceof RateLimitError)
57
+ return new SlipwayRateLimit(error.message, options);
58
+ if (error instanceof ValidationError || error instanceof TextTooLongError)
59
+ return new UsageError(error.message, options);
60
+ if (error instanceof WriteBlockedError)
61
+ return new RefusedError(error.message, options);
62
+ if (error instanceof TimeoutError)
63
+ return new SlipwayTimeout(error.message, options);
64
+ // A server error, a container that never finished processing, or no answer at all: the service's failure, worth a retry.
65
+ return new ApiError(error.message, options);
67
66
  }
68
- /** Register one tool against the server, with guarding and error handling applied. */
69
- export function register(server, contextFor, spec) {
70
- server.registerTool(spec.name, {
67
+ export function defineTool(spec) {
68
+ const { confirm: _confirm, ...shape } = spec.schema;
69
+ const handler = spec.handler;
70
+ return kit.defineTool({
71
+ name: spec.name,
71
72
  title: spec.title,
72
73
  description: spec.description,
73
- inputSchema: spec.schema,
74
- annotations: {
75
- title: spec.title,
76
- ...annotationsFor(spec.risk, { idempotent: spec.idempotent }),
77
- },
78
- },
79
- // The SDK derives its callback type from the schema generic. This wrapper is
80
- // generic over the same shape, but TypeScript cannot prove the two are equal
81
- // through the indirection, so the cast lives at this single boundary rather
82
- // than in every tool definition.
83
- (async (args, extra) => {
84
- try {
85
- const ctx = contextFor(extra);
86
- if (spec.risk !== "read") {
87
- const summary = spec.summary?.(args) ?? spec.name;
88
- const confirm = args.confirm;
89
- ctx.guard.check(spec.name, spec.risk, confirm, summary);
74
+ input: z.object(shape),
75
+ risk: spec.risk,
76
+ ...(spec.idempotent !== undefined ? { idempotent: spec.idempotent } : {}),
77
+ ...(spec.summary ? { summary: spec.summary } : {}),
78
+ handler: async (args, ctx) => {
79
+ try {
80
+ return await handler(args, ctx);
90
81
  }
91
- return ok(await spec.handler(args, ctx));
92
- }
93
- catch (error) {
94
- return fail(error);
95
- }
96
- }));
82
+ catch (error) {
83
+ throw error instanceof ThreadsError ? toSlipway(error) : error;
84
+ }
85
+ },
86
+ });
97
87
  }
98
- export function makeContext(client, config, guard) {
99
- return {
100
- client,
101
- config,
102
- guard,
103
- account: (hint) => selectAccount(config, hint),
104
- };
88
+ export function makeContext(client, config) {
89
+ return { client, config, account: (hint) => selectAccount(config, hint) };
105
90
  }
106
91
  /** Clamp a caller-supplied limit into a range Threads will accept. */
107
92
  export function clamp(value, fallback, max = 100) {
@@ -1 +1 @@
1
- {"version":3,"file":"kit.js","sourceRoot":"","sources":["../../src/tools/kit.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"kit.js","sourceRoot":"","sources":["../../src/tools/kit.ts"],"names":[],"mappings":"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"}