@viral_vector/ig-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/dist/cli.js ADDED
@@ -0,0 +1,114 @@
1
+ #!/usr/bin/env node
2
+ import { StdioServerTransport } from '@modelcontextprotocol/sdk/server/stdio.js';
3
+ import { startLocalBridgeServer } from './bridge/server.js';
4
+ import { ExtensionSessionRegistry } from './bridge/sessionRegistry.js';
5
+ import { createViralVectorMcpServer } from './mcp/server.js';
6
+ async function main() {
7
+ const options = parseArgs(process.argv.slice(2));
8
+ if (options.help) {
9
+ printHelp();
10
+ return;
11
+ }
12
+ const registry = new ExtensionSessionRegistry({
13
+ token: options.token,
14
+ requestTimeoutMs: options.requestTimeoutMs
15
+ });
16
+ const bridge = await startLocalBridgeServer({
17
+ port: options.port,
18
+ registry,
19
+ log: (message, context) => {
20
+ process.stderr.write(`[vv-ig-mcp] ${message}${context ? ` ${JSON.stringify(context)}` : ''}\n`);
21
+ }
22
+ });
23
+ process.stderr.write(`[vv-ig-mcp] bridge listening on 127.0.0.1:${bridge.port()}\n`);
24
+ const mcp = createViralVectorMcpServer(registry);
25
+ const transport = new StdioServerTransport();
26
+ const shutdown = async () => {
27
+ await bridge.close();
28
+ process.exit(0);
29
+ };
30
+ process.once('SIGINT', () => void shutdown());
31
+ process.once('SIGTERM', () => void shutdown());
32
+ await mcp.connect(transport);
33
+ }
34
+ function parseArgs(args) {
35
+ const options = {
36
+ port: parseIntEnv('VV_IG_MCP_PORT', 8765),
37
+ token: process.env.VV_IG_MCP_TOKEN ?? '',
38
+ requestTimeoutMs: parseIntEnv('VV_IG_MCP_REQUEST_TIMEOUT_MS', 5_000),
39
+ help: false
40
+ };
41
+ for (let index = 0; index < args.length; index += 1) {
42
+ const arg = args[index];
43
+ if (arg === '--help' || arg === '-h') {
44
+ options.help = true;
45
+ }
46
+ else if (arg === '--port') {
47
+ options.port = parseIntArg(args[++index], '--port');
48
+ }
49
+ else if (arg.startsWith('--port=')) {
50
+ options.port = parseIntArg(arg.slice('--port='.length), '--port');
51
+ }
52
+ else if (arg === '--token') {
53
+ options.token = requiredValue(args[++index], '--token');
54
+ }
55
+ else if (arg.startsWith('--token=')) {
56
+ options.token = requiredValue(arg.slice('--token='.length), '--token');
57
+ }
58
+ else if (arg === '--request-timeout-ms') {
59
+ options.requestTimeoutMs = parseIntArg(args[++index], '--request-timeout-ms');
60
+ }
61
+ else if (arg.startsWith('--request-timeout-ms=')) {
62
+ options.requestTimeoutMs = parseIntArg(arg.slice('--request-timeout-ms='.length), '--request-timeout-ms');
63
+ }
64
+ else {
65
+ throw new Error(`Unknown argument: ${arg}`);
66
+ }
67
+ }
68
+ options.port = Math.min(65_535, Math.max(1_024, Math.trunc(options.port)));
69
+ options.requestTimeoutMs = Math.max(100, Math.trunc(options.requestTimeoutMs));
70
+ if (!options.help && options.token.trim() === '') {
71
+ throw new Error('A pairing token is required. Pass --token or set VV_IG_MCP_TOKEN.');
72
+ }
73
+ return options;
74
+ }
75
+ function parseIntEnv(name, fallback) {
76
+ const raw = process.env[name];
77
+ if (!raw) {
78
+ return fallback;
79
+ }
80
+ return parseIntArg(raw, name);
81
+ }
82
+ function parseIntArg(value, name) {
83
+ const parsed = Number(value);
84
+ if (!Number.isFinite(parsed)) {
85
+ throw new Error(`${name} must be a finite number.`);
86
+ }
87
+ return Math.trunc(parsed);
88
+ }
89
+ function requiredValue(value, name) {
90
+ if (!value) {
91
+ throw new Error(`${name} requires a value.`);
92
+ }
93
+ return value;
94
+ }
95
+ function printHelp() {
96
+ process.stdout.write(`ViralVector Instagram MCP server
97
+
98
+ Usage:
99
+ vv-ig-mcp --token <pairing-token> [--port 8765] [--request-timeout-ms 5000]
100
+
101
+ Environment:
102
+ VV_IG_MCP_PORT
103
+ VV_IG_MCP_TOKEN
104
+ VV_IG_MCP_REQUEST_TIMEOUT_MS
105
+
106
+ The MCP protocol uses stdio. Runtime diagnostics are written to stderr.
107
+ The extension bridge listens only on 127.0.0.1.
108
+ `);
109
+ }
110
+ main().catch((error) => {
111
+ const message = error instanceof Error ? error.message : String(error);
112
+ process.stderr.write(`[vv-ig-mcp] fatal: ${message}\n`);
113
+ process.exit(1);
114
+ });
@@ -0,0 +1,3 @@
1
+ import { McpServer } from '@modelcontextprotocol/sdk/server/mcp.js';
2
+ import type { ExtensionSessionRegistry } from '../bridge/sessionRegistry.js';
3
+ export declare function createViralVectorMcpServer(registry: ExtensionSessionRegistry): McpServer;
@@ -0,0 +1,10 @@
1
+ import { McpServer } from '@modelcontextprotocol/sdk/server/mcp.js';
2
+ import { registerMcpTools } from './tools.js';
3
+ export function createViralVectorMcpServer(registry) {
4
+ const server = new McpServer({
5
+ name: '@viral_vector/ig-mcp',
6
+ version: '0.1.0'
7
+ });
8
+ registerMcpTools(server, registry);
9
+ return server;
10
+ }
@@ -0,0 +1,36 @@
1
+ import { McpServer } from '@modelcontextprotocol/sdk/server/mcp.js';
2
+ import type { ToolAnnotations } from '@modelcontextprotocol/sdk/types.js';
3
+ import { z } from 'zod';
4
+ import type { BridgeRequestResult, ExtensionSessionRegistry } from '../bridge/sessionRegistry.js';
5
+ type ToolHandler = (input: Record<string, unknown>, registry: ExtensionSessionRegistry) => Promise<ToolResponse>;
6
+ type ToolDefinition = {
7
+ name: string;
8
+ title: string;
9
+ description: string;
10
+ inputSchema: Record<string, z.ZodType>;
11
+ annotations?: ToolAnnotations;
12
+ handler: ToolHandler;
13
+ };
14
+ type ToolResponse = ReturnType<typeof jsonToolResponse> | ReturnType<typeof errorToolResponse>;
15
+ export declare const V2_TOOL_DEFINITIONS: readonly ToolDefinition[];
16
+ export declare const MCP_TOOL_DEFINITIONS: readonly ToolDefinition[];
17
+ export declare function registerMcpTools(server: McpServer, registry: ExtensionSessionRegistry): void;
18
+ declare function errorToolResponse(result: BridgeRequestResult): {
19
+ content: {
20
+ type: "text";
21
+ text: string;
22
+ }[];
23
+ } | {
24
+ isError: boolean;
25
+ content: {
26
+ type: "text";
27
+ text: string;
28
+ }[];
29
+ };
30
+ declare function jsonToolResponse(value: unknown): {
31
+ content: {
32
+ type: "text";
33
+ text: string;
34
+ }[];
35
+ };
36
+ export {};