@rsv_ink/ink-hub-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/LICENSE +21 -0
- package/README.md +54 -0
- package/dist/index.js +143 -0
- package/package.json +57 -0
package/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 João Alves
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
package/README.md
ADDED
|
@@ -0,0 +1,54 @@
|
|
|
1
|
+
# @rsv_ink/ink-hub-mcp
|
|
2
|
+
|
|
3
|
+
Cliente local que conecta Claude Desktop, Cursor e Zed ao servidor MCP do **Ink Hub**.
|
|
4
|
+
|
|
5
|
+
Clientes como o Claude Desktop só falam MCP via `stdio` — eles não conseguem se conectar diretamente a um servidor MCP remoto. Este pacote roda na sua máquina, recebe os comandos via `stdio` e repassa tudo para o servidor do Ink Hub de forma transparente.
|
|
6
|
+
|
|
7
|
+
## Uso
|
|
8
|
+
|
|
9
|
+
Não precisa instalar nada. Adicione esse bloco no `claude_desktop_config.json` (ou config equivalente do Cursor / Zed):
|
|
10
|
+
|
|
11
|
+
```json
|
|
12
|
+
{
|
|
13
|
+
"mcpServers": {
|
|
14
|
+
"ink-hub": {
|
|
15
|
+
"command": "npx",
|
|
16
|
+
"args": ["-y", "@rsv_ink/ink-hub-mcp"],
|
|
17
|
+
"env": {
|
|
18
|
+
"INK_HUB_URL": "https://seu-ink-hub.exemplo.com",
|
|
19
|
+
"MCP_AUTH_TOKEN": "seu-token"
|
|
20
|
+
}
|
|
21
|
+
}
|
|
22
|
+
}
|
|
23
|
+
}
|
|
24
|
+
```
|
|
25
|
+
|
|
26
|
+
Reinicie o cliente MCP — pronto.
|
|
27
|
+
|
|
28
|
+
## Variáveis de ambiente
|
|
29
|
+
|
|
30
|
+
| Variável | Obrigatória | Descrição |
|
|
31
|
+
| ---------------- | ----------- | -------------------------------------------------------- |
|
|
32
|
+
| `INK_HUB_URL` | sim | URL base do servidor Ink Hub (sem barra final). |
|
|
33
|
+
| `MCP_AUTH_TOKEN` | sim | Token enviado em `Authorization: Bearer <token>`. |
|
|
34
|
+
| `DEBUG` | não | `true` para logar todas as mensagens MCP em `stderr`. |
|
|
35
|
+
|
|
36
|
+
## Desenvolvimento
|
|
37
|
+
|
|
38
|
+
```bash
|
|
39
|
+
git clone https://github.com/rsv-ink/ink-hub-mcp.git
|
|
40
|
+
cd ink-hub-mcp
|
|
41
|
+
npm install
|
|
42
|
+
npm test
|
|
43
|
+
npm run build
|
|
44
|
+
```
|
|
45
|
+
|
|
46
|
+
Para subir o proxy localmente:
|
|
47
|
+
|
|
48
|
+
```bash
|
|
49
|
+
INK_HUB_URL=https://... MCP_AUTH_TOKEN=... npm run dev
|
|
50
|
+
```
|
|
51
|
+
|
|
52
|
+
## Licença
|
|
53
|
+
|
|
54
|
+
MIT — veja [LICENSE](./LICENSE).
|
package/dist/index.js
ADDED
|
@@ -0,0 +1,143 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
|
|
3
|
+
// src/index.ts
|
|
4
|
+
import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio.js";
|
|
5
|
+
import { JSONRPCRequestSchema } from "@modelcontextprotocol/sdk/types.js";
|
|
6
|
+
|
|
7
|
+
// src/transport.ts
|
|
8
|
+
import { StreamableHTTPClientTransport } from "@modelcontextprotocol/sdk/client/streamableHttp.js";
|
|
9
|
+
var isDebug = process.env.DEBUG === "true";
|
|
10
|
+
var InkHubTransport = class {
|
|
11
|
+
constructor(baseUrl, authToken) {
|
|
12
|
+
this.baseUrl = baseUrl;
|
|
13
|
+
this.authToken = authToken;
|
|
14
|
+
const authHeaders = {
|
|
15
|
+
Authorization: `Bearer ${this.authToken}`
|
|
16
|
+
};
|
|
17
|
+
this.client = new StreamableHTTPClientTransport(this.baseUrl, {
|
|
18
|
+
requestInit: {
|
|
19
|
+
headers: authHeaders
|
|
20
|
+
}
|
|
21
|
+
});
|
|
22
|
+
this.client.onmessage = (message) => {
|
|
23
|
+
if (isDebug) console.error(`[DEBUG-MCP-RECV] <- ${JSON.stringify(message)}`);
|
|
24
|
+
this.onmessage?.(message);
|
|
25
|
+
};
|
|
26
|
+
this.client.onerror = (error) => {
|
|
27
|
+
console.error("[TRANSPORT-ERROR] HTTP Transport error:", error);
|
|
28
|
+
this.onerror?.(error);
|
|
29
|
+
};
|
|
30
|
+
this.client.onclose = () => {
|
|
31
|
+
if (isDebug) console.error("[DEBUG-MCP-CLOSE] Remote SSE connection closed");
|
|
32
|
+
this.onclose?.();
|
|
33
|
+
};
|
|
34
|
+
}
|
|
35
|
+
baseUrl;
|
|
36
|
+
authToken;
|
|
37
|
+
client;
|
|
38
|
+
onclose;
|
|
39
|
+
onerror;
|
|
40
|
+
onmessage;
|
|
41
|
+
async start() {
|
|
42
|
+
if (isDebug) console.error(`[DEBUG-MCP-START] Connecting to ${this.baseUrl.toString()}`);
|
|
43
|
+
await this.client.start();
|
|
44
|
+
}
|
|
45
|
+
async close() {
|
|
46
|
+
if (isDebug) console.error("[DEBUG-MCP-CLOSE] Closing remote connection");
|
|
47
|
+
await this.client.close();
|
|
48
|
+
}
|
|
49
|
+
async send(message) {
|
|
50
|
+
if (isDebug) console.error(`[DEBUG-MCP-SEND] -> ${JSON.stringify(message)}`);
|
|
51
|
+
await this.client.send(message);
|
|
52
|
+
}
|
|
53
|
+
};
|
|
54
|
+
|
|
55
|
+
// src/index.ts
|
|
56
|
+
import process2 from "process";
|
|
57
|
+
async function run() {
|
|
58
|
+
const serverUrlStr = process2.env.INK_HUB_URL;
|
|
59
|
+
const authToken = process2.env.MCP_AUTH_TOKEN;
|
|
60
|
+
if (!serverUrlStr) {
|
|
61
|
+
console.error("Error: INK_HUB_URL environment variable is not set.");
|
|
62
|
+
console.error("Set INK_HUB_URL in the MCP client config to point to your Ink Hub server.");
|
|
63
|
+
process2.exit(1);
|
|
64
|
+
}
|
|
65
|
+
if (!authToken) {
|
|
66
|
+
console.error("Error: MCP_AUTH_TOKEN environment variable is not set.");
|
|
67
|
+
process2.exit(1);
|
|
68
|
+
}
|
|
69
|
+
let serverUrl;
|
|
70
|
+
try {
|
|
71
|
+
serverUrl = new URL(`${serverUrlStr.replace(/\/$/, "")}/api/mcp`);
|
|
72
|
+
} catch (error) {
|
|
73
|
+
console.error(
|
|
74
|
+
`Error: Invalid INK_HUB_URL ("${serverUrlStr}"). Must be a valid URL.`
|
|
75
|
+
);
|
|
76
|
+
process2.exit(1);
|
|
77
|
+
}
|
|
78
|
+
const remoteTransport = new InkHubTransport(serverUrl, authToken);
|
|
79
|
+
remoteTransport.onerror = (error) => {
|
|
80
|
+
console.error(
|
|
81
|
+
"Warning: connection issue with the Ink Hub server:",
|
|
82
|
+
error.message
|
|
83
|
+
);
|
|
84
|
+
};
|
|
85
|
+
remoteTransport.onclose = () => {
|
|
86
|
+
console.error(
|
|
87
|
+
"Connection to the Ink Hub server was closed. The server may have timed out or restarted."
|
|
88
|
+
);
|
|
89
|
+
stdioTransport.onclose?.();
|
|
90
|
+
process2.exit(1);
|
|
91
|
+
};
|
|
92
|
+
const stdioTransport = new StdioServerTransport();
|
|
93
|
+
stdioTransport.onerror = (error) => {
|
|
94
|
+
console.error("stdio connection error:", error.message);
|
|
95
|
+
};
|
|
96
|
+
stdioTransport.onclose = () => {
|
|
97
|
+
console.error("stdio connection closed. Shutting down proxy.");
|
|
98
|
+
remoteTransport.close().catch(() => {
|
|
99
|
+
});
|
|
100
|
+
process2.exit(0);
|
|
101
|
+
};
|
|
102
|
+
remoteTransport.onmessage = async (message) => {
|
|
103
|
+
try {
|
|
104
|
+
await stdioTransport.send(message);
|
|
105
|
+
} catch (err) {
|
|
106
|
+
console.error("Error routing message from server to stdio:", err);
|
|
107
|
+
process2.exit(1);
|
|
108
|
+
}
|
|
109
|
+
};
|
|
110
|
+
stdioTransport.onmessage = async (message) => {
|
|
111
|
+
try {
|
|
112
|
+
await remoteTransport.send(message);
|
|
113
|
+
} catch (err) {
|
|
114
|
+
console.error("Error routing message from stdio to server:", err);
|
|
115
|
+
const parsedRequest = JSONRPCRequestSchema.safeParse(message);
|
|
116
|
+
if (parsedRequest.success) {
|
|
117
|
+
await stdioTransport.send({
|
|
118
|
+
jsonrpc: "2.0",
|
|
119
|
+
id: parsedRequest.data.id,
|
|
120
|
+
error: {
|
|
121
|
+
code: -32603,
|
|
122
|
+
message: `Proxy failed to route message: ${err instanceof Error ? err.message : String(err)}`
|
|
123
|
+
}
|
|
124
|
+
}).catch(() => {
|
|
125
|
+
});
|
|
126
|
+
}
|
|
127
|
+
}
|
|
128
|
+
};
|
|
129
|
+
try {
|
|
130
|
+
console.error("Connecting to Ink Hub MCP server...");
|
|
131
|
+
await remoteTransport.start();
|
|
132
|
+
console.error("Connected. Starting stdio transport...");
|
|
133
|
+
await stdioTransport.start();
|
|
134
|
+
} catch (error) {
|
|
135
|
+
const msg = error instanceof Error ? error.message : String(error);
|
|
136
|
+
console.error("Fatal error initializing transports:", msg);
|
|
137
|
+
process2.exit(1);
|
|
138
|
+
}
|
|
139
|
+
}
|
|
140
|
+
run().catch((err) => {
|
|
141
|
+
console.error("Unhandled error in proxy:", err);
|
|
142
|
+
process2.exit(1);
|
|
143
|
+
});
|
package/package.json
ADDED
|
@@ -0,0 +1,57 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@rsv_ink/ink-hub-mcp",
|
|
3
|
+
"version": "0.1.0",
|
|
4
|
+
"description": "Local MCP client that bridges stdio-based MCP clients (Claude Desktop, Cursor, Zed) to the remote Ink Hub MCP server.",
|
|
5
|
+
"keywords": [
|
|
6
|
+
"mcp",
|
|
7
|
+
"model-context-protocol",
|
|
8
|
+
"claude",
|
|
9
|
+
"anthropic",
|
|
10
|
+
"ink-hub",
|
|
11
|
+
"stdio",
|
|
12
|
+
"proxy"
|
|
13
|
+
],
|
|
14
|
+
"license": "MIT",
|
|
15
|
+
"author": "João Alves <joao.alves@reserva.ink>",
|
|
16
|
+
"repository": {
|
|
17
|
+
"type": "git",
|
|
18
|
+
"url": "git+https://github.com/rsv-ink/ink-hub-mcp.git"
|
|
19
|
+
},
|
|
20
|
+
"bugs": {
|
|
21
|
+
"url": "https://github.com/rsv-ink/ink-hub-mcp/issues"
|
|
22
|
+
},
|
|
23
|
+
"homepage": "https://github.com/rsv-ink/ink-hub-mcp#readme",
|
|
24
|
+
"main": "dist/index.js",
|
|
25
|
+
"bin": {
|
|
26
|
+
"ink-hub-mcp": "dist/index.js"
|
|
27
|
+
},
|
|
28
|
+
"type": "module",
|
|
29
|
+
"files": [
|
|
30
|
+
"dist",
|
|
31
|
+
"README.md",
|
|
32
|
+
"LICENSE"
|
|
33
|
+
],
|
|
34
|
+
"engines": {
|
|
35
|
+
"node": ">=18.0.0"
|
|
36
|
+
},
|
|
37
|
+
"publishConfig": {
|
|
38
|
+
"access": "public"
|
|
39
|
+
},
|
|
40
|
+
"scripts": {
|
|
41
|
+
"build": "tsup src/index.ts --format esm --clean",
|
|
42
|
+
"dev": "tsx src/index.ts",
|
|
43
|
+
"test": "vitest run",
|
|
44
|
+
"prepublishOnly": "npm run test && npm run build"
|
|
45
|
+
},
|
|
46
|
+
"dependencies": {
|
|
47
|
+
"@modelcontextprotocol/sdk": "^1.29.0",
|
|
48
|
+
"eventsource": "^4.1.0"
|
|
49
|
+
},
|
|
50
|
+
"devDependencies": {
|
|
51
|
+
"@types/node": "^25.6.2",
|
|
52
|
+
"tsup": "^8.5.1",
|
|
53
|
+
"tsx": "^4.21.0",
|
|
54
|
+
"typescript": "^6.0.3",
|
|
55
|
+
"vitest": "^4.1.5"
|
|
56
|
+
}
|
|
57
|
+
}
|