@remcp/remcp 0.1.2 → 0.1.3

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 CHANGED
@@ -11,17 +11,15 @@ ReMCP is an open-source remote MCP bridge for computers you control. A lightweig
11
11
 
12
12
  Requires Node.js 22.5 or newer.
13
13
 
14
- 1. Sign in at <https://remcp.delio24.com> and generate a one-time pairing command.
15
- 2. Run it on the computer you want to connect:
14
+ 1. Install the CLI:
16
15
 
17
16
  ```bash
18
- npx --yes @remcp/remcp@latest connect \
19
- --server https://remcp.delio24.com \
20
- --code YOUR_PAIRING_CODE \
21
- --install
17
+ npm install --global @remcp/remcp@latest
22
18
  ```
23
19
 
24
- 3. Verify the persistent agent:
20
+ 2. Open <https://remcp.delio24.com/#connect>, sign in with Google or GitHub, and choose **Generate pairing command**. Run the exact generated command on the computer you want to pair.
21
+
22
+ 3. Verify:
25
23
 
26
24
  ```bash
27
25
  remcp --version
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@remcp/remcp",
3
- "version": "0.1.2",
3
+ "version": "0.1.3",
4
4
  "description": "Self-hosted remote MCP bridge for securely controlling your own computers from MCP clients.",
5
5
  "type": "module",
6
6
  "license": "MIT",
package/plugin.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "$schema": "https://agent-plugins.org/schemas/1.0.0/plugin.schema.json",
3
3
  "name": "remcp",
4
- "version": "0.1.2",
4
+ "version": "0.1.3",
5
5
  "description": "Securely use files, directories, searches, terminal sessions, and processes on computers you have paired with ReMCP.",
6
6
  "homepage": "https://remcp.delio24.com",
7
7
  "repository": "https://github.com/antonbaider/remcp",
package/public/app.js CHANGED
@@ -1,37 +1,37 @@
1
1
  import { initializeApp } from 'https://www.gstatic.com/firebasejs/10.14.1/firebase-app.js';
2
- import { getAuth, GoogleAuthProvider, onAuthStateChanged, signInWithPopup, signInWithEmailAndPassword, createUserWithEmailAndPassword, signOut } from 'https://www.gstatic.com/firebasejs/10.14.1/firebase-auth.js';
2
+ import { getAuth, GoogleAuthProvider, GithubAuthProvider, onAuthStateChanged, signInWithPopup, signOut } from 'https://www.gstatic.com/firebasejs/10.14.1/firebase-auth.js';
3
3
 
4
4
  const cfg = await fetch(`/api/config?fresh=${Date.now()}`, { cache: 'no-store' }).then(r => r.json());
5
5
  const auth = getAuth(initializeApp(cfg.firebase));
6
6
  const $ = selector => document.querySelector(selector);
7
- const showError = error => { $('#auth-error').textContent = error?.message || String(error); };
8
7
  const googleProvider = new GoogleAuthProvider();
8
+ const githubProvider = new GithubAuthProvider();
9
+ googleProvider.setCustomParameters({ prompt: 'select_account' });
9
10
 
10
- $('#mcp-url').textContent = cfg.mcpUrl;
11
- $('#google').onclick = async () => {
12
- const button = $('#google');
11
+ const friendlyAuthError = error => {
12
+ const code = error?.code || '';
13
+ if (code === 'auth/popup-closed-by-user' || code === 'auth/cancelled-popup-request') return '';
14
+ if (code === 'auth/account-exists-with-different-credential') return 'This email is already linked to another sign-in provider.';
15
+ if (code === 'auth/operation-not-allowed') return 'This sign-in provider is not enabled.';
16
+ return error?.message || String(error);
17
+ };
18
+ const showError = error => { $('#auth-error').textContent = friendlyAuthError(error); };
19
+
20
+ async function signIn(button, provider, idleLabel) {
13
21
  const label = button.querySelector('span');
14
22
  button.disabled = true;
15
23
  $('#auth-error').textContent = '';
16
- label.textContent = 'Opening Google…';
17
- try { await signInWithPopup(auth, googleProvider); }
24
+ label.textContent = 'Opening…';
25
+ try { await signInWithPopup(auth, provider); }
18
26
  catch (error) { showError(error); }
19
- finally { button.disabled = false; label.textContent = 'Continue with Google'; }
20
- };
21
- $('#email-login').onclick = () => signInWithEmailAndPassword(auth, $('#email').value, $('#password').value).catch(showError);
22
- $('#email-register').onclick = () => createUserWithEmailAndPassword(auth, $('#email').value, $('#password').value).catch(showError);
27
+ finally { button.disabled = false; label.textContent = idleLabel; }
28
+ }
29
+
30
+ $('#mcp-url').textContent = cfg.mcpUrl;
31
+ $('#google').onclick = () => signIn($('#google'), googleProvider, 'Continue with Google');
32
+ $('#github').onclick = () => signIn($('#github'), githubProvider, 'Continue with GitHub');
23
33
  $('#logout').onclick = () => signOut(auth);
24
34
 
25
- document.addEventListener('click', async event => {
26
- const button = event.target.closest('[data-copy]');
27
- if (!button) return;
28
- const target = document.querySelector(button.dataset.copy);
29
- if (!target) return;
30
- await navigator.clipboard.writeText(target.textContent.trim());
31
- const original = button.textContent;
32
- button.textContent = 'Copied';
33
- setTimeout(() => { button.textContent = original; }, 1200);
34
- });
35
35
  async function api(path, options = {}) {
36
36
  const token = await auth.currentUser.getIdToken();
37
37
  const response = await fetch(path, { ...options, headers: { ...(options.headers || {}), authorization: `Bearer ${token}`, 'content-type': 'application/json' } });
@@ -70,16 +70,17 @@ async function refreshDevices() {
70
70
  const data = await api('/api/me');
71
71
  const root = $('#devices');
72
72
  root.replaceChildren();
73
- if (!data.devices.length) { root.textContent = 'No devices yet.'; return; }
73
+ if (!data.devices.length) { root.textContent = 'No paired devices.'; return; }
74
74
  for (const device of data.devices) root.append(deviceRow(device));
75
75
  }
76
+
76
77
  $('#pair').onclick = async () => {
77
78
  try {
78
79
  const pairing = await api('/api/pair/create', { method: 'POST', body: '{}' });
79
80
  $('#pairing').classList.remove('hidden');
80
81
  $('#pair-command').textContent = pairing.command;
81
82
  const expiry = new Intl.DateTimeFormat(undefined, { hour: 'numeric', minute: '2-digit' }).format(new Date(pairing.expiresAt));
82
- $('#pair-expiry').textContent = `Expires ${expiry}`;
83
+ $('#pair-expiry').textContent = `One-time command · expires ${expiry}`;
83
84
  } catch (error) { showError(error); }
84
85
  };
85
86
 
@@ -90,6 +91,6 @@ onAuthStateChanged(auth, async user => {
90
91
  $('#dashboard').classList.toggle('hidden', !signedIn);
91
92
  $('#auth-error').textContent = '';
92
93
  if (!signedIn) return;
93
- $('#user-label').textContent = user.email || user.uid;
94
+ $('#user-label').textContent = user.email || user.displayName || user.uid;
94
95
  try { await refreshDevices(); } catch (error) { showError(error); }
95
96
  });
@@ -8,7 +8,7 @@
8
8
  <title>Authorize · ReMCP</title>
9
9
  <meta name="description" content="Authorize an MCP client to access computers paired to your ReMCP account.">
10
10
  <link rel="preconnect" href="https://www.gstatic.com" crossorigin>
11
- <link rel="stylesheet" href="/style.css?v=remcp-012">
11
+ <link rel="stylesheet" href="/style.css?v=remcp-013">
12
12
  <meta property="og:site_name" content="ReMCP">
13
13
  <meta property="og:image" content="https://remcp.delio24.com/assets/og-remcp.png">
14
14
  <link rel="icon" href="/favicon.ico" sizes="any">
@@ -28,29 +28,18 @@
28
28
  <img class="brand-mark" src="/android-chrome-192x192.png" width="30" height="30" alt="" aria-hidden="true">
29
29
  <span translate="no">ReMCP</span>
30
30
  </a>
31
- <nav aria-label="Primary"><a href="/docs">Docs</a><a href="/docs#install">Install</a><a href="/docs#update">Update</a><a href="/security">Security</a><a href="/support">Support</a></nav>
31
+ <nav aria-label="Primary"><a href="/docs">Docs</a><a href="/security">Security</a><a href="/support">Support</a></nav>
32
32
  </header>
33
33
  <main id="oauth-main" class="oauth-shell">
34
34
  <section class="oauth-card">
35
35
  <div id="oauth-login">
36
36
  <p class="eyebrow">Secure authorization</p>
37
37
  <h2 id="oauth-title">Sign in to ReMCP</h2>
38
- <p class="muted">Verify your account before reviewing this MCP client’s access request.</p>
39
- <button id="google" class="button google-button" type="button">
40
- <svg class="google-icon" viewBox="0 0 18 18" aria-hidden="true" focusable="false">
41
- <path fill="#4285F4" d="M17.64 9.205c0-.638-.057-1.252-.164-1.841H9v3.481h4.844a4.14 4.14 0 0 1-1.796 2.715v2.259h2.909c1.702-1.567 2.683-3.874 2.683-6.614Z"/>
42
- <path fill="#34A853" d="M9 18c2.43 0 4.468-.806 5.957-2.181l-2.909-2.259c-.806.54-1.835.859-3.048.859-2.344 0-4.328-1.585-5.037-3.714H.956v2.332A9 9 0 0 0 9 18Z"/>
43
- <path fill="#FBBC05" d="M3.963 10.705A5.41 5.41 0 0 1 3.682 9c0-.592.102-1.168.281-1.705V4.963H.956A9 9 0 0 0 0 9c0 1.452.347 2.827.956 4.037l3.007-2.332Z"/>
44
- <path fill="#EA4335" d="M9 3.581c1.321 0 2.507.454 3.441 1.346l2.581-2.581C13.464.892 11.426 0 9 0A9 9 0 0 0 .956 4.963l3.007 2.332C4.672 5.166 6.656 3.581 9 3.581Z"/>
45
- </svg>
46
- <span>Continue with Google</span>
47
- </button>
48
- <div class="divider"><span>or use email</span></div>
49
- <label for="email">Email</label>
50
- <input id="email" name="email" type="email" autocomplete="email" inputmode="email" autocapitalize="none" spellcheck="false">
51
- <label for="password">Password</label>
52
- <input id="password" name="password" type="password" autocomplete="current-password">
53
- <div class="button-row"><button id="email-login" class="button secondary" type="button">Sign In</button><button id="email-register" class="button ghost" type="button">Create Account</button></div>
38
+ <p class="muted">Continue with Google or GitHub, then review the MCP client’s access request.</p>
39
+ <div class="provider-stack">
40
+ <button id="google" class="provider-button google-button" type="button"><svg class="provider-icon" viewBox="0 0 18 18" aria-hidden="true"><path fill="#4285F4" d="M17.64 9.205c0-.638-.057-1.252-.164-1.841H9v3.481h4.844a4.14 4.14 0 0 1-1.796 2.715v2.259h2.909c1.702-1.567 2.683-3.874 2.683-6.614Z"/><path fill="#34A853" d="M9 18c2.43 0 4.468-.806 5.957-2.181l-2.909-2.259c-.806.54-1.835.859-3.048.859-2.344 0-4.328-1.585-5.037-3.714H.956v2.332A9 9 0 0 0 9 18Z"/><path fill="#FBBC05" d="M3.963 10.705A5.41 5.41 0 0 1 3.682 9c0-.592.102-1.168.281-1.705V4.963H.956A9 9 0 0 0 0 9c0 1.452.347 2.827.956 4.037l3.007-2.332Z"/><path fill="#EA4335" d="M9 3.581c1.321 0 2.507.454 3.441 1.346l2.581-2.581C13.464.892 11.426 0 9 0A9 9 0 0 0 .956 4.963l3.007 2.332C4.672 5.166 6.656 3.581 9 3.581Z"/></svg><span>Continue with Google</span></button>
41
+ <button id="github" class="provider-button github-button" type="button"><svg class="provider-icon" viewBox="0 0 24 24" aria-hidden="true"><path fill="currentColor" d="M12 .7a11.5 11.5 0 0 0-3.64 22.41c.58.11.79-.25.79-.56v-2.24c-3.22.7-3.9-1.37-3.9-1.37-.53-1.34-1.29-1.7-1.29-1.7-1.05-.72.08-.71.08-.71 1.16.08 1.77 1.19 1.77 1.19 1.04 1.77 2.72 1.26 3.38.96.1-.75.4-1.26.73-1.55-2.57-.29-5.27-1.29-5.27-5.68 0-1.26.45-2.29 1.19-3.1-.12-.29-.52-1.47.11-3.06 0 0 .97-.31 3.16 1.18a10.9 10.9 0 0 1 5.76 0c2.19-1.49 3.16-1.18 3.16-1.18.63 1.59.23 2.77.11 3.06.74.81 1.19 1.84 1.19 3.1 0 4.4-2.71 5.38-5.29 5.67.42.36.79 1.07.79 2.16v3.21c0 .31.21.68.8.56A11.5 11.5 0 0 0 12 .7Z"/></svg><span>Continue with GitHub</span></button>
42
+ </div>
54
43
  </div>
55
44
  <div id="oauth-consent" class="hidden">
56
45
  <p class="eyebrow">Access request</p>
@@ -62,9 +51,9 @@
62
51
  </div>
63
52
  <p id="status" class="muted" aria-live="polite"></p>
64
53
  <p id="error" class="error" role="alert" aria-live="assertive"></p>
65
- <p class="footer-mini"><a href="/docs">Docs</a> · <a href="/docs#install">Install</a> · <a href="/docs#update">Update</a> · <a href="/security">Security</a> · <a href="/privacy">Privacy</a> · <a href="/terms">Terms</a></p>
54
+ <p class="footer-mini"><a href="/docs">Docs</a> · <a href="/security">Security</a> · <a href="/privacy">Privacy</a> · <a href="/terms">Terms</a></p>
66
55
  </section>
67
56
  </main>
68
- <script type="module" src="/oauth-app.js?v=36155fefb47e"></script>
57
+ <script type="module" src="/oauth-app.js?v=remcp-013"></script>
69
58
  </body>
70
59
  </html>
package/public/copy.js CHANGED
@@ -14,13 +14,7 @@ function legacyCopy(text) {
14
14
 
15
15
  async function copyText(text) {
16
16
  if (window.isSecureContext && navigator.clipboard?.writeText) {
17
- try {
18
- await navigator.clipboard.writeText(text);
19
- return;
20
- } catch {
21
- legacyCopy(text);
22
- return;
23
- }
17
+ try { await navigator.clipboard.writeText(text); return; } catch {}
24
18
  }
25
19
  legacyCopy(text);
26
20
  }
@@ -30,20 +24,17 @@ document.addEventListener('click', async event => {
30
24
  if (!button) return;
31
25
  const target = document.querySelector(button.dataset.copy);
32
26
  if (!target) return;
33
-
34
- const original = button.textContent;
35
- const originalLabel = button.getAttribute('aria-label') || 'Copy command';
27
+ const text = ('value' in target ? target.value : target.textContent).trim();
28
+ const label = button.getAttribute('aria-label') || 'Copy';
36
29
  try {
37
- await copyText(target.textContent.trim());
38
- button.textContent = 'Copied';
39
- button.setAttribute('aria-label', 'Copied to clipboard');
30
+ await copyText(text);
31
+ button.dataset.copied = 'true';
32
+ button.setAttribute('aria-label', 'Copied');
40
33
  } catch {
41
- button.textContent = 'Copy failed';
42
- button.setAttribute('aria-label', 'Copy failed. Select the command manually.');
34
+ button.setAttribute('aria-label', 'Copy failed');
43
35
  }
44
-
45
36
  window.setTimeout(() => {
46
- button.textContent = original;
47
- button.setAttribute('aria-label', originalLabel);
37
+ delete button.dataset.copied;
38
+ button.setAttribute('aria-label', label);
48
39
  }, 1400);
49
40
  });
package/public/docs.html CHANGED
@@ -8,7 +8,7 @@
8
8
  <title>Docs · ReMCP</title>
9
9
  <meta name="description" content="Connect a computer to ReMCP and configure the hosted MCP endpoint.">
10
10
  <link rel="preconnect" href="https://www.gstatic.com" crossorigin>
11
- <link rel="stylesheet" href="/style.css?v=remcp-012">
11
+ <link rel="stylesheet" href="/style.css?v=remcp-013">
12
12
  <meta property="og:site_name" content="ReMCP">
13
13
  <meta property="og:image" content="https://remcp.delio24.com/assets/og-remcp.png">
14
14
  <link rel="icon" href="/favicon.ico" sizes="any">
@@ -28,57 +28,56 @@
28
28
  <img class="brand-mark" src="/android-chrome-192x192.png" width="30" height="30" alt="" aria-hidden="true">
29
29
  <span translate="no">ReMCP</span>
30
30
  </a>
31
- <nav aria-label="Primary"><a href="/docs" aria-current="page">Docs</a><a href="/docs#install">Install</a><a href="/docs#update">Update</a><a href="/security">Security</a><a href="/support">Support</a></nav>
31
+ <nav aria-label="Primary"><a href="/docs" aria-current="page">Docs</a><a href="/security">Security</a><a href="/support">Support</a></nav>
32
32
  </header>
33
33
  <main id="main" class="doc-shell">
34
34
  <aside class="doc-nav" aria-label="Documentation"><a href="/docs" aria-current="page">Setup</a><a href="/docs#install">Install</a><a href="/docs#update">Update</a><a href="/security">Security</a><a href="/support">Support</a><a href="/privacy">Privacy</a><a href="/terms">Terms</a></aside>
35
35
  <article class="prose">
36
36
  <p class="eyebrow">Documentation</p>
37
- <h1>Install, pair and keep ReMCP updated.</h1>
38
- <p>Use <code>npx</code> once to pair a computer. With <code>--install</code>, ReMCP creates a persistent global CLI and a user service, so normal operation no longer depends on the temporary npx cache.</p>
37
+ <h1>Install and pair ReMCP.</h1>
38
+ <p>Install the CLI first. Pairing happens from the signed-in workspace, which generates the real one-time command for your computer.</p>
39
39
 
40
- <h2 id="requirements">1. Requirements</h2>
41
- <p>Install Node.js 22.5 or newer. The computer needs outbound HTTPS/WSS access to <code>remcp.delio24.com</code>; no inbound device port is required.</p>
40
+ <h2 id="requirements">Requirements</h2>
41
+ <p>Node.js 22.5 or newer. The computer needs outbound HTTPS/WSS access to <code>remcp.delio24.com</code>. No inbound device port is required.</p>
42
42
 
43
- <h2 id="pair">2. Get a pairing code</h2>
44
- <p>Open <a href="/#connect">the ReMCP workspace</a>, sign in, and choose <strong>Generate Command</strong>. Pairing codes are short-lived and single-use.</p>
43
+ <h2 id="install">1. Install the CLI</h2>
44
+ <div class="copy-field"><code id="docs-install">npm install --global @remcp/remcp@latest</code><button class="copy-icon-button" type="button" data-copy="#docs-install" aria-label="Copy install command"><svg class="icon-copy" viewBox="0 0 24 24" aria-hidden="true"><rect x="9" y="9" width="11" height="11" rx="2"/><path d="M15 9V6a2 2 0 0 0-2-2H6a2 2 0 0 0-2 2v7a2 2 0 0 0 2 2h3"/></svg><svg class="icon-check" viewBox="0 0 24 24" aria-hidden="true"><path d="m5 12 4 4L19 6"/></svg></button></div>
45
+ <p>This installs the <code>remcp</code> command. It does not pair a computer and does not contain a placeholder code.</p>
45
46
 
46
- <h2 id="install">3. Install and pair</h2>
47
- <div class="code-row"><pre><code id="docs-command-1">npx --yes @remcp/remcp@latest connect --server https://remcp.delio24.com --code YOUR_CODE --install</code></pre><button class="copy-button code-copy" type="button" data-copy="#docs-command-1" aria-label="Copy command" aria-live="polite">Copy</button></div>
48
- <p>This stores a device-specific credential locally, installs the persistent <code>remcp</code> CLI, installs the compatible local device runtime, and starts the ReMCP user service.</p>
47
+ <h2 id="pair">2. Pair a computer</h2>
48
+ <p>Open the <a href="/#connect">ReMCP workspace</a>, continue with Google or GitHub, and choose <strong>Generate pairing command</strong>. Run that exact generated command on the computer you want to pair.</p>
49
+ <div class="notice"><strong>Use the generated command.</strong><p>Pairing codes are short-lived and single-use. Do not type a made-up code or reuse an expired command.</p></div>
49
50
 
50
- <h3>Verify the installation</h3>
51
- <div class="code-row"><pre><code id="docs-command-2">remcp --version
52
- remcp status</code></pre><button class="copy-button code-copy" type="button" data-copy="#docs-command-2" aria-label="Copy command" aria-live="polite">Copy</button></div>
53
- <p><code>status</code> shows the installed CLI version, paired device id, server URL and server health.</p>
51
+ <h2 id="verify">3. Verify</h2>
52
+ <div class="copy-field multiline"><pre><code id="docs-verify">remcp --version
53
+ remcp status</code></pre><button class="copy-icon-button" type="button" data-copy="#docs-verify" aria-label="Copy verification commands"><svg class="icon-copy" viewBox="0 0 24 24" aria-hidden="true"><rect x="9" y="9" width="11" height="11" rx="2"/><path d="M15 9V6a2 2 0 0 0-2-2H6a2 2 0 0 0-2 2v7a2 2 0 0 0 2 2h3"/></svg><svg class="icon-check" viewBox="0 0 24 24" aria-hidden="true"><path d="m5 12 4 4L19 6"/></svg></button></div>
54
+ <p><code>status</code> shows the installed CLI version, pairing state and server health.</p>
54
55
 
55
56
  <h2 id="mcp">4. Add the MCP endpoint</h2>
56
- <div class="code-row"><pre><code id="docs-command-3">https://remcp.delio24.com/mcp</code></pre><button class="copy-button code-copy" type="button" data-copy="#docs-command-3" aria-label="Copy MCP endpoint" aria-live="polite">Copy</button></div>
57
- <p>Choose OAuth when your MCP client asks for authentication. ReMCP uses authorization code flow with PKCE and refresh tokens.</p>
57
+ <div class="copy-field"><code id="docs-mcp">https://remcp.delio24.com/mcp</code><button class="copy-icon-button" type="button" data-copy="#docs-mcp" aria-label="Copy MCP endpoint"><svg class="icon-copy" viewBox="0 0 24 24" aria-hidden="true"><rect x="9" y="9" width="11" height="11" rx="2"/><path d="M15 9V6a2 2 0 0 0-2-2H6a2 2 0 0 0-2 2v7a2 2 0 0 0 2 2h3"/></svg><svg class="icon-check" viewBox="0 0 24 24" aria-hidden="true"><path d="m5 12 4 4L19 6"/></svg></button></div>
58
+ <p>Add this endpoint to your MCP client and use OAuth when prompted. ReMCP uses authorization code flow with PKCE and refresh-token rotation.</p>
58
59
 
59
- <h2 id="update">Update ReMCP</h2>
60
- <div class="code-row"><pre><code id="docs-command-4">remcp update</code></pre><button class="copy-button code-copy" type="button" data-copy="#docs-command-4" aria-label="Copy command" aria-live="polite">Copy</button></div>
61
- <p>The update command installs the latest published ReMCP CLI, refreshes the compatible local runtime, and restarts the user service when it is installed. Verify afterwards with <code>remcp --version</code> or <code>remcp status</code>.</p>
60
+ <h2 id="update">Update</h2>
61
+ <div class="copy-field"><code id="docs-update">remcp update</code><button class="copy-icon-button" type="button" data-copy="#docs-update" aria-label="Copy update command"><svg class="icon-copy" viewBox="0 0 24 24" aria-hidden="true"><rect x="9" y="9" width="11" height="11" rx="2"/><path d="M15 9V6a2 2 0 0 0-2-2H6a2 2 0 0 0-2 2v7a2 2 0 0 0 2 2h3"/></svg><svg class="icon-check" viewBox="0 0 24 24" aria-hidden="true"><path d="m5 12 4 4L19 6"/></svg></button></div>
62
+ <p>Updates the installed ReMCP CLI and compatible local runtime, then restarts the user service when present.</p>
62
63
 
63
64
  <h2 id="service">Service commands</h2>
64
- <div class="code-row"><pre><code id="docs-command-5">remcp status
65
+ <div class="copy-field multiline"><pre><code id="docs-service">remcp status
65
66
  remcp doctor
66
67
  remcp install
67
- remcp start</code></pre><button class="copy-button code-copy" type="button" data-copy="#docs-command-5" aria-label="Copy command" aria-live="polite">Copy</button></div>
68
- <p><code>start</code> runs the agent in the foreground. <code>install</code> repairs or reinstalls the persistent user service for an already paired computer.</p>
68
+ remcp start</code></pre><button class="copy-icon-button" type="button" data-copy="#docs-service" aria-label="Copy service commands"><svg class="icon-copy" viewBox="0 0 24 24" aria-hidden="true"><rect x="9" y="9" width="11" height="11" rx="2"/><path d="M15 9V6a2 2 0 0 0-2-2H6a2 2 0 0 0-2 2v7a2 2 0 0 0 2 2h3"/></svg><svg class="icon-check" viewBox="0 0 24 24" aria-hidden="true"><path d="m5 12 4 4L19 6"/></svg></button></div>
69
+ <p><code>install</code> installs or repairs the background user service for an already paired computer. <code>start</code> runs the agent in the foreground.</p>
69
70
 
70
71
  <h2 id="uninstall">Uninstall</h2>
71
- <div class="code-row"><pre><code id="docs-command-6">remcp uninstall</code></pre><button class="copy-button code-copy" type="button" data-copy="#docs-command-6" aria-label="Copy command" aria-live="polite">Copy</button></div>
72
- <p>This stops and removes the background user service but keeps the CLI and local pairing configuration.</p>
73
- <div class="code-row"><pre><code id="docs-command-7">remcp uninstall --purge</code></pre><button class="copy-button code-copy" type="button" data-copy="#docs-command-7" aria-label="Copy command" aria-live="polite">Copy</button></div>
74
- <p><code>--purge</code> also removes the globally installed ReMCP packages. The local pairing configuration remains in <code>~/.config/remcp</code> so it is not silently destroyed.</p>
72
+ <div class="copy-field"><code id="docs-uninstall">remcp uninstall</code><button class="copy-icon-button" type="button" data-copy="#docs-uninstall" aria-label="Copy uninstall command"><svg class="icon-copy" viewBox="0 0 24 24" aria-hidden="true"><rect x="9" y="9" width="11" height="11" rx="2"/><path d="M15 9V6a2 2 0 0 0-2-2H6a2 2 0 0 0-2 2v7a2 2 0 0 0 2 2h3"/></svg><svg class="icon-check" viewBox="0 0 24 24" aria-hidden="true"><path d="m5 12 4 4L19 6"/></svg></button></div>
73
+ <p>Removes the background service. To also remove globally installed ReMCP packages:</p>
74
+ <div class="copy-field"><code id="docs-purge">remcp uninstall --purge</code><button class="copy-icon-button" type="button" data-copy="#docs-purge" aria-label="Copy purge command"><svg class="icon-copy" viewBox="0 0 24 24" aria-hidden="true"><rect x="9" y="9" width="11" height="11" rx="2"/><path d="M15 9V6a2 2 0 0 0-2-2H6a2 2 0 0 0-2 2v7a2 2 0 0 0 2 2h3"/></svg><svg class="icon-check" viewBox="0 0 24 24" aria-hidden="true"><path d="m5 12 4 4L19 6"/></svg></button></div>
75
75
 
76
76
  <h2 id="connection-model">Connection model</h2>
77
- <p>The device agent creates an outbound secure WebSocket connection to the relay. You do not need to expose a listener on the computer.</p>
78
- <div class="notice"><strong>Review mutating actions.</strong><p>Some tools can write files or run processes. Review the action requested by your MCP client before approving it.</p></div>
77
+ <p>The device agent opens an outbound secure WebSocket connection to the relay. MCP clients connect to the HTTPS MCP endpoint through OAuth. Only devices paired to the signed-in account are exposed to that account.</p>
79
78
 
80
79
  <h2 id="self-hosting">Self-hosting</h2>
81
- <p>The central ReMCP service runs in Docker with persistent account, device and OAuth metadata. Device agents run natively so host access does not require a privileged container.</p>
80
+ <p>The server can be self-hosted with Docker. Keep it behind TLS, persist its data volume, and proxy WebSocket upgrades for the device-agent route. See the repository README for deployment variables.</p>
82
81
  </article>
83
82
  </main>
84
83
  <footer class="site-footer">
@@ -86,9 +85,9 @@ remcp start</code></pre><button class="copy-button code-copy" type="button" data
86
85
  <img class="brand-mark" src="/android-chrome-192x192.png" width="30" height="30" alt="" aria-hidden="true">
87
86
  <span translate="no">ReMCP</span>
88
87
  </div>
89
- <nav aria-label="Footer"><a href="/docs">Docs</a><a href="/docs#install">Install</a><a href="/docs#update">Update</a><a href="/security">Security</a><a href="/support">Support</a><a href="/privacy">Privacy</a><a href="/terms">Terms</a></nav>
88
+ <nav aria-label="Footer"><a href="/docs">Docs</a><a href="/security">Security</a><a href="/support">Support</a><a href="/privacy">Privacy</a><a href="/terms">Terms</a></nav>
90
89
  <p>Open-source remote MCP infrastructure.</p>
91
90
  </footer>
92
- <script type="module" src="/copy.js?v=remcp-012"></script>
91
+ <script type="module" src="/copy.js?v=remcp-013"></script>
93
92
  </body>
94
93
  </html>
package/public/index.html CHANGED
@@ -8,7 +8,7 @@
8
8
  <title>ReMCP — Your computers over MCP</title>
9
9
  <meta name="description" content="Securely pair your own computers and use their files, terminal and processes through authenticated MCP clients.">
10
10
  <link rel="preconnect" href="https://www.gstatic.com" crossorigin>
11
- <link rel="stylesheet" href="/style.css?v=remcp-012">
11
+ <link rel="stylesheet" href="/style.css?v=remcp-013">
12
12
  <meta property="og:site_name" content="ReMCP">
13
13
  <meta property="og:image" content="https://remcp.delio24.com/assets/og-remcp.png">
14
14
  <link rel="icon" href="/favicon.ico" sizes="any">
@@ -28,17 +28,17 @@
28
28
  <img class="brand-mark" src="/android-chrome-192x192.png" width="30" height="30" alt="" aria-hidden="true">
29
29
  <span translate="no">ReMCP</span>
30
30
  </a>
31
- <nav aria-label="Primary"><a href="/docs">Docs</a><a href="/docs#install">Install</a><a href="/docs#update">Update</a><a href="/security">Security</a><a href="/support">Support</a></nav>
31
+ <nav aria-label="Primary"><a href="/docs">Docs</a><a href="/security">Security</a><a href="/support">Support</a></nav>
32
32
  </header>
33
33
  <main id="main">
34
34
  <section class="hero">
35
35
  <div class="hero-copy">
36
- <p class="eyebrow">Remote MCP, without exposed device ports</p>
37
- <h1>Your computers.<br>Available to MCP.</h1>
38
- <p class="lede">Pair a device once. ReMCP routes authenticated tool calls to its local agent while the device keeps an outbound-only connection.</p>
36
+ <p class="eyebrow">Remote MCP for your computers</p>
37
+ <h1>Use your computers from any MCP client.</h1>
38
+ <p class="lede">ReMCP pairs a computer to one authenticated MCP endpoint. The local agent connects outbound, so the computer does not need a public port.</p>
39
39
  <div class="hero-actions">
40
- <a class="button" href="#connect">Connect a Device</a>
41
- <a class="text-link" href="/docs">Read Setup Guide <span aria-hidden="true">→</span></a>
40
+ <a class="button" href="#connect">Open workspace</a>
41
+ <a class="text-link" href="/docs">Read docs <span aria-hidden="true">→</span></a>
42
42
  </div>
43
43
  </div>
44
44
  <div class="hero-visual" role="img" aria-label="ReMCP connection diagram">
@@ -50,66 +50,52 @@
50
50
  </div>
51
51
  </section>
52
52
 
53
- <section class="principles" aria-label="Product principles">
54
- <div><span>01</span><h2>Private by default</h2><p>Accounts and devices are isolated by authenticated user identity and revocable device credentials.</p></div>
55
- <div><span>02</span><h2>No inbound laptop port</h2><p>The device agent connects outward to ReMCP. Your laptop does not need a public IP or open listener.</p></div>
56
- <div><span>03</span><h2>Explicit control</h2><p>Read, write and destructive tools declare their behavior so MCP clients can apply the right review flow.</p></div>
53
+ <section class="principles" aria-label="Connection facts">
54
+ <div><span>Connection</span><h2>Outbound only</h2><p>The device agent opens the connection to ReMCP. No inbound device port is required.</p></div>
55
+ <div><span>Authentication</span><h2>OAuth + PKCE</h2><p>MCP clients authorize against your ReMCP account. Device credentials are independent and revocable.</p></div>
56
+ <div><span>Control</span><h2>Your paired devices</h2><p>Tool calls are routed only to computers paired with the signed-in account.</p></div>
57
57
  </section>
58
58
 
59
59
  <section id="install" class="quickstart">
60
60
  <div class="section-heading">
61
- <p class="eyebrow">Quick start</p>
62
- <h2>One command to pair. One command to update.</h2>
63
- <p>Use npx only for the first pairing. <code>--install</code> creates a persistent <code>remcp</code> CLI and background user service.</p>
61
+ <p class="eyebrow">Setup</p>
62
+ <h2>Install first. Pair from the workspace.</h2>
63
+ <p>The public install command contains no pairing code. Sign in below to generate the exact one-time command for your computer.</p>
64
64
  </div>
65
65
  <div class="quickstart-grid">
66
66
  <article class="command-card">
67
- <span>01</span><h3>Install &amp; pair</h3>
68
- <div class="command-row"><code id="install-command">npx --yes @remcp/remcp@latest connect --server https://remcp.delio24.com --code YOUR_CODE --install</code><button class="copy-button" type="button" data-copy="#install-command">Copy</button></div>
69
- <p>Generate <code>YOUR_CODE</code> in the workspace below.</p>
67
+ <span>01</span><h3>Install the CLI</h3>
68
+ <div class="copy-field"><code id="install-command">npm install --global @remcp/remcp@latest</code><button class="copy-icon-button" type="button" data-copy="#install-command" aria-label="Copy install command"><svg class="icon-copy" viewBox="0 0 24 24" aria-hidden="true"><rect x="9" y="9" width="11" height="11" rx="2"/><path d="M15 9V6a2 2 0 0 0-2-2H6a2 2 0 0 0-2 2v7a2 2 0 0 0 2 2h3"/></svg><svg class="icon-check" viewBox="0 0 24 24" aria-hidden="true"><path d="m5 12 4 4L19 6"/></svg></button></div>
69
+ <p>Installs the current <code>remcp</code> command globally.</p>
70
70
  </article>
71
71
  <article class="command-card">
72
- <span>02</span><h3>Check</h3>
73
- <div class="command-row"><code id="status-command">remcp status</code><button class="copy-button" type="button" data-copy="#status-command">Copy</button></div>
74
- <p>Confirm the local CLI version, pairing and server health.</p>
72
+ <span>02</span><h3>Pair a computer</h3>
73
+ <p>Sign in to the workspace, choose <strong>Generate pairing command</strong>, then run the generated command on that computer.</p>
75
74
  </article>
76
- <article id="update" class="command-card">
77
- <span>03</span><h3>Update</h3>
78
- <div class="command-row"><code id="update-command">remcp update</code><button class="copy-button" type="button" data-copy="#update-command">Copy</button></div>
79
- <p>Updates the CLI and restarts the installed user service.</p>
75
+ <article class="command-card">
76
+ <span>03</span><h3>Verify</h3>
77
+ <div class="copy-field"><code id="status-command">remcp status</code><button class="copy-icon-button" type="button" data-copy="#status-command" aria-label="Copy status command"><svg class="icon-copy" viewBox="0 0 24 24" aria-hidden="true"><rect x="9" y="9" width="11" height="11" rx="2"/><path d="M15 9V6a2 2 0 0 0-2-2H6a2 2 0 0 0-2 2v7a2 2 0 0 0 2 2h3"/></svg><svg class="icon-check" viewBox="0 0 24 24" aria-hidden="true"><path d="m5 12 4 4L19 6"/></svg></button></div>
78
+ <p>Checks the installed version, pairing state and server health.</p>
80
79
  </article>
81
80
  </div>
82
- <a class="text-link" href="/docs">Full installation and CLI guide <span aria-hidden="true">→</span></a>
81
+ <div class="update-line"><span>Already installed?</span><div class="copy-field compact"><code id="update-command">remcp update</code><button class="copy-icon-button" type="button" data-copy="#update-command" aria-label="Copy update command"><svg class="icon-copy" viewBox="0 0 24 24" aria-hidden="true"><rect x="9" y="9" width="11" height="11" rx="2"/><path d="M15 9V6a2 2 0 0 0-2-2H6a2 2 0 0 0-2 2v7a2 2 0 0 0 2 2h3"/></svg><svg class="icon-check" viewBox="0 0 24 24" aria-hidden="true"><path d="m5 12 4 4L19 6"/></svg></button></div></div>
82
+ <a class="text-link" href="/docs">Installation and CLI reference <span aria-hidden="true">→</span></a>
83
83
  </section>
84
84
 
85
85
  <section id="connect" class="workspace">
86
86
  <div class="section-heading">
87
87
  <p class="eyebrow">Workspace</p>
88
- <h2>Pair and manage devices</h2>
89
- <p>Sign in to generate one-time pairing commands and revoke computers you no longer trust.</p>
88
+ <h2>Workspace</h2>
89
+ <p>Sign in with Google or GitHub to generate pairing commands and manage your devices.</p>
90
90
  </div>
91
91
  <div class="workspace-grid">
92
92
  <section class="auth-pane" aria-labelledby="account-title">
93
93
  <h3 id="account-title">Account</h3>
94
94
  <div id="signed-out" class="stack">
95
- <p class="muted">Sign in to access your ReMCP device workspace.</p>
96
- <button id="google" class="button google-button" type="button">
97
- <svg class="google-icon" viewBox="0 0 18 18" aria-hidden="true" focusable="false">
98
- <path fill="#4285F4" d="M17.64 9.205c0-.638-.057-1.252-.164-1.841H9v3.481h4.844a4.14 4.14 0 0 1-1.796 2.715v2.259h2.909c1.702-1.567 2.683-3.874 2.683-6.614Z"/>
99
- <path fill="#34A853" d="M9 18c2.43 0 4.468-.806 5.957-2.181l-2.909-2.259c-.806.54-1.835.859-3.048.859-2.344 0-4.328-1.585-5.037-3.714H.956v2.332A9 9 0 0 0 9 18Z"/>
100
- <path fill="#FBBC05" d="M3.963 10.705A5.41 5.41 0 0 1 3.682 9c0-.592.102-1.168.281-1.705V4.963H.956A9 9 0 0 0 0 9c0 1.452.347 2.827.956 4.037l3.007-2.332Z"/>
101
- <path fill="#EA4335" d="M9 3.581c1.321 0 2.507.454 3.441 1.346l2.581-2.581C13.464.892 11.426 0 9 0A9 9 0 0 0 .956 4.963l3.007 2.332C4.672 5.166 6.656 3.581 9 3.581Z"/>
102
- </svg>
103
- <span>Continue with Google</span>
104
- </button>
105
- <div class="divider"><span>or use email</span></div>
106
- <label for="email">Email</label>
107
- <input id="email" name="email" type="email" autocomplete="email" inputmode="email" autocapitalize="none" spellcheck="false">
108
- <label for="password">Password</label>
109
- <input id="password" name="password" type="password" autocomplete="current-password">
110
- <div class="button-row">
111
- <button id="email-login" class="button secondary" type="button">Sign In</button>
112
- <button id="email-register" class="button ghost" type="button">Create Account</button>
95
+ <p class="muted">Sign in to manage your paired computers.</p>
96
+ <div class="provider-stack">
97
+ <button id="google" class="provider-button google-button" type="button"><svg class="provider-icon" viewBox="0 0 18 18" aria-hidden="true"><path fill="#4285F4" d="M17.64 9.205c0-.638-.057-1.252-.164-1.841H9v3.481h4.844a4.14 4.14 0 0 1-1.796 2.715v2.259h2.909c1.702-1.567 2.683-3.874 2.683-6.614Z"/><path fill="#34A853" d="M9 18c2.43 0 4.468-.806 5.957-2.181l-2.909-2.259c-.806.54-1.835.859-3.048.859-2.344 0-4.328-1.585-5.037-3.714H.956v2.332A9 9 0 0 0 9 18Z"/><path fill="#FBBC05" d="M3.963 10.705A5.41 5.41 0 0 1 3.682 9c0-.592.102-1.168.281-1.705V4.963H.956A9 9 0 0 0 0 9c0 1.452.347 2.827.956 4.037l3.007-2.332Z"/><path fill="#EA4335" d="M9 3.581c1.321 0 2.507.454 3.441 1.346l2.581-2.581C13.464.892 11.426 0 9 0A9 9 0 0 0 .956 4.963l3.007 2.332C4.672 5.166 6.656 3.581 9 3.581Z"/></svg><span>Continue with Google</span></button>
98
+ <button id="github" class="provider-button github-button" type="button"><svg class="provider-icon" viewBox="0 0 24 24" aria-hidden="true"><path fill="currentColor" d="M12 .7a11.5 11.5 0 0 0-3.64 22.41c.58.11.79-.25.79-.56v-2.24c-3.22.7-3.9-1.37-3.9-1.37-.53-1.34-1.29-1.7-1.29-1.7-1.05-.72.08-.71.08-.71 1.16.08 1.77 1.19 1.77 1.19 1.04 1.77 2.72 1.26 3.38.96.1-.75.4-1.26.73-1.55-2.57-.29-5.27-1.29-5.27-5.68 0-1.26.45-2.29 1.19-3.1-.12-.29-.52-1.47.11-3.06 0 0 .97-.31 3.16 1.18a10.9 10.9 0 0 1 5.76 0c2.19-1.49 3.16-1.18 3.16-1.18.63 1.59.23 2.77.11 3.06.74.81 1.19 1.84 1.19 3.1 0 4.4-2.71 5.38-5.29 5.67.42.36.79 1.07.79 2.16v3.21c0 .31.21.68.8.56A11.5 11.5 0 0 0 12 .7Z"/></svg><span>Continue with GitHub</span></button>
113
99
  </div>
114
100
  <p id="auth-error" class="error" role="alert" aria-live="polite"></p>
115
101
  </div>
@@ -120,35 +106,29 @@
120
106
  </section>
121
107
  <section class="endpoint-pane" aria-labelledby="endpoint-title">
122
108
  <div><h3 id="endpoint-title">MCP endpoint</h3><p class="muted">Use this HTTPS endpoint when adding ReMCP to an MCP client.</p></div>
123
- <div class="command-row"><code id="mcp-url">https://remcp.delio24.com/mcp</code><button class="copy-button" type="button" data-copy="#mcp-url" aria-label="Copy MCP endpoint">Copy</button></div>
109
+ <div class="copy-field"><code id="mcp-url">https://remcp.delio24.com/mcp</code><button class="copy-icon-button" type="button" data-copy="#mcp-url" aria-label="Copy MCP endpoint"><svg class="icon-copy" viewBox="0 0 24 24" aria-hidden="true"><rect x="9" y="9" width="11" height="11" rx="2"/><path d="M15 9V6a2 2 0 0 0-2-2H6a2 2 0 0 0-2 2v7a2 2 0 0 0 2 2h3"/></svg><svg class="icon-check" viewBox="0 0 24 24" aria-hidden="true"><path d="m5 12 4 4L19 6"/></svg></button></div>
124
110
  <dl class="endpoint-facts"><div><dt>Transport</dt><dd>Streamable HTTP</dd></div><div><dt>Authentication</dt><dd>OAuth 2.1 + PKCE</dd></div></dl>
125
111
  </section>
126
112
  </div>
127
113
  <section id="dashboard" class="hidden device-workspace" aria-label="Device management">
128
114
  <div class="pair-panel">
129
- <div><p class="eyebrow">Add a computer</p><h3>Generate a one-time pairing command</h3><p class="muted">The code expires automatically and can only be claimed once.</p></div>
130
- <button id="pair" class="button" type="button">Generate Command</button>
131
- <div id="pairing" class="hidden pairing-output"><code id="pair-command"></code><button class="copy-button" type="button" data-copy="#pair-command">Copy</button><p id="pair-expiry" class="muted"></p></div>
115
+ <div><p class="eyebrow">Add a computer</p><h3>Generate pairing command</h3><p class="muted">The generated command contains a short-lived one-time code. Run it only on the computer you want to pair.</p></div>
116
+ <button id="pair" class="button" type="button">Generate pairing command</button>
117
+ <div id="pairing" class="hidden pairing-output"><div class="copy-field"><code id="pair-command"></code><button class="copy-icon-button" type="button" data-copy="#pair-command" aria-label="Copy pairing command"><svg class="icon-copy" viewBox="0 0 24 24" aria-hidden="true"><rect x="9" y="9" width="11" height="11" rx="2"/><path d="M15 9V6a2 2 0 0 0-2-2H6a2 2 0 0 0-2 2v7a2 2 0 0 0 2 2h3"/></svg><svg class="icon-check" viewBox="0 0 24 24" aria-hidden="true"><path d="m5 12 4 4L19 6"/></svg></button></div><p id="pair-expiry" class="muted"></p></div>
132
118
  </div>
133
119
  <div class="devices-panel"><div class="panel-title"><h3>Paired devices</h3><span class="muted">Online state updates when the page refreshes.</span></div><div id="devices" class="device-list" aria-live="polite">No devices yet.</div></div>
134
120
  </section>
135
121
  </section>
136
-
137
- <section class="final-cta">
138
- <p class="eyebrow">Self-hostable architecture</p>
139
- <h2>Keep the relay yours.</h2>
140
- <p>ReMCP can run as a small Docker service while each computer runs its own local agent.</p>
141
- <a class="text-link" href="/security">Review the Security Model <span aria-hidden="true">→</span></a>
142
- </section>
143
122
  </main>
144
123
  <footer class="site-footer">
145
124
  <div class="wordmark">
146
125
  <img class="brand-mark" src="/android-chrome-192x192.png" width="30" height="30" alt="" aria-hidden="true">
147
126
  <span translate="no">ReMCP</span>
148
127
  </div>
149
- <nav aria-label="Footer"><a href="/docs">Docs</a><a href="/docs#install">Install</a><a href="/docs#update">Update</a><a href="/security">Security</a><a href="/support">Support</a><a href="/privacy">Privacy</a><a href="/terms">Terms</a></nav>
128
+ <nav aria-label="Footer"><a href="/docs">Docs</a><a href="/security">Security</a><a href="/support">Support</a><a href="/privacy">Privacy</a><a href="/terms">Terms</a></nav>
150
129
  <p>Open-source remote MCP infrastructure.</p>
151
130
  </footer>
152
- <script type="module" src="/app.js?v=14a728f07dd1"></script>
131
+ <script type="module" src="/copy.js?v=remcp-013"></script>
132
+ <script type="module" src="/app.js?v=remcp-013"></script>
153
133
  </body>
154
134
  </html>
@@ -1,35 +1,44 @@
1
1
  import { initializeApp } from 'https://www.gstatic.com/firebasejs/10.14.1/firebase-app.js';
2
- import { getAuth, GoogleAuthProvider, onAuthStateChanged, signInWithPopup, signInWithEmailAndPassword, createUserWithEmailAndPassword } from 'https://www.gstatic.com/firebasejs/10.14.1/firebase-auth.js';
2
+ import { getAuth, GoogleAuthProvider, GithubAuthProvider, onAuthStateChanged, signInWithPopup } from 'https://www.gstatic.com/firebasejs/10.14.1/firebase-auth.js';
3
3
 
4
4
  const cfg = await fetch(`/api/config?fresh=${Date.now()}`, { cache: 'no-store' }).then(r => r.json());
5
5
  const auth = getAuth(initializeApp(cfg.firebase));
6
6
  const query = new URLSearchParams(location.search);
7
7
  const $ = selector => document.querySelector(selector);
8
- const showError = error => { $('#error').textContent = error?.message || String(error); };
8
+ const googleProvider = new GoogleAuthProvider();
9
+ const githubProvider = new GithubAuthProvider();
10
+ googleProvider.setCustomParameters({ prompt: 'select_account' });
9
11
  let currentUser = null;
10
12
  let completing = false;
11
- const googleProvider = new GoogleAuthProvider();
12
13
 
13
- $('#client-id').textContent = query.get('client_id') || 'MCP client';
14
- $('#google').onclick = async () => {
15
- const button = $('#google');
14
+ const showError = error => {
15
+ const code = error?.code || '';
16
+ if (code === 'auth/popup-closed-by-user' || code === 'auth/cancelled-popup-request') return;
17
+ $('#error').textContent = code === 'auth/account-exists-with-different-credential'
18
+ ? 'This email is already linked to another sign-in provider.'
19
+ : error?.message || String(error);
20
+ };
21
+ async function signIn(button, provider, idleLabel) {
16
22
  const label = button.querySelector('span');
17
23
  button.disabled = true;
18
24
  $('#error').textContent = '';
19
- label.textContent = 'Opening Google…';
20
- try { await signInWithPopup(auth, googleProvider); }
25
+ label.textContent = 'Opening…';
26
+ try { await signInWithPopup(auth, provider); }
21
27
  catch (error) { showError(error); }
22
- finally { button.disabled = false; label.textContent = 'Continue with Google'; }
23
- };
24
- $('#email-login').onclick = () => signInWithEmailAndPassword(auth, $('#email').value, $('#password').value).catch(showError);
25
- $('#email-register').onclick = () => createUserWithEmailAndPassword(auth, $('#email').value, $('#password').value).catch(showError);
28
+ finally { button.disabled = false; label.textContent = idleLabel; }
29
+ }
30
+
31
+ $('#client-id').textContent = query.get('client_id') || 'MCP client';
32
+ $('#google').onclick = () => signIn($('#google'), googleProvider, 'Continue with Google');
33
+ $('#github').onclick = () => signIn($('#github'), githubProvider, 'Continue with GitHub');
26
34
 
27
35
  onAuthStateChanged(auth, user => {
28
36
  currentUser = user;
29
37
  $('#oauth-login').classList.toggle('hidden', Boolean(user));
30
38
  $('#oauth-consent').classList.toggle('hidden', !user);
31
- $('#status').textContent = user ? `Signed in as ${user.email || 'ReMCP user'}. Review access before continuing.` : '';
39
+ $('#status').textContent = user ? `Signed in as ${user.email || user.displayName || 'ReMCP user'}.` : '';
32
40
  });
41
+
33
42
  $('#authorize').onclick = async () => {
34
43
  if (!currentUser || completing) return;
35
44
  completing = true;
@@ -8,7 +8,7 @@
8
8
  <title>Privacy Policy · ReMCP</title>
9
9
  <meta name="description" content="How ReMCP processes account, device, OAuth and remote-computer data.">
10
10
  <link rel="preconnect" href="https://www.gstatic.com" crossorigin>
11
- <link rel="stylesheet" href="/style.css?v=remcp-012">
11
+ <link rel="stylesheet" href="/style.css?v=remcp-013">
12
12
  <meta property="og:site_name" content="ReMCP">
13
13
  <meta property="og:image" content="https://remcp.delio24.com/assets/og-remcp.png">
14
14
  <link rel="icon" href="/favicon.ico" sizes="any">
@@ -28,24 +28,44 @@
28
28
  <img class="brand-mark" src="/android-chrome-192x192.png" width="30" height="30" alt="" aria-hidden="true">
29
29
  <span translate="no">ReMCP</span>
30
30
  </a>
31
- <nav aria-label="Primary"><a href="/docs">Docs</a><a href="/docs#install">Install</a><a href="/docs#update">Update</a><a href="/security">Security</a><a href="/support">Support</a></nav>
31
+ <nav aria-label="Primary"><a href="/docs">Docs</a><a href="/security">Security</a><a href="/support">Support</a></nav>
32
32
  </header>
33
33
  <main id="main" class="doc-shell">
34
34
  <aside class="doc-nav" aria-label="Documentation"><a href="/docs">Setup</a><a href="/docs#install">Install</a><a href="/docs#update">Update</a><a href="/security">Security</a><a href="/support">Support</a><a href="/privacy" aria-current="page">Privacy</a><a href="/terms">Terms</a></aside>
35
35
  <article class="prose">
36
36
  <p class="eyebrow">Privacy</p>
37
37
  <h1>Privacy Policy</h1>
38
- <p><strong>Effective September 16, 2026.</strong> This policy describes the hosted ReMCP service at remcp.delio24.com. A self-hosted deployment is operated by its own administrator and may have different practices.</p>
39
- <h2>What ReMCP does</h2><p>ReMCP authenticates an MCP client, identifies computers you have paired, and relays authorized tool calls between that client and the selected computer. Device agents connect outbound to the ReMCP service.</p>
40
- <h2>Account and Google Sign-In data</h2><p>Authentication is provided by Firebase Authentication. If you choose Google Sign-In, Firebase may provide ReMCP with your Firebase user identifier, email address and display name. ReMCP uses this information only to authenticate you, keep your devices separated from other accounts, and administer your ReMCP account. ReMCP does not request Gmail, Google Drive, Google Calendar or other Google API data.</p>
41
- <h2>Device and security metadata</h2><p>ReMCP stores device identifiers, device names and basic platform metadata, one-way hashes of device credentials, pairing records, OAuth client metadata, and one-way hashes of refresh credentials. Pairing codes are short-lived and single-use. Raw device credentials are returned to the paired device and are not stored in plaintext by the service.</p>
42
- <h2>Files, commands and tool results</h2><p>When you use an MCP tool, its request and response may pass through the ReMCP relay. This can include filenames, file contents, command output and process information that you explicitly ask the paired computer to process. ReMCP does not intentionally retain those tool payloads as product data. Operational security logs may retain limited metadata such as timestamps, status codes and errors.</p>
43
- <h2>How data is used and shared</h2><p>Data is used to provide authentication, device pairing, OAuth authorization, request routing, abuse prevention, security and reliability. ReMCP does not sell personal information and does not serve advertising. Data may be processed by infrastructure and authentication providers only as needed to operate the service, including Firebase/Google for authentication.</p>
44
- <h2>Retention and control</h2><p>Pairing codes expire after 10 minutes by default. MCP access tokens expire after 1 hour by default. Refresh credentials expire after 30 days by default and are rotated on use. Device records remain until you revoke or remove the device. ReMCP does not intentionally retain MCP tool request or response payloads as product data. Hosted Nginx access and error logs are rotated daily with 14 rotated copies. Application container logs are size-bounded to three files of at most 50 MB each rather than retained for a fixed number of days. These operational logs are used only for security, reliability, and troubleshooting and are not intended to contain authentication secrets or MCP tool payloads. You can revoke a paired device from the ReMCP workspace, and account-data or deletion requests can be made through the Support page.</p>
45
- <h2>Restricted data</h2><p>ReMCP is not intended to collect or process passwords, MFA or OTP codes, API or private keys, payment-card data, protected health information, or government identifiers through plugin tool calls. Users should keep those data out of ReMCP requests and use a safer local workflow when a requested file or command would expose them.</p>
46
- <h2>Security and international processing</h2><p>ReMCP uses TLS for network transport, hashes reusable credentials before storage, and scopes device access to the authenticated account. Internet services may process data in more than one country depending on infrastructure and authentication providers. See the <a href="/security">Security page</a> for the current security model.</p>
47
- <h2>Children</h2><p>ReMCP is a developer and systems-administration tool and is not directed to children under 13.</p>
48
- <h2>Changes</h2><p>Material changes to this policy will be published at this URL with an updated effective date.</p>
38
+ <p><strong>Effective September 16, 2026.</strong> This policy covers the hosted ReMCP service at <code>remcp.delio24.com</code>. Self-hosted deployments are controlled by their own operators.</p>
39
+
40
+ <h2>Account data</h2>
41
+ <p>Hosted sign-in is provided by Firebase Authentication using Google or GitHub. ReMCP may receive your authentication user id, email address, email-verification status and display name. These data are used to authenticate you and separate your devices and OAuth grants from other accounts.</p>
42
+
43
+ <h2>Google and GitHub</h2>
44
+ <p>ReMCP uses Google and GitHub only as sign-in providers through Firebase Authentication. The hosted ReMCP application does not use Google access to read Gmail, Drive, Calendar or Contacts, and it does not use GitHub provider tokens to read repositories or perform GitHub actions.</p>
45
+
46
+ <h2>Device and OAuth metadata</h2>
47
+ <p>ReMCP stores device identifiers, device names, basic platform metadata, one-way hashes of device credentials, pairing records, OAuth client metadata and one-way hashes of refresh credentials. Raw reusable device credentials are not stored in plaintext by the relay.</p>
48
+
49
+ <h2>Files, commands and tool results</h2>
50
+ <p>When you invoke an MCP tool, the request and result pass through the relay to the selected device. This can include paths, file contents, command output and process information you asked ReMCP to handle. ReMCP does not intentionally retain MCP tool payloads as product data.</p>
51
+
52
+ <h2>Use and sharing</h2>
53
+ <p>Data are used to provide authentication, pairing, OAuth authorization, request routing, abuse prevention, security and reliability. ReMCP does not sell personal information and does not serve advertising. Infrastructure and authentication providers process data only as needed to operate the service.</p>
54
+
55
+ <h2>Retention and control</h2>
56
+ <p>Pairing codes expire after 10 minutes by default. MCP access tokens expire after 1 hour by default. Refresh credentials expire after 30 days by default and rotate on use. Device records remain until revoked or removed. Hosted Nginx access and error logs rotate daily with 14 rotated copies. Application container logs are limited to three files of at most 50 MB each. You can revoke paired devices from the workspace.</p>
57
+
58
+ <h2>Restricted data</h2>
59
+ <p>Do not send passwords, MFA or OTP codes, API/private keys, payment-card data, protected health information or government identifiers through ReMCP tool calls.</p>
60
+
61
+ <h2>Security and international processing</h2>
62
+ <p>ReMCP uses TLS for network transport and one-way hashes for reusable server-side credentials. Internet infrastructure and authentication providers may process data in more than one country. See the <a href="/security">Security page</a> for the current model.</p>
63
+
64
+ <h2>Children</h2>
65
+ <p>ReMCP is a developer and systems-administration tool and is not directed to children under 13.</p>
66
+
67
+ <h2>Changes and requests</h2>
68
+ <p>Material changes are published at this URL with an updated effective date. Account-data or deletion requests can be made through the <a href="/support">Support page</a>.</p>
49
69
  </article>
50
70
  </main>
51
71
  <footer class="site-footer">
@@ -53,7 +73,7 @@
53
73
  <img class="brand-mark" src="/android-chrome-192x192.png" width="30" height="30" alt="" aria-hidden="true">
54
74
  <span translate="no">ReMCP</span>
55
75
  </div>
56
- <nav aria-label="Footer"><a href="/docs">Docs</a><a href="/docs#install">Install</a><a href="/docs#update">Update</a><a href="/security">Security</a><a href="/support">Support</a><a href="/privacy">Privacy</a><a href="/terms">Terms</a></nav>
76
+ <nav aria-label="Footer"><a href="/docs">Docs</a><a href="/security">Security</a><a href="/support">Support</a><a href="/privacy">Privacy</a><a href="/terms">Terms</a></nav>
57
77
  <p>Open-source remote MCP infrastructure.</p>
58
78
  </footer>
59
79
  </body>
@@ -8,7 +8,7 @@
8
8
  <title>Security · ReMCP</title>
9
9
  <meta name="description" content="How ReMCP isolates accounts, devices, credentials and remote MCP tool access.">
10
10
  <link rel="preconnect" href="https://www.gstatic.com" crossorigin>
11
- <link rel="stylesheet" href="/style.css?v=remcp-012">
11
+ <link rel="stylesheet" href="/style.css?v=remcp-013">
12
12
  <meta property="og:site_name" content="ReMCP">
13
13
  <meta property="og:image" content="https://remcp.delio24.com/assets/og-remcp.png">
14
14
  <link rel="icon" href="/favicon.ico" sizes="any">
@@ -28,21 +28,34 @@
28
28
  <img class="brand-mark" src="/android-chrome-192x192.png" width="30" height="30" alt="" aria-hidden="true">
29
29
  <span translate="no">ReMCP</span>
30
30
  </a>
31
- <nav aria-label="Primary"><a href="/docs">Docs</a><a href="/docs#install">Install</a><a href="/docs#update">Update</a><a href="/security" aria-current="page">Security</a><a href="/support">Support</a></nav>
31
+ <nav aria-label="Primary"><a href="/docs">Docs</a><a href="/security" aria-current="page">Security</a><a href="/support">Support</a></nav>
32
32
  </header>
33
33
  <main id="main" class="doc-shell">
34
34
  <aside class="doc-nav" aria-label="Documentation"><a href="/docs">Setup</a><a href="/docs#install">Install</a><a href="/docs#update">Update</a><a href="/security" aria-current="page">Security</a><a href="/support">Support</a><a href="/privacy">Privacy</a><a href="/terms">Terms</a></aside>
35
35
  <article class="prose">
36
36
  <p class="eyebrow">Security</p>
37
- <h1>A narrow relay between the model and your machine.</h1>
38
- <p>ReMCP treats remote computer control as privileged access. Authentication, device isolation and explicit tool behavior are part of the core design.</p>
39
- <h2>Identity and tenancy</h2><p>User authentication is handled with Firebase Authentication. MCP sessions and paired device records are scoped to the same authenticated user identity.</p>
40
- <h2>Device credentials</h2><p>Pairing codes are short-lived and one-time. Each paired computer receives an independent random credential. Server storage keeps a one-way hash of that credential.</p>
41
- <h2>Network model</h2><p>The local agent opens an outbound secure WebSocket connection to the relay. No inbound port needs to be opened on the laptop or workstation.</p>
42
- <h2>Tool risk</h2><p>Tool descriptors explicitly declare read-only, destructive and open-world hints. Terminal execution can change local or external state depending on the command supplied.</p>
43
- <h2>Revocation</h2><p>Revoke a device from the signed-in workspace if a computer is lost, retired, or no longer trusted. Revoked credentials cannot reconnect.</p>
44
- <h2>Transport</h2><p>Production traffic uses HTTPS/WSS. OAuth uses PKCE S256. Tokens and device credentials are not placed in public source or page markup.</p>
45
- <div class="notice"><strong>Operator trust.</strong><p>If you use a third-party ReMCP deployment, that deployment operator controls the relay infrastructure. For highest control, run your own deployment.</p></div>
37
+ <h1>Security model.</h1>
38
+ <p>ReMCP is remote access infrastructure. Account identity, device credentials and tool risk are kept separate so each layer can be revoked independently.</p>
39
+
40
+ <h2>Account identity</h2>
41
+ <p>The hosted service uses Firebase Authentication with Google and GitHub sign-in. ReMCP does not provide hosted email/password sign-in. MCP authorization is scoped to the authenticated ReMCP account.</p>
42
+
43
+ <h2>Device pairing</h2>
44
+ <p>Pairing commands contain short-lived, single-use codes. A successfully paired computer receives its own random device credential; the server stores only a one-way hash of that credential.</p>
45
+
46
+ <h2>Network model</h2>
47
+ <p>The local agent opens an outbound WSS connection to the relay. The computer does not need a public IP address or inbound listening port.</p>
48
+
49
+ <h2>MCP authorization</h2>
50
+ <p>The public MCP endpoint uses OAuth authorization code flow with PKCE S256. Access tokens are short-lived and refresh credentials rotate on use.</p>
51
+
52
+ <h2>Tool risk</h2>
53
+ <p>MCP tool descriptors declare read-only, destructive and open-world hints. File writes, configuration changes and process execution can change local state; terminal commands can also reach external systems.</p>
54
+
55
+ <h2>Revocation</h2>
56
+ <p>Revoke a paired device from the workspace if it is lost, retired or no longer trusted. Revoked device credentials cannot reconnect.</p>
57
+
58
+ <div class="notice"><strong>Relay operator trust.</strong><p>A hosted relay can observe requests while routing them. For the highest infrastructure control, self-host ReMCP and secure that deployment as privileged infrastructure.</p></div>
46
59
  </article>
47
60
  </main>
48
61
  <footer class="site-footer">
@@ -50,7 +63,7 @@
50
63
  <img class="brand-mark" src="/android-chrome-192x192.png" width="30" height="30" alt="" aria-hidden="true">
51
64
  <span translate="no">ReMCP</span>
52
65
  </div>
53
- <nav aria-label="Footer"><a href="/docs">Docs</a><a href="/docs#install">Install</a><a href="/docs#update">Update</a><a href="/security">Security</a><a href="/support">Support</a><a href="/privacy">Privacy</a><a href="/terms">Terms</a></nav>
66
+ <nav aria-label="Footer"><a href="/docs">Docs</a><a href="/security">Security</a><a href="/support">Support</a><a href="/privacy">Privacy</a><a href="/terms">Terms</a></nav>
54
67
  <p>Open-source remote MCP infrastructure.</p>
55
68
  </footer>
56
69
  </body>
package/public/style.css CHANGED
@@ -46,7 +46,7 @@ img, svg { display: block; }
46
46
  .site-header nav a[aria-current="page"] { font-weight: 680; }
47
47
 
48
48
  main { display: block; }
49
- .hero { max-width: var(--container); min-height: 650px; margin: 0 auto; padding: clamp(72px, 9vw, 112px) 20px; display: grid; grid-template-columns: minmax(0, 1.03fr) minmax(360px, .97fr); align-items: center; gap: clamp(48px, 7vw, 96px); }
49
+ .hero { max-width: var(--container); min-height: 560px; margin: 0 auto; padding: clamp(64px, 8vw, 92px) 20px; display: grid; grid-template-columns: minmax(0, 1.03fr) minmax(360px, .97fr); align-items: center; gap: clamp(48px, 7vw, 96px); }
50
50
  .hero-copy { max-width: 650px; }
51
51
  .eyebrow { margin: 0 0 16px; color: var(--accent); font-size: 12px; font-weight: 760; letter-spacing: .13em; text-transform: uppercase; }
52
52
  .hero h1, .section-heading h2, .final-cta h2, .prose h1 { text-wrap: balance; }
@@ -64,10 +64,14 @@ main { display: block; }
64
64
  .text-link { display: inline-flex; align-items: center; gap: 6px; padding: 7px 0; color: var(--ink); font-weight: 650; border-bottom: 1px solid var(--line-strong); }
65
65
  .text-link:hover { border-color: var(--ink); }
66
66
 
67
- .google-button { position: relative; width: min(100%, 400px); min-height: 44px; padding: 9px 16px 9px 44px; border: 1px solid #747775; border-radius: 4px; background: #fff; color: #1f1f1f; font-family: Roboto, Arial, sans-serif; font-size: 14px; font-weight: 500; letter-spacing: .1px; box-shadow: none; }
68
- .google-button:hover { border-color: #6f7274; background: #f8fafd; color: #1f1f1f; }
69
- .google-button:active { background: #f1f3f4; transform: none; }
70
- .google-icon { position: absolute; left: 12px; top: 50%; width: 20px; height: 20px; transform: translateY(-50%); }
67
+ .provider-stack { width: min(100%, 400px); display: grid; gap: 10px; margin-top: 4px; }
68
+ .provider-button { position: relative; width: 100%; min-height: 46px; display: flex; align-items: center; justify-content: center; padding: 10px 16px 10px 48px; border-radius: 7px; font-size: 14px; font-weight: 600; line-height: 1; text-align: center; box-shadow: none; }
69
+ .provider-button:active { transform: none; }
70
+ .provider-icon { position: absolute; left: 14px; top: 50%; width: 20px; height: 20px; transform: translateY(-50%); }
71
+ .google-button { border: 1px solid #747775; background: #fff; color: #1f1f1f; font-family: Roboto, Arial, sans-serif; font-weight: 500; }
72
+ .google-button:hover { border-color: #5f6368; background: #f8fafd; color: #1f1f1f; }
73
+ .github-button { border: 1px solid #1f2328; background: #24292f; color: #fff; }
74
+ .github-button:hover { border-color: #1f2328; background: #1f2328; color: #fff; }
71
75
 
72
76
  .hero-visual { width: 100%; max-width: 520px; margin-left: auto; }
73
77
  .node { min-height: 62px; display: flex; align-items: center; justify-content: space-between; gap: 20px; padding: 17px 18px; border: 1px solid var(--line); border-radius: var(--radius); background: var(--surface); }
@@ -96,7 +100,6 @@ main { display: block; }
96
100
  .command-card > span { color: var(--muted); font-size: 12px; font-variant-numeric: tabular-nums; }
97
101
  .command-card h3 { margin: 18px 0 8px; font-size: 20px; letter-spacing: -.025em; }
98
102
  .command-card p { margin: 12px 0 0; color: var(--muted); font-size: 14px; }
99
- .command-card .command-row { margin-top: 14px; }
100
103
  .site-header nav { min-width: 0; overflow-x: auto; scrollbar-width: none; }
101
104
  .site-header nav::-webkit-scrollbar { display: none; }
102
105
 
@@ -112,32 +115,35 @@ main { display: block; }
112
115
  .auth-pane h3, .endpoint-pane h3, .pair-panel h3, .devices-panel h3, .oauth-card h2 { margin: 0 0 9px; font-size: 20px; line-height: 1.25; letter-spacing: -.025em; }
113
116
  .stack { display: flex; flex-direction: column; gap: 10px; }
114
117
  .muted { color: var(--muted); }
115
- label { display: block; margin: 10px 0 6px; color: #343438; font-size: 13px; font-weight: 650; }
116
- .stack label { margin: 3px 0 -4px; }
117
- input { width: 100%; min-height: 44px; padding: 10px 12px; border: 1px solid var(--line-strong); border-radius: 8px; background: var(--surface); color: var(--ink); transition: border-color 140ms ease, box-shadow 140ms ease; }
118
- input:hover { border-color: #b9b9b2; }
119
- input:focus-visible { border-color: var(--accent); }
120
- .button-row { display: flex; gap: 9px; margin-top: 5px; }
121
- .divider { display: flex; align-items: center; gap: 11px; margin: 7px 0; color: var(--muted); font-size: 12px; }
122
- .divider::before, .divider::after { content: ""; flex: 1; height: 1px; background: var(--line); }
123
118
  .error { margin: 2px 0 0; color: var(--danger); font-size: 13px; }
124
119
  p:empty, .error:empty, #status:empty { display: none; }
125
120
  .identity { display: flex; align-items: center; gap: 11px; }
126
121
  .identity small { display: block; color: var(--muted); }
127
122
  .status-dot { width: 9px; height: 9px; flex: 0 0 9px; border-radius: 50%; background: var(--ok); box-shadow: 0 0 0 4px var(--ok-soft); }
128
123
 
129
- .command-row, .pairing-output { display: grid; grid-template-columns: minmax(0, 1fr) auto; gap: 9px; align-items: start; margin-top: 20px; }
130
- .command-row code, .pairing-output code, .code-block { overflow: auto; padding: 12px 13px; border: 1px solid var(--line); border-radius: 8px; background: var(--surface-subtle); font: 12.5px/1.55 ui-monospace, SFMono-Regular, Menlo, Consolas, monospace; word-break: break-all; }
131
- .copy-button { min-height: 42px; padding: 9px 12px; border: 1px solid var(--line-strong); border-radius: 8px; background: var(--surface); color: var(--ink); font-weight: 650; }
132
- .copy-button:hover { background: var(--surface-subtle); }
124
+ .copy-field { position: relative; min-width: 0; display: flex; align-items: center; margin-top: 14px; border: 1px solid var(--line-strong); border-radius: 9px; background: var(--surface); overflow: hidden; }
125
+ .copy-field code { min-width: 0; flex: 1; overflow-x: auto; padding: 12px 48px 12px 13px; color: #2e2e33; font: 12.5px/1.55 ui-monospace, SFMono-Regular, Menlo, Consolas, monospace; white-space: pre; scrollbar-width: thin; }
126
+ .copy-field pre { min-width: 0; flex: 1; margin: 0; overflow: auto; }
127
+ .copy-field pre code { display: block; }
128
+ .copy-field.multiline { align-items: stretch; }
129
+ .copy-field.compact { width: min(100%, 300px); margin-top: 0; }
130
+ .copy-icon-button { position: absolute; top: 50%; right: 6px; width: 34px; height: 34px; display: grid; place-items: center; padding: 0; transform: translateY(-50%); border: 0; border-radius: 7px; background: transparent; color: #65656b; }
131
+ .copy-icon-button:hover { background: var(--surface-subtle); color: var(--ink); }
132
+ .copy-icon-button svg { width: 17px; height: 17px; fill: none; stroke: currentColor; stroke-width: 1.8; stroke-linecap: round; stroke-linejoin: round; }
133
+ .copy-icon-button .icon-check { display: none; }
134
+ .copy-icon-button[data-copied="true"] { color: var(--ok); }
135
+ .copy-icon-button[data-copied="true"] .icon-copy { display: none; }
136
+ .copy-icon-button[data-copied="true"] .icon-check { display: block; }
137
+ .pairing-output { grid-column: 1 / -1; margin-top: 4px; }
138
+ .pairing-output .copy-field { width: 100%; }
139
+ .pairing-output p { margin: 8px 0 0; }
140
+ .update-line { display: flex; align-items: center; gap: 14px; margin: 20px 0 24px; color: var(--muted); font-size: 13px; }
133
141
  .endpoint-facts { margin: 28px 0 0; border-top: 1px solid var(--line); }
134
142
  .endpoint-facts div { display: flex; justify-content: space-between; gap: 20px; padding: 12px 0; border-bottom: 1px solid var(--line); }
135
143
  .endpoint-facts dt { color: var(--muted); }
136
144
  .endpoint-facts dd { margin: 0; text-align: right; font-weight: 650; }
137
145
  .device-workspace { margin-top: 52px; }
138
146
  .pair-panel { display: grid; grid-template-columns: minmax(0, 1fr) auto; gap: 20px; align-items: center; padding-bottom: 34px; border-bottom: 1px solid var(--line); }
139
- .pairing-output { grid-column: 1 / -1; }
140
- .pairing-output p { grid-column: 1 / -1; margin: 0; }
141
147
  .devices-panel { padding-top: 34px; }
142
148
  .panel-title { display: flex; align-items: baseline; justify-content: space-between; gap: 20px; }
143
149
  .device-list { margin-top: 14px; border-top: 1px solid var(--line); }
@@ -168,10 +174,9 @@ p:empty, .error:empty, #status:empty { display: none; }
168
174
  .prose p { margin: 0 0 12px; }
169
175
  .prose a { color: #3538ae; text-decoration: underline; text-decoration-color: #a5a7e9; text-underline-offset: 3px; }
170
176
  .prose a:hover { text-decoration-color: #3538ae; }
171
- .prose pre { min-width: 0; overflow: auto; margin: 0; padding: 13px 14px; background: transparent; color: #f4f4f2; }
172
- .prose .code-row { display: grid; grid-template-columns: minmax(0, 1fr) auto; align-items: center; gap: 8px; margin: 12px 0 16px; overflow: hidden; border-radius: 10px; background: #1e1e21; }
173
- .prose .code-row .code-copy { min-height: 34px; margin-right: 8px; padding: 7px 10px; border-color: #4b4b50; background: #2b2b2f; color: #f4f4f2; font-size: 12px; white-space: nowrap; }
174
- .prose .code-row .code-copy:hover { border-color: #66666d; background: #38383d; }
177
+ .prose pre { margin: 0; }
178
+ .prose .copy-field { margin: 12px 0 16px; background: #fbfbfa; }
179
+ .prose .copy-field code { font-size: 12.5px; }
175
180
  .prose code { font-family: ui-monospace, SFMono-Regular, Menlo, Consolas, monospace; font-size: .9em; }
176
181
  .prose :not(pre) > code { padding: 2px 5px; border-radius: 5px; background: var(--surface-subtle); color: #34343a; }
177
182
  .prose hr { margin: 46px 0; border: 0; border-top: 1px solid var(--line); }
@@ -182,7 +187,7 @@ p:empty, .error:empty, #status:empty { display: none; }
182
187
  .oauth-card { width: min(100%, 520px); padding: 30px; border: 1px solid var(--line); border-radius: 14px; background: var(--surface); }
183
188
  .oauth-card .eyebrow { margin-bottom: 11px; }
184
189
  .oauth-card > p:first-child { margin-top: 0; }
185
- .oauth-card .google-button { width: 100%; }
190
+ .oauth-card .provider-stack { width: 100%; margin-top: 20px; }
186
191
  .scope-list { margin: 24px 0; padding: 0; list-style: none; border-top: 1px solid var(--line); }
187
192
  .scope-list li { display: flex; justify-content: space-between; gap: 20px; padding: 13px 0; border-bottom: 1px solid var(--line); }
188
193
  .scope-list strong { color: var(--muted); font-family: ui-monospace, SFMono-Regular, Menlo, Consolas, monospace; font-size: 12px; font-weight: 600; }
@@ -229,13 +234,13 @@ input:focus-visible, button:focus-visible, a:focus-visible { outline: 3px solid
229
234
  .section-heading { margin-bottom: 30px; }
230
235
  .section-heading h2, .final-cta h2 { font-size: 36px; }
231
236
  .section-heading > p:last-child, .final-cta > p { margin-top: 12px; font-size: 16px; }
232
- .button-row, .oauth-actions { flex-direction: column; }
233
- .button-row .button, .oauth-actions .button { width: 100%; }
237
+ .oauth-actions { flex-direction: column; }
238
+ .oauth-actions .button { width: 100%; }
239
+ .update-line { align-items: stretch; flex-direction: column; gap: 8px; }
240
+ .copy-field.compact { width: 100%; }
234
241
  .pair-panel { grid-template-columns: 1fr; }
235
242
  .pair-panel .button { justify-self: start; }
236
243
  .panel-title { align-items: flex-start; flex-direction: column; }
237
- .command-row, .pairing-output { grid-template-columns: minmax(0, 1fr) auto; }
238
- .copy-button { justify-self: stretch; }
239
244
  .endpoint-facts div { align-items: flex-start; flex-direction: column; gap: 2px; }
240
245
  .endpoint-facts dd { text-align: left; }
241
246
  .site-footer { padding: 24px 18px; }
@@ -245,9 +250,6 @@ input:focus-visible, button:focus-visible, a:focus-visible { outline: 3px solid
245
250
  .prose h2 { margin-top: 28px; font-size: 21px; }
246
251
  .prose h3 { margin-top: 21px; }
247
252
  .prose p, .prose li { font-size: 15px; }
248
- .prose .code-row { margin: 10px 0 14px; }
249
- .prose .code-row pre { padding: 12px 10px 12px 13px; }
250
- .prose .code-row .code-copy { margin-right: 7px; }
251
253
  .oauth-shell { min-height: calc(100svh - 62px); padding: 28px 14px 60px; place-items: start center; }
252
254
  .oauth-card { padding: 22px 18px; }
253
255
  .scope-list li { align-items: flex-start; flex-direction: column; gap: 4px; }
@@ -8,7 +8,7 @@
8
8
  <title>Support · ReMCP</title>
9
9
  <meta name="description" content="Troubleshoot ReMCP sign-in, device pairing, agent connectivity and MCP authorization.">
10
10
  <link rel="preconnect" href="https://www.gstatic.com" crossorigin>
11
- <link rel="stylesheet" href="/style.css?v=remcp-012">
11
+ <link rel="stylesheet" href="/style.css?v=remcp-013">
12
12
  <meta property="og:site_name" content="ReMCP">
13
13
  <meta property="og:image" content="https://remcp.delio24.com/assets/og-remcp.png">
14
14
  <link rel="icon" href="/favicon.ico" sizes="any">
@@ -28,22 +28,38 @@
28
28
  <img class="brand-mark" src="/android-chrome-192x192.png" width="30" height="30" alt="" aria-hidden="true">
29
29
  <span translate="no">ReMCP</span>
30
30
  </a>
31
- <nav aria-label="Primary"><a href="/docs">Docs</a><a href="/docs#install">Install</a><a href="/docs#update">Update</a><a href="/security">Security</a><a href="/support" aria-current="page">Support</a></nav>
31
+ <nav aria-label="Primary"><a href="/docs">Docs</a><a href="/security">Security</a><a href="/support" aria-current="page">Support</a></nav>
32
32
  </header>
33
33
  <main id="main" class="doc-shell">
34
34
  <aside class="doc-nav" aria-label="Documentation"><a href="/docs">Setup</a><a href="/docs#install">Install</a><a href="/docs#update">Update</a><a href="/security">Security</a><a href="/support" aria-current="page">Support</a><a href="/privacy">Privacy</a><a href="/terms">Terms</a></aside>
35
35
  <article class="prose">
36
36
  <p class="eyebrow">Support</p>
37
- <h1>Troubleshoot ReMCP.</h1>
38
- <p>Most connection failures fall into one of three layers: account authentication, device pairing, or the local device agent.</p>
39
- <h2>Device shows offline</h2><p>Verify the ReMCP agent service is running and outbound HTTPS/WSS access to <code>remcp.delio24.com</code> is allowed. Re-pair the device if its credential was revoked.</p>
40
- <h2>OAuth does not complete</h2><p>Return to the authorization screen, sign in to the intended ReMCP account, review the requested access, and choose <strong>Authorize ReMCP Access</strong>.</p>
41
- <h2>MCP tool cannot run</h2><p>Confirm the target computer is online and use <code>list_devices</code> to obtain its current device id. Device tools require that id.</p>
42
- <h2>Pairing code expired</h2><p>Generate a new pairing command from the workspace. Pairing codes are intentionally short-lived and single-use.</p>
43
- <h2>Check the installed agent</h2><div class="code-row"><pre><code id="support-command-1">remcp --version
44
- remcp status</code></pre><button class="copy-button code-copy" type="button" data-copy="#support-command-1" aria-label="Copy command" aria-live="polite">Copy</button></div><p>If <code>remcp</code> is not found, repeat the <a href="/docs#install">install command</a>. The first npx invocation is temporary; <code>--install</code> creates the persistent CLI.</p>
45
- <h2>Update or repair</h2><div class="code-row"><pre><code id="support-command-2">remcp update</code></pre><button class="copy-button code-copy" type="button" data-copy="#support-command-2" aria-label="Copy command" aria-live="polite">Copy</button></div><p>This refreshes the published CLI and restarts the installed user service. For an already paired device whose service is missing, run <code>remcp install</code>.</p>
46
- <h2>Need deployment help?</h2><p>For a self-hosted deployment, contact the operator who provisioned your ReMCP instance and include the affected layer: sign-in, pairing, agent connectivity, or MCP authorization.</p>
37
+ <h1>Troubleshooting.</h1>
38
+ <p>Check the layer that is failing: sign-in, pairing, the local agent, or MCP authorization.</p>
39
+
40
+ <h2>Sign-in does not open</h2>
41
+ <p>Use <strong>Continue with Google</strong> or <strong>Continue with GitHub</strong>. ReMCP does not use email/password sign-in on the hosted site. If a popup is blocked, allow popups for <code>remcp.delio24.com</code> and try again.</p>
42
+
43
+ <h2>The <code>remcp</code> command is missing</h2>
44
+ <div class="copy-field"><code id="support-install">npm install --global @remcp/remcp@latest</code><button class="copy-icon-button" type="button" data-copy="#support-install" aria-label="Copy install command"><svg class="icon-copy" viewBox="0 0 24 24" aria-hidden="true"><rect x="9" y="9" width="11" height="11" rx="2"/><path d="M15 9V6a2 2 0 0 0-2-2H6a2 2 0 0 0-2 2v7a2 2 0 0 0 2 2h3"/></svg><svg class="icon-check" viewBox="0 0 24 24" aria-hidden="true"><path d="m5 12 4 4L19 6"/></svg></button></div>
45
+ <p>After installation, pair the computer from the signed-in workspace. The public install command alone does not pair a device.</p>
46
+
47
+ <h2>Pairing command expired</h2>
48
+ <p>Open the workspace and generate a new command. Each pairing command contains a one-time code and expires automatically.</p>
49
+
50
+ <h2>Device shows offline</h2>
51
+ <div class="copy-field"><code id="support-status">remcp status</code><button class="copy-icon-button" type="button" data-copy="#support-status" aria-label="Copy status command"><svg class="icon-copy" viewBox="0 0 24 24" aria-hidden="true"><rect x="9" y="9" width="11" height="11" rx="2"/><path d="M15 9V6a2 2 0 0 0-2-2H6a2 2 0 0 0-2 2v7a2 2 0 0 0 2 2h3"/></svg><svg class="icon-check" viewBox="0 0 24 24" aria-hidden="true"><path d="m5 12 4 4L19 6"/></svg></button></div>
52
+ <p>Confirm the user service is running and outbound HTTPS/WSS access to <code>remcp.delio24.com</code> is allowed. Re-pair only if the device credential was revoked or the local pairing state was removed.</p>
53
+
54
+ <h2>OAuth does not complete</h2>
55
+ <p>Return to the authorization page, sign in with the intended ReMCP account, review the requested scopes, and choose <strong>Authorize ReMCP Access</strong>.</p>
56
+
57
+ <h2>MCP tool cannot run</h2>
58
+ <p>Confirm the target device is online. A device tool needs the current ReMCP device id; clients can obtain it with <code>list_devices</code>.</p>
59
+
60
+ <h2>Update or repair</h2>
61
+ <div class="copy-field"><code id="support-update">remcp update</code><button class="copy-icon-button" type="button" data-copy="#support-update" aria-label="Copy update command"><svg class="icon-copy" viewBox="0 0 24 24" aria-hidden="true"><rect x="9" y="9" width="11" height="11" rx="2"/><path d="M15 9V6a2 2 0 0 0-2-2H6a2 2 0 0 0-2 2v7a2 2 0 0 0 2 2h3"/></svg><svg class="icon-check" viewBox="0 0 24 24" aria-hidden="true"><path d="m5 12 4 4L19 6"/></svg></button></div>
62
+ <p>If the CLI is paired but its background service is missing, run <code>remcp install</code>.</p>
47
63
  </article>
48
64
  </main>
49
65
  <footer class="site-footer">
@@ -51,9 +67,9 @@ remcp status</code></pre><button class="copy-button code-copy" type="button" dat
51
67
  <img class="brand-mark" src="/android-chrome-192x192.png" width="30" height="30" alt="" aria-hidden="true">
52
68
  <span translate="no">ReMCP</span>
53
69
  </div>
54
- <nav aria-label="Footer"><a href="/docs">Docs</a><a href="/docs#install">Install</a><a href="/docs#update">Update</a><a href="/security">Security</a><a href="/support">Support</a><a href="/privacy">Privacy</a><a href="/terms">Terms</a></nav>
70
+ <nav aria-label="Footer"><a href="/docs">Docs</a><a href="/security">Security</a><a href="/support">Support</a><a href="/privacy">Privacy</a><a href="/terms">Terms</a></nav>
55
71
  <p>Open-source remote MCP infrastructure.</p>
56
72
  </footer>
57
- <script type="module" src="/copy.js?v=remcp-012"></script>
73
+ <script type="module" src="/copy.js?v=remcp-013"></script>
58
74
  </body>
59
75
  </html>
package/public/terms.html CHANGED
@@ -8,7 +8,7 @@
8
8
  <title>Terms of Service · ReMCP</title>
9
9
  <meta name="description" content="Terms for using the hosted ReMCP service and its remote-computer capabilities.">
10
10
  <link rel="preconnect" href="https://www.gstatic.com" crossorigin>
11
- <link rel="stylesheet" href="/style.css?v=remcp-012">
11
+ <link rel="stylesheet" href="/style.css?v=remcp-013">
12
12
  <meta property="og:site_name" content="ReMCP">
13
13
  <meta property="og:image" content="https://remcp.delio24.com/assets/og-remcp.png">
14
14
  <link rel="icon" href="/favicon.ico" sizes="any">
@@ -28,24 +28,41 @@
28
28
  <img class="brand-mark" src="/android-chrome-192x192.png" width="30" height="30" alt="" aria-hidden="true">
29
29
  <span translate="no">ReMCP</span>
30
30
  </a>
31
- <nav aria-label="Primary"><a href="/docs">Docs</a><a href="/docs#install">Install</a><a href="/docs#update">Update</a><a href="/security">Security</a><a href="/support">Support</a></nav>
31
+ <nav aria-label="Primary"><a href="/docs">Docs</a><a href="/security">Security</a><a href="/support">Support</a></nav>
32
32
  </header>
33
33
  <main id="main" class="doc-shell">
34
34
  <aside class="doc-nav" aria-label="Documentation"><a href="/docs">Setup</a><a href="/docs#install">Install</a><a href="/docs#update">Update</a><a href="/security">Security</a><a href="/support">Support</a><a href="/privacy">Privacy</a><a href="/terms" aria-current="page">Terms</a></aside>
35
35
  <article class="prose">
36
36
  <p class="eyebrow">Legal</p>
37
37
  <h1>Terms of Service</h1>
38
- <p><strong>Effective September 16, 2026.</strong> These Terms apply to the hosted ReMCP service at remcp.delio24.com. The open-source software may also be self-hosted under its applicable software license.</p>
39
- <h2>Your account and devices</h2><p>You may connect only computers and accounts that you own or are authorized to administer. You are responsible for protecting your sign-in account, reviewing paired devices, and revoking devices or OAuth grants you no longer trust.</p>
40
- <h2>Remote actions</h2><p>ReMCP can expose powerful local operations, including reading and modifying files and starting or terminating processes. Some actions can be destructive or can affect external systems when a command run on your computer reaches them. You are responsible for reviewing and authorizing requested actions and for maintaining appropriate backups and operating-system permissions.</p>
41
- <h2>Acceptable use</h2><p>You may not use ReMCP to access systems without authorization, distribute malware, evade security controls, interfere with other users, conduct credential theft, or violate applicable law or third-party rights. You may not attempt to access devices belonging to another ReMCP account.</p>
42
- <h2>Service operation</h2><p>The hosted service may be updated, rate-limited, suspended or discontinued to protect users, respond to abuse, maintain security or operate the service. ReMCP does not guarantee uninterrupted availability. Self-hosted deployments are operated and secured by their administrators.</p>
43
- <h2>Third-party services and software</h2><p>Authentication may rely on Firebase/Google, and device functionality may rely on open-source dependencies. Those services and packages are subject to their own terms and licenses. ReMCP does not grant rights to third-party systems that you access from a paired device.</p>
44
- <h2>Open-source software</h2><p>The ReMCP source distribution includes software under open-source licenses. License notices in the source distribution govern those components independently of these hosted-service Terms.</p>
45
- <h2>No warranty</h2><p>To the maximum extent permitted by applicable law, the service and software are provided on an “as is” and “as available” basis without warranties of uninterrupted operation, fitness for a particular purpose, or freedom from all defects. Nothing in these Terms limits rights that cannot legally be excluded.</p>
46
- <h2>Responsibility for losses</h2><p>You are responsible for commands and changes made through devices you authorize. To the maximum extent permitted by applicable law, ReMCP is not responsible for indirect, incidental or consequential losses arising from device changes, lost data, third-party systems or service interruptions. Mandatory consumer or statutory rights remain unaffected.</p>
47
- <h2>Termination</h2><p>You may stop using the service and revoke your devices at any time. Access may be suspended for security, abuse or legal reasons. Provisions that by their nature should survive termination, including responsibility for prior actions and license obligations, continue to apply.</p>
48
- <h2>Changes</h2><p>Material changes to these Terms will be published at this URL with a new effective date. Continued use after changes become effective constitutes acceptance where permitted by law.</p>
38
+ <p><strong>Effective September 16, 2026.</strong> These Terms apply to the hosted ReMCP service at <code>remcp.delio24.com</code>. The open-source software can also be self-hosted under its software licenses.</p>
39
+
40
+ <h2>Authorized systems only</h2>
41
+ <p>You may pair and control only computers and accounts that you own or are authorized to administer. You are responsible for protecting your sign-in account and revoking devices or OAuth grants you no longer trust.</p>
42
+
43
+ <h2>Remote actions</h2>
44
+ <p>ReMCP can read and modify files and can start, interact with or terminate processes. Some commands can affect external systems. Review consequential actions and maintain appropriate backups and operating-system permissions.</p>
45
+
46
+ <h2>Acceptable use</h2>
47
+ <p>Do not use ReMCP to access systems without authorization, steal credentials, distribute malware, evade security controls, interfere with other users, or violate applicable law or third-party rights.</p>
48
+
49
+ <h2>Sign-in providers</h2>
50
+ <p>The hosted service uses Firebase Authentication with Google and GitHub sign-in. Those providers and other infrastructure dependencies are governed by their own terms. ReMCP does not grant rights to third-party systems accessible from a paired computer.</p>
51
+
52
+ <h2>Service operation</h2>
53
+ <p>The hosted service may be updated, rate-limited, suspended or discontinued for security, abuse prevention, maintenance or legal reasons. Uninterrupted availability is not guaranteed. Self-hosted deployments are operated and secured by their administrators.</p>
54
+
55
+ <h2>Open-source software</h2>
56
+ <p>ReMCP and its dependencies include open-source software. Their license notices govern those software components independently of these hosted-service Terms.</p>
57
+
58
+ <h2>No warranty</h2>
59
+ <p>To the maximum extent permitted by applicable law, the service and software are provided “as is” and “as available,” without warranties of uninterrupted operation or fitness for a particular purpose. Rights that cannot legally be excluded remain unaffected.</p>
60
+
61
+ <h2>Responsibility for actions</h2>
62
+ <p>You are responsible for commands and changes made through devices you authorize. To the maximum extent permitted by law, ReMCP is not responsible for indirect or consequential loss arising from device changes, lost data, third-party systems or service interruption.</p>
63
+
64
+ <h2>Termination and changes</h2>
65
+ <p>You may stop using the service and revoke devices at any time. Access may be suspended for security, abuse or legal reasons. Material changes to these Terms will be published at this URL with a new effective date.</p>
49
66
  </article>
50
67
  </main>
51
68
  <footer class="site-footer">
@@ -53,7 +70,7 @@
53
70
  <img class="brand-mark" src="/android-chrome-192x192.png" width="30" height="30" alt="" aria-hidden="true">
54
71
  <span translate="no">ReMCP</span>
55
72
  </div>
56
- <nav aria-label="Footer"><a href="/docs">Docs</a><a href="/docs#install">Install</a><a href="/docs#update">Update</a><a href="/security">Security</a><a href="/support">Support</a><a href="/privacy">Privacy</a><a href="/terms">Terms</a></nav>
73
+ <nav aria-label="Footer"><a href="/docs">Docs</a><a href="/security">Security</a><a href="/support">Support</a><a href="/privacy">Privacy</a><a href="/terms">Terms</a></nav>
57
74
  <p>Open-source remote MCP infrastructure.</p>
58
75
  </footer>
59
76
  </body>