@event4u/agent-config 1.36.1 → 1.38.0
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/.claude-plugin/marketplace.json +1 -1
- package/CHANGELOG.md +77 -0
- package/README.md +25 -1
- package/docs/contracts/mcp-cloud-scope.md +182 -0
- package/docs/contracts/mcp-phase-1-scope.md +195 -0
- package/docs/guidelines/agent-infra/mcp-request-signing.md +4 -0
- package/docs/mcp-server.md +164 -0
- package/docs/setup/mcp-cloud-endpoints.md +93 -0
- package/docs/setup/mcp-cloud-registry-listing.md +99 -0
- package/docs/setup/mcp-cloud-setup.md +152 -0
- package/docs/setup/mcp-r2-bootstrap.md +82 -0
- package/docs/setup/mcp-server-docker.md +97 -0
- package/package.json +1 -1
- package/scripts/agent-config +29 -0
- package/scripts/mcp_parity_smoke.py +146 -0
- package/scripts/mcp_server/__init__.py +13 -0
- package/scripts/mcp_server/__main__.py +12 -0
- package/scripts/mcp_server/metadata.py +75 -0
- package/scripts/mcp_server/prompts.py +305 -0
- package/scripts/mcp_server/requirements.txt +4 -0
- package/scripts/mcp_server/resources.py +201 -0
- package/scripts/mcp_server/server.py +269 -0
- package/scripts/mcp_server/tools.py +363 -0
- package/scripts/mcp_setup.sh +87 -0
- package/scripts/pack_mcp_content.py +274 -0
- package/scripts/readme_linter.py +1 -1
- package/scripts/skill_linter.py +7 -0
|
@@ -0,0 +1,164 @@
|
|
|
1
|
+
# MCP Server
|
|
2
|
+
|
|
3
|
+
> Status: **experimental** — Phase 1 + 2 + 3 shipped. No `tools/*` primitive yet (Phase 4, deferred behind a design call).
|
|
4
|
+
|
|
5
|
+
`agent-config` ships a built-in [Model Context Protocol](https://modelcontextprotocol.io)
|
|
6
|
+
server that exposes the package's read-only governance surface to MCP-aware
|
|
7
|
+
clients (Claude Desktop, Cursor, Zed, Continue, Codex via MCP). Three channels
|
|
8
|
+
coexist:
|
|
9
|
+
|
|
10
|
+
- **File projection** — `task generate-tools` writes `.claude/`, `.cursor/`,
|
|
11
|
+
`.clinerules/`, `.windsurfrules`. Used by Aider, Cline, Windsurf, Gemini CLI.
|
|
12
|
+
- **Local stdio MCP server** — `scripts/mcp_server/` exposes the same content
|
|
13
|
+
over JSON-RPC. Used by clients that speak MCP natively. Default for personal
|
|
14
|
+
installs.
|
|
15
|
+
- **Remote MCP** *(experimental, opt-in)* — a Cloudflare-hosted TypeScript
|
|
16
|
+
Worker (`workers/mcp/`) serves the same wire surface over HTTP/SSE for
|
|
17
|
+
hosted-agent platforms. URL shapes pinned in
|
|
18
|
+
[`docs/setup/mcp-cloud-endpoints.md`](setup/mcp-cloud-endpoints.md);
|
|
19
|
+
safety contract in
|
|
20
|
+
[`docs/contracts/mcp-cloud-scope.md`](contracts/mcp-cloud-scope.md).
|
|
21
|
+
Wire-parity-checked against the local stdio kernel on every release.
|
|
22
|
+
|
|
23
|
+
The MCP server **never executes engine code, never writes files, never spawns
|
|
24
|
+
shells**. It is a read-only instructional surface — see
|
|
25
|
+
[`docs/contracts/mcp-phase-1-scope.md`](contracts/mcp-phase-1-scope.md).
|
|
26
|
+
|
|
27
|
+
## What the server exposes
|
|
28
|
+
|
|
29
|
+
| Primitive | URIs | Source | Count (this package) |
|
|
30
|
+
|---|---|---|---|
|
|
31
|
+
| `prompts/list` + `prompts/get` | `skill.<name>`, `command.<name>` | `.agent-src/skills/`, `.agent-src/commands/` | 174 skills + 104 commands |
|
|
32
|
+
| `resources/list` + `resources/read` | `rule://<stem>` | `.agent-src/rules/` | 60 rules |
|
|
33
|
+
| ↳ | `guideline://<relpath>` | `docs/guidelines/` | 69 guidelines |
|
|
34
|
+
| ↳ | `context://<relpath>` | `.agent-src/contexts/` | 31 contexts |
|
|
35
|
+
|
|
36
|
+
All resources are served with `mimeType: text/markdown`. Pagination is
|
|
37
|
+
cursor-based (default page size: 100). Hot-reload triggers automatically on
|
|
38
|
+
file mtime changes — edit a rule, reissue `resources/list`, see the update.
|
|
39
|
+
|
|
40
|
+
## Setup — one-line install
|
|
41
|
+
|
|
42
|
+
```bash
|
|
43
|
+
task mcp:setup # maintainer / dev repo
|
|
44
|
+
./agent-config mcp:setup # consumer projects (uses the package CLI wrapper)
|
|
45
|
+
```
|
|
46
|
+
|
|
47
|
+
Either form creates `.venv-mcp/` (Python 3.11+), installs the `mcp` SDK, and
|
|
48
|
+
prints the client config snippet. Run once per checkout.
|
|
49
|
+
|
|
50
|
+
If you do not have `task` or the CLI wrapper available:
|
|
51
|
+
|
|
52
|
+
```bash
|
|
53
|
+
bash scripts/mcp_setup.sh
|
|
54
|
+
```
|
|
55
|
+
|
|
56
|
+
## Running the server
|
|
57
|
+
|
|
58
|
+
```bash
|
|
59
|
+
task mcp:run # maintainer / dev repo
|
|
60
|
+
./agent-config mcp:run # consumer projects
|
|
61
|
+
```
|
|
62
|
+
|
|
63
|
+
Both forms launch `python -m scripts.mcp_server` over stdio against the
|
|
64
|
+
local `.venv-mcp/`. Use these for ad-hoc smoke tests; long-running clients
|
|
65
|
+
(Claude Desktop, Cursor, Zed, Continue) launch the server themselves via
|
|
66
|
+
the config snippets below.
|
|
67
|
+
|
|
68
|
+
## Client configuration
|
|
69
|
+
|
|
70
|
+
### Claude Desktop
|
|
71
|
+
|
|
72
|
+
Edit `~/Library/Application Support/Claude/claude_desktop_config.json` (macOS)
|
|
73
|
+
or `%APPDATA%\Claude\claude_desktop_config.json` (Windows):
|
|
74
|
+
|
|
75
|
+
```json
|
|
76
|
+
{
|
|
77
|
+
"mcpServers": {
|
|
78
|
+
"agent-config": {
|
|
79
|
+
"command": "/absolute/path/to/agent-config/.venv-mcp/bin/python",
|
|
80
|
+
"args": ["-m", "scripts.mcp_server"],
|
|
81
|
+
"cwd": "/absolute/path/to/agent-config"
|
|
82
|
+
}
|
|
83
|
+
}
|
|
84
|
+
}
|
|
85
|
+
```
|
|
86
|
+
|
|
87
|
+
Restart Claude Desktop. The skills, commands, rules, guidelines, and contexts
|
|
88
|
+
appear under the connector dropdown.
|
|
89
|
+
|
|
90
|
+
### Cursor
|
|
91
|
+
|
|
92
|
+
`~/.cursor/mcp.json` (or `<repo>/.cursor/mcp.json`):
|
|
93
|
+
|
|
94
|
+
```json
|
|
95
|
+
{
|
|
96
|
+
"mcpServers": {
|
|
97
|
+
"agent-config": {
|
|
98
|
+
"command": "/absolute/path/to/agent-config/.venv-mcp/bin/python",
|
|
99
|
+
"args": ["-m", "scripts.mcp_server"],
|
|
100
|
+
"cwd": "/absolute/path/to/agent-config"
|
|
101
|
+
}
|
|
102
|
+
}
|
|
103
|
+
}
|
|
104
|
+
```
|
|
105
|
+
|
|
106
|
+
### Zed
|
|
107
|
+
|
|
108
|
+
`~/.config/zed/settings.json`:
|
|
109
|
+
|
|
110
|
+
```json
|
|
111
|
+
{
|
|
112
|
+
"context_servers": {
|
|
113
|
+
"agent-config": {
|
|
114
|
+
"command": {
|
|
115
|
+
"path": "/absolute/path/to/agent-config/.venv-mcp/bin/python",
|
|
116
|
+
"args": ["-m", "scripts.mcp_server"]
|
|
117
|
+
},
|
|
118
|
+
"settings": {}
|
|
119
|
+
}
|
|
120
|
+
}
|
|
121
|
+
}
|
|
122
|
+
```
|
|
123
|
+
|
|
124
|
+
### Continue (`continue.dev`)
|
|
125
|
+
|
|
126
|
+
`~/.continue/config.yaml`:
|
|
127
|
+
|
|
128
|
+
```yaml
|
|
129
|
+
mcpServers:
|
|
130
|
+
- name: agent-config
|
|
131
|
+
command: /absolute/path/to/agent-config/.venv-mcp/bin/python
|
|
132
|
+
args: ["-m", "scripts.mcp_server"]
|
|
133
|
+
cwd: /absolute/path/to/agent-config
|
|
134
|
+
```
|
|
135
|
+
|
|
136
|
+
## Smoke test
|
|
137
|
+
|
|
138
|
+
After configuring a client, run a manual stdio handshake to verify the server
|
|
139
|
+
boots cleanly:
|
|
140
|
+
|
|
141
|
+
```bash
|
|
142
|
+
./agent-config mcp:run < /dev/null
|
|
143
|
+
# Expect stderr: "mcp-server: loaded N prompts (0 warnings)" and
|
|
144
|
+
# "mcp-server: loaded 160 resources (0 warnings)"
|
|
145
|
+
```
|
|
146
|
+
|
|
147
|
+
## Troubleshooting
|
|
148
|
+
|
|
149
|
+
| Symptom | Fix |
|
|
150
|
+
|---|---|
|
|
151
|
+
| Client shows no prompts | Confirm the `cwd` points at the repo root (where `.agent-src/` lives), not at `scripts/`. |
|
|
152
|
+
| `ModuleNotFoundError: mcp` | Re-run `task mcp:setup`. The MCP runtime is isolated in `.venv-mcp/` — the project's base Python 3.9 deliberately does not see it. |
|
|
153
|
+
| Stale prompts after editing | Hot-reload triggers on mtime; touch the file or reissue `resources/list`. |
|
|
154
|
+
| Client refuses to start the server | Check the client's log for the full command. Most clients require **absolute** paths in `command` and `cwd`. |
|
|
155
|
+
|
|
156
|
+
## Scope
|
|
157
|
+
|
|
158
|
+
- **In scope:** read-only prompts + resources, pagination, hot-reload, stdio
|
|
159
|
+
transport, free-tier client compatibility.
|
|
160
|
+
- **Out of scope (Phase 4+):** `tools/*` primitive, SSE / HTTP transport,
|
|
161
|
+
cloud distribution, signed payloads. Tracked in
|
|
162
|
+
[`agents/roadmaps/road-to-mcp-server.md`](../agents/roadmaps/road-to-mcp-server.md).
|
|
163
|
+
|
|
164
|
+
← [Architecture](architecture.md) · [MCP config generation (consumer side)](mcp.md)
|
|
@@ -0,0 +1,93 @@
|
|
|
1
|
+
# MCP Cloud Endpoints — URL shapes & DNS
|
|
2
|
+
|
|
3
|
+
Public URL shapes for the hosted `agent-config-mcp` Worker. Governed
|
|
4
|
+
by `docs/contracts/mcp-cloud-scope.md` (A0-cloud) and Phase 5.2 of
|
|
5
|
+
`agents/roadmaps/road-to-cloudflare-mcp-hosting.md`.
|
|
6
|
+
|
|
7
|
+
## Stability
|
|
8
|
+
|
|
9
|
+
**Experimental.** Inherits the label from `mcp-phase-1-scope.md`. URL
|
|
10
|
+
shapes below are pinned for the lifetime of the *experimental* window;
|
|
11
|
+
breaking changes require a stability-label bump.
|
|
12
|
+
|
|
13
|
+
## URL shapes (pinned)
|
|
14
|
+
|
|
15
|
+
Two surfaces, both serve identical wire contracts (JSON-RPC over POST,
|
|
16
|
+
SSE on GET — A0-cloud invariant 1):
|
|
17
|
+
|
|
18
|
+
| Shape | Resolves to | Use case |
|
|
19
|
+
|---|---|---|
|
|
20
|
+
| `https://mcp.<domain>/latest/sse` | the release currently pointed at by `releases/latest.txt` in R2 | client wants the rolling cutting-edge build |
|
|
21
|
+
| `https://mcp.<domain>/v<X.Y.Z>/sse` | the immutable release `<X.Y.Z>` from the R2 archive | client wants a pinned, reproducible build |
|
|
22
|
+
|
|
23
|
+
The `<domain>` placeholder is operator-configured; the package itself
|
|
24
|
+
does not own DNS. Pin the chosen domain in your fork's
|
|
25
|
+
`mcp-cloud-scope.md` § Bucket / DNS.
|
|
26
|
+
|
|
27
|
+
For JSON-RPC, drop the `/sse` suffix:
|
|
28
|
+
|
|
29
|
+
| JSON-RPC | SSE |
|
|
30
|
+
|---|---|
|
|
31
|
+
| `POST https://mcp.<domain>/latest` | `GET https://mcp.<domain>/latest/sse` |
|
|
32
|
+
| `POST https://mcp.<domain>/v1.37.0` | `GET https://mcp.<domain>/v1.37.0/sse` |
|
|
33
|
+
|
|
34
|
+
The Worker reads its bundled blob at module init (per A0-cloud
|
|
35
|
+
invariant 2); the path prefix in MVP-1 is a routing artefact, not a
|
|
36
|
+
content selector. Multi-version routing lands in MVP-2.
|
|
37
|
+
|
|
38
|
+
## DNS setup (operator-side)
|
|
39
|
+
|
|
40
|
+
One-time, requires Cloudflare account + zone access:
|
|
41
|
+
|
|
42
|
+
```sh
|
|
43
|
+
# 1. Add the Worker custom domain in Cloudflare dashboard:
|
|
44
|
+
# Workers & Pages → agent-config-mcp → Settings → Domains & Routes
|
|
45
|
+
# → Add Custom Domain → "mcp.<your-domain>"
|
|
46
|
+
#
|
|
47
|
+
# 2. Cloudflare creates the AAAA + A records automatically. No manual
|
|
48
|
+
# CNAME — Custom Domains is the supported path (not "Routes").
|
|
49
|
+
#
|
|
50
|
+
# 3. Verify:
|
|
51
|
+
curl -s -X POST https://mcp.<your-domain>/ \
|
|
52
|
+
-H "content-type: application/json" \
|
|
53
|
+
-d '{"jsonrpc":"2.0","id":1,"method":"ping","params":{}}'
|
|
54
|
+
```
|
|
55
|
+
|
|
56
|
+
After DNS is live, uncomment the `routes` block in
|
|
57
|
+
`workers/mcp/wrangler.toml` and redeploy via `wrangler deploy` (or let
|
|
58
|
+
the GitHub Action pick it up on the next release).
|
|
59
|
+
|
|
60
|
+
The fallback `*.workers.dev` URL stays live for free; the custom
|
|
61
|
+
domain is only the public stability promise.
|
|
62
|
+
|
|
63
|
+
## Health probe
|
|
64
|
+
|
|
65
|
+
Every URL accepts `GET /` with no body and returns release identity:
|
|
66
|
+
|
|
67
|
+
```json
|
|
68
|
+
{
|
|
69
|
+
"ok": true,
|
|
70
|
+
"name": "agent-config-mcp",
|
|
71
|
+
"release_key": "v1.37.0-2fc5084",
|
|
72
|
+
"package_version": "1.37.0",
|
|
73
|
+
"signature": "35bc3c5e8b83",
|
|
74
|
+
"schema_version": 1
|
|
75
|
+
}
|
|
76
|
+
```
|
|
77
|
+
|
|
78
|
+
The `signature` field is the wire-surface `skillSetSignature` — same
|
|
79
|
+
hash that MCP clients see under `_meta.skillSetSignature` on the
|
|
80
|
+
identity surface.
|
|
81
|
+
|
|
82
|
+
## Parity smoke
|
|
83
|
+
|
|
84
|
+
Post-deploy CI runs `scripts/mcp_parity_smoke.py` against the new
|
|
85
|
+
deployment with `--target https://mcp.<domain>`. A non-zero exit
|
|
86
|
+
aborts the `latest.txt` repoint, so the previous release keeps
|
|
87
|
+
serving on `/latest/`.
|
|
88
|
+
|
|
89
|
+
## See also
|
|
90
|
+
|
|
91
|
+
- A0-cloud contract: `docs/contracts/mcp-cloud-scope.md`
|
|
92
|
+
- R2 bootstrap: `docs/setup/mcp-r2-bootstrap.md`
|
|
93
|
+
- Local stdio fallback: `scripts/mcp_server/` (unchanged)
|
|
@@ -0,0 +1,99 @@
|
|
|
1
|
+
# MCP Registry Listing — submission package
|
|
2
|
+
|
|
3
|
+
Single source of truth for every MCP-registry submission of the hosted
|
|
4
|
+
`agent-config-mcp` Worker. Copy-paste sections from this file into the
|
|
5
|
+
target registry's template; do not maintain per-registry forks.
|
|
6
|
+
|
|
7
|
+
Phase 6.1 of `agents/roadmaps/road-to-cloudflare-mcp-hosting.md`.
|
|
8
|
+
|
|
9
|
+
## One-liner
|
|
10
|
+
|
|
11
|
+
> Read-only governance surface for AI coding agents — 174 skills, 104
|
|
12
|
+
> commands, 60 rules, 100 guidelines + contexts. Hosted MCP bridge
|
|
13
|
+
> over the `event4u/agent-config` package.
|
|
14
|
+
|
|
15
|
+
## Endpoints
|
|
16
|
+
|
|
17
|
+
| Shape | URL | Use |
|
|
18
|
+
|---|---|---|
|
|
19
|
+
| Rolling latest | `https://mcp.<operator-domain>/latest/sse` | clients tracking the live build |
|
|
20
|
+
| Pinned release | `https://mcp.<operator-domain>/v<X.Y.Z>/sse` | clients pinning a reproducible version |
|
|
21
|
+
| Liveness | `GET https://mcp.<operator-domain>/` | release identity + signature |
|
|
22
|
+
|
|
23
|
+
The `<operator-domain>` placeholder reflects the package's design —
|
|
24
|
+
every operator hosts their own Worker. The package upstream does not
|
|
25
|
+
run a public reference deployment; consumers point their Worker at
|
|
26
|
+
their own R2 bucket per `docs/setup/mcp-r2-bootstrap.md`.
|
|
27
|
+
|
|
28
|
+
## Wire surface (MVP-1)
|
|
29
|
+
|
|
30
|
+
| Method | Status |
|
|
31
|
+
|---|---|
|
|
32
|
+
| `initialize` | implemented |
|
|
33
|
+
| `ping` | implemented |
|
|
34
|
+
| `prompts/list`, `prompts/get` | implemented |
|
|
35
|
+
| `resources/list`, `resources/read` | implemented |
|
|
36
|
+
| `tools/list` | implemented (returns deprecated stubs only) |
|
|
37
|
+
| `tools/call` | **not implemented** — returns `-32601 Method not found` |
|
|
38
|
+
| `notifications/*` | not implemented |
|
|
39
|
+
|
|
40
|
+
No mutation, no auth, no subrequests at runtime. Full contract:
|
|
41
|
+
`docs/contracts/mcp-cloud-scope.md` § A0-cloud.
|
|
42
|
+
|
|
43
|
+
## Stability
|
|
44
|
+
|
|
45
|
+
**Experimental.** Wire surface, URL shapes, and the `_meta.signature`
|
|
46
|
+
field are pinned for the lifetime of the *experimental* window.
|
|
47
|
+
Breaking changes require a stability-label bump (see
|
|
48
|
+
`docs/contracts/mcp-phase-1-scope.md`).
|
|
49
|
+
|
|
50
|
+
## Identity & reproducibility
|
|
51
|
+
|
|
52
|
+
Every response carries `_meta.skillSetSignature` — a 12-char SHA-256
|
|
53
|
+
prefix over the sorted `(uri, body)` pairs of the bundled content.
|
|
54
|
+
Identical content → identical signature, across machines and builds.
|
|
55
|
+
R2 archives every release indefinitely under
|
|
56
|
+
`releases/v<X.Y.Z>-<sha>/`.
|
|
57
|
+
|
|
58
|
+
## Categories (for registry tagging)
|
|
59
|
+
|
|
60
|
+
- `governance`
|
|
61
|
+
- `meta-prompting`
|
|
62
|
+
- `skills`
|
|
63
|
+
- `agent-infrastructure`
|
|
64
|
+
- `code-review`
|
|
65
|
+
- `experimental`
|
|
66
|
+
|
|
67
|
+
## License & contact
|
|
68
|
+
|
|
69
|
+
| Field | Value |
|
|
70
|
+
|---|---|
|
|
71
|
+
| License | MIT |
|
|
72
|
+
| Source | `https://github.com/event4u-app/agent-config` |
|
|
73
|
+
| Maintainer | event4u-app (org) |
|
|
74
|
+
| Contact | GitHub issues |
|
|
75
|
+
|
|
76
|
+
## Links to upstream contracts
|
|
77
|
+
|
|
78
|
+
- A0-cloud safety contract: `docs/contracts/mcp-cloud-scope.md`
|
|
79
|
+
- Phase-1 scope (inherited): `docs/contracts/mcp-phase-1-scope.md`
|
|
80
|
+
- URL shapes & DNS: `docs/setup/mcp-cloud-endpoints.md`
|
|
81
|
+
- Local stdio kernel (predecessor): `scripts/mcp_server/`
|
|
82
|
+
|
|
83
|
+
## Submission targets
|
|
84
|
+
|
|
85
|
+
| Target | Status | Notes |
|
|
86
|
+
|---|---|---|
|
|
87
|
+
| [`awesome-mcp-servers`](https://github.com/punkpeye/awesome-mcp-servers) | ready for PR | low-friction listing, accepts experimental |
|
|
88
|
+
| [`modelcontextprotocol.io` catalog](https://modelcontextprotocol.io/servers) | ready for PR after `awesome-mcp-servers` merges | needs evidence of community uptake |
|
|
89
|
+
|
|
90
|
+
Both submissions reuse the **One-liner**, **Endpoints**, **Wire
|
|
91
|
+
surface**, **Stability**, and **License & contact** sections verbatim
|
|
92
|
+
from this file.
|
|
93
|
+
|
|
94
|
+
## Out of scope for this roadmap
|
|
95
|
+
|
|
96
|
+
npm-launcher listing (`npx @event4u/agent-config-mcp`) targets the
|
|
97
|
+
**local stdio** server, not the hosted Worker. Different transport,
|
|
98
|
+
different installation pattern, different audience — captured in
|
|
99
|
+
`agents/roadmaps/road-to-mcp-server.md` if revived.
|
|
@@ -0,0 +1,152 @@
|
|
|
1
|
+
# Cloudflare MCP — Operator Setup
|
|
2
|
+
|
|
3
|
+
One-stop landing for onboarding a Cloudflare account to host the
|
|
4
|
+
`agent-config-mcp` Worker. Combines bucket bootstrap, DNS, GitHub
|
|
5
|
+
secrets, and troubleshooting in one place.
|
|
6
|
+
|
|
7
|
+
Governed by [`docs/contracts/mcp-cloud-scope.md`](../contracts/mcp-cloud-scope.md)
|
|
8
|
+
(A0-cloud). Deploys run **only** in CI
|
|
9
|
+
([`.github/workflows/deploy-mcp-worker.yml`](../../.github/workflows/deploy-mcp-worker.yml))
|
|
10
|
+
— per A0-cloud invariant 7, never `wrangler deploy` from a developer
|
|
11
|
+
machine.
|
|
12
|
+
|
|
13
|
+
## TL;DR — the happy path
|
|
14
|
+
|
|
15
|
+
```sh
|
|
16
|
+
task mcp:cloud:login # one-time, opens browser
|
|
17
|
+
task mcp:cloud:setup # check → r2-create → r2-verify → whoami
|
|
18
|
+
# Copy account id from output → GitHub Secrets (see § GitHub Secrets)
|
|
19
|
+
# Create scoped API token (see § API Token) → GitHub Secrets
|
|
20
|
+
# Done. First `release: published` triggers the deploy.
|
|
21
|
+
```
|
|
22
|
+
|
|
23
|
+
## Prerequisites
|
|
24
|
+
|
|
25
|
+
| Tool | Version | Install |
|
|
26
|
+
|---|---|---|
|
|
27
|
+
| Node.js | ≥ 20 | <https://nodejs.org/> or `nvm install 20` |
|
|
28
|
+
| `npx`/`wrangler` | wrangler ≥ 4.0 (auto-fetched on first run) | bundled with Node |
|
|
29
|
+
| `gh` CLI | latest | <https://cli.github.com/> (only for manual `deploy-dispatch`) |
|
|
30
|
+
| Cloudflare account | any plan | <https://dash.cloudflare.com/sign-up> |
|
|
31
|
+
|
|
32
|
+
Run `task mcp:cloud:check` to verify all four in one shot.
|
|
33
|
+
|
|
34
|
+
## Step 1 — Cloudflare login
|
|
35
|
+
|
|
36
|
+
```sh
|
|
37
|
+
task mcp:cloud:login
|
|
38
|
+
```
|
|
39
|
+
|
|
40
|
+
Opens a browser to authorize wrangler against your Cloudflare account.
|
|
41
|
+
One-time per developer machine; the token is stored in
|
|
42
|
+
`~/Library/Preferences/.wrangler/` (macOS) or `~/.wrangler/` (Linux).
|
|
43
|
+
|
|
44
|
+
## Step 2 — Enable R2
|
|
45
|
+
|
|
46
|
+
Cloudflare requires a one-time plan activation before R2 buckets can
|
|
47
|
+
be created. **You will hit error `code: 10042` on the first attempt
|
|
48
|
+
if you skip this.**
|
|
49
|
+
|
|
50
|
+
1. <https://dash.cloudflare.com/?to=/:account/r2/overview>
|
|
51
|
+
2. Click **Purchase R2 Plan**
|
|
52
|
+
3. Select **Free Tier** — 10 GB storage / 1 M Class-A / 10 M Class-B
|
|
53
|
+
ops per month at **$0** (credit card required, $0 within quota,
|
|
54
|
+
$0 egress)
|
|
55
|
+
4. Confirm; wait ~30 s for activation
|
|
56
|
+
|
|
57
|
+
## Step 3 — Create the R2 bucket
|
|
58
|
+
|
|
59
|
+
```sh
|
|
60
|
+
task mcp:cloud:r2-create # idempotent — safe to re-run
|
|
61
|
+
task mcp:cloud:r2-verify # ✅ if present
|
|
62
|
+
```
|
|
63
|
+
|
|
64
|
+
The bucket is named `agent-config-mcp` and configured per
|
|
65
|
+
[`docs/setup/mcp-r2-bootstrap.md`](mcp-r2-bootstrap.md) (private,
|
|
66
|
+
indefinite retention, Worker reads via binding).
|
|
67
|
+
|
|
68
|
+
`task mcp:cloud:setup` chains steps 1, 3, and the account-id readout
|
|
69
|
+
in one shot.
|
|
70
|
+
|
|
71
|
+
## Step 4 — API Token
|
|
72
|
+
|
|
73
|
+
The CI deploy pipeline needs a **scoped** token — never reuse the
|
|
74
|
+
Global API Key or a production-tenant token.
|
|
75
|
+
|
|
76
|
+
Dashboard → **My Profile → API Tokens → Create Token → Custom token**:
|
|
77
|
+
|
|
78
|
+
| Permission | Resource | Access |
|
|
79
|
+
|---|---|---|
|
|
80
|
+
| Account · Workers Scripts | your account | Edit |
|
|
81
|
+
| Account · Workers R2 Storage | your account | Edit |
|
|
82
|
+
| User · User Details | — | Read |
|
|
83
|
+
|
|
84
|
+
If you uncomment the `routes` block in `workers/mcp/wrangler.toml`
|
|
85
|
+
(custom domain cutover, Phase 5.2), add **Zone · DNS · Edit** on the
|
|
86
|
+
relevant zone.
|
|
87
|
+
|
|
88
|
+
Copy the generated token immediately — Cloudflare shows it once.
|
|
89
|
+
|
|
90
|
+
## Step 5 — GitHub Secrets
|
|
91
|
+
|
|
92
|
+
Repository → **Settings → Secrets and variables → Actions → New
|
|
93
|
+
repository secret**:
|
|
94
|
+
|
|
95
|
+
| Secret | Value | Source |
|
|
96
|
+
|---|---|---|
|
|
97
|
+
| `CLOUDFLARE_API_TOKEN` | scoped token from Step 4 | dashboard |
|
|
98
|
+
| `CLOUDFLARE_ACCOUNT_ID` | account id | `task mcp:cloud:whoami` |
|
|
99
|
+
|
|
100
|
+
Set them in **Actions** secrets, not **Codespaces** or **Dependabot**
|
|
101
|
+
scopes.
|
|
102
|
+
|
|
103
|
+
## Step 6 — Validate
|
|
104
|
+
|
|
105
|
+
Trigger the deploy workflow manually against an existing tag — no
|
|
106
|
+
release event needed:
|
|
107
|
+
|
|
108
|
+
```sh
|
|
109
|
+
task mcp:cloud:deploy-dispatch TAG=v1.37.0
|
|
110
|
+
gh run watch
|
|
111
|
+
```
|
|
112
|
+
|
|
113
|
+
Green smoke step → `latest.txt` repoints → release is live on
|
|
114
|
+
`*.workers.dev`. A red smoke step leaves `latest.txt` on the previous
|
|
115
|
+
release.
|
|
116
|
+
|
|
117
|
+
## Step 7 — DNS (optional, Phase 5.2)
|
|
118
|
+
|
|
119
|
+
Custom domain `mcp.<your-domain>` setup lives in
|
|
120
|
+
[`docs/setup/mcp-cloud-endpoints.md`](mcp-cloud-endpoints.md) § DNS
|
|
121
|
+
setup. Until cutover, the Worker serves on the free
|
|
122
|
+
`agent-config-mcp.<account>.workers.dev` URL.
|
|
123
|
+
|
|
124
|
+
## Troubleshooting
|
|
125
|
+
|
|
126
|
+
| Symptom | Cause | Fix |
|
|
127
|
+
|---|---|---|
|
|
128
|
+
| `code: 10042` on bucket create | R2 not enabled on account | Step 2 — Enable R2 |
|
|
129
|
+
| `wrangler whoami` shows no Account ID | not logged in | `task mcp:cloud:login` |
|
|
130
|
+
| Workflow fails on `wrangler deploy` with auth error | secret missing/wrong scope | re-check Step 4 token permissions |
|
|
131
|
+
| Smoke step red after deploy | bundle vs. SDK mismatch | check `compatibility_date` in `wrangler.toml` |
|
|
132
|
+
| Bucket create returns `already exists` | bucket present | not an error — `task mcp:cloud:r2-verify` to confirm |
|
|
133
|
+
|
|
134
|
+
## Available tasks
|
|
135
|
+
|
|
136
|
+
| Task | Purpose |
|
|
137
|
+
|---|---|
|
|
138
|
+
| `task mcp:cloud:check` | Preflight — tools + login status |
|
|
139
|
+
| `task mcp:cloud:login` | Interactive wrangler login |
|
|
140
|
+
| `task mcp:cloud:whoami` | Print account id for GitHub Secret |
|
|
141
|
+
| `task mcp:cloud:r2-create` | Create R2 bucket (idempotent) |
|
|
142
|
+
| `task mcp:cloud:r2-verify` | Verify R2 bucket exists |
|
|
143
|
+
| `task mcp:cloud:setup` | Full chain — check → r2 → whoami |
|
|
144
|
+
| `task mcp:cloud:dev` | Local `wrangler dev` on :8787 |
|
|
145
|
+
| `task mcp:cloud:deploy-dispatch TAG=v…` | Manual workflow trigger |
|
|
146
|
+
|
|
147
|
+
## See also
|
|
148
|
+
|
|
149
|
+
- [`docs/contracts/mcp-cloud-scope.md`](../contracts/mcp-cloud-scope.md) — A0-cloud contract
|
|
150
|
+
- [`docs/setup/mcp-r2-bootstrap.md`](mcp-r2-bootstrap.md) — R2 layout & break-glass
|
|
151
|
+
- [`docs/setup/mcp-cloud-endpoints.md`](mcp-cloud-endpoints.md) — URL shapes & DNS
|
|
152
|
+
- [`workers/mcp/README.md`](../../workers/mcp/README.md) — Worker source overview
|
|
@@ -0,0 +1,82 @@
|
|
|
1
|
+
# R2 Bootstrap — agent-config MCP
|
|
2
|
+
|
|
3
|
+
One-time setup for the R2 bucket that holds the Worker's release archive.
|
|
4
|
+
Owned by `mcp-cloud-scope.md` §3.3 and consumed by the deploy pipeline
|
|
5
|
+
(`.github/workflows/deploy-mcp-worker.yml`).
|
|
6
|
+
|
|
7
|
+
## Bucket
|
|
8
|
+
|
|
9
|
+
| Field | Value |
|
|
10
|
+
|---|---|
|
|
11
|
+
| Bucket name | `agent-config-mcp` |
|
|
12
|
+
| Location hint | `auto` (Cloudflare-chosen) |
|
|
13
|
+
| Public access | **off** — Worker reads via binding, never via signed URL |
|
|
14
|
+
| Object retention | indefinite — every release stays for forensics |
|
|
15
|
+
|
|
16
|
+
## Layout
|
|
17
|
+
|
|
18
|
+
```
|
|
19
|
+
agent-config-mcp/
|
|
20
|
+
├─ releases/
|
|
21
|
+
│ ├─ v<X.Y.Z>-<sha>/
|
|
22
|
+
│ │ ├─ content.json.gz # gzipped content blob (R2 archival copy)
|
|
23
|
+
│ │ └─ manifest.json # uncompressed manifest sidecar
|
|
24
|
+
│ └─ latest.txt # one-line: v<X.Y.Z>-<sha>
|
|
25
|
+
└─ (no other prefixes)
|
|
26
|
+
```
|
|
27
|
+
|
|
28
|
+
`latest.txt` is the only mutable object. Every `releases/v*/` directory
|
|
29
|
+
is **immutable** once written; the pipeline refuses to overwrite an
|
|
30
|
+
existing release prefix.
|
|
31
|
+
|
|
32
|
+
## Bootstrap — one-time
|
|
33
|
+
|
|
34
|
+
Requires `wrangler` ≥ 4.0 and a Cloudflare API token with R2 admin scope.
|
|
35
|
+
|
|
36
|
+
```sh
|
|
37
|
+
# 1. Authenticate (interactive, opens browser).
|
|
38
|
+
npx wrangler login
|
|
39
|
+
|
|
40
|
+
# 2. Create the bucket.
|
|
41
|
+
npx wrangler r2 bucket create agent-config-mcp
|
|
42
|
+
|
|
43
|
+
# 3. Verify.
|
|
44
|
+
npx wrangler r2 bucket list | grep agent-config-mcp
|
|
45
|
+
```
|
|
46
|
+
|
|
47
|
+
The Worker binding is declared in `workers/mcp/wrangler.toml` under
|
|
48
|
+
`[[r2_buckets]]`. The pipeline reads/writes via the wrangler CLI in CI,
|
|
49
|
+
not via the Worker — A0-cloud invariant 2 forbids the Worker from
|
|
50
|
+
issuing R2 writes.
|
|
51
|
+
|
|
52
|
+
## Secrets in CI
|
|
53
|
+
|
|
54
|
+
The deploy pipeline needs two GitHub secrets:
|
|
55
|
+
|
|
56
|
+
| Secret | Scope |
|
|
57
|
+
|---|---|
|
|
58
|
+
| `CLOUDFLARE_API_TOKEN` | `Workers Scripts:Edit` + `Workers R2 Storage:Edit` |
|
|
59
|
+
| `CLOUDFLARE_ACCOUNT_ID` | account id (not a token) |
|
|
60
|
+
|
|
61
|
+
The token must be scoped to **this account only**; do not reuse a
|
|
62
|
+
production-tenant token.
|
|
63
|
+
|
|
64
|
+
## Manual fixes — break-glass
|
|
65
|
+
|
|
66
|
+
If `latest.txt` ends up pointing to a broken release, the recovery is to
|
|
67
|
+
repoint it manually:
|
|
68
|
+
|
|
69
|
+
```sh
|
|
70
|
+
# Repoint latest to a known-good release.
|
|
71
|
+
echo -n "v1.36.0-abc1234" | \
|
|
72
|
+
npx wrangler r2 object put agent-config-mcp/releases/latest.txt --pipe
|
|
73
|
+
```
|
|
74
|
+
|
|
75
|
+
Past `releases/v*/` directories are not deleted in recovery — leave the
|
|
76
|
+
forensics intact.
|
|
77
|
+
|
|
78
|
+
## Terraform note
|
|
79
|
+
|
|
80
|
+
The repo does not yet manage CF resources via Terraform. When TF lands,
|
|
81
|
+
this bucket should move into a `cloudflare_r2_bucket` resource and this
|
|
82
|
+
doc shrinks to a pointer.
|
|
@@ -0,0 +1,97 @@
|
|
|
1
|
+
# MCP server — Docker (stdio bundle)
|
|
2
|
+
|
|
3
|
+
Phase-6 F3 ships `docker/mcp-server/Dockerfile`: a stdio-only image of
|
|
4
|
+
the agent-config MCP server, pinned to the same `mcp` + `PyYAML`
|
|
5
|
+
versions the test suite runs against. No HTTP / SSE transport — that
|
|
6
|
+
lives in [`road-to-mcp-distribution.md`](../../agents/roadmaps/road-to-mcp-distribution.md)
|
|
7
|
+
under its own A0 amendment.
|
|
8
|
+
|
|
9
|
+
## Build
|
|
10
|
+
|
|
11
|
+
Build context is the **repo root**, not `docker/mcp-server/` — the
|
|
12
|
+
`COPY` lines reference paths relative to the project root.
|
|
13
|
+
|
|
14
|
+
```bash
|
|
15
|
+
docker build -f docker/mcp-server/Dockerfile -t agent-config-mcp:local .
|
|
16
|
+
```
|
|
17
|
+
|
|
18
|
+
Tag conventions:
|
|
19
|
+
|
|
20
|
+
- `:local` — your machine, current working tree
|
|
21
|
+
- `:vX.Y.Z` — pinned to `package.json::version` at release time
|
|
22
|
+
- `:latest` — most recent release (avoid in MCP client configs; pin)
|
|
23
|
+
|
|
24
|
+
## Run (stdio)
|
|
25
|
+
|
|
26
|
+
The image speaks MCP over **stdin / stdout**. `docker run` must be
|
|
27
|
+
invoked with `-i` (interactive stdin) — without it the server has
|
|
28
|
+
nothing to read and exits silently.
|
|
29
|
+
|
|
30
|
+
```bash
|
|
31
|
+
docker run --rm -i agent-config-mcp:local
|
|
32
|
+
```
|
|
33
|
+
|
|
34
|
+
You should see, on **stderr**:
|
|
35
|
+
|
|
36
|
+
```
|
|
37
|
+
mcp-server: loaded 278 prompts (0 warnings)
|
|
38
|
+
mcp-server: loaded 160 resources (0 warnings)
|
|
39
|
+
mcp-server: registered 2 tools: ['chat_history_append', 'lint_skills']
|
|
40
|
+
mcp-server: identity serverVersion=0.1.0 packageVersion=1.36.1 skillSetSignature=<12-hex>
|
|
41
|
+
```
|
|
42
|
+
|
|
43
|
+
The fourth line is the F1 identity surface — see
|
|
44
|
+
[`mcp-phase-1-scope.md § Phase 6`](../contracts/mcp-phase-1-scope.md)
|
|
45
|
+
for semantics.
|
|
46
|
+
|
|
47
|
+
## Wire into an MCP client
|
|
48
|
+
|
|
49
|
+
```jsonc
|
|
50
|
+
// .mcp.json (or your client's equivalent)
|
|
51
|
+
{
|
|
52
|
+
"mcpServers": {
|
|
53
|
+
"agent-config": {
|
|
54
|
+
"command": "docker",
|
|
55
|
+
"args": ["run", "--rm", "-i", "agent-config-mcp:vX.Y.Z"]
|
|
56
|
+
}
|
|
57
|
+
}
|
|
58
|
+
}
|
|
59
|
+
```
|
|
60
|
+
|
|
61
|
+
## Volume mounts (`chat_history_append`)
|
|
62
|
+
|
|
63
|
+
The `chat_history_append` tool writes to
|
|
64
|
+
`agents/.agent-chat-history` **inside the container**. For writes to
|
|
65
|
+
survive container lifecycle, mount the host directory:
|
|
66
|
+
|
|
67
|
+
```bash
|
|
68
|
+
docker run --rm -i \
|
|
69
|
+
-v "$(pwd)/agents/.agent-chat-history:/app/agents/.agent-chat-history" \
|
|
70
|
+
agent-config-mcp:local
|
|
71
|
+
```
|
|
72
|
+
|
|
73
|
+
Without the mount the tool still succeeds (path-scope check passes
|
|
74
|
+
inside the container), but the appended JSONL evaporates when the
|
|
75
|
+
container exits. The `lint_skills` tool is read-only and needs no
|
|
76
|
+
mount.
|
|
77
|
+
|
|
78
|
+
## Security posture
|
|
79
|
+
|
|
80
|
+
The image inherits the A0 contract verbatim — see
|
|
81
|
+
[`mcp-phase-1-scope.md`](../contracts/mcp-phase-1-scope.md):
|
|
82
|
+
|
|
83
|
+
- No `subprocess`, `os.system`, `requests`, `httpx`, or `urllib`
|
|
84
|
+
imports anywhere on the MCP wire surface (enforced by
|
|
85
|
+
`test_no_unsafe_imports_in_*` tests).
|
|
86
|
+
- Tools allowlist is hardcoded in `scripts/mcp_server/tools.py`. The
|
|
87
|
+
container cannot grow new tools at runtime.
|
|
88
|
+
- Image runs as a non-root user (`mcp:mcp`). Mounted host paths must
|
|
89
|
+
be writable by uid/gid `999` or you'll see permission errors.
|
|
90
|
+
- No HTTP listener — there is no network attack surface. Stdin/stdout
|
|
91
|
+
only.
|
|
92
|
+
|
|
93
|
+
## Size
|
|
94
|
+
|
|
95
|
+
The runtime stage is `python:3.11-slim` + the pinned deps + the
|
|
96
|
+
`.agent-src/` content. Expect ~150-200 MB; the builder stage is
|
|
97
|
+
discarded.
|
package/package.json
CHANGED