@tesselunits/mcp-connector 1.0.2
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.dev.md +54 -0
- package/README.md +26 -0
- package/dist/index.d.mts +1 -0
- package/dist/index.d.ts +1 -0
- package/dist/index.js +113 -0
- package/dist/index.mjs +90 -0
- package/package.json +37 -0
package/README.dev.md
ADDED
|
@@ -0,0 +1,54 @@
|
|
|
1
|
+
# Tessel MCP Connector
|
|
2
|
+
|
|
3
|
+
see [README.md](README.md) for usage instructions.
|
|
4
|
+
|
|
5
|
+
## Features
|
|
6
|
+
|
|
7
|
+
- **HTTP Stream Bridge**: Bridges remote Server-Sent Events (SSE) or Fetch-based streams to Stdio.
|
|
8
|
+
- **Auto Session ID**: Manages session continuity automatically.
|
|
9
|
+
- **Authentication**: Supports Bearer token authentication.
|
|
10
|
+
|
|
11
|
+
## Development
|
|
12
|
+
|
|
13
|
+
```bash
|
|
14
|
+
npm install
|
|
15
|
+
npm run build
|
|
16
|
+
```
|
|
17
|
+
|
|
18
|
+
## Deployment
|
|
19
|
+
|
|
20
|
+
This package is automatically published to npm via GitHub Actions.
|
|
21
|
+
|
|
22
|
+
### Manual Release
|
|
23
|
+
|
|
24
|
+
To trigger a new version and publish to npm:
|
|
25
|
+
|
|
26
|
+
1. Go to **GitHub Actions** tab.
|
|
27
|
+
2. Select **Publish MCP Connector**.
|
|
28
|
+
3. Click **Run workflow**.
|
|
29
|
+
4. Choose the `Version type` (patch, minor, or major).
|
|
30
|
+
|
|
31
|
+
The workflow will:
|
|
32
|
+
|
|
33
|
+
- Update the version in `package.json`.
|
|
34
|
+
- Inject the `NEXT_PUBLIC_APP_URL` from GitHub Secrets into the build.
|
|
35
|
+
- Publish the package to npmjs.com.
|
|
36
|
+
|
|
37
|
+
### Local Publication (Alternative)
|
|
38
|
+
|
|
39
|
+
If you need to publish manually from your local machine:
|
|
40
|
+
|
|
41
|
+
```bash
|
|
42
|
+
# 1. Ensure you are logged in to npm
|
|
43
|
+
npm login
|
|
44
|
+
|
|
45
|
+
# 2. Build with the target app URL
|
|
46
|
+
NEXT_PUBLIC_APP_URL=https://your-app.com npm run build
|
|
47
|
+
|
|
48
|
+
# 3. Publish
|
|
49
|
+
npm publish --access public
|
|
50
|
+
```
|
|
51
|
+
|
|
52
|
+
## License
|
|
53
|
+
|
|
54
|
+
MIT
|
package/README.md
ADDED
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
# Tessel Units MCP Connector
|
|
2
|
+
|
|
3
|
+
A bridge to connect to the Tessel Units MCP server at https://tesselunits.art.
|
|
4
|
+
|
|
5
|
+
## Usage
|
|
6
|
+
|
|
7
|
+
Go to your profile page at https://tesselunits.art/en/profile and create/copy your API token.
|
|
8
|
+
|
|
9
|
+
```bash
|
|
10
|
+
npx @tesselunits/mcp-connector <YOUR_API_TOKEN>
|
|
11
|
+
```
|
|
12
|
+
|
|
13
|
+
### Example for Claude Desktop
|
|
14
|
+
|
|
15
|
+
Add the following to your `claude_desktop_config.json`:
|
|
16
|
+
|
|
17
|
+
```json
|
|
18
|
+
{
|
|
19
|
+
"mcpServers": {
|
|
20
|
+
"tessel": {
|
|
21
|
+
"command": "npx",
|
|
22
|
+
"args": ["@tesselunits/mcp-connector", "<YOUR_API_TOKEN>"]
|
|
23
|
+
}
|
|
24
|
+
}
|
|
25
|
+
}
|
|
26
|
+
```
|
package/dist/index.d.mts
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
package/dist/index.js
ADDED
|
@@ -0,0 +1,113 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
"use strict";
|
|
3
|
+
var __create = Object.create;
|
|
4
|
+
var __defProp = Object.defineProperty;
|
|
5
|
+
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
|
|
6
|
+
var __getOwnPropNames = Object.getOwnPropertyNames;
|
|
7
|
+
var __getProtoOf = Object.getPrototypeOf;
|
|
8
|
+
var __hasOwnProp = Object.prototype.hasOwnProperty;
|
|
9
|
+
var __copyProps = (to, from, except, desc) => {
|
|
10
|
+
if (from && typeof from === "object" || typeof from === "function") {
|
|
11
|
+
for (let key of __getOwnPropNames(from))
|
|
12
|
+
if (!__hasOwnProp.call(to, key) && key !== except)
|
|
13
|
+
__defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
|
|
14
|
+
}
|
|
15
|
+
return to;
|
|
16
|
+
};
|
|
17
|
+
var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps(
|
|
18
|
+
// If the importer is in node compatibility mode or this is not an ESM
|
|
19
|
+
// file that has been converted to a CommonJS file using a Babel-
|
|
20
|
+
// compatible transform (i.e. "__esModule" has not been set), then set
|
|
21
|
+
// "default" to the CommonJS "module.exports" for node compatibility.
|
|
22
|
+
isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { value: mod, enumerable: true }) : target,
|
|
23
|
+
mod
|
|
24
|
+
));
|
|
25
|
+
|
|
26
|
+
// src/index.ts
|
|
27
|
+
var import_streamableHttp = require("@modelcontextprotocol/sdk/client/streamableHttp.js");
|
|
28
|
+
var import_stdio = require("@modelcontextprotocol/sdk/server/stdio.js");
|
|
29
|
+
var import_crypto = __toESM(require("crypto"));
|
|
30
|
+
async function main() {
|
|
31
|
+
let url;
|
|
32
|
+
let token;
|
|
33
|
+
const bakedUrl = true ? "https://tesselunits.art" : void 0;
|
|
34
|
+
if (bakedUrl) {
|
|
35
|
+
url = bakedUrl;
|
|
36
|
+
token = process.argv[2];
|
|
37
|
+
} else {
|
|
38
|
+
url = process.argv[2];
|
|
39
|
+
token = process.argv[3];
|
|
40
|
+
}
|
|
41
|
+
if (!url || !token) {
|
|
42
|
+
if (bakedUrl) {
|
|
43
|
+
console.error("Usage: npx tessel-mcp-connector <TOKEN>");
|
|
44
|
+
} else {
|
|
45
|
+
console.error("Usage: npx tessel-mcp-connector <URL> <TOKEN>");
|
|
46
|
+
}
|
|
47
|
+
console.error("");
|
|
48
|
+
console.error("Arguments:");
|
|
49
|
+
if (!bakedUrl) {
|
|
50
|
+
console.error(" URL The base URL of the remote MCP server");
|
|
51
|
+
}
|
|
52
|
+
console.error(" TOKEN Your authentication token");
|
|
53
|
+
process.exit(1);
|
|
54
|
+
}
|
|
55
|
+
if (!url.endsWith("/api/mcp") && !url.includes("/api/mcp?")) {
|
|
56
|
+
const urlObj = new URL(url);
|
|
57
|
+
urlObj.pathname = "/api/mcp";
|
|
58
|
+
url = urlObj.toString();
|
|
59
|
+
}
|
|
60
|
+
const sessionId = import_crypto.default.randomUUID();
|
|
61
|
+
let connectionUrl;
|
|
62
|
+
try {
|
|
63
|
+
connectionUrl = new URL(url);
|
|
64
|
+
} catch {
|
|
65
|
+
console.error(`Invalid URL: ${url}`);
|
|
66
|
+
process.exit(1);
|
|
67
|
+
}
|
|
68
|
+
connectionUrl.searchParams.set("sessionId", sessionId);
|
|
69
|
+
connectionUrl.searchParams.set("token", token);
|
|
70
|
+
console.error(`[Bridge] Connecting to ${connectionUrl.origin}${connectionUrl.pathname}...`);
|
|
71
|
+
const transport = new import_streamableHttp.StreamableHTTPClientTransport(connectionUrl, {
|
|
72
|
+
sessionId,
|
|
73
|
+
requestInit: {
|
|
74
|
+
headers: { "Authorization": `Bearer ${token}` }
|
|
75
|
+
}
|
|
76
|
+
});
|
|
77
|
+
try {
|
|
78
|
+
await transport.start();
|
|
79
|
+
console.error("[Bridge] HTTP Transport connected");
|
|
80
|
+
const stdioTransport = new import_stdio.StdioServerTransport();
|
|
81
|
+
stdioTransport.onmessage = async (message) => {
|
|
82
|
+
await transport.send(message);
|
|
83
|
+
};
|
|
84
|
+
transport.onmessage = async (message) => {
|
|
85
|
+
await stdioTransport.send(message);
|
|
86
|
+
};
|
|
87
|
+
await stdioTransport.start();
|
|
88
|
+
console.error("[Bridge] Stdio Transport started. Bridge is active.");
|
|
89
|
+
transport.onclose = () => {
|
|
90
|
+
console.error("[Bridge] Closed by server.");
|
|
91
|
+
process.exit(0);
|
|
92
|
+
};
|
|
93
|
+
stdioTransport.onclose = () => {
|
|
94
|
+
console.error("[Bridge] Closed by stdio.");
|
|
95
|
+
process.exit(0);
|
|
96
|
+
};
|
|
97
|
+
process.on("SIGINT", () => {
|
|
98
|
+
console.error("[Bridge] Caught interrupt signal");
|
|
99
|
+
process.exit(0);
|
|
100
|
+
});
|
|
101
|
+
process.on("SIGTERM", () => {
|
|
102
|
+
console.error("[Bridge] Caught terminate signal");
|
|
103
|
+
process.exit(0);
|
|
104
|
+
});
|
|
105
|
+
} catch (error) {
|
|
106
|
+
console.error("[Bridge] Failed to connect:", error);
|
|
107
|
+
process.exit(1);
|
|
108
|
+
}
|
|
109
|
+
}
|
|
110
|
+
main().catch((err) => {
|
|
111
|
+
console.error("Unexpected error:", err);
|
|
112
|
+
process.exit(1);
|
|
113
|
+
});
|
package/dist/index.mjs
ADDED
|
@@ -0,0 +1,90 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
|
|
3
|
+
// src/index.ts
|
|
4
|
+
import { StreamableHTTPClientTransport } from "@modelcontextprotocol/sdk/client/streamableHttp.js";
|
|
5
|
+
import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio.js";
|
|
6
|
+
import crypto from "crypto";
|
|
7
|
+
async function main() {
|
|
8
|
+
let url;
|
|
9
|
+
let token;
|
|
10
|
+
const bakedUrl = true ? "https://tesselunits.art" : void 0;
|
|
11
|
+
if (bakedUrl) {
|
|
12
|
+
url = bakedUrl;
|
|
13
|
+
token = process.argv[2];
|
|
14
|
+
} else {
|
|
15
|
+
url = process.argv[2];
|
|
16
|
+
token = process.argv[3];
|
|
17
|
+
}
|
|
18
|
+
if (!url || !token) {
|
|
19
|
+
if (bakedUrl) {
|
|
20
|
+
console.error("Usage: npx tessel-mcp-connector <TOKEN>");
|
|
21
|
+
} else {
|
|
22
|
+
console.error("Usage: npx tessel-mcp-connector <URL> <TOKEN>");
|
|
23
|
+
}
|
|
24
|
+
console.error("");
|
|
25
|
+
console.error("Arguments:");
|
|
26
|
+
if (!bakedUrl) {
|
|
27
|
+
console.error(" URL The base URL of the remote MCP server");
|
|
28
|
+
}
|
|
29
|
+
console.error(" TOKEN Your authentication token");
|
|
30
|
+
process.exit(1);
|
|
31
|
+
}
|
|
32
|
+
if (!url.endsWith("/api/mcp") && !url.includes("/api/mcp?")) {
|
|
33
|
+
const urlObj = new URL(url);
|
|
34
|
+
urlObj.pathname = "/api/mcp";
|
|
35
|
+
url = urlObj.toString();
|
|
36
|
+
}
|
|
37
|
+
const sessionId = crypto.randomUUID();
|
|
38
|
+
let connectionUrl;
|
|
39
|
+
try {
|
|
40
|
+
connectionUrl = new URL(url);
|
|
41
|
+
} catch {
|
|
42
|
+
console.error(`Invalid URL: ${url}`);
|
|
43
|
+
process.exit(1);
|
|
44
|
+
}
|
|
45
|
+
connectionUrl.searchParams.set("sessionId", sessionId);
|
|
46
|
+
connectionUrl.searchParams.set("token", token);
|
|
47
|
+
console.error(`[Bridge] Connecting to ${connectionUrl.origin}${connectionUrl.pathname}...`);
|
|
48
|
+
const transport = new StreamableHTTPClientTransport(connectionUrl, {
|
|
49
|
+
sessionId,
|
|
50
|
+
requestInit: {
|
|
51
|
+
headers: { "Authorization": `Bearer ${token}` }
|
|
52
|
+
}
|
|
53
|
+
});
|
|
54
|
+
try {
|
|
55
|
+
await transport.start();
|
|
56
|
+
console.error("[Bridge] HTTP Transport connected");
|
|
57
|
+
const stdioTransport = new StdioServerTransport();
|
|
58
|
+
stdioTransport.onmessage = async (message) => {
|
|
59
|
+
await transport.send(message);
|
|
60
|
+
};
|
|
61
|
+
transport.onmessage = async (message) => {
|
|
62
|
+
await stdioTransport.send(message);
|
|
63
|
+
};
|
|
64
|
+
await stdioTransport.start();
|
|
65
|
+
console.error("[Bridge] Stdio Transport started. Bridge is active.");
|
|
66
|
+
transport.onclose = () => {
|
|
67
|
+
console.error("[Bridge] Closed by server.");
|
|
68
|
+
process.exit(0);
|
|
69
|
+
};
|
|
70
|
+
stdioTransport.onclose = () => {
|
|
71
|
+
console.error("[Bridge] Closed by stdio.");
|
|
72
|
+
process.exit(0);
|
|
73
|
+
};
|
|
74
|
+
process.on("SIGINT", () => {
|
|
75
|
+
console.error("[Bridge] Caught interrupt signal");
|
|
76
|
+
process.exit(0);
|
|
77
|
+
});
|
|
78
|
+
process.on("SIGTERM", () => {
|
|
79
|
+
console.error("[Bridge] Caught terminate signal");
|
|
80
|
+
process.exit(0);
|
|
81
|
+
});
|
|
82
|
+
} catch (error) {
|
|
83
|
+
console.error("[Bridge] Failed to connect:", error);
|
|
84
|
+
process.exit(1);
|
|
85
|
+
}
|
|
86
|
+
}
|
|
87
|
+
main().catch((err) => {
|
|
88
|
+
console.error("Unexpected error:", err);
|
|
89
|
+
process.exit(1);
|
|
90
|
+
});
|
package/package.json
ADDED
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@tesselunits/mcp-connector",
|
|
3
|
+
"version": "1.0.2",
|
|
4
|
+
"description": "A bridge to connect Model Context Protocol (MCP) servers over HTTP streams to local Stdio",
|
|
5
|
+
"main": "./dist/index.js",
|
|
6
|
+
"module": "./dist/index.mjs",
|
|
7
|
+
"types": "./dist/index.d.ts",
|
|
8
|
+
"bin": {
|
|
9
|
+
"tessel-mcp-connector": "./dist/index.js"
|
|
10
|
+
},
|
|
11
|
+
"files": [
|
|
12
|
+
"dist",
|
|
13
|
+
"README.md"
|
|
14
|
+
],
|
|
15
|
+
"scripts": {
|
|
16
|
+
"build": "tsup src/index.ts --clean --format cjs,esm --dts --define.MCP_URL=\"\\\"$NEXT_PUBLIC_APP_URL\\\"\"",
|
|
17
|
+
"build:local": "NEXT_PUBLIC_APP_URL=$(grep NEXT_PUBLIC_APP_URL ../../.env.local | cut -d '=' -f2) npm run build",
|
|
18
|
+
"dev": "tsup src/index.ts --format cjs,esm --watch --dts",
|
|
19
|
+
"start": "node dist/index.js",
|
|
20
|
+
"lint": "tsc --noEmit"
|
|
21
|
+
},
|
|
22
|
+
"keywords": [
|
|
23
|
+
"mcp",
|
|
24
|
+
"model-context-protocol",
|
|
25
|
+
"bridge",
|
|
26
|
+
"tessel-units"
|
|
27
|
+
],
|
|
28
|
+
"author": "TesselUnits",
|
|
29
|
+
"license": "MIT",
|
|
30
|
+
"dependencies": {
|
|
31
|
+
"@modelcontextprotocol/sdk": "^1.1.0"
|
|
32
|
+
},
|
|
33
|
+
"devDependencies": {
|
|
34
|
+
"typescript": "^5.0.0",
|
|
35
|
+
"tsup": "^8.0.0"
|
|
36
|
+
}
|
|
37
|
+
}
|