@relayrail/server 0.1.4 → 0.1.6
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 +44 -11
- package/dist/cli.js +78 -11
- package/dist/index.d.ts +4 -0
- package/dist/index.js +7 -1
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -6,7 +6,7 @@ RelayRail MCP Server - SMS and email connectivity for AI agents via Model Contex
|
|
|
6
6
|
|
|
7
7
|
```bash
|
|
8
8
|
# Use with npx (recommended)
|
|
9
|
-
npx @relayrail/server
|
|
9
|
+
npx @relayrail/server
|
|
10
10
|
|
|
11
11
|
# Or install globally
|
|
12
12
|
npm install -g @relayrail/server
|
|
@@ -23,21 +23,21 @@ Sign up at [relayrail.dev](https://relayrail.dev) and create an agent to get you
|
|
|
23
23
|
**Claude Code (CLI):**
|
|
24
24
|
|
|
25
25
|
```bash
|
|
26
|
-
claude mcp add
|
|
27
|
-
|
|
28
|
-
-- npx @relayrail/server
|
|
26
|
+
claude mcp add relayrail \
|
|
27
|
+
-e RELAYRAIL_API_KEY=rr_your_api_key \
|
|
28
|
+
-- npx @relayrail/server
|
|
29
29
|
```
|
|
30
30
|
|
|
31
31
|
**Claude Desktop:**
|
|
32
32
|
|
|
33
|
-
Add to `~/.config/claude/claude_desktop_config.json
|
|
33
|
+
Add to your config file (`~/.config/claude/claude_desktop_config.json` on macOS/Linux or `%APPDATA%\Claude\claude_desktop_config.json` on Windows):
|
|
34
34
|
|
|
35
35
|
```json
|
|
36
36
|
{
|
|
37
37
|
"mcpServers": {
|
|
38
38
|
"relayrail": {
|
|
39
39
|
"command": "npx",
|
|
40
|
-
"args": ["@relayrail/server"
|
|
40
|
+
"args": ["@relayrail/server"],
|
|
41
41
|
"env": {
|
|
42
42
|
"RELAYRAIL_API_KEY": "rr_your_api_key"
|
|
43
43
|
}
|
|
@@ -46,24 +46,57 @@ Add to `~/.config/claude/claude_desktop_config.json`:
|
|
|
46
46
|
}
|
|
47
47
|
```
|
|
48
48
|
|
|
49
|
+
**Cursor / Cline:**
|
|
50
|
+
|
|
51
|
+
Same JSON format as above in your MCP settings.
|
|
52
|
+
|
|
49
53
|
## Available Tools
|
|
50
54
|
|
|
51
55
|
| Tool | Description |
|
|
52
56
|
|------|-------------|
|
|
53
|
-
| `request_approval` | Request
|
|
54
|
-
| `send_notification` | Send a one-way notification to the user |
|
|
55
|
-
| `await_response` | Wait for a user response to
|
|
57
|
+
| `request_approval` | Request user approval with custom options (Yes/No or custom choices) |
|
|
58
|
+
| `send_notification` | Send a one-way notification to the user (no response expected) |
|
|
59
|
+
| `await_response` | Wait for a user response to a previous approval request |
|
|
56
60
|
| `get_pending_commands` | Retrieve commands sent by the user via SMS/email |
|
|
57
61
|
| `register_agent` | Self-register a new agent (if no API key configured) |
|
|
58
62
|
| `get_account_status` | Check quota usage and account status |
|
|
59
63
|
|
|
64
|
+
### Tool Parameters
|
|
65
|
+
|
|
66
|
+
**`request_approval`**
|
|
67
|
+
- `message` (required): The approval request message
|
|
68
|
+
- `options`: Custom response options (default: `["Yes", "No"]`)
|
|
69
|
+
- `severity`: `"info"` | `"warning"` | `"critical"` - affects notification priority
|
|
70
|
+
- `timeout_minutes`: How long to wait for response (default: 60, max: 1440)
|
|
71
|
+
- `context`: Additional context data (object)
|
|
72
|
+
|
|
73
|
+
**`send_notification`**
|
|
74
|
+
- `message` (required): The notification message
|
|
75
|
+
- `severity`: `"info"` | `"warning"` | `"critical"`
|
|
76
|
+
- `context`: Additional context data (object)
|
|
77
|
+
|
|
78
|
+
**`await_response`**
|
|
79
|
+
- `request_id` (required): The request_id from a previous `request_approval` call
|
|
80
|
+
- `timeout_seconds`: How long to wait (default: 30, max: 300)
|
|
81
|
+
|
|
60
82
|
## Environment Variables
|
|
61
83
|
|
|
62
84
|
| Variable | Required | Description |
|
|
63
85
|
|----------|----------|-------------|
|
|
64
86
|
| `RELAYRAIL_API_KEY` | Yes | Your agent's API key from relayrail.dev |
|
|
65
|
-
| `
|
|
66
|
-
| `RELAYRAIL_DEBUG` | No | Enable debug logging |
|
|
87
|
+
| `RELAYRAIL_BASE_URL` | No | Override API endpoint (default: https://www.relayrail.dev) |
|
|
88
|
+
| `RELAYRAIL_DEBUG` | No | Enable debug logging (set to `true`) |
|
|
89
|
+
|
|
90
|
+
> **Note:** You only need `RELAYRAIL_API_KEY`. The server automatically routes messages through the RelayRail API - no local Telnyx or Resend credentials required.
|
|
91
|
+
|
|
92
|
+
## How It Works
|
|
93
|
+
|
|
94
|
+
1. Your agent calls a tool like `request_approval`
|
|
95
|
+
2. RelayRail sends an SMS or email to the user (based on their preferences)
|
|
96
|
+
3. The user responds via the link or by replying directly
|
|
97
|
+
4. Your agent retrieves the response with `await_response`
|
|
98
|
+
|
|
99
|
+
All message delivery is handled by the RelayRail service - you don't need to configure any SMS or email providers.
|
|
67
100
|
|
|
68
101
|
## Documentation
|
|
69
102
|
|
package/dist/cli.js
CHANGED
|
@@ -147,7 +147,7 @@ function getApiKeyPrefix(apiKey) {
|
|
|
147
147
|
if (!apiKey.startsWith(API_KEY_PREFIX)) {
|
|
148
148
|
return "";
|
|
149
149
|
}
|
|
150
|
-
return apiKey.substring(0, API_KEY_PREFIX.length +
|
|
150
|
+
return apiKey.substring(0, API_KEY_PREFIX.length + 7);
|
|
151
151
|
}
|
|
152
152
|
async function authenticateApiKey(supabase, apiKey) {
|
|
153
153
|
if (!apiKey || !apiKey.startsWith(API_KEY_PREFIX)) {
|
|
@@ -1875,6 +1875,12 @@ var RelayRailServer = class {
|
|
|
1875
1875
|
getContext() {
|
|
1876
1876
|
return this.context;
|
|
1877
1877
|
}
|
|
1878
|
+
/**
|
|
1879
|
+
* Set authentication context directly (from pre-validated API key)
|
|
1880
|
+
*/
|
|
1881
|
+
setAuthContext(context) {
|
|
1882
|
+
this.context = context;
|
|
1883
|
+
}
|
|
1878
1884
|
/**
|
|
1879
1885
|
* Get the underlying MCP server instance
|
|
1880
1886
|
*/
|
|
@@ -1906,6 +1912,23 @@ function createServer(config) {
|
|
|
1906
1912
|
}
|
|
1907
1913
|
|
|
1908
1914
|
// src/cli.ts
|
|
1915
|
+
async function validateApiKey(apiKey, baseUrl) {
|
|
1916
|
+
try {
|
|
1917
|
+
const response = await fetch(`${baseUrl}/api/auth/validate`, {
|
|
1918
|
+
method: "POST",
|
|
1919
|
+
headers: { "Content-Type": "application/json" },
|
|
1920
|
+
body: JSON.stringify({ api_key: apiKey })
|
|
1921
|
+
});
|
|
1922
|
+
const data = await response.json();
|
|
1923
|
+
return data;
|
|
1924
|
+
} catch (error) {
|
|
1925
|
+
return {
|
|
1926
|
+
valid: false,
|
|
1927
|
+
error: `Failed to connect to RelayRail API: ${error instanceof Error ? error.message : "Unknown error"}`,
|
|
1928
|
+
hint: "Check your internet connection and try again."
|
|
1929
|
+
};
|
|
1930
|
+
}
|
|
1931
|
+
}
|
|
1909
1932
|
async function main() {
|
|
1910
1933
|
const apiKey = process.env.RELAYRAIL_API_KEY;
|
|
1911
1934
|
if (!apiKey) {
|
|
@@ -1927,25 +1950,69 @@ async function main() {
|
|
|
1927
1950
|
}, null, 2));
|
|
1928
1951
|
process.exit(1);
|
|
1929
1952
|
}
|
|
1953
|
+
const baseUrl = process.env.RELAYRAIL_BASE_URL || "https://www.relayrail.dev";
|
|
1954
|
+
const validation = await validateApiKey(apiKey, baseUrl);
|
|
1955
|
+
if (!validation.valid) {
|
|
1956
|
+
console.error(`Error: ${validation.error || "Invalid API key"}`);
|
|
1957
|
+
if (validation.hint) {
|
|
1958
|
+
console.error(`Hint: ${validation.hint}`);
|
|
1959
|
+
}
|
|
1960
|
+
console.error("");
|
|
1961
|
+
console.error("Get a new API key from https://relayrail.dev/dashboard/agents");
|
|
1962
|
+
process.exit(1);
|
|
1963
|
+
}
|
|
1930
1964
|
const config = {
|
|
1931
1965
|
supabaseUrl: process.env.SUPABASE_URL || process.env.NEXT_PUBLIC_SUPABASE_URL || "https://lcmdokppykqmigqcwnol.supabase.co",
|
|
1932
|
-
supabaseServiceRoleKey: process.env.SUPABASE_SERVICE_ROLE_KEY || "
|
|
1933
|
-
baseUrl
|
|
1966
|
+
supabaseServiceRoleKey: process.env.SUPABASE_SERVICE_ROLE_KEY || "",
|
|
1967
|
+
baseUrl,
|
|
1934
1968
|
resendApiKey: process.env.RESEND_API_KEY,
|
|
1935
1969
|
telnyxApiKey: process.env.TELNYX_API_KEY,
|
|
1936
1970
|
telnyxPhoneNumber: process.env.TELNYX_PHONE_NUMBER,
|
|
1937
|
-
apiKey
|
|
1971
|
+
apiKey,
|
|
1938
1972
|
// Used for proxy routing when local email/SMS credentials unavailable
|
|
1973
|
+
// Pre-validated context from hosted endpoint
|
|
1974
|
+
validatedAgent: validation.agent,
|
|
1975
|
+
validatedUser: validation.user
|
|
1939
1976
|
};
|
|
1940
1977
|
try {
|
|
1941
1978
|
const server = createServer(config);
|
|
1942
|
-
|
|
1943
|
-
|
|
1944
|
-
|
|
1945
|
-
|
|
1946
|
-
|
|
1947
|
-
|
|
1948
|
-
|
|
1979
|
+
if (validation.agent && validation.user) {
|
|
1980
|
+
const agent = {
|
|
1981
|
+
id: validation.agent.id,
|
|
1982
|
+
name: validation.agent.name,
|
|
1983
|
+
user_id: validation.agent.user_id,
|
|
1984
|
+
is_active: validation.agent.is_active,
|
|
1985
|
+
created_at: validation.agent.created_at,
|
|
1986
|
+
// These fields are not needed for tool operations but required by type
|
|
1987
|
+
api_key_hash: "",
|
|
1988
|
+
api_key_prefix: "",
|
|
1989
|
+
last_seen_at: null,
|
|
1990
|
+
metadata: {}
|
|
1991
|
+
};
|
|
1992
|
+
const user = {
|
|
1993
|
+
id: validation.user.id,
|
|
1994
|
+
email: validation.user.email,
|
|
1995
|
+
phone: validation.user.phone,
|
|
1996
|
+
tier: validation.user.tier,
|
|
1997
|
+
notification_preferences: validation.user.notification_preferences,
|
|
1998
|
+
allow_email_overage: validation.user.allow_email_overage,
|
|
1999
|
+
allow_sms_overage: validation.user.allow_sms_overage,
|
|
2000
|
+
// These fields are not needed for tool operations but required by type
|
|
2001
|
+
stripe_customer_id: null,
|
|
2002
|
+
email_verified: true,
|
|
2003
|
+
created_at: (/* @__PURE__ */ new Date()).toISOString(),
|
|
2004
|
+
updated_at: (/* @__PURE__ */ new Date()).toISOString()
|
|
2005
|
+
};
|
|
2006
|
+
server.setAuthContext({ agent, user });
|
|
2007
|
+
} else {
|
|
2008
|
+
const authenticated = await server.authenticate(apiKey);
|
|
2009
|
+
if (!authenticated) {
|
|
2010
|
+
console.error("Error: Invalid API key");
|
|
2011
|
+
console.error("");
|
|
2012
|
+
console.error("Please check your RELAYRAIL_API_KEY and try again.");
|
|
2013
|
+
console.error("Get a new API key from https://relayrail.dev/dashboard/agents");
|
|
2014
|
+
process.exit(1);
|
|
2015
|
+
}
|
|
1949
2016
|
}
|
|
1950
2017
|
await server.start();
|
|
1951
2018
|
} catch (error) {
|
package/dist/index.d.ts
CHANGED
|
@@ -251,6 +251,10 @@ declare class RelayRailServer {
|
|
|
251
251
|
* Get the current authentication context
|
|
252
252
|
*/
|
|
253
253
|
getContext(): ToolContext | null;
|
|
254
|
+
/**
|
|
255
|
+
* Set authentication context directly (from pre-validated API key)
|
|
256
|
+
*/
|
|
257
|
+
setAuthContext(context: ToolContext): void;
|
|
254
258
|
/**
|
|
255
259
|
* Get the underlying MCP server instance
|
|
256
260
|
*/
|
package/dist/index.js
CHANGED
|
@@ -145,7 +145,7 @@ function getApiKeyPrefix(apiKey) {
|
|
|
145
145
|
if (!apiKey.startsWith(API_KEY_PREFIX)) {
|
|
146
146
|
return "";
|
|
147
147
|
}
|
|
148
|
-
return apiKey.substring(0, API_KEY_PREFIX.length +
|
|
148
|
+
return apiKey.substring(0, API_KEY_PREFIX.length + 7);
|
|
149
149
|
}
|
|
150
150
|
async function authenticateApiKey(supabase, apiKey) {
|
|
151
151
|
if (!apiKey || !apiKey.startsWith(API_KEY_PREFIX)) {
|
|
@@ -1873,6 +1873,12 @@ var RelayRailServer = class {
|
|
|
1873
1873
|
getContext() {
|
|
1874
1874
|
return this.context;
|
|
1875
1875
|
}
|
|
1876
|
+
/**
|
|
1877
|
+
* Set authentication context directly (from pre-validated API key)
|
|
1878
|
+
*/
|
|
1879
|
+
setAuthContext(context) {
|
|
1880
|
+
this.context = context;
|
|
1881
|
+
}
|
|
1876
1882
|
/**
|
|
1877
1883
|
* Get the underlying MCP server instance
|
|
1878
1884
|
*/
|