tunnel-mcp 0.1.8 → 0.1.9
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/CHANGELOG.md +12 -1
- package/README.md +6 -5
- package/dist/invite.d.ts +11 -0
- package/dist/invite.js +19 -0
- package/dist/session.d.ts +1 -0
- package/dist/session.js +4 -1
- package/dist/tools.js +1 -1
- package/package.json +1 -1
package/CHANGELOG.md
CHANGED
|
@@ -11,6 +11,16 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
|
|
|
11
11
|
|
|
12
12
|
- Nothing yet.
|
|
13
13
|
|
|
14
|
+
## [0.1.9] - 2026-07-02
|
|
15
|
+
|
|
16
|
+
### Added
|
|
17
|
+
|
|
18
|
+
- **`tunnel_open` now returns `invite`** — a ready-to-forward plain-text message
|
|
19
|
+
containing the one-time setup command (`claude mcp add tunnel -- npx -y
|
|
20
|
+
tunnel-mcp`) and the join link, so the host's human can paste one message to
|
|
21
|
+
the other developer instead of explaining the install. The tool description
|
|
22
|
+
directs the agent to relay it verbatim.
|
|
23
|
+
|
|
14
24
|
## [0.1.8] - 2026-07-02
|
|
15
25
|
|
|
16
26
|
### Added
|
|
@@ -171,7 +181,8 @@ install-skill` copies the `tunnel-etiquette` skill into `~/.claude/skills`
|
|
|
171
181
|
declaring a fix "confirmed".
|
|
172
182
|
- Test suite of 109 tests built with vitest, developed test-first (TDD).
|
|
173
183
|
|
|
174
|
-
[Unreleased]: https://github.com/zachlikefolio/tunnel-mcp/compare/v0.1.
|
|
184
|
+
[Unreleased]: https://github.com/zachlikefolio/tunnel-mcp/compare/v0.1.9...HEAD
|
|
185
|
+
[0.1.9]: https://github.com/zachlikefolio/tunnel-mcp/compare/v0.1.8...v0.1.9
|
|
175
186
|
[0.1.8]: https://github.com/zachlikefolio/tunnel-mcp/compare/v0.1.7...v0.1.8
|
|
176
187
|
[0.1.7]: https://github.com/zachlikefolio/tunnel-mcp/compare/v0.1.6...v0.1.7
|
|
177
188
|
[0.1.6]: https://github.com/zachlikefolio/tunnel-mcp/compare/v0.1.5...v0.1.6
|
package/README.md
CHANGED
|
@@ -96,11 +96,12 @@ it isn't already on your `PATH` — there's nothing extra to install.
|
|
|
96
96
|
|
|
97
97
|
> "Open a tunnel to pair on debugging the checkout flow."
|
|
98
98
|
|
|
99
|
-
Claude calls `tunnel_open({ goal })` and
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
**
|
|
103
|
-
|
|
99
|
+
Claude calls `tunnel_open({ goal })` and hands back a ready-to-forward
|
|
100
|
+
**invite** — one plain-text message containing the one-time setup command and
|
|
101
|
+
the join link. Paste it to the other developer over a trusted channel (Slack
|
|
102
|
+
DM, etc.) — **the link is a secret**, since it contains the encryption key for
|
|
103
|
+
the session. It is **single-use and expires after ~10 minutes**
|
|
104
|
+
(`tunnel_open` reports `joinLinkExpiresInSec`), so share it promptly.
|
|
104
105
|
|
|
105
106
|
**Guest** — paste the link and ask Claude to join:
|
|
106
107
|
|
package/dist/invite.d.ts
ADDED
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The ready-to-forward invite a host's human sends to the other developer.
|
|
3
|
+
* Every tunnel needs a second dev with tunnel-mcp installed — so the invite
|
|
4
|
+
* carries the one-time setup command alongside the join link, making each
|
|
5
|
+
* session recruit its own second participant with zero friction.
|
|
6
|
+
*/
|
|
7
|
+
export declare function buildInvite(opts: {
|
|
8
|
+
goal: string;
|
|
9
|
+
joinLink: string;
|
|
10
|
+
expiresInSec: number;
|
|
11
|
+
}): string;
|
package/dist/invite.js
ADDED
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The ready-to-forward invite a host's human sends to the other developer.
|
|
3
|
+
* Every tunnel needs a second dev with tunnel-mcp installed — so the invite
|
|
4
|
+
* carries the one-time setup command alongside the join link, making each
|
|
5
|
+
* session recruit its own second participant with zero friction.
|
|
6
|
+
*/
|
|
7
|
+
export function buildInvite(opts) {
|
|
8
|
+
const mins = Math.max(1, Math.ceil(opts.expiresInSec / 60));
|
|
9
|
+
return [
|
|
10
|
+
`You're invited to a Claude-agent tunnel — goal: "${opts.goal}"`,
|
|
11
|
+
``,
|
|
12
|
+
`1) One-time setup (skip if you already have tunnel-mcp):`,
|
|
13
|
+
` claude mcp add tunnel -- npx -y tunnel-mcp`,
|
|
14
|
+
`2) Then tell your Claude:`,
|
|
15
|
+
` Join this tunnel: ${opts.joinLink}`,
|
|
16
|
+
``,
|
|
17
|
+
`The link is single-use and expires in ~${mins} minute${mins === 1 ? '' : 's'}.`,
|
|
18
|
+
].join('\n');
|
|
19
|
+
}
|
package/dist/session.d.ts
CHANGED
package/dist/session.js
CHANGED
|
@@ -7,6 +7,7 @@ import { GuestClient } from './relay/guestClient.js';
|
|
|
7
7
|
import { ensureCloudflared as realEnsure } from './cloudflared/provision.js';
|
|
8
8
|
import { startCloudflared as realStart } from './cloudflared/tunnelProcess.js';
|
|
9
9
|
import { DEFAULT_LISTEN_TIMEOUT_MS, DEFAULT_IDLE_TEARDOWN_MS, DEFAULT_JOIN_LINK_TTL_MS, OPEN_RETRY_ATTEMPTS, } from './config.js';
|
|
10
|
+
import { buildInvite } from './invite.js';
|
|
10
11
|
const DEFAULT_DEPS = {
|
|
11
12
|
ensureCloudflared: realEnsure,
|
|
12
13
|
startCloudflared: (bin, port) => realStart(bin, port),
|
|
@@ -76,11 +77,13 @@ export class TunnelSession {
|
|
|
76
77
|
void this.close();
|
|
77
78
|
});
|
|
78
79
|
relay.submitLocal(buildSystem('host', `tunnel opened — goal: ${goal}`));
|
|
80
|
+
const joinLinkExpiresInSec = Math.round(joinTtlMs / 1000);
|
|
79
81
|
return {
|
|
80
82
|
tunnelId,
|
|
81
83
|
joinLink,
|
|
82
84
|
status: 'waiting_for_guest',
|
|
83
|
-
joinLinkExpiresInSec
|
|
85
|
+
joinLinkExpiresInSec,
|
|
86
|
+
invite: buildInvite({ goal, joinLink, expiresInSec: joinLinkExpiresInSec }),
|
|
84
87
|
};
|
|
85
88
|
}
|
|
86
89
|
async join(joinLink, guestName) {
|
package/dist/tools.js
CHANGED
|
@@ -28,7 +28,7 @@ function register(server, name, schema, cb) {
|
|
|
28
28
|
}
|
|
29
29
|
export function registerTools(server, session, opts) {
|
|
30
30
|
register(server, 'tunnel_open', {
|
|
31
|
-
description: 'Open a tunnel as host and get a join link to share. The link is a secret — share it over a trusted channel. It is single-use (works for exactly one guest) and expires (see joinLinkExpiresInSec in the result), so tell the human to share it promptly.',
|
|
31
|
+
description: 'Open a tunnel as host and get a join link to share. The link is a secret — share it over a trusted channel. It is single-use (works for exactly one guest) and expires (see joinLinkExpiresInSec in the result), so tell the human to share it promptly. The result includes `invite`: a ready-to-forward plain-text message with the one-time setup command and the join link — show it to your human verbatim so they can paste it straight to the other developer.',
|
|
32
32
|
inputSchema: { goal: z.string() },
|
|
33
33
|
}, async ({ goal }) => ok(await session.open(goal, opts.displayName)));
|
|
34
34
|
register(server, 'tunnel_join', {
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "tunnel-mcp",
|
|
3
3
|
"mcpName": "io.github.zachlikefolio/tunnel-mcp",
|
|
4
|
-
"version": "0.1.
|
|
4
|
+
"version": "0.1.9",
|
|
5
5
|
"description": "Let two developers' Claude agents talk directly through an ephemeral, end-to-end-encrypted tunnel.",
|
|
6
6
|
"type": "module",
|
|
7
7
|
"bin": {
|