@edgegap/mcp 0.1.2 → 0.1.4
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 +96 -44
- package/dist/auth.js +14 -8
- package/dist/tools.js +7 -1
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -1,15 +1,40 @@
|
|
|
1
1
|
# edgegap-mcp
|
|
2
2
|
|
|
3
|
-
An MCP server that lets a coding agent take a developer from "I
|
|
4
|
-
server container" to "players are connected to it" without the
|
|
5
|
-
reading the API reference.
|
|
3
|
+
An MCP server for Edgegap that lets a coding agent take a developer from "I
|
|
4
|
+
have a game server container" to "players are connected to it" without the
|
|
5
|
+
developer reading the API reference.
|
|
6
6
|
|
|
7
7
|
Ten tools, hand-picked. Not generated from the OpenAPI spec — see
|
|
8
8
|
[Scope](#scope) for why.
|
|
9
9
|
|
|
10
10
|
## Install
|
|
11
11
|
|
|
12
|
-
|
|
12
|
+
Two ways to run it. Pick based on how much you care about where your token
|
|
13
|
+
goes — see [Where your token goes](#where-your-token-goes).
|
|
14
|
+
|
|
15
|
+
### Remote endpoint
|
|
16
|
+
|
|
17
|
+
Hosted by Edgegap as a Cloudflare Worker. Nothing to install.
|
|
18
|
+
|
|
19
|
+
```json
|
|
20
|
+
{
|
|
21
|
+
"mcpServers": {
|
|
22
|
+
"edgegap": {
|
|
23
|
+
"type": "http",
|
|
24
|
+
"url": "https://mcp.edgegap.dev/mcp",
|
|
25
|
+
"headers": { "Authorization": "token YOUR_API_TOKEN" }
|
|
26
|
+
}
|
|
27
|
+
}
|
|
28
|
+
}
|
|
29
|
+
```
|
|
30
|
+
|
|
31
|
+
Also works as a custom connector in claude.ai: add
|
|
32
|
+
`https://mcp.edgegap.dev/mcp` and supply the same token.
|
|
33
|
+
|
|
34
|
+
### Local
|
|
35
|
+
|
|
36
|
+
Runs on your own machine, spawned by your editor. One line in your MCP client
|
|
37
|
+
config, nothing to clone, nothing to build.
|
|
13
38
|
|
|
14
39
|
```json
|
|
15
40
|
{
|
|
@@ -25,15 +50,18 @@ One line in your MCP client config. Nothing to clone, nothing to build.
|
|
|
25
50
|
Works in Claude Code, Cursor, Codex, and VS Code. Pin a version in production
|
|
26
51
|
(`@edgegap/mcp@0.1.0`) rather than floating on latest.
|
|
27
52
|
|
|
28
|
-
|
|
29
|
-
|
|
53
|
+
Registered in the official MCP registry as `dev.edgegap/mcp`.
|
|
54
|
+
|
|
55
|
+
> **Node version:** the local server needs Node 18+. Deploying your own copy of
|
|
56
|
+
> the Cloudflare Worker needs Node 22+, because `wrangler` requires it.
|
|
57
|
+
|
|
58
|
+
## Where your token goes
|
|
30
59
|
|
|
31
|
-
|
|
60
|
+
This differs by mode, and the difference is the reason both modes exist.
|
|
32
61
|
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
accepting it. Where that token then lives, exhaustively:
|
|
62
|
+
**Local.** The server runs as a process on your own computer. The first tool
|
|
63
|
+
call asks you for a token, shows what it authorises, and requires an explicit
|
|
64
|
+
acknowledgement before accepting it. Where that token then lives, exhaustively:
|
|
37
65
|
|
|
38
66
|
- one variable in that process's memory, for the life of your editor session
|
|
39
67
|
|
|
@@ -42,18 +70,24 @@ any Edgegap server — the only thing sent to Edgegap is the API call itself,
|
|
|
42
70
|
exactly as if you had run `curl`. Closing your editor revokes this server's
|
|
43
71
|
access completely.
|
|
44
72
|
|
|
73
|
+
**Remote.** Your token is sent to `mcp.edgegap.dev` on every request and
|
|
74
|
+
forwarded from there to the Edgegap API. It transits infrastructure Edgegap
|
|
75
|
+
operates. The worker holds it for the life of the request and does not persist
|
|
76
|
+
it, but that is a "we don't store it" claim rather than a "we never see it"
|
|
77
|
+
claim. The two are different, and only local mode makes the second one.
|
|
78
|
+
|
|
45
79
|
Generate a token at <https://app.edgegap.com/user-settings?tab=tokens>.
|
|
46
80
|
|
|
47
|
-
|
|
48
|
-
clients that cannot show prompts. Do not pass a token as a
|
|
49
|
-
argument — arguments are visible to other processes via `ps`, and
|
|
50
|
-
warns if it detects one.
|
|
81
|
+
In local mode, setting `EDGEGAP_API_TOKEN` takes precedence over the prompt,
|
|
82
|
+
for CI and for clients that cannot show prompts. Do not pass a token as a
|
|
83
|
+
command-line argument — arguments are visible to other processes via `ps`, and
|
|
84
|
+
the server warns if it detects one.
|
|
51
85
|
|
|
52
|
-
**
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
86
|
+
**Which to use.** Remote for a first try, a demo, or a supervised session where
|
|
87
|
+
setup friction matters more than custody. Local for anything unattended,
|
|
88
|
+
anything in an organization with a live game in it, and anything where you
|
|
89
|
+
would rather not extend trust you don't have to. The guardrails described below
|
|
90
|
+
exist only in local mode.
|
|
57
91
|
|
|
58
92
|
## Read this before connecting an agent
|
|
59
93
|
|
|
@@ -70,22 +104,28 @@ Consequences worth being deliberate about:
|
|
|
70
104
|
- Anything the agent logs, echoes, or sends to a model provider is a place the
|
|
71
105
|
token could end up. This server does not log it, but it cannot control what
|
|
72
106
|
the rest of the agent does.
|
|
107
|
+
- On the remote endpoint, the same unscoped token is additionally handled by
|
|
108
|
+
Edgegap's worker on every call.
|
|
73
109
|
|
|
74
110
|
Recommended setup, in decreasing order of caution:
|
|
75
111
|
|
|
76
112
|
| Situation | Setup |
|
|
77
113
|
| --- | --- |
|
|
78
|
-
| Unattended or autonomous agent | Separate non-production organization, plus `EDGEGAP_READ_ONLY=1` |
|
|
79
|
-
| Supervised agent, live game in the org | `EDGEGAP_APP_ALLOWLIST` scoped to the app being worked on, plus `EDGEGAP_MAX_DURATION_MINUTES` |
|
|
80
|
-
| Solo developer, no production workload | Defaults are fine; revoke the token when finished |
|
|
114
|
+
| Unattended or autonomous agent | Local mode. Separate non-production organization, plus `EDGEGAP_READ_ONLY=1` |
|
|
115
|
+
| Supervised agent, live game in the org | Local mode. `EDGEGAP_APP_ALLOWLIST` scoped to the app being worked on, plus `EDGEGAP_MAX_DURATION_MINUTES` |
|
|
116
|
+
| Solo developer, no production workload | Either mode. Defaults are fine; revoke the token when finished |
|
|
81
117
|
|
|
82
|
-
The allowlist and read-only flag are enforced in
|
|
83
|
-
protect against an agent that makes a mistake, not against one that has
|
|
84
|
-
compromised into calling the API directly. They narrow the blast radius;
|
|
85
|
-
do not remove it.
|
|
118
|
+
The allowlist and read-only flag are enforced in the local server, which means
|
|
119
|
+
they protect against an agent that makes a mistake, not against one that has
|
|
120
|
+
been compromised into calling the API directly. They narrow the blast radius;
|
|
121
|
+
they do not remove it.
|
|
86
122
|
|
|
87
123
|
### Environment variables
|
|
88
124
|
|
|
125
|
+
These configure the local server. On the remote endpoint they are set by
|
|
126
|
+
Edgegap and cannot be changed per developer — if you need any of them, run
|
|
127
|
+
locally.
|
|
128
|
+
|
|
89
129
|
| Variable | Default | Purpose |
|
|
90
130
|
| --- | --- | --- |
|
|
91
131
|
| `EDGEGAP_API_TOKEN` | *(prompted)* | API token. Optional — omit it and the developer is asked at first use. The `token ` prefix is added for you. |
|
|
@@ -94,22 +134,23 @@ do not remove it.
|
|
|
94
134
|
| `EDGEGAP_MAX_DURATION_MINUTES` | `60` | Ceiling on `max_duration` the agent may set on a version. Caps runaway cost from an unattended agent. |
|
|
95
135
|
| `EDGEGAP_TIMEOUT_MS` | `30000` | Per-request HTTP timeout. |
|
|
96
136
|
|
|
97
|
-
##
|
|
137
|
+
## Tools
|
|
98
138
|
|
|
99
|
-
|
|
139
|
+
Ten tools, listed in the order they fall along the golden path. The same ten in
|
|
140
|
+
both modes.
|
|
100
141
|
|
|
101
|
-
|
|
|
102
|
-
| --- | --- | --- |
|
|
103
|
-
|
|
|
104
|
-
|
|
|
105
|
-
|
|
|
106
|
-
|
|
|
107
|
-
|
|
|
108
|
-
|
|
|
109
|
-
|
|
|
110
|
-
|
|
|
111
|
-
|
|
|
112
|
-
|
|
|
142
|
+
| Tool | Mutating | What it's for |
|
|
143
|
+
| --- | --- | --- |
|
|
144
|
+
| `edgegap_list_apps` | | Orient before doing anything. Prevents duplicate applications. |
|
|
145
|
+
| `edgegap_create_app` | ● | Create the container for versions. |
|
|
146
|
+
| `edgegap_list_app_versions` | | Find a deployable version, or copy settings from a working one. |
|
|
147
|
+
| `edgegap_create_app_version` | ● | Register a container image with CPU, memory, and ports. |
|
|
148
|
+
| `edgegap_deploy` | ● | Start one instance near specified players. |
|
|
149
|
+
| `edgegap_get_deployment` | | Single status read. |
|
|
150
|
+
| `edgegap_wait_for_deployment` | | Poll to ready with backoff, then return the connection address. |
|
|
151
|
+
| `edgegap_list_deployments` | | Find orphaned servers from earlier sessions. |
|
|
152
|
+
| `edgegap_stop_deployment` | ● | Graceful SIGTERM, one deployment at a time. |
|
|
153
|
+
| `edgegap_get_deployment_logs` | | Container output and crash exit code after a failure. |
|
|
113
154
|
|
|
114
155
|
## Design decisions
|
|
115
156
|
|
|
@@ -135,6 +176,13 @@ player location are caught here rather than surfacing as an opaque 400.
|
|
|
135
176
|
There is no bulk-stop tool, because an agent with a filter expression and a bug
|
|
136
177
|
can stop a production fleet.
|
|
137
178
|
|
|
179
|
+
**Both a hosted endpoint and a local package.** The hosted endpoint removes
|
|
180
|
+
every step between finding this server and calling a tool, which is where most
|
|
181
|
+
developers drop out. The local package is the only way to run the server
|
|
182
|
+
without extending custody of an unscoped token to a third party, including us.
|
|
183
|
+
Neither one dominates the other, so both ship. See `worker/DECISION.md` for the
|
|
184
|
+
longer version.
|
|
185
|
+
|
|
138
186
|
## Scope
|
|
139
187
|
|
|
140
188
|
Not exposed, on purpose: matchmaking, relays, private fleets, smart fleets,
|
|
@@ -147,6 +195,9 @@ would trade the conversion path for surface area.
|
|
|
147
195
|
|
|
148
196
|
## Known limitation: asking for the token at all
|
|
149
197
|
|
|
198
|
+
This applies to local mode, where the token is collected through elicitation
|
|
199
|
+
rather than read from config.
|
|
200
|
+
|
|
150
201
|
The MCP specification says servers should not use elicitation to collect
|
|
151
202
|
sensitive data, and an API token is sensitive. This server does it anyway,
|
|
152
203
|
because requiring a token in a config file before anything works is the largest
|
|
@@ -159,9 +210,10 @@ plain-language disclosure, required acknowledgement, redaction from all output,
|
|
|
159
210
|
and the environment variable always winning when present. Removing any of them
|
|
160
211
|
breaks the trade.
|
|
161
212
|
|
|
162
|
-
The real fix is on Edgegap's side
|
|
163
|
-
issued through OAuth rather than pasted as
|
|
164
|
-
interactive prompt is a workaround and is
|
|
213
|
+
The real fix is on Edgegap's side and would improve both modes: scoped,
|
|
214
|
+
revocable, deploy-only credentials, issued through OAuth rather than pasted as
|
|
215
|
+
a secret. Until those exist, the interactive prompt is a workaround and is
|
|
216
|
+
labelled as one in the code.
|
|
165
217
|
|
|
166
218
|
## Development
|
|
167
219
|
|
package/dist/auth.js
CHANGED
|
@@ -189,24 +189,30 @@ export class TokenProvider {
|
|
|
189
189
|
return token;
|
|
190
190
|
}
|
|
191
191
|
}
|
|
192
|
-
/**
|
|
193
|
-
* Credential source for the hosted Worker: the token arrives on the request
|
|
194
|
-
* and lives only as long as this object, which is created per request and
|
|
195
|
-
* garbage collected with it. Nothing is cached across requests, deliberately.
|
|
196
|
-
*/
|
|
197
192
|
export class StaticTokenProvider {
|
|
198
193
|
token;
|
|
194
|
+
unavailableMessage;
|
|
199
195
|
used = false;
|
|
200
|
-
|
|
196
|
+
/**
|
|
197
|
+
* @param token credential for this request, if the caller found a usable one
|
|
198
|
+
* @param unavailableMessage what to tell the agent when it calls a tool and
|
|
199
|
+
* there is no token. The transport knows WHY the token is missing — absent
|
|
200
|
+
* header, or a header carrying some other client's credential — and that
|
|
201
|
+
* distinction is the whole difference between a developer who can fix their
|
|
202
|
+
* setup and one staring at a generic 401. Defaults to the generic text.
|
|
203
|
+
*/
|
|
204
|
+
constructor(token, unavailableMessage) {
|
|
201
205
|
this.token = token;
|
|
206
|
+
this.unavailableMessage = unavailableMessage;
|
|
202
207
|
}
|
|
203
208
|
get current() {
|
|
204
209
|
return this.token;
|
|
205
210
|
}
|
|
206
211
|
async get() {
|
|
207
212
|
if (!this.token) {
|
|
208
|
-
throw new TokenUnavailableError(
|
|
209
|
-
'
|
|
213
|
+
throw new TokenUnavailableError(this.unavailableMessage ??
|
|
214
|
+
'No Edgegap API token on this request. Send it as an Authorization ' +
|
|
215
|
+
'header on the MCP connection.');
|
|
210
216
|
}
|
|
211
217
|
return this.token;
|
|
212
218
|
}
|
package/dist/tools.js
CHANGED
|
@@ -55,7 +55,13 @@ function guard(auth, fn) {
|
|
|
55
55
|
function errorHint(err) {
|
|
56
56
|
switch (err.status) {
|
|
57
57
|
case 401:
|
|
58
|
-
|
|
58
|
+
// Deliberately does not promise a re-prompt: the local server asks again
|
|
59
|
+
// on the next call, the hosted relay cannot, and a hint that lies about
|
|
60
|
+
// what happens next sends the developer looking in the wrong place.
|
|
61
|
+
return ('Edgegap rejected the token. It may be expired, revoked, or from a ' +
|
|
62
|
+
'different organization. Check it at ' +
|
|
63
|
+
'https://app.edgegap.com/user-settings?tab=tokens. The token has been ' +
|
|
64
|
+
'discarded from this session.');
|
|
59
65
|
case 404:
|
|
60
66
|
return 'the application or version name does not exist. Call edgegap_list_apps first.';
|
|
61
67
|
case 409:
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@edgegap/mcp",
|
|
3
3
|
"mcpName": "dev.edgegap/mcp",
|
|
4
|
-
"version": "0.1.
|
|
4
|
+
"version": "0.1.4",
|
|
5
5
|
"description": "Deploy game servers on Edgegap from your coding agent. Runs locally; your API token never leaves your machine.",
|
|
6
6
|
"scripts": {
|
|
7
7
|
"prebuild": "rm -rf dist",
|