taskr-mcp-client 1.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 ADDED
@@ -0,0 +1,49 @@
1
+ # taskr-mcp-client
2
+
3
+ stdio to HTTP bridge for Taskr MCP server. Connects Claude Code to the Taskr production MCP endpoint.
4
+
5
+ ## Installation
6
+
7
+ No installation needed! Use with `npx`:
8
+
9
+ ```bash
10
+ npx taskr-mcp-client
11
+ ```
12
+
13
+ ## Usage with Claude Code
14
+
15
+ Add to your `.mcp.json`:
16
+
17
+ ```json
18
+ {
19
+ "mcpServers": {
20
+ "taskr": {
21
+ "command": "npx",
22
+ "args": ["-y", "taskr-mcp-client"],
23
+ "env": {
24
+ "MCP_API_URL": "https://taskr-six.vercel.app/api/mcp",
25
+ "MCP_PROJECT_ID": "your-project-id",
26
+ "MCP_USER_API_KEY": "your-api-key"
27
+ }
28
+ }
29
+ }
30
+ }
31
+ ```
32
+
33
+ ## Environment Variables
34
+
35
+ - `MCP_API_URL` - Taskr MCP endpoint URL
36
+ - `MCP_PROJECT_ID` - Your Taskr project ID (format: `PR_*`)
37
+ - `MCP_USER_API_KEY` - Your Taskr API key
38
+
39
+ ## How It Works
40
+
41
+ This bridge translates between:
42
+ - **stdin/stdout** (MCP protocol used by Claude Code)
43
+ - **HTTP POST** (JSON-RPC 2.0 endpoint used by Taskr server)
44
+
45
+ It allows Claude Code to communicate with Taskr's serverless MCP endpoint deployed on Vercel.
46
+
47
+ ## License
48
+
49
+ MIT
package/bridge.js ADDED
@@ -0,0 +1,111 @@
1
+ #!/usr/bin/env node
2
+
3
+ /**
4
+ * MCP HTTP Client Bridge using official MCP SDK
5
+ * Bridges stdio-based MCP clients to HTTP JSON-RPC endpoints
6
+ */
7
+
8
+ import { Client } from '@modelcontextprotocol/sdk/client/index.js';
9
+ import { StdioClientTransport } from '@modelcontextprotocol/sdk/client/stdio.js';
10
+
11
+ // Configuration from environment variables
12
+ const MCP_API_URL = process.env.MCP_API_URL;
13
+ const MCP_PROJECT_ID = process.env.MCP_PROJECT_ID;
14
+ const MCP_USER_API_KEY = process.env.MCP_USER_API_KEY;
15
+
16
+ if (!MCP_API_URL || !MCP_PROJECT_ID || !MCP_USER_API_KEY) {
17
+ console.error('Error: Missing required environment variables');
18
+ console.error('Required: MCP_API_URL, MCP_PROJECT_ID, MCP_USER_API_KEY');
19
+ process.exit(1);
20
+ }
21
+
22
+ // Custom HTTP transport that wraps our JSON-RPC endpoint
23
+ class CustomHttpTransport {
24
+ constructor(url, headers) {
25
+ this.url = url;
26
+ this.headers = headers;
27
+ }
28
+
29
+ async start() {
30
+ // No persistent connection needed
31
+ }
32
+
33
+ async send(message) {
34
+ const https = await import('https');
35
+ const http = await import('http');
36
+
37
+ const url = new URL(this.url);
38
+ const isHttps = url.protocol === 'https:';
39
+ const httpModule = isHttps ? https : http;
40
+
41
+ return new Promise((resolve, reject) => {
42
+ const requestBody = JSON.stringify(message);
43
+
44
+ const options = {
45
+ hostname: url.hostname,
46
+ port: url.port || (isHttps ? 443 : 80),
47
+ path: url.pathname,
48
+ method: 'POST',
49
+ headers: {
50
+ 'Content-Type': 'application/json',
51
+ 'Content-Length': Buffer.byteLength(requestBody),
52
+ ...this.headers
53
+ },
54
+ rejectUnauthorized: false
55
+ };
56
+
57
+ const req = httpModule.request(options, (res) => {
58
+ let data = '';
59
+
60
+ res.on('data', (chunk) => {
61
+ data += chunk;
62
+ });
63
+
64
+ res.on('end', () => {
65
+ try {
66
+ resolve(JSON.parse(data));
67
+ } catch (error) {
68
+ reject(new Error('Failed to parse response'));
69
+ }
70
+ });
71
+ });
72
+
73
+ req.on('error', reject);
74
+ req.write(requestBody);
75
+ req.end();
76
+ });
77
+ }
78
+
79
+ async close() {
80
+ // No persistent connection to close
81
+ }
82
+ }
83
+
84
+ // Create and start the bridge
85
+ async function main() {
86
+ const transport = new CustomHttpTransport(MCP_API_URL, {
87
+ 'x-project-id': MCP_PROJECT_ID,
88
+ 'x-user-api-key': MCP_USER_API_KEY,
89
+ 'MCP-Protocol-Version': '2025-06-18'
90
+ });
91
+
92
+ const client = new Client({
93
+ name: 'taskr-http-client',
94
+ version: '1.0.0'
95
+ }, {
96
+ capabilities: {}
97
+ });
98
+
99
+ // Use stdio transport for communication with Claude Code
100
+ const stdioTransport = new StdioClientTransport();
101
+
102
+ await client.connect(transport);
103
+
104
+ // Keep process alive
105
+ process.stdin.resume();
106
+ }
107
+
108
+ main().catch((error) => {
109
+ console.error('Fatal error:', error);
110
+ process.exit(1);
111
+ });
package/index.js ADDED
@@ -0,0 +1,116 @@
1
+ #!/usr/bin/env node
2
+
3
+ /**
4
+ * MCP HTTP Client - stdio to HTTP bridge for MCP servers
5
+ * Bridges stdio-based MCP clients (like Claude Code) to HTTP-only JSON-RPC MCP servers
6
+ */
7
+
8
+ const readline = require('readline');
9
+ const https = require('https');
10
+ const http = require('http');
11
+
12
+ // Configuration from environment variables
13
+ const MCP_API_URL = process.env.MCP_API_URL;
14
+ const MCP_PROJECT_ID = process.env.MCP_PROJECT_ID;
15
+ const MCP_USER_API_KEY = process.env.MCP_USER_API_KEY;
16
+
17
+ if (!MCP_API_URL || !MCP_PROJECT_ID || !MCP_USER_API_KEY) {
18
+ process.stderr.write('Error: Missing required environment variables\n');
19
+ process.stderr.write('Required: MCP_API_URL, MCP_PROJECT_ID, MCP_USER_API_KEY\n');
20
+ process.exit(1);
21
+ }
22
+
23
+ // Parse URL
24
+ const url = new URL(MCP_API_URL);
25
+ const isHttps = url.protocol === 'https:';
26
+ const httpModule = isHttps ? https : http;
27
+
28
+ // Read JSON-RPC requests from stdin, forward to HTTP endpoint, write responses to stdout
29
+ const rl = readline.createInterface({
30
+ input: process.stdin,
31
+ terminal: false
32
+ });
33
+
34
+ rl.on('line', async (line) => {
35
+ try {
36
+ // Parse JSON-RPC request from stdin
37
+ const jsonrpcRequest = JSON.parse(line);
38
+
39
+ // Forward to HTTP endpoint
40
+ const requestBody = JSON.stringify(jsonrpcRequest);
41
+ const options = {
42
+ hostname: url.hostname,
43
+ port: url.port || (isHttps ? 443 : 80),
44
+ path: url.pathname,
45
+ method: 'POST',
46
+ headers: {
47
+ 'Content-Type': 'application/json',
48
+ 'Content-Length': Buffer.byteLength(requestBody),
49
+ 'x-project-id': MCP_PROJECT_ID,
50
+ 'x-user-api-key': MCP_USER_API_KEY,
51
+ 'MCP-Protocol-Version': '2025-06-18'
52
+ },
53
+ // Disable SSL certificate validation (Windows SSL issues)
54
+ rejectUnauthorized: false
55
+ };
56
+
57
+ const req = httpModule.request(options, (res) => {
58
+ let data = '';
59
+
60
+ res.on('data', (chunk) => {
61
+ data += chunk;
62
+ });
63
+
64
+ res.on('end', () => {
65
+ try {
66
+ // Write JSON-RPC response to stdout (one line, newline terminated)
67
+ const output = data.trim() + '\n';
68
+ process.stdout.write(output, () => {
69
+ // Flush completed
70
+ });
71
+ } catch (error) {
72
+ const errorResponse = {
73
+ jsonrpc: '2.0',
74
+ id: jsonrpcRequest.id,
75
+ error: {
76
+ code: -32603,
77
+ message: 'Internal error: Failed to parse server response'
78
+ }
79
+ };
80
+ process.stdout.write(JSON.stringify(errorResponse) + '\n', () => {
81
+ // Flush completed
82
+ });
83
+ }
84
+ });
85
+ });
86
+
87
+ req.on('error', (error) => {
88
+ const errorResponse = {
89
+ jsonrpc: '2.0',
90
+ id: jsonrpcRequest.id,
91
+ error: {
92
+ code: -32603,
93
+ message: `HTTP request failed: ${error.message}`
94
+ }
95
+ };
96
+ process.stdout.write(JSON.stringify(errorResponse) + '\n');
97
+ });
98
+
99
+ req.write(requestBody);
100
+ req.end();
101
+ } catch (error) {
102
+ const errorResponse = {
103
+ jsonrpc: '2.0',
104
+ id: null,
105
+ error: {
106
+ code: -32700,
107
+ message: 'Parse error'
108
+ }
109
+ };
110
+ process.stdout.write(JSON.stringify(errorResponse) + '\n');
111
+ }
112
+ });
113
+
114
+ rl.on('close', () => {
115
+ process.exit(0);
116
+ });
package/package.json ADDED
@@ -0,0 +1,40 @@
1
+ {
2
+ "name": "taskr-mcp-client",
3
+ "version": "1.0.0",
4
+ "description": "stdio to HTTP bridge for Taskr MCP server - connects Claude Code to HTTP-only JSON-RPC MCP endpoints",
5
+ "main": "index.js",
6
+ "bin": {
7
+ "taskr-mcp-client": "./index.js"
8
+ },
9
+ "scripts": {
10
+ "test": "echo \"Error: no test specified\" && exit 1"
11
+ },
12
+ "keywords": [
13
+ "taskr",
14
+ "mcp",
15
+ "model-context-protocol",
16
+ "json-rpc",
17
+ "bridge",
18
+ "stdio",
19
+ "http",
20
+ "ai",
21
+ "task-management"
22
+ ],
23
+ "author": "Taskr Team",
24
+ "license": "MIT",
25
+ "repository": {
26
+ "type": "git",
27
+ "url": "https://github.com/echo-of-machines/Taskr.git",
28
+ "directory": "mcp-http-client"
29
+ },
30
+ "homepage": "https://github.com/echo-of-machines/Taskr#readme",
31
+ "bugs": {
32
+ "url": "https://github.com/echo-of-machines/Taskr/issues"
33
+ },
34
+ "engines": {
35
+ "node": ">=14.0.0"
36
+ },
37
+ "dependencies": {
38
+ "@modelcontextprotocol/sdk": "^1.20.2"
39
+ }
40
+ }
package/test-stdin.js ADDED
@@ -0,0 +1,20 @@
1
+ const readline = require('readline');
2
+
3
+ console.error('Starting test...');
4
+
5
+ const rl = readline.createInterface({
6
+ input: process.stdin,
7
+ terminal: false
8
+ });
9
+
10
+ rl.on('line', (line) => {
11
+ console.error(`Got line: ${line}`);
12
+ console.log(`ECHO: ${line}`);
13
+ });
14
+
15
+ rl.on('close', () => {
16
+ console.error('Stdin closed');
17
+ process.exit(0);
18
+ });
19
+
20
+ console.error('Waiting for input...');
package/test.js ADDED
@@ -0,0 +1,52 @@
1
+ const https = require('https');
2
+
3
+ const url = new URL('https://taskr-six.vercel.app/api/mcp');
4
+
5
+ const data = JSON.stringify({
6
+ jsonrpc: '2.0',
7
+ id: 1,
8
+ method: 'tools/list',
9
+ params: {}
10
+ });
11
+
12
+ const options = {
13
+ hostname: url.hostname,
14
+ port: 443,
15
+ path: url.pathname,
16
+ method: 'POST',
17
+ headers: {
18
+ 'Content-Type': 'application/json',
19
+ 'Content-Length': data.length,
20
+ 'x-project-id': 'PRMGYS22KCZPJ0KRIQM100000000',
21
+ 'x-user-api-key': '89cab946b8d6e51b38db993ba1441d617a06ff55e6f8c7174d0f6dd61d424bf2',
22
+ 'MCP-Protocol-Version': '2025-06-18'
23
+ },
24
+ rejectUnauthorized: false
25
+ };
26
+
27
+ console.error('Making request to:', url.href);
28
+ console.error('Options:', JSON.stringify(options, null, 2));
29
+
30
+ const req = https.request(options, (res) => {
31
+ console.error('Status:', res.statusCode);
32
+ console.error('Headers:', JSON.stringify(res.headers, null, 2));
33
+
34
+ let responseData = '';
35
+
36
+ res.on('data', (chunk) => {
37
+ responseData += chunk;
38
+ });
39
+
40
+ res.on('end', () => {
41
+ console.error('Response length:', responseData.length);
42
+ console.log(responseData);
43
+ });
44
+ });
45
+
46
+ req.on('error', (error) => {
47
+ console.error('Request error:', error.message);
48
+ process.exit(1);
49
+ });
50
+
51
+ req.write(data);
52
+ req.end();