@xreplyai/mcp 0.1.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 ADDED
@@ -0,0 +1,153 @@
1
+ # @xreplyai/mcp
2
+
3
+ MCP server for [XReply AI](https://xreply.ai) — voice-aware post generation, viral library discovery, and post management for AI agents.
4
+
5
+ ## Features
6
+
7
+ 13 tools covering the full posts workflow:
8
+
9
+ - **Discovery** — Browse the viral tweet library filtered by niche
10
+ - **Generation** — Generate single posts or batches in your voice
11
+ - **Post management** — Create, edit, delete posts
12
+ - **Publishing** — Publish immediately or schedule to X/Twitter
13
+ - **Context** — Check billing, voice profile, preferences, and custom rules
14
+
15
+ ## Requirements
16
+
17
+ - Node.js 20+
18
+ - An XReply account (get your JWT token from Settings)
19
+
20
+ ## Setup
21
+
22
+ ### Get your token
23
+
24
+ Sign in to [XReply](https://xreply.ai), go to **Settings**, and copy your API token.
25
+
26
+ ### Claude Desktop
27
+
28
+ Add to `~/Library/Application Support/Claude/claude_desktop_config.json`:
29
+
30
+ ```json
31
+ {
32
+ "mcpServers": {
33
+ "xreply": {
34
+ "command": "npx",
35
+ "args": ["@xreplyai/mcp"],
36
+ "env": {
37
+ "XREPLY_TOKEN": "your-jwt-token-here"
38
+ }
39
+ }
40
+ }
41
+ }
42
+ ```
43
+
44
+ ### Cursor
45
+
46
+ Add to `.cursor/mcp.json` in your project (or `~/.cursor/mcp.json` globally):
47
+
48
+ ```json
49
+ {
50
+ "mcpServers": {
51
+ "xreply": {
52
+ "command": "npx",
53
+ "args": ["@xreplyai/mcp"],
54
+ "env": {
55
+ "XREPLY_TOKEN": "your-jwt-token-here"
56
+ }
57
+ }
58
+ }
59
+ }
60
+ ```
61
+
62
+ ### Windsurf
63
+
64
+ Add to `~/.codeium/windsurf/mcp_config.json`:
65
+
66
+ ```json
67
+ {
68
+ "mcpServers": {
69
+ "xreply": {
70
+ "command": "npx",
71
+ "args": ["@xreplyai/mcp"],
72
+ "env": {
73
+ "XREPLY_TOKEN": "your-jwt-token-here"
74
+ }
75
+ }
76
+ }
77
+ }
78
+ ```
79
+
80
+ ## Tools
81
+
82
+ ### Discovery
83
+
84
+ | Tool | Description |
85
+ |------|-------------|
86
+ | `xreply_viral_library` | Browse viral tweets (100+ likes) filtered by niche and sort |
87
+
88
+ ### Generation
89
+
90
+ | Tool | Description |
91
+ |------|-------------|
92
+ | `xreply_posts_generate` | Generate a single post in your voice |
93
+ | `xreply_posts_generate_batch` | Generate 1-9 posts at once by category |
94
+
95
+ ### Post Management
96
+
97
+ | Tool | Description |
98
+ |------|-------------|
99
+ | `xreply_posts_list` | List all posts in your queue |
100
+ | `xreply_posts_create` | Save a post draft |
101
+ | `xreply_posts_edit` | Edit body or scheduled time |
102
+ | `xreply_posts_delete` | Delete a post |
103
+
104
+ ### Publishing
105
+
106
+ | Tool | Description |
107
+ |------|-------------|
108
+ | `xreply_posts_publish` | Publish now or schedule to X/Twitter |
109
+
110
+ ### Context
111
+
112
+ | Tool | Description |
113
+ |------|-------------|
114
+ | `xreply_billing_status` | Check subscription tier and quota |
115
+ | `xreply_voice_status` | Check voice profile analysis status |
116
+ | `xreply_preferences_get` | Get generation preferences |
117
+ | `xreply_preferences_set` | Update tone, emoji, structure preferences |
118
+ | `xreply_rules_list` | List custom writing rules |
119
+
120
+ ## Example workflows
121
+
122
+ ### Plan posts for the week
123
+
124
+ ```
125
+ 1. xreply_viral_library (niche: "saas") — find inspiration
126
+ 2. xreply_posts_generate_batch (category: "for_you", count: 7) — generate 7 posts
127
+ 3. xreply_posts_create — save the ones you like
128
+ 4. xreply_posts_edit (id: X, scheduled_at: "2026-03-10T09:00:00Z") — schedule each
129
+ ```
130
+
131
+ ### Quick post
132
+
133
+ ```
134
+ 1. xreply_posts_generate (topic: "my SaaS hit 1000 users", angle: "story_arc")
135
+ 2. xreply_posts_create (body: "<generated text>")
136
+ 3. xreply_posts_publish (id: X) — post immediately
137
+ ```
138
+
139
+ ## Environment variables
140
+
141
+ | Variable | Required | Default | Description |
142
+ |----------|----------|---------|-------------|
143
+ | `XREPLY_TOKEN` | Yes | — | Your XReply JWT token |
144
+ | `XREPLY_API_URL` | No | `https://x-reply-ai-backend.onrender.com` | Override API base URL |
145
+
146
+ ## Development
147
+
148
+ ```bash
149
+ npm install
150
+ npm run build
151
+ npm test
152
+ XREPLY_TOKEN=your-token npx tsx src/index.ts
153
+ ```
@@ -0,0 +1,15 @@
1
+ export declare class XReplyClient {
2
+ private token;
3
+ private baseUrl;
4
+ constructor(token: string, baseUrl?: string);
5
+ private headers;
6
+ private timeoutMs;
7
+ private request;
8
+ get<T>(path: string): Promise<T>;
9
+ post<T>(path: string, body?: unknown): Promise<T>;
10
+ patch<T>(path: string, body?: unknown): Promise<T>;
11
+ delete(path: string): Promise<void>;
12
+ }
13
+ export declare function getClient(): XReplyClient;
14
+ export declare function createClient(token: string, baseUrl?: string): XReplyClient;
15
+ //# sourceMappingURL=client.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"client.d.ts","sourceRoot":"","sources":["../src/client.ts"],"names":[],"mappings":"AAUA,qBAAa,YAAY;IACvB,OAAO,CAAC,KAAK,CAAS;IACtB,OAAO,CAAC,OAAO,CAAS;gBAEZ,KAAK,EAAE,MAAM,EAAE,OAAO,CAAC,EAAE,MAAM;IAQ3C,OAAO,CAAC,OAAO;IAQf,OAAO,CAAC,SAAS;YAIH,OAAO;IAwDrB,GAAG,CAAC,CAAC,EAAE,IAAI,EAAE,MAAM,GAAG,OAAO,CAAC,CAAC,CAAC;IAIhC,IAAI,CAAC,CAAC,EAAE,IAAI,EAAE,MAAM,EAAE,IAAI,CAAC,EAAE,OAAO,GAAG,OAAO,CAAC,CAAC,CAAC;IAIjD,KAAK,CAAC,CAAC,EAAE,IAAI,EAAE,MAAM,EAAE,IAAI,CAAC,EAAE,OAAO,GAAG,OAAO,CAAC,CAAC,CAAC;IAIlD,MAAM,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;CAGpC;AAID,wBAAgB,SAAS,IAAI,YAAY,CASxC;AAED,wBAAgB,YAAY,CAAC,KAAK,EAAE,MAAM,EAAE,OAAO,CAAC,EAAE,MAAM,GAAG,YAAY,CAE1E"}
package/dist/client.js ADDED
@@ -0,0 +1,95 @@
1
+ const DEFAULT_BASE_URL = "https://x-reply-ai-backend.onrender.com";
2
+ const DEFAULT_TIMEOUT_MS = 30_000;
3
+ const GENERATION_TIMEOUT_MS = 60_000;
4
+ const GENERATION_PATHS = ["/generate", "/generate_batch"];
5
+ function isGenerationPath(path) {
6
+ return GENERATION_PATHS.some((p) => path.includes(p));
7
+ }
8
+ export class XReplyClient {
9
+ token;
10
+ baseUrl;
11
+ constructor(token, baseUrl) {
12
+ this.token = token;
13
+ this.baseUrl = (baseUrl ?? process.env.XREPLY_API_URL ?? DEFAULT_BASE_URL).replace(/\/$/, "");
14
+ }
15
+ headers() {
16
+ return {
17
+ Authorization: `Bearer ${this.token}`,
18
+ "Content-Type": "application/json",
19
+ Accept: "application/json",
20
+ };
21
+ }
22
+ timeoutMs(path) {
23
+ return isGenerationPath(path) ? GENERATION_TIMEOUT_MS : DEFAULT_TIMEOUT_MS;
24
+ }
25
+ async request(method, path, body) {
26
+ const url = `${this.baseUrl}${path}`;
27
+ const timeout = this.timeoutMs(path);
28
+ const controller = new AbortController();
29
+ const timer = setTimeout(() => controller.abort(), timeout);
30
+ let response;
31
+ try {
32
+ response = await fetch(url, {
33
+ method,
34
+ headers: this.headers(),
35
+ body: body !== undefined ? JSON.stringify(body) : undefined,
36
+ signal: controller.signal,
37
+ });
38
+ }
39
+ catch (err) {
40
+ clearTimeout(timer);
41
+ if (err instanceof Error && err.name === "AbortError") {
42
+ throw new Error(`Request timed out after ${timeout / 1000}s: ${method} ${path}`);
43
+ }
44
+ throw new Error(`Network error: ${err instanceof Error ? err.message : String(err)}`);
45
+ }
46
+ clearTimeout(timer);
47
+ if (response.status === 401) {
48
+ throw new Error("Authentication failed: your XREPLY_TOKEN is expired or invalid. Generate a new token from the XReply settings page.");
49
+ }
50
+ if (response.status === 204) {
51
+ return undefined;
52
+ }
53
+ let data;
54
+ const contentType = response.headers.get("content-type") ?? "";
55
+ if (contentType.includes("application/json")) {
56
+ data = await response.json();
57
+ }
58
+ else {
59
+ const text = await response.text();
60
+ throw new Error(`Unexpected response (${response.status}): ${text}`);
61
+ }
62
+ if (!response.ok) {
63
+ const err = data;
64
+ throw new Error(err.message ?? err.error ?? `Request failed with status ${response.status}`);
65
+ }
66
+ return data;
67
+ }
68
+ get(path) {
69
+ return this.request("GET", path);
70
+ }
71
+ post(path, body) {
72
+ return this.request("POST", path, body ?? {});
73
+ }
74
+ patch(path, body) {
75
+ return this.request("PATCH", path, body ?? {});
76
+ }
77
+ delete(path) {
78
+ return this.request("DELETE", path);
79
+ }
80
+ }
81
+ let _client = null;
82
+ export function getClient() {
83
+ if (!_client) {
84
+ const token = process.env.XREPLY_TOKEN;
85
+ if (!token) {
86
+ throw new Error("XREPLY_TOKEN environment variable is not set");
87
+ }
88
+ _client = new XReplyClient(token);
89
+ }
90
+ return _client;
91
+ }
92
+ export function createClient(token, baseUrl) {
93
+ return new XReplyClient(token, baseUrl);
94
+ }
95
+ //# sourceMappingURL=client.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"client.js","sourceRoot":"","sources":["../src/client.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,3 @@
1
+ #!/usr/bin/env node
2
+ export {};
3
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":""}
package/dist/index.js ADDED
@@ -0,0 +1,14 @@
1
+ #!/usr/bin/env node
2
+ import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio.js";
3
+ import { createServer } from "./server.js";
4
+ const token = process.env.XREPLY_TOKEN;
5
+ if (!token) {
6
+ console.error("Error: XREPLY_TOKEN environment variable is required.\n" +
7
+ "Get your token from XReply settings and add it to your MCP config:\n" +
8
+ ' "env": { "XREPLY_TOKEN": "your-token-here" }');
9
+ process.exit(1);
10
+ }
11
+ const server = createServer();
12
+ const transport = new StdioServerTransport();
13
+ await server.connect(transport);
14
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":";AACA,OAAO,EAAE,oBAAoB,EAAE,MAAM,2CAA2C,CAAC;AACjF,OAAO,EAAE,YAAY,EAAE,MAAM,aAAa,CAAC;AAE3C,MAAM,KAAK,GAAG,OAAO,CAAC,GAAG,CAAC,YAAY,CAAC;AACvC,IAAI,CAAC,KAAK,EAAE,CAAC;IACX,OAAO,CAAC,KAAK,CACX,yDAAyD;QACvD,sEAAsE;QACtE,gDAAgD,CACnD,CAAC;IACF,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;AAClB,CAAC;AAED,MAAM,MAAM,GAAG,YAAY,EAAE,CAAC;AAC9B,MAAM,SAAS,GAAG,IAAI,oBAAoB,EAAE,CAAC;AAE7C,MAAM,MAAM,CAAC,OAAO,CAAC,SAAS,CAAC,CAAC"}
@@ -0,0 +1,3 @@
1
+ import { Server } from "@modelcontextprotocol/sdk/server/index.js";
2
+ export declare function createServer(): Server;
3
+ //# sourceMappingURL=server.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"server.d.ts","sourceRoot":"","sources":["../src/server.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,MAAM,EAAE,MAAM,2CAA2C,CAAC;AAwBnE,wBAAgB,YAAY,IAAI,MAAM,CA8BrC"}
package/dist/server.js ADDED
@@ -0,0 +1,38 @@
1
+ import { Server } from "@modelcontextprotocol/sdk/server/index.js";
2
+ import { CallToolRequestSchema, ListToolsRequestSchema, } from "@modelcontextprotocol/sdk/types.js";
3
+ import { getClient } from "./client.js";
4
+ import { postTools } from "./tools/posts.js";
5
+ import { publishTools } from "./tools/publish.js";
6
+ import { viralLibraryTools } from "./tools/viral-library.js";
7
+ import { contextTools } from "./tools/context.js";
8
+ const ALL_TOOLS = [
9
+ ...postTools,
10
+ ...publishTools,
11
+ ...viralLibraryTools,
12
+ ...contextTools,
13
+ ];
14
+ const TOOL_MAP = new Map(ALL_TOOLS.map((t) => [t.name, t]));
15
+ export function createServer() {
16
+ const server = new Server({ name: "xreply-mcp", version: "0.1.0" }, { capabilities: { tools: {} } });
17
+ server.setRequestHandler(ListToolsRequestSchema, async () => ({
18
+ tools: ALL_TOOLS.map((t) => ({
19
+ name: t.name,
20
+ description: t.description,
21
+ inputSchema: t.inputSchema,
22
+ })),
23
+ }));
24
+ server.setRequestHandler(CallToolRequestSchema, async (request) => {
25
+ const { name, arguments: args } = request.params;
26
+ const tool = TOOL_MAP.get(name);
27
+ if (!tool) {
28
+ return {
29
+ content: [{ type: "text", text: `Unknown tool: ${name}` }],
30
+ isError: true,
31
+ };
32
+ }
33
+ const client = getClient();
34
+ return tool.handler((args ?? {}), client);
35
+ });
36
+ return server;
37
+ }
38
+ //# sourceMappingURL=server.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"server.js","sourceRoot":"","sources":["../src/server.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,MAAM,EAAE,MAAM,2CAA2C,CAAC;AACnE,OAAO,EACL,qBAAqB,EACrB,sBAAsB,GAEvB,MAAM,oCAAoC,CAAC;AAC5C,OAAO,EAAE,SAAS,EAAE,MAAM,aAAa,CAAC;AACxC,OAAO,EAAE,SAAS,EAAE,MAAM,kBAAkB,CAAC;AAC7C,OAAO,EAAE,YAAY,EAAE,MAAM,oBAAoB,CAAC;AAClD,OAAO,EAAE,iBAAiB,EAAE,MAAM,0BAA0B,CAAC;AAC7D,OAAO,EAAE,YAAY,EAAE,MAAM,oBAAoB,CAAC;AAGlD,MAAM,SAAS,GAAqB;IAClC,GAAG,SAAS;IACZ,GAAG,YAAY;IACf,GAAG,iBAAiB;IACpB,GAAG,YAAY;CAChB,CAAC;AAEF,MAAM,QAAQ,GAAG,IAAI,GAAG,CACtB,SAAS,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,CAAC,IAAI,EAAE,CAAC,CAAC,CAAC,CAClC,CAAC;AAEF,MAAM,UAAU,YAAY;IAC1B,MAAM,MAAM,GAAG,IAAI,MAAM,CACvB,EAAE,IAAI,EAAE,YAAY,EAAE,OAAO,EAAE,OAAO,EAAE,EACxC,EAAE,YAAY,EAAE,EAAE,KAAK,EAAE,EAAE,EAAE,EAAE,CAChC,CAAC;IAEF,MAAM,CAAC,iBAAiB,CAAC,sBAAsB,EAAE,KAAK,IAAI,EAAE,CAAC,CAAC;QAC5D,KAAK,EAAE,SAAS,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC;YAC3B,IAAI,EAAE,CAAC,CAAC,IAAI;YACZ,WAAW,EAAE,CAAC,CAAC,WAAW;YAC1B,WAAW,EAAE,CAAC,CAAC,WAAW;SAC3B,CAAC,CAAC;KACJ,CAAC,CAAC,CAAC;IAEJ,MAAM,CAAC,iBAAiB,CAAC,qBAAqB,EAAE,KAAK,EAAE,OAAO,EAA2B,EAAE;QACzF,MAAM,EAAE,IAAI,EAAE,SAAS,EAAE,IAAI,EAAE,GAAG,OAAO,CAAC,MAAM,CAAC;QACjD,MAAM,IAAI,GAAG,QAAQ,CAAC,GAAG,CAAC,IAAI,CAAC,CAAC;QAEhC,IAAI,CAAC,IAAI,EAAE,CAAC;YACV,OAAO;gBACL,OAAO,EAAE,CAAC,EAAE,IAAI,EAAE,MAAM,EAAE,IAAI,EAAE,iBAAiB,IAAI,EAAE,EAAE,CAAC;gBAC1D,OAAO,EAAE,IAAI;aACd,CAAC;QACJ,CAAC;QAED,MAAM,MAAM,GAAG,SAAS,EAAE,CAAC;QAC3B,OAAO,IAAI,CAAC,OAAO,CAAC,CAAC,IAAI,IAAI,EAAE,CAA4B,EAAE,MAAM,CAAC,CAAC;IACvE,CAAC,CAAC,CAAC;IAEH,OAAO,MAAM,CAAC;AAChB,CAAC"}
@@ -0,0 +1,3 @@
1
+ import type { ToolDefinition } from "./posts.js";
2
+ export declare const contextTools: ToolDefinition[];
3
+ //# sourceMappingURL=context.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"context.d.ts","sourceRoot":"","sources":["../../src/tools/context.ts"],"names":[],"mappings":"AAQA,OAAO,KAAK,EAAE,cAAc,EAAc,MAAM,YAAY,CAAC;AAuB7D,eAAO,MAAM,YAAY,EAAE,cAAc,EAoHxC,CAAC"}
@@ -0,0 +1,128 @@
1
+ import { z } from "zod";
2
+ function ok(data) {
3
+ return { content: [{ type: "text", text: JSON.stringify(data, null, 2) }] };
4
+ }
5
+ function err(error) {
6
+ const message = error instanceof Error ? error.message : String(error);
7
+ return { content: [{ type: "text", text: `Error: ${message}` }], isError: true };
8
+ }
9
+ const PreferencesSetSchema = z.object({
10
+ tone: z
11
+ .enum(["auto", "casual", "professional", "witty", "empathetic"])
12
+ .optional()
13
+ .describe("Tone preference"),
14
+ include_emoji: z.boolean().nullable().optional().describe("Include emoji in generated posts"),
15
+ structure: z
16
+ .enum(["one_liner", "paragraph", "question", "list", "story_arc"])
17
+ .optional()
18
+ .describe("Default post structure"),
19
+ });
20
+ export const contextTools = [
21
+ {
22
+ name: "xreply_billing_status",
23
+ description: "Get the current billing and subscription status — tier (free/byok/pro), quota usage, daily limits, and subscription details.",
24
+ inputSchema: {
25
+ type: "object",
26
+ properties: {},
27
+ required: [],
28
+ },
29
+ async handler(_args, client) {
30
+ try {
31
+ const result = await client.get("/api/v1/billing/subscriptions/current");
32
+ return ok(result);
33
+ }
34
+ catch (e) {
35
+ return err(e);
36
+ }
37
+ },
38
+ },
39
+ {
40
+ name: "xreply_voice_status",
41
+ description: "Get the voice profile status — whether it has been analyzed, tweet count, AI provider configured, and writing style summary. The voice profile powers personalized post generation.",
42
+ inputSchema: {
43
+ type: "object",
44
+ properties: {},
45
+ required: [],
46
+ },
47
+ async handler(_args, client) {
48
+ try {
49
+ const result = await client.get("/api/v1/voice_profile");
50
+ return ok(result);
51
+ }
52
+ catch (e) {
53
+ return err(e);
54
+ }
55
+ },
56
+ },
57
+ {
58
+ name: "xreply_preferences_get",
59
+ description: "Get the current post generation preferences — tone, emoji usage, and default structure.",
60
+ inputSchema: {
61
+ type: "object",
62
+ properties: {},
63
+ required: [],
64
+ },
65
+ async handler(_args, client) {
66
+ try {
67
+ const result = await client.get("/api/v1/preferences");
68
+ return ok(result);
69
+ }
70
+ catch (e) {
71
+ return err(e);
72
+ }
73
+ },
74
+ },
75
+ {
76
+ name: "xreply_preferences_set",
77
+ description: "Update post generation preferences. Provide only the fields you want to change — tone (auto/casual/professional/witty/empathetic), include_emoji (true/false/null), or structure (one_liner/paragraph/question/list/story_arc).",
78
+ inputSchema: {
79
+ type: "object",
80
+ properties: {
81
+ tone: {
82
+ type: "string",
83
+ enum: ["auto", "casual", "professional", "witty", "empathetic"],
84
+ description: "Tone preference",
85
+ },
86
+ include_emoji: {
87
+ type: ["boolean", "null"],
88
+ description: "Whether to include emoji",
89
+ },
90
+ structure: {
91
+ type: "string",
92
+ enum: ["one_liner", "paragraph", "question", "list", "story_arc"],
93
+ description: "Default post structure",
94
+ },
95
+ },
96
+ required: [],
97
+ },
98
+ async handler(args, client) {
99
+ try {
100
+ const params = PreferencesSetSchema.parse(args);
101
+ const result = await client.patch("/api/v1/preferences", { preferences: params });
102
+ return ok(result);
103
+ }
104
+ catch (e) {
105
+ return err(e);
106
+ }
107
+ },
108
+ },
109
+ {
110
+ name: "xreply_rules_list",
111
+ description: "List custom writing rules that are applied during post generation — e.g., 'never use hashtags', 'always end with a question'. Requires Pro or BYOK subscription.",
112
+ inputSchema: {
113
+ type: "object",
114
+ properties: {},
115
+ required: [],
116
+ },
117
+ async handler(_args, client) {
118
+ try {
119
+ const result = await client.get("/api/v1/custom_rules");
120
+ return ok(result);
121
+ }
122
+ catch (e) {
123
+ return err(e);
124
+ }
125
+ },
126
+ },
127
+ ];
128
+ //# sourceMappingURL=context.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"context.js","sourceRoot":"","sources":["../../src/tools/context.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,11 @@
1
+ import type { CallToolResult } from "@modelcontextprotocol/sdk/types.js";
2
+ import type { XReplyClient } from "../client.js";
3
+ export type ToolResult = CallToolResult;
4
+ export interface ToolDefinition {
5
+ name: string;
6
+ description: string;
7
+ inputSchema: Record<string, unknown>;
8
+ handler: (args: Record<string, unknown>, client: XReplyClient) => Promise<ToolResult>;
9
+ }
10
+ export declare const postTools: ToolDefinition[];
11
+ //# sourceMappingURL=posts.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"posts.d.ts","sourceRoot":"","sources":["../../src/tools/posts.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,oCAAoC,CAAC;AACzE,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,cAAc,CAAC;AASjD,MAAM,MAAM,UAAU,GAAG,cAAc,CAAC;AAExC,MAAM,WAAW,cAAc;IAC7B,IAAI,EAAE,MAAM,CAAC;IACb,WAAW,EAAE,MAAM,CAAC;IACpB,WAAW,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;IACrC,OAAO,EAAE,CAAC,IAAI,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,EAAE,MAAM,EAAE,YAAY,KAAK,OAAO,CAAC,UAAU,CAAC,CAAC;CACvF;AAqDD,eAAO,MAAM,SAAS,EAAE,cAAc,EA2LrC,CAAC"}
@@ -0,0 +1,213 @@
1
+ import { z } from "zod";
2
+ function ok(data) {
3
+ return { content: [{ type: "text", text: JSON.stringify(data, null, 2) }] };
4
+ }
5
+ function err(error) {
6
+ const message = error instanceof Error ? error.message : String(error);
7
+ return { content: [{ type: "text", text: `Error: ${message}` }], isError: true };
8
+ }
9
+ const CreatePostSchema = z.object({
10
+ body: z.string().min(1).max(280).describe("The post body text (max 280 chars)"),
11
+ });
12
+ const GeneratePostSchema = z.object({
13
+ topic: z
14
+ .string()
15
+ .max(280)
16
+ .optional()
17
+ .describe("Optional topic or prompt for the post (max 280 chars)"),
18
+ angle: z
19
+ .enum(["one_liner", "list", "question", "story_arc", "paragraph", "my_voice"])
20
+ .optional()
21
+ .describe("Writing angle for the post"),
22
+ });
23
+ const GenerateBatchSchema = z.object({
24
+ category: z
25
+ .enum(["personalized", "trending", "viral"])
26
+ .describe("Category of posts to generate"),
27
+ count: z
28
+ .number()
29
+ .int()
30
+ .min(1)
31
+ .max(9)
32
+ .describe("Number of posts to generate (1-9). Cannot exceed your remaining daily quota."),
33
+ });
34
+ const EditPostSchema = z.object({
35
+ id: z.number().int().positive().describe("Post ID"),
36
+ body: z.string().min(1).max(280).optional().describe("New post body text"),
37
+ scheduled_at: z
38
+ .string()
39
+ .nullable()
40
+ .optional()
41
+ .describe("ISO 8601 datetime to schedule, or null to unschedule"),
42
+ });
43
+ const DeletePostSchema = z.object({
44
+ id: z.number().int().positive().describe("Post ID to delete"),
45
+ });
46
+ export const postTools = [
47
+ {
48
+ name: "xreply_posts_list",
49
+ description: "List all posts in the queue (drafts, scheduled, and recent). Returns post IDs, body text, status, and scheduled times.",
50
+ inputSchema: {
51
+ type: "object",
52
+ properties: {},
53
+ required: [],
54
+ },
55
+ async handler(_args, client) {
56
+ try {
57
+ const result = await client.get("/api/v1/posts");
58
+ return ok(result);
59
+ }
60
+ catch (e) {
61
+ return err(e);
62
+ }
63
+ },
64
+ },
65
+ {
66
+ name: "xreply_posts_create",
67
+ description: "Create a new post draft. The post is saved but not published until you call xreply_posts_publish.",
68
+ inputSchema: {
69
+ type: "object",
70
+ properties: {
71
+ body: { type: "string", minLength: 1, maxLength: 280, description: "Post body text" },
72
+ },
73
+ required: ["body"],
74
+ },
75
+ async handler(args, client) {
76
+ try {
77
+ const { body } = CreatePostSchema.parse(args);
78
+ const result = await client.post("/api/v1/posts", { post: { body } });
79
+ return ok(result);
80
+ }
81
+ catch (e) {
82
+ return err(e);
83
+ }
84
+ },
85
+ },
86
+ {
87
+ name: "xreply_posts_generate",
88
+ description: "Generate a single AI post in the user's voice and auto-save it as a draft. Optionally provide a topic and writing angle. Returns the generated body and the saved post ID — edit or delete from the queue as needed. Counts as 1 generation against the daily quota (5/day free, 100/day pro).",
89
+ inputSchema: {
90
+ type: "object",
91
+ properties: {
92
+ topic: {
93
+ type: "string",
94
+ maxLength: 280,
95
+ description: "Optional topic or prompt for the post",
96
+ },
97
+ angle: {
98
+ type: "string",
99
+ enum: ["one_liner", "list", "question", "story_arc", "paragraph", "my_voice"],
100
+ description: "Writing angle",
101
+ },
102
+ },
103
+ required: [],
104
+ },
105
+ async handler(args, client) {
106
+ try {
107
+ const params = GeneratePostSchema.parse(args);
108
+ const generated = await client.post("/api/v1/posts/generate", params);
109
+ const saved = await client.post("/api/v1/posts", {
110
+ post: { body: generated.body },
111
+ });
112
+ return ok({ body: generated.body, post: saved.post });
113
+ }
114
+ catch (e) {
115
+ return err(e);
116
+ }
117
+ },
118
+ },
119
+ {
120
+ name: "xreply_posts_generate_batch",
121
+ description: "Generate multiple AI posts at once in the user's voice. Use 'personalized' for posts tailored to your voice profile, 'trending' for timely content, or 'viral' for posts inspired by viral formats. Returns an array of post body strings. Each post counts as 1 generation against the daily quota (5/day free, 100/day pro) — a single batch of 9 will exhaust a free account. Check xreply_billing_status first if quota is a concern.",
122
+ inputSchema: {
123
+ type: "object",
124
+ properties: {
125
+ category: {
126
+ type: "string",
127
+ enum: ["personalized", "trending", "viral"],
128
+ description: "Category of posts to generate",
129
+ },
130
+ count: {
131
+ type: "integer",
132
+ minimum: 1,
133
+ maximum: 9,
134
+ description: "Number of posts to generate (1-9). Cannot exceed your remaining daily quota.",
135
+ },
136
+ },
137
+ required: ["category", "count"],
138
+ },
139
+ async handler(args, client) {
140
+ try {
141
+ const { category, count } = GenerateBatchSchema.parse(args);
142
+ const billing = await client.get("/api/v1/billing/subscriptions/current");
143
+ const remaining = billing.quota.replies_remaining_today;
144
+ if (remaining !== undefined && remaining !== null && remaining <= 0) {
145
+ return err(`Daily generation quota exhausted (${billing.quota.daily_limit}/day on ${billing.tier} plan). Resets at midnight.`);
146
+ }
147
+ const safeCount = remaining !== undefined && remaining !== null
148
+ ? Math.min(count, remaining)
149
+ : count;
150
+ const result = await client.post("/api/v1/posts/generate_batch", { category, count: safeCount });
151
+ const extra = safeCount < count
152
+ ? {
153
+ quota_warning: `Only ${safeCount} of ${count} requested posts generated — daily quota limit reached (${billing.quota.daily_limit}/day on ${billing.tier} plan).`,
154
+ }
155
+ : {};
156
+ return ok({ ...result, ...extra });
157
+ }
158
+ catch (e) {
159
+ return err(e);
160
+ }
161
+ },
162
+ },
163
+ {
164
+ name: "xreply_posts_edit",
165
+ description: "Edit a post's body text or scheduled time. Set scheduled_at to an ISO 8601 datetime to schedule it, or null to move it back to draft. Cannot edit posts that are processing or already posted.",
166
+ inputSchema: {
167
+ type: "object",
168
+ properties: {
169
+ id: { type: "integer", description: "Post ID" },
170
+ body: { type: "string", minLength: 1, maxLength: 280, description: "New post body" },
171
+ scheduled_at: {
172
+ type: ["string", "null"],
173
+ description: "ISO 8601 datetime or null to unschedule",
174
+ },
175
+ },
176
+ required: ["id"],
177
+ },
178
+ async handler(args, client) {
179
+ try {
180
+ const { id, ...rest } = EditPostSchema.parse(args);
181
+ const result = await client.patch(`/api/v1/posts/${id}`, {
182
+ post: rest,
183
+ });
184
+ return ok(result);
185
+ }
186
+ catch (e) {
187
+ return err(e);
188
+ }
189
+ },
190
+ },
191
+ {
192
+ name: "xreply_posts_delete",
193
+ description: "Delete a post. Cannot delete posts that are currently processing or already published.",
194
+ inputSchema: {
195
+ type: "object",
196
+ properties: {
197
+ id: { type: "integer", description: "Post ID to delete" },
198
+ },
199
+ required: ["id"],
200
+ },
201
+ async handler(args, client) {
202
+ try {
203
+ const { id } = DeletePostSchema.parse(args);
204
+ await client.delete(`/api/v1/posts/${id}`);
205
+ return ok({ success: true, message: `Post ${id} deleted.` });
206
+ }
207
+ catch (e) {
208
+ return err(e);
209
+ }
210
+ },
211
+ },
212
+ ];
213
+ //# sourceMappingURL=posts.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"posts.js","sourceRoot":"","sources":["../../src/tools/posts.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,3 @@
1
+ import type { ToolDefinition } from "./posts.js";
2
+ export declare const publishTools: ToolDefinition[];
3
+ //# sourceMappingURL=publish.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"publish.d.ts","sourceRoot":"","sources":["../../src/tools/publish.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,cAAc,EAAc,MAAM,YAAY,CAAC;AAmB7D,eAAO,MAAM,YAAY,EAAE,cAAc,EA4BxC,CAAC"}
@@ -0,0 +1,46 @@
1
+ import { z } from "zod";
2
+ function ok(data) {
3
+ return { content: [{ type: "text", text: JSON.stringify(data, null, 2) }] };
4
+ }
5
+ function err(error) {
6
+ const message = error instanceof Error ? error.message : String(error);
7
+ return { content: [{ type: "text", text: `Error: ${message}` }], isError: true };
8
+ }
9
+ const PublishSchema = z.object({
10
+ id: z.number().int().positive().describe("Post ID to publish"),
11
+ scheduled_at: z
12
+ .string()
13
+ .optional()
14
+ .describe("ISO 8601 datetime to schedule the post (omit to post immediately)"),
15
+ });
16
+ export const publishTools = [
17
+ {
18
+ name: "xreply_posts_publish",
19
+ description: "Publish or schedule a post. If scheduled_at is provided (ISO 8601), the post will be queued for that time. If omitted, the post is published immediately to X/Twitter. Requires X account to be connected.",
20
+ inputSchema: {
21
+ type: "object",
22
+ properties: {
23
+ id: { type: "integer", description: "Post ID" },
24
+ scheduled_at: {
25
+ type: "string",
26
+ description: "ISO 8601 datetime to schedule (omit to post now)",
27
+ },
28
+ },
29
+ required: ["id"],
30
+ },
31
+ async handler(args, client) {
32
+ try {
33
+ const { id, scheduled_at } = PublishSchema.parse(args);
34
+ const body = {};
35
+ if (scheduled_at !== undefined)
36
+ body.scheduled_at = scheduled_at;
37
+ const result = await client.post(`/api/v1/posts/${id}/publishes`, body);
38
+ return ok(result);
39
+ }
40
+ catch (e) {
41
+ return err(e);
42
+ }
43
+ },
44
+ },
45
+ ];
46
+ //# sourceMappingURL=publish.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"publish.js","sourceRoot":"","sources":["../../src/tools/publish.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AAIxB,SAAS,EAAE,CAAC,IAAa;IACvB,OAAO,EAAE,OAAO,EAAE,CAAC,EAAE,IAAI,EAAE,MAAM,EAAE,IAAI,EAAE,IAAI,CAAC,SAAS,CAAC,IAAI,EAAE,IAAI,EAAE,CAAC,CAAC,EAAE,CAAC,EAAE,CAAC;AAC9E,CAAC;AAED,SAAS,GAAG,CAAC,KAAc;IACzB,MAAM,OAAO,GAAG,KAAK,YAAY,KAAK,CAAC,CAAC,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC;IACvE,OAAO,EAAE,OAAO,EAAE,CAAC,EAAE,IAAI,EAAE,MAAM,EAAE,IAAI,EAAE,UAAU,OAAO,EAAE,EAAE,CAAC,EAAE,OAAO,EAAE,IAAI,EAAE,CAAC;AACnF,CAAC;AAED,MAAM,aAAa,GAAG,CAAC,CAAC,MAAM,CAAC;IAC7B,EAAE,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,GAAG,EAAE,CAAC,QAAQ,EAAE,CAAC,QAAQ,CAAC,oBAAoB,CAAC;IAC9D,YAAY,EAAE,CAAC;SACZ,MAAM,EAAE;SACR,QAAQ,EAAE;SACV,QAAQ,CAAC,mEAAmE,CAAC;CACjF,CAAC,CAAC;AAEH,MAAM,CAAC,MAAM,YAAY,GAAqB;IAC5C;QACE,IAAI,EAAE,sBAAsB;QAC5B,WAAW,EACT,4MAA4M;QAC9M,WAAW,EAAE;YACX,IAAI,EAAE,QAAQ;YACd,UAAU,EAAE;gBACV,EAAE,EAAE,EAAE,IAAI,EAAE,SAAS,EAAE,WAAW,EAAE,SAAS,EAAE;gBAC/C,YAAY,EAAE;oBACZ,IAAI,EAAE,QAAQ;oBACd,WAAW,EAAE,kDAAkD;iBAChE;aACF;YACD,QAAQ,EAAE,CAAC,IAAI,CAAC;SACjB;QACD,KAAK,CAAC,OAAO,CAAC,IAA6B,EAAE,MAAoB;YAC/D,IAAI,CAAC;gBACH,MAAM,EAAE,EAAE,EAAE,YAAY,EAAE,GAAG,aAAa,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC;gBACvD,MAAM,IAAI,GAA4B,EAAE,CAAC;gBACzC,IAAI,YAAY,KAAK,SAAS;oBAAE,IAAI,CAAC,YAAY,GAAG,YAAY,CAAC;gBACjE,MAAM,MAAM,GAAG,MAAM,MAAM,CAAC,IAAI,CAAC,iBAAiB,EAAE,YAAY,EAAE,IAAI,CAAC,CAAC;gBACxE,OAAO,EAAE,CAAC,MAAM,CAAC,CAAC;YACpB,CAAC;YAAC,OAAO,CAAC,EAAE,CAAC;gBACX,OAAO,GAAG,CAAC,CAAC,CAAC,CAAC;YAChB,CAAC;QACH,CAAC;KACF;CACF,CAAC"}
@@ -0,0 +1,3 @@
1
+ import type { ToolDefinition } from "./posts.js";
2
+ export declare const viralLibraryTools: ToolDefinition[];
3
+ //# sourceMappingURL=viral-library.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"viral-library.d.ts","sourceRoot":"","sources":["../../src/tools/viral-library.ts"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAAE,cAAc,EAAc,MAAM,YAAY,CAAC;AAsB7D,eAAO,MAAM,iBAAiB,EAAE,cAAc,EAoC7C,CAAC"}
@@ -0,0 +1,58 @@
1
+ import { z } from "zod";
2
+ function ok(data) {
3
+ return { content: [{ type: "text", text: JSON.stringify(data, null, 2) }] };
4
+ }
5
+ function err(error) {
6
+ const message = error instanceof Error ? error.message : String(error);
7
+ return { content: [{ type: "text", text: `Error: ${message}` }], isError: true };
8
+ }
9
+ const ViralLibrarySchema = z.object({
10
+ niche: z
11
+ .enum(["ai", "saas", "marketing", "productivity", "startups", "growth"])
12
+ .optional()
13
+ .describe("Filter by niche"),
14
+ sort: z
15
+ .enum(["top_engaged", "recent"])
16
+ .optional()
17
+ .describe("Sort order (default: top_engaged)"),
18
+ });
19
+ export const viralLibraryTools = [
20
+ {
21
+ name: "xreply_viral_library",
22
+ description: "Browse the viral tweet library — high-performing tweets (100+ likes) that can inspire post ideas. Filter by niche (ai/saas/marketing/productivity/startups/growth) and sort by engagement or recency. Requires Pro or BYOK subscription.",
23
+ inputSchema: {
24
+ type: "object",
25
+ properties: {
26
+ niche: {
27
+ type: "string",
28
+ enum: ["ai", "saas", "marketing", "productivity", "startups", "growth"],
29
+ description: "Filter by niche",
30
+ },
31
+ sort: {
32
+ type: "string",
33
+ enum: ["top_engaged", "recent"],
34
+ description: "Sort order (default: top_engaged)",
35
+ },
36
+ },
37
+ required: [],
38
+ },
39
+ async handler(args, client) {
40
+ try {
41
+ const params = ViralLibrarySchema.parse(args);
42
+ const query = new URLSearchParams();
43
+ if (params.niche)
44
+ query.set("niche", params.niche);
45
+ if (params.sort)
46
+ query.set("sort", params.sort);
47
+ const qs = query.toString();
48
+ const path = `/api/v1/viral_library${qs ? `?${qs}` : ""}`;
49
+ const result = await client.get(path);
50
+ return ok(result);
51
+ }
52
+ catch (e) {
53
+ return err(e);
54
+ }
55
+ },
56
+ },
57
+ ];
58
+ //# sourceMappingURL=viral-library.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"viral-library.js","sourceRoot":"","sources":["../../src/tools/viral-library.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AAKxB,SAAS,EAAE,CAAC,IAAa;IACvB,OAAO,EAAE,OAAO,EAAE,CAAC,EAAE,IAAI,EAAE,MAAM,EAAE,IAAI,EAAE,IAAI,CAAC,SAAS,CAAC,IAAI,EAAE,IAAI,EAAE,CAAC,CAAC,EAAE,CAAC,EAAE,CAAC;AAC9E,CAAC;AAED,SAAS,GAAG,CAAC,KAAc;IACzB,MAAM,OAAO,GAAG,KAAK,YAAY,KAAK,CAAC,CAAC,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC;IACvE,OAAO,EAAE,OAAO,EAAE,CAAC,EAAE,IAAI,EAAE,MAAM,EAAE,IAAI,EAAE,UAAU,OAAO,EAAE,EAAE,CAAC,EAAE,OAAO,EAAE,IAAI,EAAE,CAAC;AACnF,CAAC;AAED,MAAM,kBAAkB,GAAG,CAAC,CAAC,MAAM,CAAC;IAClC,KAAK,EAAE,CAAC;SACL,IAAI,CAAC,CAAC,IAAI,EAAE,MAAM,EAAE,WAAW,EAAE,cAAc,EAAE,UAAU,EAAE,QAAQ,CAAC,CAAC;SACvE,QAAQ,EAAE;SACV,QAAQ,CAAC,iBAAiB,CAAC;IAC9B,IAAI,EAAE,CAAC;SACJ,IAAI,CAAC,CAAC,aAAa,EAAE,QAAQ,CAAC,CAAC;SAC/B,QAAQ,EAAE;SACV,QAAQ,CAAC,mCAAmC,CAAC;CACjD,CAAC,CAAC;AAEH,MAAM,CAAC,MAAM,iBAAiB,GAAqB;IACjD;QACE,IAAI,EAAE,sBAAsB;QAC5B,WAAW,EACT,0OAA0O;QAC5O,WAAW,EAAE;YACX,IAAI,EAAE,QAAQ;YACd,UAAU,EAAE;gBACV,KAAK,EAAE;oBACL,IAAI,EAAE,QAAQ;oBACd,IAAI,EAAE,CAAC,IAAI,EAAE,MAAM,EAAE,WAAW,EAAE,cAAc,EAAE,UAAU,EAAE,QAAQ,CAAC;oBACvE,WAAW,EAAE,iBAAiB;iBAC/B;gBACD,IAAI,EAAE;oBACJ,IAAI,EAAE,QAAQ;oBACd,IAAI,EAAE,CAAC,aAAa,EAAE,QAAQ,CAAC;oBAC/B,WAAW,EAAE,mCAAmC;iBACjD;aACF;YACD,QAAQ,EAAE,EAAE;SACb;QACD,KAAK,CAAC,OAAO,CAAC,IAA6B,EAAE,MAAoB;YAC/D,IAAI,CAAC;gBACH,MAAM,MAAM,GAAG,kBAAkB,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC;gBAC9C,MAAM,KAAK,GAAG,IAAI,eAAe,EAAE,CAAC;gBACpC,IAAI,MAAM,CAAC,KAAK;oBAAE,KAAK,CAAC,GAAG,CAAC,OAAO,EAAE,MAAM,CAAC,KAAK,CAAC,CAAC;gBACnD,IAAI,MAAM,CAAC,IAAI;oBAAE,KAAK,CAAC,GAAG,CAAC,MAAM,EAAE,MAAM,CAAC,IAAI,CAAC,CAAC;gBAChD,MAAM,EAAE,GAAG,KAAK,CAAC,QAAQ,EAAE,CAAC;gBAC5B,MAAM,IAAI,GAAG,wBAAwB,EAAE,CAAC,CAAC,CAAC,IAAI,EAAE,EAAE,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC;gBAC1D,MAAM,MAAM,GAAG,MAAM,MAAM,CAAC,GAAG,CAAuB,IAAI,CAAC,CAAC;gBAC5D,OAAO,EAAE,CAAC,MAAM,CAAC,CAAC;YACpB,CAAC;YAAC,OAAO,CAAC,EAAE,CAAC;gBACX,OAAO,GAAG,CAAC,CAAC,CAAC,CAAC;YAChB,CAAC;QACH,CAAC;KACF;CACF,CAAC"}
@@ -0,0 +1,108 @@
1
+ export type AIProvider = "gemini" | "chatgpt" | "claude";
2
+ export type TonePreference = "auto" | "casual" | "professional" | "witty" | "empathetic";
3
+ export type StructurePreference = "one_liner" | "paragraph" | "question" | "list" | "story_arc";
4
+ export type VoiceProfileStatus = "not_configured" | "analyzing" | "ready" | "error";
5
+ export type PostStatus = "draft" | "scheduled" | "processing" | "posted" | "failed";
6
+ export type PostAngle = "one_liner" | "list" | "question" | "story_arc" | "paragraph" | "my_voice";
7
+ export type BatchCategory = "for_you" | "trending" | "viral";
8
+ export type ViralLibraryNiche = "ai" | "saas" | "marketing" | "productivity" | "startups" | "growth";
9
+ export type ViralLibrarySort = "top_engaged" | "recent";
10
+ export interface UserPreferences {
11
+ tone?: TonePreference;
12
+ include_emoji?: boolean | null;
13
+ structure?: StructurePreference;
14
+ }
15
+ export interface CustomRule {
16
+ id: number;
17
+ title: string;
18
+ content: string;
19
+ active: boolean;
20
+ created_at: string;
21
+ updated_at: string;
22
+ }
23
+ export interface CustomRulesResponse {
24
+ custom_rules: CustomRule[];
25
+ }
26
+ export interface Post {
27
+ id: number;
28
+ body: string;
29
+ status: PostStatus;
30
+ scheduled_at: string | null;
31
+ published_at: string | null;
32
+ created_at: string;
33
+ updated_at: string;
34
+ }
35
+ export interface PostsResponse {
36
+ posts: Post[];
37
+ }
38
+ export interface PostResponse {
39
+ post: Post;
40
+ }
41
+ export interface PostGenerateResponse {
42
+ body: string;
43
+ }
44
+ export interface PostBatchGenerateResponse {
45
+ posts: string[];
46
+ }
47
+ export interface ViralLibraryTweet {
48
+ tweet_id: string;
49
+ author_handle: string;
50
+ author_name: string;
51
+ tweet_text: string;
52
+ like_count: number;
53
+ retweet_count: number;
54
+ reply_count: number;
55
+ impression_count: number;
56
+ niche: string;
57
+ tweeted_at: string;
58
+ }
59
+ export interface ViralLibraryResponse {
60
+ tweets: ViralLibraryTweet[];
61
+ }
62
+ export interface VoiceProfile {
63
+ id: string;
64
+ ai_provider: string | null;
65
+ api_key_configured: boolean;
66
+ platform_managed: boolean;
67
+ api_key_preview?: string;
68
+ model_version?: string;
69
+ voice_preset_id?: string | null;
70
+ voice_preset_name?: string | null;
71
+ analyzed_at: string;
72
+ tweet_count: number;
73
+ writing_style: Record<string, unknown>;
74
+ }
75
+ export interface VoiceProfileResponse {
76
+ voice_profile: VoiceProfile;
77
+ summary?: string;
78
+ }
79
+ export interface APIError {
80
+ message: string;
81
+ code: string;
82
+ details?: unknown;
83
+ }
84
+ export type SubscriptionTier = "free" | "byok" | "pro";
85
+ export interface QuotaInfo {
86
+ tier: SubscriptionTier | null;
87
+ daily_limit?: number | null;
88
+ replies_used_today?: number;
89
+ replies_remaining_today?: number;
90
+ resets_at?: string;
91
+ message?: string;
92
+ requires_subscription?: boolean;
93
+ }
94
+ export interface Subscription {
95
+ id: number;
96
+ status: string;
97
+ current_period_start: string;
98
+ current_period_end: string;
99
+ cancel_at_period_end: boolean;
100
+ canceled_at?: string;
101
+ days_until_renewal: number;
102
+ }
103
+ export interface SubscriptionStatus {
104
+ subscription: Subscription | null;
105
+ tier: SubscriptionTier;
106
+ quota: QuotaInfo;
107
+ }
108
+ //# sourceMappingURL=types.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":"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"}
package/dist/types.js ADDED
@@ -0,0 +1,2 @@
1
+ export {};
2
+ //# sourceMappingURL=types.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"types.js","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":""}
package/package.json ADDED
@@ -0,0 +1,67 @@
1
+ {
2
+ "name": "@xreplyai/mcp",
3
+ "version": "0.1.0",
4
+ "description": "MCP server for XReply AI — voice-aware post generation, viral library, and post management",
5
+ "type": "module",
6
+ "bin": {
7
+ "xreplyai-mcp": "./dist/index.js"
8
+ },
9
+ "main": "./dist/index.js",
10
+ "files": [
11
+ "dist"
12
+ ],
13
+ "scripts": {
14
+ "build": "tsc",
15
+ "dev": "tsx src/index.ts",
16
+ "test": "node --experimental-vm-modules node_modules/.bin/jest",
17
+ "prepublishOnly": "npm run build"
18
+ },
19
+ "dependencies": {
20
+ "@modelcontextprotocol/sdk": "^1.0.0",
21
+ "zod": "^3.23.8"
22
+ },
23
+ "devDependencies": {
24
+ "@types/jest": "^29.5.12",
25
+ "@types/node": "^20.14.0",
26
+ "jest": "^29.7.0",
27
+ "ts-jest": "^29.1.4",
28
+ "tsx": "^4.15.6",
29
+ "typescript": "^5.4.5"
30
+ },
31
+ "jest": {
32
+ "preset": "ts-jest/presets/default-esm",
33
+ "testEnvironment": "node",
34
+ "extensionsToTreatAsEsm": [
35
+ ".ts"
36
+ ],
37
+ "moduleNameMapper": {
38
+ "^(\\.{1,2}/.*)\\.js$": "$1"
39
+ },
40
+ "transform": {
41
+ "^.+\\.tsx?$": [
42
+ "ts-jest",
43
+ {
44
+ "useESM": true,
45
+ "tsconfig": {
46
+ "module": "ESNext",
47
+ "moduleResolution": "bundler"
48
+ }
49
+ }
50
+ ]
51
+ },
52
+ "transformIgnorePatterns": [
53
+ "/node_modules/(?!(@modelcontextprotocol|zod)/)"
54
+ ]
55
+ },
56
+ "engines": {
57
+ "node": ">=20"
58
+ },
59
+ "keywords": [
60
+ "mcp",
61
+ "xreply",
62
+ "ai",
63
+ "twitter",
64
+ "x"
65
+ ],
66
+ "license": "MIT"
67
+ }