@remcp/remcp 0.1.1 → 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 +85 -42
- package/assets/remcp-icon.png +0 -0
- package/mcp.json +9 -0
- package/package.json +4 -2
- package/plugin.json +37 -0
- package/public/app.js +25 -24
- package/public/assets/art/hero-relay.webp +0 -0
- package/public/assets/art/relay-detail.webp +0 -0
- package/public/authorize.html +10 -21
- package/public/copy.js +9 -18
- package/public/docs.html +31 -32
- package/public/index.html +38 -58
- package/public/oauth-app.js +22 -13
- package/public/privacy.html +34 -13
- package/public/security.html +25 -12
- package/public/style.css +34 -32
- package/public/support.html +30 -14
- package/public/terms.html +31 -14
- package/skills/remcp-operator/SKILL.md +1 -1
- package/src/auth.mjs +1 -0
- package/src/config.mjs +1 -1
- package/src/db.mjs +8 -5
- package/src/mcp.mjs +1 -1
- package/src/oauth.mjs +24 -5
- package/src/util.mjs +1 -1
- package/chatgpt-app-submission.json +0 -356
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-
|
|
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="/
|
|
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
|
|
37
|
-
<h1>
|
|
38
|
-
<p class="lede">
|
|
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">
|
|
41
|
-
<a class="text-link" href="/docs">Read
|
|
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="
|
|
54
|
-
<div><span>
|
|
55
|
-
<div><span>
|
|
56
|
-
<div><span>
|
|
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">
|
|
62
|
-
<h2>
|
|
63
|
-
<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
|
|
68
|
-
<div class="
|
|
69
|
-
<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>
|
|
73
|
-
<
|
|
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
|
|
77
|
-
<span>03</span><h3>
|
|
78
|
-
<div class="
|
|
79
|
-
<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
|
-
<
|
|
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>
|
|
89
|
-
<p>Sign in to generate
|
|
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
|
|
96
|
-
<
|
|
97
|
-
|
|
98
|
-
|
|
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="
|
|
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
|
|
130
|
-
<button id="pair" class="button" type="button">Generate
|
|
131
|
-
<div id="pairing" class="hidden pairing-output"><code id="pair-command"></code><button class="copy-button" type="button" data-copy="#pair-command"
|
|
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="/
|
|
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="/
|
|
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>
|
package/public/oauth-app.js
CHANGED
|
@@ -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
|
|
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
|
|
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
|
-
|
|
14
|
-
|
|
15
|
-
|
|
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
|
|
20
|
-
try { await signInWithPopup(auth,
|
|
25
|
+
label.textContent = 'Opening…';
|
|
26
|
+
try { await signInWithPopup(auth, provider); }
|
|
21
27
|
catch (error) { showError(error); }
|
|
22
|
-
finally { button.disabled = false; label.textContent =
|
|
23
|
-
}
|
|
24
|
-
|
|
25
|
-
$('#
|
|
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'}
|
|
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;
|
package/public/privacy.html
CHANGED
|
@@ -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-
|
|
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,23 +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="/
|
|
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
|
|
39
|
-
|
|
40
|
-
<h2>Account
|
|
41
|
-
<
|
|
42
|
-
|
|
43
|
-
<h2>
|
|
44
|
-
<
|
|
45
|
-
|
|
46
|
-
<h2>
|
|
47
|
-
<
|
|
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>
|
|
48
69
|
</article>
|
|
49
70
|
</main>
|
|
50
71
|
<footer class="site-footer">
|
|
@@ -52,7 +73,7 @@
|
|
|
52
73
|
<img class="brand-mark" src="/android-chrome-192x192.png" width="30" height="30" alt="" aria-hidden="true">
|
|
53
74
|
<span translate="no">ReMCP</span>
|
|
54
75
|
</div>
|
|
55
|
-
<nav aria-label="Footer"><a href="/docs">Docs</a><a href="/
|
|
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>
|
|
56
77
|
<p>Open-source remote MCP infrastructure.</p>
|
|
57
78
|
</footer>
|
|
58
79
|
</body>
|
package/public/security.html
CHANGED
|
@@ -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-
|
|
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="/
|
|
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>
|
|
38
|
-
<p>ReMCP
|
|
39
|
-
|
|
40
|
-
<h2>
|
|
41
|
-
<
|
|
42
|
-
|
|
43
|
-
<h2>
|
|
44
|
-
<
|
|
45
|
-
|
|
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="/
|
|
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:
|
|
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
|
-
.
|
|
68
|
-
.
|
|
69
|
-
.
|
|
70
|
-
.
|
|
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
|
-
.
|
|
130
|
-
.
|
|
131
|
-
.copy-
|
|
132
|
-
.copy-
|
|
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 {
|
|
172
|
-
.prose .
|
|
173
|
-
.prose .
|
|
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 .
|
|
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
|
-
.
|
|
233
|
-
.
|
|
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; }
|