@exileum/meta-mcp 7.0.0 → 8.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 +31 -7
- package/dist/constants/fields.d.ts +6 -0
- package/dist/constants/fields.d.ts.map +1 -0
- package/dist/constants/fields.js +25 -0
- package/dist/constants/fields.js.map +1 -0
- package/dist/http-transport.d.ts +20 -0
- package/dist/http-transport.d.ts.map +1 -0
- package/dist/http-transport.js +228 -0
- package/dist/http-transport.js.map +1 -0
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +76 -26
- package/dist/index.js.map +1 -1
- package/dist/prompts/index.d.ts +56 -0
- package/dist/prompts/index.d.ts.map +1 -1
- package/dist/prompts/index.js +264 -41
- package/dist/prompts/index.js.map +1 -1
- package/dist/resources/instagram.d.ts.map +1 -1
- package/dist/resources/instagram.js +13 -4
- package/dist/resources/instagram.js.map +1 -1
- package/dist/resources/threads.d.ts.map +1 -1
- package/dist/resources/threads.js +13 -4
- package/dist/resources/threads.js.map +1 -1
- package/dist/services/meta-client.d.ts +22 -3
- package/dist/services/meta-client.d.ts.map +1 -1
- package/dist/services/meta-client.js +132 -6
- package/dist/services/meta-client.js.map +1 -1
- package/dist/shutdown.d.ts +18 -0
- package/dist/shutdown.d.ts.map +1 -0
- package/dist/shutdown.js +60 -0
- package/dist/shutdown.js.map +1 -0
- package/dist/tools/instagram/comments.d.ts.map +1 -1
- package/dist/tools/instagram/comments.js +14 -19
- package/dist/tools/instagram/comments.js.map +1 -1
- package/dist/tools/instagram/hashtags.d.ts +1 -0
- package/dist/tools/instagram/hashtags.d.ts.map +1 -1
- package/dist/tools/instagram/hashtags.js +19 -19
- package/dist/tools/instagram/hashtags.js.map +1 -1
- package/dist/tools/instagram/media.d.ts.map +1 -1
- package/dist/tools/instagram/media.js +8 -11
- package/dist/tools/instagram/media.js.map +1 -1
- package/dist/tools/instagram/mentions.d.ts.map +1 -1
- package/dist/tools/instagram/mentions.js +2 -7
- package/dist/tools/instagram/mentions.js.map +1 -1
- package/dist/tools/instagram/messaging.d.ts.map +1 -1
- package/dist/tools/instagram/messaging.js +10 -20
- package/dist/tools/instagram/messaging.js.map +1 -1
- package/dist/tools/instagram/profile.d.ts +2 -0
- package/dist/tools/instagram/profile.d.ts.map +1 -1
- package/dist/tools/instagram/profile.js +13 -15
- package/dist/tools/instagram/profile.js.map +1 -1
- package/dist/tools/instagram/publishing.d.ts.map +1 -1
- package/dist/tools/instagram/publishing.js +133 -96
- package/dist/tools/instagram/publishing.js.map +1 -1
- package/dist/tools/meta/auth.d.ts.map +1 -1
- package/dist/tools/meta/auth.js +18 -2
- package/dist/tools/meta/auth.js.map +1 -1
- package/dist/tools/threads/insights.d.ts.map +1 -1
- package/dist/tools/threads/insights.js +2 -5
- package/dist/tools/threads/insights.js.map +1 -1
- package/dist/tools/threads/media.d.ts.map +1 -1
- package/dist/tools/threads/media.js +5 -47
- package/dist/tools/threads/media.js.map +1 -1
- package/dist/tools/threads/mentions.d.ts.map +1 -1
- package/dist/tools/threads/mentions.js +3 -10
- package/dist/tools/threads/mentions.js.map +1 -1
- package/dist/tools/threads/profile.d.ts +2 -0
- package/dist/tools/threads/profile.d.ts.map +1 -1
- package/dist/tools/threads/profile.js +10 -1
- package/dist/tools/threads/profile.js.map +1 -1
- package/dist/tools/threads/publishing.d.ts.map +1 -1
- package/dist/tools/threads/publishing.js +122 -103
- package/dist/tools/threads/publishing.js.map +1 -1
- package/dist/tools/threads/replies.d.ts.map +1 -1
- package/dist/tools/threads/replies.js +15 -23
- package/dist/tools/threads/replies.js.map +1 -1
- package/dist/utils/container.d.ts +16 -4
- package/dist/utils/container.d.ts.map +1 -1
- package/dist/utils/container.js +36 -6
- package/dist/utils/container.js.map +1 -1
- package/dist/utils/errors.d.ts +23 -3
- package/dist/utils/errors.d.ts.map +1 -1
- package/dist/utils/errors.js +32 -2
- package/dist/utils/errors.js.map +1 -1
- package/dist/utils/logger.d.ts +28 -0
- package/dist/utils/logger.d.ts.map +1 -0
- package/dist/utils/logger.js +32 -0
- package/dist/utils/logger.js.map +1 -0
- package/dist/utils/params.d.ts +3 -0
- package/dist/utils/params.d.ts.map +1 -0
- package/dist/utils/params.js +14 -0
- package/dist/utils/params.js.map +1 -0
- package/dist/utils/progress.d.ts +42 -0
- package/dist/utils/progress.d.ts.map +1 -0
- package/dist/utils/progress.js +35 -0
- package/dist/utils/progress.js.map +1 -0
- package/package.json +3 -2
package/README.md
CHANGED
|
@@ -71,9 +71,25 @@ npm run build
|
|
|
71
71
|
| `META_APP_SECRET` | For token/webhook tools | Meta App Secret |
|
|
72
72
|
| `META_API_VERSION` | Optional | Meta Graph API version for Instagram and Facebook endpoints — defaults to `v25.0` (verified 2026-05-06). Override only when Meta deprecates a version before meta-mcp ships a new release. Format: `vMAJOR.MINOR` (e.g., `v26.0`); malformed values fall back to the default with a stderr warning. OAuth token endpoints are unversioned and unaffected by this setting |
|
|
73
73
|
| `THREADS_API_VERSION` | Optional | Threads API version — defaults to `v1.0` (verified 2026-05-06). Threads runs a separate single-major-version track and is not bumped in lockstep with the Graph API. Same `vMAJOR.MINOR` format and fallback behavior as `META_API_VERSION` |
|
|
74
|
+
| `MCP_TRANSPORT` | Optional | Transport to serve MCP over — `stdio` (default) or `http`. See [HTTP Transport](#http-transport) |
|
|
75
|
+
| `MCP_HTTP_PORT` | Optional (http) | TCP port for the HTTP transport — defaults to `3000`. Must be an integer 1–65535 |
|
|
76
|
+
| `MCP_HTTP_HOST` | Optional (http) | Bind address for the HTTP transport — defaults to `127.0.0.1` (loopback only). Set to `0.0.0.0` to accept connections from other hosts (e.g. in Docker), but only behind a TLS/auth reverse proxy |
|
|
77
|
+
| `MCP_HTTP_ALLOWED_HOSTS` | Optional (http) | Comma-separated `host:port` allowlist for DNS-rebinding protection. Defaults to loopback variants at the bound port; set this when binding to a non-loopback host so legitimate requests pass the Host check |
|
|
74
78
|
|
|
75
79
|
The server validates these at startup. Malformed values for `INSTAGRAM_USER_ID`, `THREADS_USER_ID`, or `META_APP_ID` cause the process to exit with `Invalid meta-mcp configuration: …`. Setting only one half of a credential pair (e.g., `INSTAGRAM_ACCESS_TOKEN` without `INSTAGRAM_USER_ID`) prints a stderr warning and continues; related tool invocations still fail at call time.
|
|
76
80
|
|
|
81
|
+
## HTTP Transport
|
|
82
|
+
|
|
83
|
+
By default the server speaks MCP over **stdio** — the right choice for local clients (Claude Desktop, Claude Code, etc.). Set `MCP_TRANSPORT=http` to instead serve the SDK's **Streamable HTTP** transport, which enables remote/web-based MCP clients, cloud deployments, and multiple concurrent client sessions.
|
|
84
|
+
|
|
85
|
+
```bash
|
|
86
|
+
MCP_TRANSPORT=http MCP_HTTP_PORT=3000 npx @exileum/meta-mcp
|
|
87
|
+
```
|
|
88
|
+
|
|
89
|
+
The server then listens on `http://127.0.0.1:3000/mcp`: `POST` to send messages, `GET` for the server→client SSE stream, `DELETE` to end a session. Each client gets an isolated session keyed by the `Mcp-Session-Id` header, so multiple clients can connect at once.
|
|
90
|
+
|
|
91
|
+
**Security.** The transport binds to `127.0.0.1` (loopback) by default and enables DNS-rebinding protection scoped to localhost, so it is not reachable off-host out of the box. To expose it to other machines (e.g. a container), set `MCP_HTTP_HOST=0.0.0.0` and run it **behind a reverse proxy that terminates TLS and handles authentication** — the server itself performs no auth. When bound to a non-loopback address, set `MCP_HTTP_ALLOWED_HOSTS` to the `host:port` values clients will use so the Host-header check passes (otherwise rebinding protection is disabled with a stderr warning).
|
|
92
|
+
|
|
77
93
|
## Account Requirements
|
|
78
94
|
|
|
79
95
|
| Platform | Account Type | Notes |
|
|
@@ -93,6 +109,10 @@ The server validates these at startup. Malformed values for `INSTAGRAM_USER_ID`,
|
|
|
93
109
|
- Rate limit tracking via `x-app-usage` header — and **automatic client-side throttling** at 80% (1s slowdown) / 90% (5s backoff) so a burst of tool calls stays under Meta's per-app quota
|
|
94
110
|
- **Automatic retry** for transient Meta API failures (HTTP `429`/`500`/`502`/`503`/`504`, network errors, `fetch` timeouts) with exponential backoff and `Retry-After` honoring; tunable via `MetaClient`'s `maxRetries` option (default 3, set to 0 to disable)
|
|
95
111
|
- **Structured error responses** with `error_type` (`auth`, `validation`, `rate_limit`, `server`, `network`, `internal`), HTTP status, Meta API code/subcode/type, and a `remediation` hint where actionable — see [`CHANGELOG.md`](./CHANGELOG.md) for the JSON shape
|
|
112
|
+
- **MCP server `instructions`** sent during `initialize` so clients know required env vars, the two-step publish flow, expected video processing times, and the `_rateLimit` envelope without re-reading the README
|
|
113
|
+
- **MCP `notifications/progress`** emitted while polling container status during publishing — attach a `progressToken` to `ig_publish_*` / `threads_publish_image|video|carousel` calls and the server reports each poll attempt
|
|
114
|
+
- **Structured MCP logging** via the `notifications/message` channel (the server declares the `logging` capability) — each API call logs `debug` (method + path, never the token-bearing URL), terminal failures log `error` (status/code/sanitized message), rate-limit pressure logs `warning`, and `DELETE`/publish operations log an `info` audit line. Clients can raise the floor with `logging/setLevel` (default emits all levels, including `debug`)
|
|
115
|
+
- **Optional HTTP transport** — set `MCP_TRANSPORT=http` to serve the MCP Streamable HTTP transport (stateful multi-session, localhost-bound by default) instead of stdio, for remote/cloud deployments — see [HTTP Transport](#http-transport)
|
|
96
116
|
|
|
97
117
|
## Tools
|
|
98
118
|
|
|
@@ -230,14 +250,14 @@ The server validates these at startup. Malformed values for `INSTAGRAM_USER_ID`,
|
|
|
230
250
|
| Resource URI | Description |
|
|
231
251
|
|-------------|-------------|
|
|
232
252
|
| `meta-mcp://instagram/profile` | Instagram account profile data |
|
|
233
|
-
| `meta-mcp://threads/profile` | Threads account profile data (includes is_verified) |
|
|
253
|
+
| `meta-mcp://threads/profile` | Threads account profile data (includes is_verified and is_eligible_for_geo_gating) |
|
|
234
254
|
|
|
235
255
|
## Prompts
|
|
236
256
|
|
|
237
|
-
| Prompt | Description |
|
|
238
|
-
|
|
239
|
-
| `content_publish` | Cross-post content to Instagram and Threads |
|
|
240
|
-
| `analytics_report` | Generate combined analytics report |
|
|
257
|
+
| Prompt | Description | Arguments (all optional) |
|
|
258
|
+
|--------|-------------|--------------------------|
|
|
259
|
+
| `content_publish` | Cross-post content to Instagram and Threads | `platform` (`instagram` \| `threads` \| `both`), `content_type` (`text` \| `image` \| `video` \| `carousel`), `media_url`, `caption` |
|
|
260
|
+
| `analytics_report` | Generate combined analytics report | `platform` (`instagram` \| `threads` \| `both`), `time_range` (`7d` \| `30d` \| `90d`), `focus` (`engagement` \| `growth` \| `content`) |
|
|
241
261
|
|
|
242
262
|
## Setup Guide
|
|
243
263
|
|
|
@@ -333,11 +353,15 @@ Access tokens expire after ~60 days. Refresh before expiration (token must be at
|
|
|
333
353
|
&access_token=CURRENT_LONG_LIVED_TOKEN
|
|
334
354
|
```
|
|
335
355
|
|
|
356
|
+
When you rotate a token through `meta_refresh_token` or `meta_exchange_token`, the new token is **automatically applied in-memory** to the running MCP server — subsequent tool calls use it immediately, no server restart needed. The new token is still returned in the response so you can persist it in your environment for the next process restart. A single `[meta-mcp] <Platform> access token updated in-memory after <tool>…` line is logged to stderr when this happens.
|
|
357
|
+
|
|
336
358
|
Check token status anytime with `meta_debug_token`.
|
|
337
359
|
|
|
338
360
|
## Troubleshooting
|
|
339
361
|
|
|
340
|
-
Tool failures return `isError: true` with a JSON body in `content[0].text` matching the envelope documented in [`CHANGELOG.md`](./CHANGELOG.md): `{ error: true, error_type, http_status, code, subcode, type, message, remediation, fbtrace_id, raw }`. The fastest path to a fix is to read `error_type` and the Meta API `code`, then jump to the matching subsection below. The full code reference is the [Meta Graph API error handling guide](https://developers.facebook.com/docs/graph-api/guides/error-handling/).
|
|
362
|
+
Tool failures return `isError: true` with a JSON body in `content[0].text` matching the envelope documented in [`CHANGELOG.md`](./CHANGELOG.md): `{ error: true, error_type, http_status, code, subcode, type, step, container_id, message, remediation, fbtrace_id, raw }`. The fastest path to a fix is to read `error_type` and the Meta API `code`, then jump to the matching subsection below. The full code reference is the [Meta Graph API error handling guide](https://developers.facebook.com/docs/graph-api/guides/error-handling/).
|
|
363
|
+
|
|
364
|
+
On the publish tools (`ig_publish_*`, `threads_publish_*`, `threads_reply`), errors also include `step` (`container creation` / `processing` / `publishing`, plus `child container creation` / `child processing` / `parent container creation` / `parent processing` on carousels) and `container_id` when one was created. The `message` mirrors them: `"Publish photo failed at processing (container: 17889615324): Container processing timed out after 30s"`. Use these to decide whether to retry the publish, clean up an orphaned container, or treat the existing container as still reusable.
|
|
341
365
|
|
|
342
366
|
### `error_type: "auth"` — expired, revoked, or under-scoped token
|
|
343
367
|
|
|
@@ -362,7 +386,7 @@ Triggered by Meta API codes `4`, `17`, `32`, `341`, `613`, the business-use-case
|
|
|
362
386
|
What to do:
|
|
363
387
|
|
|
364
388
|
1. Inspect the `_rateLimit` field on prior successful tool responses. `callCount`, `totalCpuTime`, and `totalTime` come from Meta's `x-app-usage` header; when any approaches `100` you are near the per-app threshold.
|
|
365
|
-
2. meta-mcp already self-throttles once `max(callCount, totalCpuTime, totalTime)` crosses 80% (1s slowdown) or 90% (5s backoff) —
|
|
389
|
+
2. meta-mcp already self-throttles once `max(callCount, totalCpuTime, totalTime)` crosses 80% (1s slowdown) or 90% (5s backoff) — watch for the `warning`-level MCP log message (`logger: "meta-client"`, with `usage_pct` and `delay_ms`) the server emits before each throttled call. Profile reads (`ig_get_profile`, `threads_get_profile`, and the matching `meta-mcp://*/profile` resources) and hashtag-name lookups (`ig_search_hashtag`) are also cached in-process for 5 minutes / 7 days respectively, with cache hits skipping the network entirely. If you are still hitting `rate_limit` errors despite all that, reduce request volume further.
|
|
366
390
|
3. Threads has hard daily quotas (250 publishes, 100 deletes) — query the remaining quota with `threads_get_publishing_limit` before bulk operations.
|
|
367
391
|
|
|
368
392
|
### `error_type: "validation"` — bad parameter, wrong ID, or unsupported field
|
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
export declare const IG_PROFILE_FIELDS = "id,name,username,biography,followers_count,follows_count,media_count,profile_picture_url,website";
|
|
2
|
+
export declare const IG_MEDIA_FIELDS = "id,caption,media_type,media_url,permalink,thumbnail_url,timestamp,like_count,comments_count";
|
|
3
|
+
export declare const IG_HASHTAG_MEDIA_FIELDS = "id,caption,media_type,media_url,permalink,timestamp,like_count,comments_count";
|
|
4
|
+
export declare const THREADS_PROFILE_FIELDS = "id,username,name,threads_profile_picture_url,threads_biography,is_verified,is_eligible_for_geo_gating";
|
|
5
|
+
export declare const THREADS_MEDIA_FIELDS: string;
|
|
6
|
+
//# sourceMappingURL=fields.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"fields.d.ts","sourceRoot":"","sources":["../../src/constants/fields.ts"],"names":[],"mappings":"AAAA,eAAO,MAAM,iBAAiB,qGACsE,CAAC;AAErG,eAAO,MAAM,eAAe,gGACmE,CAAC;AAIhG,eAAO,MAAM,uBAAuB,kFAC6C,CAAC;AAElF,eAAO,MAAM,sBAAsB,0GACsE,CAAC;AAE1G,eAAO,MAAM,oBAAoB,QAiBtB,CAAC"}
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
export const IG_PROFILE_FIELDS = "id,name,username,biography,followers_count,follows_count,media_count,profile_picture_url,website";
|
|
2
|
+
export const IG_MEDIA_FIELDS = "id,caption,media_type,media_url,permalink,thumbnail_url,timestamp,like_count,comments_count";
|
|
3
|
+
// thumbnail_url is intentionally omitted — the Instagram Hashtag Search API
|
|
4
|
+
// does not return it on hashtag media results, only on user-owned media.
|
|
5
|
+
export const IG_HASHTAG_MEDIA_FIELDS = "id,caption,media_type,media_url,permalink,timestamp,like_count,comments_count";
|
|
6
|
+
export const THREADS_PROFILE_FIELDS = "id,username,name,threads_profile_picture_url,threads_biography,is_verified,is_eligible_for_geo_gating";
|
|
7
|
+
export const THREADS_MEDIA_FIELDS = [
|
|
8
|
+
"id",
|
|
9
|
+
"media_product_type",
|
|
10
|
+
"media_type",
|
|
11
|
+
"media_url",
|
|
12
|
+
"permalink",
|
|
13
|
+
"text",
|
|
14
|
+
"timestamp",
|
|
15
|
+
"shortcode",
|
|
16
|
+
"is_quote_post",
|
|
17
|
+
"has_replies",
|
|
18
|
+
"reply_audience",
|
|
19
|
+
"topic_tag",
|
|
20
|
+
"link_attachment_url",
|
|
21
|
+
"poll_attachment{option_a,option_b,option_c,option_d,option_a_votes_percentage,option_b_votes_percentage,option_c_votes_percentage,option_d_votes_percentage,total_votes,expiration_timestamp}",
|
|
22
|
+
"gif_url",
|
|
23
|
+
"alt_text",
|
|
24
|
+
].join(",");
|
|
25
|
+
//# sourceMappingURL=fields.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"fields.js","sourceRoot":"","sources":["../../src/constants/fields.ts"],"names":[],"mappings":"AAAA,MAAM,CAAC,MAAM,iBAAiB,GAC5B,kGAAkG,CAAC;AAErG,MAAM,CAAC,MAAM,eAAe,GAC1B,6FAA6F,CAAC;AAEhG,4EAA4E;AAC5E,yEAAyE;AACzE,MAAM,CAAC,MAAM,uBAAuB,GAClC,+EAA+E,CAAC;AAElF,MAAM,CAAC,MAAM,sBAAsB,GACjC,uGAAuG,CAAC;AAE1G,MAAM,CAAC,MAAM,oBAAoB,GAAG;IAClC,IAAI;IACJ,oBAAoB;IACpB,YAAY;IACZ,WAAW;IACX,WAAW;IACX,MAAM;IACN,WAAW;IACX,WAAW;IACX,eAAe;IACf,aAAa;IACb,gBAAgB;IAChB,WAAW;IACX,qBAAqB;IACrB,+LAA+L;IAC/L,SAAS;IACT,UAAU;CACX,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC"}
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
import type { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
|
|
2
|
+
export declare const DEFAULT_HTTP_HOST = "127.0.0.1";
|
|
3
|
+
export declare const DEFAULT_HTTP_PORT = 3000;
|
|
4
|
+
export declare const MCP_ENDPOINT = "/mcp";
|
|
5
|
+
export interface HttpTransportConfig {
|
|
6
|
+
host: string;
|
|
7
|
+
port: number;
|
|
8
|
+
allowedHosts: string[] | undefined;
|
|
9
|
+
}
|
|
10
|
+
export interface StartHttpTransportOptions extends HttpTransportConfig {
|
|
11
|
+
createServer: () => McpServer;
|
|
12
|
+
log?: (msg: string) => void;
|
|
13
|
+
}
|
|
14
|
+
export interface HttpTransportHandle {
|
|
15
|
+
port: number;
|
|
16
|
+
close(): Promise<void>;
|
|
17
|
+
}
|
|
18
|
+
export declare function parseHttpTransportConfig(env: NodeJS.ProcessEnv): HttpTransportConfig;
|
|
19
|
+
export declare function startHttpTransport(options: StartHttpTransportOptions): Promise<HttpTransportHandle>;
|
|
20
|
+
//# sourceMappingURL=http-transport.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"http-transport.d.ts","sourceRoot":"","sources":["../src/http-transport.ts"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,yCAAyC,CAAC;AAIzE,eAAO,MAAM,iBAAiB,cAAc,CAAC;AAC7C,eAAO,MAAM,iBAAiB,OAAO,CAAC;AACtC,eAAO,MAAM,YAAY,SAAS,CAAC;AAKnC,MAAM,WAAW,mBAAmB;IAClC,IAAI,EAAE,MAAM,CAAC;IACb,IAAI,EAAE,MAAM,CAAC;IAEb,YAAY,EAAE,MAAM,EAAE,GAAG,SAAS,CAAC;CACpC;AAED,MAAM,WAAW,yBAA0B,SAAQ,mBAAmB;IAEpE,YAAY,EAAE,MAAM,SAAS,CAAC;IAC9B,GAAG,CAAC,EAAE,CAAC,GAAG,EAAE,MAAM,KAAK,IAAI,CAAC;CAC7B;AAED,MAAM,WAAW,mBAAmB;IAClC,IAAI,EAAE,MAAM,CAAC;IACb,KAAK,IAAI,OAAO,CAAC,IAAI,CAAC,CAAC;CACxB;AAED,wBAAgB,wBAAwB,CAAC,GAAG,EAAE,MAAM,CAAC,UAAU,GAAG,mBAAmB,CAsBpF;AAED,wBAAsB,kBAAkB,CACtC,OAAO,EAAE,yBAAyB,GACjC,OAAO,CAAC,mBAAmB,CAAC,CAoI9B"}
|
|
@@ -0,0 +1,228 @@
|
|
|
1
|
+
import { randomUUID } from "node:crypto";
|
|
2
|
+
import { createServer } from "node:http";
|
|
3
|
+
import { StreamableHTTPServerTransport } from "@modelcontextprotocol/sdk/server/streamableHttp.js";
|
|
4
|
+
import { isInitializeRequest } from "@modelcontextprotocol/sdk/types.js";
|
|
5
|
+
export const DEFAULT_HTTP_HOST = "127.0.0.1";
|
|
6
|
+
export const DEFAULT_HTTP_PORT = 3000;
|
|
7
|
+
export const MCP_ENDPOINT = "/mcp";
|
|
8
|
+
// Node's http server imposes no body limit; cap reads to avoid memory exhaustion.
|
|
9
|
+
const MAX_BODY_BYTES = 4 * 1024 * 1024;
|
|
10
|
+
export function parseHttpTransportConfig(env) {
|
|
11
|
+
const host = env.MCP_HTTP_HOST?.trim() || DEFAULT_HTTP_HOST;
|
|
12
|
+
let port = DEFAULT_HTTP_PORT;
|
|
13
|
+
const rawPort = env.MCP_HTTP_PORT?.trim();
|
|
14
|
+
if (rawPort) {
|
|
15
|
+
// Number() (unlike parseInt) rejects "3000abc" as NaN.
|
|
16
|
+
const parsed = Number(rawPort);
|
|
17
|
+
if (!Number.isInteger(parsed) || parsed < 1 || parsed > 65535) {
|
|
18
|
+
throw new Error(`MCP_HTTP_PORT must be an integer between 1 and 65535 (got "${rawPort}")`);
|
|
19
|
+
}
|
|
20
|
+
port = parsed;
|
|
21
|
+
}
|
|
22
|
+
const rawAllowed = env.MCP_HTTP_ALLOWED_HOSTS?.trim();
|
|
23
|
+
const allowedHosts = rawAllowed
|
|
24
|
+
? rawAllowed.split(",").map((h) => h.trim()).filter(Boolean)
|
|
25
|
+
: undefined;
|
|
26
|
+
return { host, port, allowedHosts };
|
|
27
|
+
}
|
|
28
|
+
export async function startHttpTransport(options) {
|
|
29
|
+
const { host, createServer: createMcpServer } = options;
|
|
30
|
+
const log = options.log ?? ((msg) => console.error(msg));
|
|
31
|
+
const sessions = new Map();
|
|
32
|
+
// Resolved after listen() so DNS-rebinding allowlists can include the actual
|
|
33
|
+
// bound port (matters when port is 0, e.g. in tests).
|
|
34
|
+
let allowedHosts = [];
|
|
35
|
+
let dnsRebindingProtection = false;
|
|
36
|
+
const httpServer = createServer((req, res) => {
|
|
37
|
+
void handleRequest(req, res).catch((err) => {
|
|
38
|
+
log(`[meta-mcp] HTTP handler error — ${errMessage(err)}`);
|
|
39
|
+
sendJsonRpcError(res, 500, -32603, "Internal server error");
|
|
40
|
+
});
|
|
41
|
+
});
|
|
42
|
+
async function handleRequest(req, res) {
|
|
43
|
+
const url = new URL(req.url ?? "/", `http://${req.headers.host ?? host}`);
|
|
44
|
+
if (url.pathname !== MCP_ENDPOINT) {
|
|
45
|
+
sendJsonRpcError(res, 404, -32601, `Not found: ${url.pathname}`);
|
|
46
|
+
return;
|
|
47
|
+
}
|
|
48
|
+
const method = req.method ?? "GET";
|
|
49
|
+
const sessionId = headerValue(req.headers["mcp-session-id"]);
|
|
50
|
+
if (method === "POST") {
|
|
51
|
+
let body;
|
|
52
|
+
try {
|
|
53
|
+
body = await readJsonBody(req);
|
|
54
|
+
}
|
|
55
|
+
catch (err) {
|
|
56
|
+
// Fixed messages only — never echo exception text back to a remote client.
|
|
57
|
+
if (err instanceof PayloadTooLargeError) {
|
|
58
|
+
sendJsonRpcError(res, 413, -32600, "Request body too large");
|
|
59
|
+
}
|
|
60
|
+
else {
|
|
61
|
+
sendJsonRpcError(res, 400, -32700, "Invalid JSON in request body");
|
|
62
|
+
}
|
|
63
|
+
return;
|
|
64
|
+
}
|
|
65
|
+
if (sessionId) {
|
|
66
|
+
const transport = sessions.get(sessionId);
|
|
67
|
+
if (!transport) {
|
|
68
|
+
sendJsonRpcError(res, 404, -32001, "Session not found");
|
|
69
|
+
return;
|
|
70
|
+
}
|
|
71
|
+
await transport.handleRequest(req, res, body);
|
|
72
|
+
return;
|
|
73
|
+
}
|
|
74
|
+
if (isInitializeRequest(body)) {
|
|
75
|
+
const transport = new StreamableHTTPServerTransport({
|
|
76
|
+
sessionIdGenerator: () => randomUUID(),
|
|
77
|
+
enableDnsRebindingProtection: dnsRebindingProtection,
|
|
78
|
+
allowedHosts,
|
|
79
|
+
onsessioninitialized: (sid) => {
|
|
80
|
+
sessions.set(sid, transport);
|
|
81
|
+
},
|
|
82
|
+
});
|
|
83
|
+
// Drop the session on close (DELETE or client drop) so the map can't leak.
|
|
84
|
+
transport.onclose = () => {
|
|
85
|
+
const sid = transport.sessionId;
|
|
86
|
+
if (sid)
|
|
87
|
+
sessions.delete(sid);
|
|
88
|
+
};
|
|
89
|
+
try {
|
|
90
|
+
await createMcpServer().connect(transport);
|
|
91
|
+
await transport.handleRequest(req, res, body);
|
|
92
|
+
}
|
|
93
|
+
catch (err) {
|
|
94
|
+
// Close so onclose evicts a half-initialized session from the map.
|
|
95
|
+
await transport.close().catch(() => undefined);
|
|
96
|
+
throw err;
|
|
97
|
+
}
|
|
98
|
+
return;
|
|
99
|
+
}
|
|
100
|
+
sendJsonRpcError(res, 400, -32000, "Bad Request: missing or invalid session ID");
|
|
101
|
+
return;
|
|
102
|
+
}
|
|
103
|
+
if (method === "GET" || method === "DELETE") {
|
|
104
|
+
if (!sessionId) {
|
|
105
|
+
sendJsonRpcError(res, 400, -32000, "Bad Request: missing session ID");
|
|
106
|
+
return;
|
|
107
|
+
}
|
|
108
|
+
const transport = sessions.get(sessionId);
|
|
109
|
+
if (!transport) {
|
|
110
|
+
sendJsonRpcError(res, 404, -32001, "Session not found");
|
|
111
|
+
return;
|
|
112
|
+
}
|
|
113
|
+
await transport.handleRequest(req, res);
|
|
114
|
+
return;
|
|
115
|
+
}
|
|
116
|
+
sendJsonRpcError(res, 405, -32601, `Method not allowed: ${method}`);
|
|
117
|
+
}
|
|
118
|
+
await new Promise((resolve, reject) => {
|
|
119
|
+
const onListenError = (err) => reject(err);
|
|
120
|
+
httpServer.once("error", onListenError);
|
|
121
|
+
httpServer.listen(options.port, host, () => {
|
|
122
|
+
httpServer.removeListener("error", onListenError);
|
|
123
|
+
resolve();
|
|
124
|
+
});
|
|
125
|
+
});
|
|
126
|
+
const actualPort = httpServer.address().port;
|
|
127
|
+
if (options.allowedHosts && options.allowedHosts.length > 0) {
|
|
128
|
+
allowedHosts = options.allowedHosts;
|
|
129
|
+
dnsRebindingProtection = true;
|
|
130
|
+
}
|
|
131
|
+
else if (isLoopbackHost(host)) {
|
|
132
|
+
allowedHosts = loopbackHosts(actualPort);
|
|
133
|
+
dnsRebindingProtection = true;
|
|
134
|
+
}
|
|
135
|
+
else {
|
|
136
|
+
// Bound to a routable interface (e.g. 0.0.0.0 in Docker) with no allowlist —
|
|
137
|
+
// a Host allowlist can't be derived, so leave protection off and tell the
|
|
138
|
+
// operator to front it with a proxy or set MCP_HTTP_ALLOWED_HOSTS.
|
|
139
|
+
log(`[meta-mcp] Warning: HTTP transport bound to non-loopback host ${host} without ` +
|
|
140
|
+
`MCP_HTTP_ALLOWED_HOSTS — DNS-rebinding protection is disabled. Run behind a ` +
|
|
141
|
+
`reverse proxy and/or set MCP_HTTP_ALLOWED_HOSTS.`);
|
|
142
|
+
}
|
|
143
|
+
log(`[meta-mcp] HTTP transport listening on http://${host}:${actualPort}${MCP_ENDPOINT}`);
|
|
144
|
+
return {
|
|
145
|
+
port: actualPort,
|
|
146
|
+
close: () => closeHttpTransport(httpServer, sessions),
|
|
147
|
+
};
|
|
148
|
+
}
|
|
149
|
+
async function closeHttpTransport(httpServer, sessions) {
|
|
150
|
+
// Close transports first: each open SSE stream holds a socket that
|
|
151
|
+
// httpServer.close() would otherwise wait on forever.
|
|
152
|
+
for (const transport of sessions.values()) {
|
|
153
|
+
try {
|
|
154
|
+
await transport.close();
|
|
155
|
+
}
|
|
156
|
+
catch {
|
|
157
|
+
// best-effort — keep tearing down the rest
|
|
158
|
+
}
|
|
159
|
+
}
|
|
160
|
+
sessions.clear();
|
|
161
|
+
httpServer.closeIdleConnections();
|
|
162
|
+
await new Promise((resolve, reject) => {
|
|
163
|
+
httpServer.close((err) => (err ? reject(err) : resolve()));
|
|
164
|
+
});
|
|
165
|
+
}
|
|
166
|
+
class PayloadTooLargeError extends Error {
|
|
167
|
+
}
|
|
168
|
+
function readJsonBody(req) {
|
|
169
|
+
return new Promise((resolve, reject) => {
|
|
170
|
+
const chunks = [];
|
|
171
|
+
let size = 0;
|
|
172
|
+
let settled = false;
|
|
173
|
+
const settle = (fn) => {
|
|
174
|
+
if (settled)
|
|
175
|
+
return;
|
|
176
|
+
settled = true;
|
|
177
|
+
fn();
|
|
178
|
+
};
|
|
179
|
+
req.on("data", (chunk) => {
|
|
180
|
+
size += chunk.length;
|
|
181
|
+
if (size > MAX_BODY_BYTES) {
|
|
182
|
+
// Reject and stop buffering, but keep draining the socket so the 413
|
|
183
|
+
// response writes cleanly — destroying req here would kill res too.
|
|
184
|
+
settle(() => reject(new PayloadTooLargeError(`Request body exceeds ${MAX_BODY_BYTES} bytes`)));
|
|
185
|
+
return;
|
|
186
|
+
}
|
|
187
|
+
chunks.push(chunk);
|
|
188
|
+
});
|
|
189
|
+
req.on("end", () => {
|
|
190
|
+
settle(() => {
|
|
191
|
+
const raw = Buffer.concat(chunks).toString("utf8");
|
|
192
|
+
if (!raw) {
|
|
193
|
+
resolve(undefined);
|
|
194
|
+
return;
|
|
195
|
+
}
|
|
196
|
+
try {
|
|
197
|
+
resolve(JSON.parse(raw));
|
|
198
|
+
}
|
|
199
|
+
catch {
|
|
200
|
+
reject(new SyntaxError("Invalid JSON in request body"));
|
|
201
|
+
}
|
|
202
|
+
});
|
|
203
|
+
});
|
|
204
|
+
req.on("error", (err) => settle(() => reject(err)));
|
|
205
|
+
});
|
|
206
|
+
}
|
|
207
|
+
function sendJsonRpcError(res, status, code, message) {
|
|
208
|
+
if (res.headersSent || res.writableEnded || res.destroyed)
|
|
209
|
+
return;
|
|
210
|
+
res.writeHead(status, { "Content-Type": "application/json" });
|
|
211
|
+
res.end(JSON.stringify({ jsonrpc: "2.0", error: { code, message }, id: null }));
|
|
212
|
+
}
|
|
213
|
+
function headerValue(value) {
|
|
214
|
+
if (Array.isArray(value))
|
|
215
|
+
return value[0];
|
|
216
|
+
return value;
|
|
217
|
+
}
|
|
218
|
+
function isLoopbackHost(host) {
|
|
219
|
+
// The whole 127.0.0.0/8 range is loopback, plus localhost and IPv6 ::1.
|
|
220
|
+
return host === "localhost" || host === "::1" || /^127\.\d{1,3}\.\d{1,3}\.\d{1,3}$/.test(host);
|
|
221
|
+
}
|
|
222
|
+
function loopbackHosts(port) {
|
|
223
|
+
return [`127.0.0.1:${port}`, `localhost:${port}`, `[::1]:${port}`];
|
|
224
|
+
}
|
|
225
|
+
function errMessage(err) {
|
|
226
|
+
return err instanceof Error ? err.message : String(err);
|
|
227
|
+
}
|
|
228
|
+
//# sourceMappingURL=http-transport.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"http-transport.js","sourceRoot":"","sources":["../src/http-transport.ts"],"names":[],"mappings":"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"}
|
package/dist/index.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":";
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":";AAKA,OAAO,EAAE,SAAS,EAAE,MAAM,yCAAyC,CAAC;AAwEpE,wBAAgB,mBAAmB,IAAI,SAAS,CAU/C"}
|
package/dist/index.js
CHANGED
|
@@ -1,40 +1,72 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
|
+
import { realpathSync } from "node:fs";
|
|
2
3
|
import { createRequire } from "node:module";
|
|
4
|
+
import { pathToFileURL } from "node:url";
|
|
3
5
|
import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
|
|
4
6
|
import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio.js";
|
|
5
7
|
import { loadConfig } from "./config.js";
|
|
8
|
+
import { parseHttpTransportConfig, startHttpTransport, } from "./http-transport.js";
|
|
6
9
|
import { MetaClient } from "./services/meta-client.js";
|
|
7
10
|
import { registerAll } from "./register-all.js";
|
|
11
|
+
import { setupFatalErrorHandlers, setupShutdownHandlers } from "./shutdown.js";
|
|
12
|
+
import { createMcpLogger } from "./utils/logger.js";
|
|
8
13
|
const require = createRequire(import.meta.url);
|
|
9
14
|
const { version: SERVER_VERSION } = require("../package.json");
|
|
10
|
-
const
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
15
|
+
const SERVER_INSTRUCTIONS = [
|
|
16
|
+
"Meta MCP server for managing Instagram and Threads via the Meta Graph API.",
|
|
17
|
+
"Instagram tools require INSTAGRAM_ACCESS_TOKEN and INSTAGRAM_USER_ID; Threads tools require THREADS_ACCESS_TOKEN and THREADS_USER_ID.",
|
|
18
|
+
"Token-rotation tools (meta_exchange_token, meta_refresh_token) additionally need META_APP_ID and META_APP_SECRET.",
|
|
19
|
+
"Most publishing tools follow a two-step flow internally: create a container, wait for processing (up to 30s for images, up to 5 minutes for videos), then publish — exposed as a single MCP tool call.",
|
|
20
|
+
"When the client sets a progressToken on a publish call, the server emits notifications/progress events while polling container status.",
|
|
21
|
+
"Tool responses include a _rateLimit field when the Meta API returns rate-limit headers; check it to throttle subsequent calls.",
|
|
22
|
+
].join(" ");
|
|
23
|
+
// Server is built before the client so the client can be handed a logger that
|
|
24
|
+
// emits to the MCP `notifications/message` channel. `capabilities.logging`
|
|
25
|
+
// must be declared or sendLoggingMessage is a silent no-op (#62).
|
|
26
|
+
function buildServer(config) {
|
|
27
|
+
const server = new McpServer({
|
|
28
|
+
name: "meta-mcp",
|
|
29
|
+
version: SERVER_VERSION,
|
|
30
|
+
}, {
|
|
31
|
+
instructions: SERVER_INSTRUCTIONS,
|
|
32
|
+
capabilities: { logging: {} },
|
|
33
|
+
});
|
|
34
|
+
const client = new MetaClient(config, { logger: createMcpLogger(server, "meta-client") });
|
|
35
|
+
registerAll(server, client);
|
|
36
|
+
return server;
|
|
21
37
|
}
|
|
22
|
-
const client = new MetaClient(config);
|
|
23
|
-
registerAll(server, client);
|
|
24
38
|
async function main() {
|
|
25
|
-
|
|
26
|
-
|
|
39
|
+
let config;
|
|
40
|
+
let httpConfig = null;
|
|
41
|
+
try {
|
|
42
|
+
config = loadConfig();
|
|
43
|
+
const kind = (process.env.MCP_TRANSPORT ?? "stdio").trim().toLowerCase();
|
|
44
|
+
if (kind === "http") {
|
|
45
|
+
httpConfig = parseHttpTransportConfig(process.env);
|
|
46
|
+
}
|
|
47
|
+
else if (kind !== "stdio") {
|
|
48
|
+
throw new Error(`MCP_TRANSPORT must be "stdio" or "http" (got "${kind}")`);
|
|
49
|
+
}
|
|
50
|
+
}
|
|
51
|
+
catch (err) {
|
|
52
|
+
console.error(err instanceof Error ? err.message : String(err));
|
|
53
|
+
process.exit(1);
|
|
54
|
+
}
|
|
55
|
+
if (httpConfig) {
|
|
56
|
+
const handle = await startHttpTransport({
|
|
57
|
+
...httpConfig,
|
|
58
|
+
createServer: () => buildServer(config),
|
|
59
|
+
});
|
|
60
|
+
setupShutdownHandlers(handle);
|
|
61
|
+
}
|
|
62
|
+
else {
|
|
63
|
+
const server = buildServer(config);
|
|
64
|
+
await server.connect(new StdioServerTransport());
|
|
65
|
+
setupShutdownHandlers(server);
|
|
66
|
+
}
|
|
27
67
|
}
|
|
28
|
-
main().catch((err) => {
|
|
29
|
-
console.error("Fatal error:", err);
|
|
30
|
-
process.exit(1);
|
|
31
|
-
});
|
|
32
68
|
// ── Smithery Sandbox ──
|
|
33
69
|
export function createSandboxServer() {
|
|
34
|
-
const sandbox = new McpServer({
|
|
35
|
-
name: "meta-mcp",
|
|
36
|
-
version: SERVER_VERSION,
|
|
37
|
-
});
|
|
38
70
|
const mockConfig = {
|
|
39
71
|
appId: "",
|
|
40
72
|
appSecret: "",
|
|
@@ -43,8 +75,26 @@ export function createSandboxServer() {
|
|
|
43
75
|
threadsAccessToken: "",
|
|
44
76
|
threadsUserId: "",
|
|
45
77
|
};
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
78
|
+
return buildServer(mockConfig);
|
|
79
|
+
}
|
|
80
|
+
// Guard keeps `import { createSandboxServer }` and test imports side-effect-free —
|
|
81
|
+
// without it, importing this module would always run main() and connect stdio.
|
|
82
|
+
function isInvokedAsCli() {
|
|
83
|
+
const entry = process.argv[1];
|
|
84
|
+
if (!entry)
|
|
85
|
+
return false;
|
|
86
|
+
try {
|
|
87
|
+
return import.meta.url === pathToFileURL(realpathSync(entry)).href;
|
|
88
|
+
}
|
|
89
|
+
catch {
|
|
90
|
+
return false;
|
|
91
|
+
}
|
|
92
|
+
}
|
|
93
|
+
if (isInvokedAsCli()) {
|
|
94
|
+
setupFatalErrorHandlers();
|
|
95
|
+
main().catch((err) => {
|
|
96
|
+
console.error("Fatal error:", err);
|
|
97
|
+
process.exit(1);
|
|
98
|
+
});
|
|
49
99
|
}
|
|
50
100
|
//# 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":";AAEA,OAAO,EAAE,aAAa,EAAE,MAAM,aAAa,CAAC;AAC5C,OAAO,EAAE,SAAS,EAAE,MAAM,yCAAyC,CAAC;AACpE,OAAO,EAAE,oBAAoB,EAAE,MAAM,2CAA2C,CAAC;AACjF,OAAO,EAAE,UAAU,EAAc,MAAM,aAAa,CAAC;AACrD,OAAO,EAAE,UAAU,EAAE,MAAM,2BAA2B,CAAC;AACvD,OAAO,EAAE,WAAW,EAAE,MAAM,mBAAmB,CAAC;
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"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"}
|
package/dist/prompts/index.d.ts
CHANGED
|
@@ -1,3 +1,59 @@
|
|
|
1
1
|
import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
|
|
2
|
+
import { z } from "zod";
|
|
3
|
+
/**
|
|
4
|
+
* Tool names referenced by prompts. Cross-checked against the registered tool
|
|
5
|
+
* list in `src/prompts/index.test.ts` — if any tool is renamed/removed/split,
|
|
6
|
+
* the test fails and forces both the registration site and the prompt to
|
|
7
|
+
* update together. `ig_publish_video` is deliberately omitted: it's deprecated
|
|
8
|
+
* (CHANGELOG v4.0.0 / #118) and the prompt steers callers to
|
|
9
|
+
* `ig_publish_reel` for video content instead.
|
|
10
|
+
*/
|
|
11
|
+
export declare const PROMPT_TOOL_NAMES: {
|
|
12
|
+
readonly IG_PUBLISH_PHOTO: "ig_publish_photo";
|
|
13
|
+
readonly IG_PUBLISH_REEL: "ig_publish_reel";
|
|
14
|
+
readonly IG_PUBLISH_CAROUSEL: "ig_publish_carousel";
|
|
15
|
+
readonly THREADS_PUBLISH_TEXT: "threads_publish_text";
|
|
16
|
+
readonly THREADS_PUBLISH_IMAGE: "threads_publish_image";
|
|
17
|
+
readonly THREADS_PUBLISH_VIDEO: "threads_publish_video";
|
|
18
|
+
readonly THREADS_PUBLISH_CAROUSEL: "threads_publish_carousel";
|
|
19
|
+
readonly IG_GET_PROFILE: "ig_get_profile";
|
|
20
|
+
readonly IG_GET_ACCOUNT_INSIGHTS: "ig_get_account_insights";
|
|
21
|
+
readonly IG_GET_MEDIA_LIST: "ig_get_media_list";
|
|
22
|
+
readonly THREADS_GET_PROFILE: "threads_get_profile";
|
|
23
|
+
readonly THREADS_GET_USER_INSIGHTS: "threads_get_user_insights";
|
|
24
|
+
readonly THREADS_GET_POSTS: "threads_get_posts";
|
|
25
|
+
};
|
|
26
|
+
export declare const contentPublishArgsSchema: {
|
|
27
|
+
platform: z.ZodOptional<z.ZodEnum<{
|
|
28
|
+
instagram: "instagram";
|
|
29
|
+
threads: "threads";
|
|
30
|
+
both: "both";
|
|
31
|
+
}>>;
|
|
32
|
+
content_type: z.ZodOptional<z.ZodEnum<{
|
|
33
|
+
text: "text";
|
|
34
|
+
image: "image";
|
|
35
|
+
video: "video";
|
|
36
|
+
carousel: "carousel";
|
|
37
|
+
}>>;
|
|
38
|
+
media_url: z.ZodOptional<z.ZodString>;
|
|
39
|
+
caption: z.ZodOptional<z.ZodString>;
|
|
40
|
+
};
|
|
41
|
+
export declare const analyticsReportArgsSchema: {
|
|
42
|
+
platform: z.ZodOptional<z.ZodEnum<{
|
|
43
|
+
instagram: "instagram";
|
|
44
|
+
threads: "threads";
|
|
45
|
+
both: "both";
|
|
46
|
+
}>>;
|
|
47
|
+
time_range: z.ZodOptional<z.ZodEnum<{
|
|
48
|
+
"7d": "7d";
|
|
49
|
+
"30d": "30d";
|
|
50
|
+
"90d": "90d";
|
|
51
|
+
}>>;
|
|
52
|
+
focus: z.ZodOptional<z.ZodEnum<{
|
|
53
|
+
content: "content";
|
|
54
|
+
engagement: "engagement";
|
|
55
|
+
growth: "growth";
|
|
56
|
+
}>>;
|
|
57
|
+
};
|
|
2
58
|
export declare function registerPrompts(server: McpServer): void;
|
|
3
59
|
//# sourceMappingURL=index.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/prompts/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,SAAS,EAAE,MAAM,yCAAyC,CAAC;
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/prompts/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,SAAS,EAAE,MAAM,yCAAyC,CAAC;AACpE,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AAExB;;;;;;;GAOG;AACH,eAAO,MAAM,iBAAiB;;;;;;;;;;;;;;CAcpB,CAAC;AAEX,eAAO,MAAM,wBAAwB;;;;;;;;;;;;;;CAkBpC,CAAC;AAEF,eAAO,MAAM,yBAAyB;;;;;;;;;;;;;;;;CAerC,CAAC;AAsQF,wBAAgB,eAAe,CAAC,MAAM,EAAE,SAAS,QAwChD"}
|