From 01cf5f66e16e3c04f1714c9ca14fe439b51e2315 Mon Sep 17 00:00:00 2001 From: Claude Date: Wed, 24 Jun 2026 07:33:27 +0000 Subject: [PATCH 1/2] Add boj-server.net website: install configurator + cartridge catalogue MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Static, no-build Cloudflare Pages bundle in site/ serving as the project's permanent presence and access point: - Hub page (site/index.html) with a live install configurator (base boj-server + NeSy / Agentic / Coordination bundles, per-client commands) and a browsable catalogue of all 139 cartridges generated from the canonical registry. - Vanilla CSS/JS, zero dependencies; strict first-party CSP in site/_headers. - catalog.json snapshot + tools/site-catalog/build-catalog.sh regenerator. - Estate-standard deploy config: wrangler.toml (output dir site/), cloudflare-dns-zone.txt reference, scripts/cloudflare/*.affine (avow parity). - docs/website/CLOUDFLARE-SETUP.adoc runbook (dashboard Git-connect go-live, API-token scopes for agent-driven DNS/Pages). Licensing: establish the two-licence scheme — LICENSES/ now holds MPL-2.0 + CC-BY-SA-4.0 with a README; new code is MPL-2.0, new docs CC-BY-SA-4.0. Co-Authored-By: Claude Opus 4.8 Claude-Session: https://claude.ai/code/session_01XrPAh7eBSUcVKauTVdXH9Y --- LICENSES/CC-BY-SA-4.0.txt | 170 +++++++++++++ LICENSES/README.adoc | 43 +++- cloudflare-dns-zone.txt | 27 ++ docs/website/CLOUDFLARE-SETUP.adoc | 122 +++++++++ scripts/cloudflare/CreatePagesProject.affine | 85 +++++++ scripts/cloudflare/DeployDirect.affine | 71 ++++++ site/.well-known/security.txt | 10 + site/CNAME | 1 + site/README.adoc | 17 ++ site/_headers | 20 ++ site/_redirects | 10 + site/assets/app.js | 253 +++++++++++++++++++ site/assets/favicon.svg | 7 + site/assets/style.css | 175 +++++++++++++ site/catalog.json | 146 +++++++++++ site/index.html | 186 ++++++++++++++ site/index.md | 23 -- site/robots.txt | 5 + site/sitemap.xml | 10 + tools/site-catalog/build-catalog.sh | 53 ++++ wrangler.toml | 7 + 21 files changed, 1411 insertions(+), 30 deletions(-) create mode 100644 LICENSES/CC-BY-SA-4.0.txt create mode 100644 cloudflare-dns-zone.txt create mode 100644 docs/website/CLOUDFLARE-SETUP.adoc create mode 100644 scripts/cloudflare/CreatePagesProject.affine create mode 100644 scripts/cloudflare/DeployDirect.affine create mode 100644 site/.well-known/security.txt create mode 100644 site/CNAME create mode 100644 site/README.adoc create mode 100644 site/_headers create mode 100644 site/_redirects create mode 100644 site/assets/app.js create mode 100644 site/assets/favicon.svg create mode 100644 site/assets/style.css create mode 100644 site/catalog.json create mode 100644 site/index.html delete mode 100644 site/index.md create mode 100644 site/robots.txt create mode 100644 site/sitemap.xml create mode 100755 tools/site-catalog/build-catalog.sh create mode 100644 wrangler.toml diff --git a/LICENSES/CC-BY-SA-4.0.txt b/LICENSES/CC-BY-SA-4.0.txt new file mode 100644 index 00000000..835a6836 --- /dev/null +++ b/LICENSES/CC-BY-SA-4.0.txt @@ -0,0 +1,170 @@ +Creative Commons Attribution-ShareAlike 4.0 International + + Creative Commons Corporation (“Creative Commons”) is not a law firm and does not provide legal services or legal advice. Distribution of Creative Commons public licenses does not create a lawyer-client or other relationship. Creative Commons makes its licenses and related information available on an “as-is” basis. Creative Commons gives no warranties regarding its licenses, any material licensed under their terms and conditions, or any related information. Creative Commons disclaims all liability for damages resulting from their use to the fullest extent possible. + +Using Creative Commons Public Licenses + +Creative Commons public licenses provide a standard set of terms and conditions that creators and other rights holders may use to share original works of authorship and other material subject to copyright and certain other rights specified in the public license below. The following considerations are for informational purposes only, are not exhaustive, and do not form part of our licenses. + +Considerations for licensors: Our public licenses are intended for use by those authorized to give the public permission to use material in ways otherwise restricted by copyright and certain other rights. Our licenses are irrevocable. Licensors should read and understand the terms and conditions of the license they choose before applying it. Licensors should also secure all rights necessary before applying our licenses so that the public can reuse the material as expected. Licensors should clearly mark any material not subject to the license. This includes other CC-licensed material, or material used under an exception or limitation to copyright. More considerations for licensors. + +Considerations for the public: By using one of our public licenses, a licensor grants the public permission to use the licensed material under specified terms and conditions. If the licensor’s permission is not necessary for any reason–for example, because of any applicable exception or limitation to copyright–then that use is not regulated by the license. Our licenses grant only permissions under copyright and certain other rights that a licensor has authority to grant. Use of the licensed material may still be restricted for other reasons, including because others have copyright or other rights in the material. A licensor may make special requests, such as asking that all changes be marked or described. + +Although not required by our licenses, you are encouraged to respect those requests where reasonable. More considerations for the public. + +Creative Commons Attribution-ShareAlike 4.0 International Public License + +By exercising the Licensed Rights (defined below), You accept and agree to be bound by the terms and conditions of this Creative Commons Attribution-ShareAlike 4.0 International Public License ("Public License"). To the extent this Public License may be interpreted as a contract, You are granted the Licensed Rights in consideration of Your acceptance of these terms and conditions, and the Licensor grants You such rights in consideration of benefits the Licensor receives from making the Licensed Material available under these terms and conditions. + +Section 1 – Definitions. + + a. Adapted Material means material subject to Copyright and Similar Rights that is derived from or based upon the Licensed Material and in which the Licensed Material is translated, altered, arranged, transformed, or otherwise modified in a manner requiring permission under the Copyright and Similar Rights held by the Licensor. For purposes of this Public License, where the Licensed Material is a musical work, performance, or sound recording, Adapted Material is always produced where the Licensed Material is synched in timed relation with a moving image. + + b. Adapter's License means the license You apply to Your Copyright and Similar Rights in Your contributions to Adapted Material in accordance with the terms and conditions of this Public License. + + c. BY-SA Compatible License means a license listed at creativecommons.org/compatiblelicenses, approved by Creative Commons as essentially the equivalent of this Public License. + + d. Copyright and Similar Rights means copyright and/or similar rights closely related to copyright including, without limitation, performance, broadcast, sound recording, and Sui Generis Database Rights, without regard to how the rights are labeled or categorized. For purposes of this Public License, the rights specified in Section 2(b)(1)-(2) are not Copyright and Similar Rights. + + e. Effective Technological Measures means those measures that, in the absence of proper authority, may not be circumvented under laws fulfilling obligations under Article 11 of the WIPO Copyright Treaty adopted on December 20, 1996, and/or similar international agreements. + + f. Exceptions and Limitations means fair use, fair dealing, and/or any other exception or limitation to Copyright and Similar Rights that applies to Your use of the Licensed Material. + + g. License Elements means the license attributes listed in the name of a Creative Commons Public License. The License Elements of this Public License are Attribution and ShareAlike. + + h. Licensed Material means the artistic or literary work, database, or other material to which the Licensor applied this Public License. + + i. Licensed Rights means the rights granted to You subject to the terms and conditions of this Public License, which are limited to all Copyright and Similar Rights that apply to Your use of the Licensed Material and that the Licensor has authority to license. + + j. Licensor means the individual(s) or entity(ies) granting rights under this Public License. + + k. Share means to provide material to the public by any means or process that requires permission under the Licensed Rights, such as reproduction, public display, public performance, distribution, dissemination, communication, or importation, and to make material available to the public including in ways that members of the public may access the material from a place and at a time individually chosen by them. + + l. Sui Generis Database Rights means rights other than copyright resulting from Directive 96/9/EC of the European Parliament and of the Council of 11 March 1996 on the legal protection of databases, as amended and/or succeeded, as well as other essentially equivalent rights anywhere in the world. + + m. You means the individual or entity exercising the Licensed Rights under this Public License. Your has a corresponding meaning. + +Section 2 – Scope. + + a. License grant. + + 1. Subject to the terms and conditions of this Public License, the Licensor hereby grants You a worldwide, royalty-free, non-sublicensable, non-exclusive, irrevocable license to exercise the Licensed Rights in the Licensed Material to: + + A. reproduce and Share the Licensed Material, in whole or in part; and + + B. produce, reproduce, and Share Adapted Material. + + 2. Exceptions and Limitations. For the avoidance of doubt, where Exceptions and Limitations apply to Your use, this Public License does not apply, and You do not need to comply with its terms and conditions. + + 3. Term. The term of this Public License is specified in Section 6(a). + + 4. Media and formats; technical modifications allowed. The Licensor authorizes You to exercise the Licensed Rights in all media and formats whether now known or hereafter created, and to make technical modifications necessary to do so. The Licensor waives and/or agrees not to assert any right or authority to forbid You from making technical modifications necessary to exercise the Licensed Rights, including technical modifications necessary to circumvent Effective Technological Measures. For purposes of this Public License, simply making modifications authorized by this Section 2(a)(4) never produces Adapted Material. + + 5. Downstream recipients. + + A. Offer from the Licensor – Licensed Material. Every recipient of the Licensed Material automatically receives an offer from the Licensor to exercise the Licensed Rights under the terms and conditions of this Public License. + + B. Additional offer from the Licensor – Adapted Material. Every recipient of Adapted Material from You automatically receives an offer from the Licensor to exercise the Licensed Rights in the Adapted Material under the conditions of the Adapter’s License You apply. + + C. No downstream restrictions. You may not offer or impose any additional or different terms or conditions on, or apply any Effective Technological Measures to, the Licensed Material if doing so restricts exercise of the Licensed Rights by any recipient of the Licensed Material. + + 6. No endorsement. Nothing in this Public License constitutes or may be construed as permission to assert or imply that You are, or that Your use of the Licensed Material is, connected with, or sponsored, endorsed, or granted official status by, the Licensor or others designated to receive attribution as provided in Section 3(a)(1)(A)(i). + + b. Other rights. + + 1. Moral rights, such as the right of integrity, are not licensed under this Public License, nor are publicity, privacy, and/or other similar personality rights; however, to the extent possible, the Licensor waives and/or agrees not to assert any such rights held by the Licensor to the limited extent necessary to allow You to exercise the Licensed Rights, but not otherwise. + + 2. Patent and trademark rights are not licensed under this Public License. + + 3. To the extent possible, the Licensor waives any right to collect royalties from You for the exercise of the Licensed Rights, whether directly or through a collecting society under any voluntary or waivable statutory or compulsory licensing scheme. In all other cases the Licensor expressly reserves any right to collect such royalties. + +Section 3 – License Conditions. + +Your exercise of the Licensed Rights is expressly made subject to the following conditions. + + a. Attribution. + + 1. If You Share the Licensed Material (including in modified form), You must: + + A. retain the following if it is supplied by the Licensor with the Licensed Material: + + i. identification of the creator(s) of the Licensed Material and any others designated to receive attribution, in any reasonable manner requested by the Licensor (including by pseudonym if designated); + + ii. a copyright notice; + + iii. a notice that refers to this Public License; + + iv. a notice that refers to the disclaimer of warranties; + + v. a URI or hyperlink to the Licensed Material to the extent reasonably practicable; + + B. indicate if You modified the Licensed Material and retain an indication of any previous modifications; and + + C. indicate the Licensed Material is licensed under this Public License, and include the text of, or the URI or hyperlink to, this Public License. + + 2. You may satisfy the conditions in Section 3(a)(1) in any reasonable manner based on the medium, means, and context in which You Share the Licensed Material. For example, it may be reasonable to satisfy the conditions by providing a URI or hyperlink to a resource that includes the required information. + + 3. If requested by the Licensor, You must remove any of the information required by Section 3(a)(1)(A) to the extent reasonably practicable. + + b. ShareAlike.In addition to the conditions in Section 3(a), if You Share Adapted Material You produce, the following conditions also apply. + + 1. The Adapter’s License You apply must be a Creative Commons license with the same License Elements, this version or later, or a BY-SA Compatible License. + + 2. You must include the text of, or the URI or hyperlink to, the Adapter's License You apply. You may satisfy this condition in any reasonable manner based on the medium, means, and context in which You Share Adapted Material. + + 3. You may not offer or impose any additional or different terms or conditions on, or apply any Effective Technological Measures to, Adapted Material that restrict exercise of the rights granted under the Adapter's License You apply. + +Section 4 – Sui Generis Database Rights. + +Where the Licensed Rights include Sui Generis Database Rights that apply to Your use of the Licensed Material: + + a. for the avoidance of doubt, Section 2(a)(1) grants You the right to extract, reuse, reproduce, and Share all or a substantial portion of the contents of the database; + + b. if You include all or a substantial portion of the database contents in a database in which You have Sui Generis Database Rights, then the database in which You have Sui Generis Database Rights (but not its individual contents) is Adapted Material, including for purposes of Section 3(b); and + + c. You must comply with the conditions in Section 3(a) if You Share all or a substantial portion of the contents of the database. +For the avoidance of doubt, this Section 4 supplements and does not replace Your obligations under this Public License where the Licensed Rights include other Copyright and Similar Rights. + +Section 5 – Disclaimer of Warranties and Limitation of Liability. + + a. Unless otherwise separately undertaken by the Licensor, to the extent possible, the Licensor offers the Licensed Material as-is and as-available, and makes no representations or warranties of any kind concerning the Licensed Material, whether express, implied, statutory, or other. This includes, without limitation, warranties of title, merchantability, fitness for a particular purpose, non-infringement, absence of latent or other defects, accuracy, or the presence or absence of errors, whether or not known or discoverable. Where disclaimers of warranties are not allowed in full or in part, this disclaimer may not apply to You. + + b. To the extent possible, in no event will the Licensor be liable to You on any legal theory (including, without limitation, negligence) or otherwise for any direct, special, indirect, incidental, consequential, punitive, exemplary, or other losses, costs, expenses, or damages arising out of this Public License or use of the Licensed Material, even if the Licensor has been advised of the possibility of such losses, costs, expenses, or damages. Where a limitation of liability is not allowed in full or in part, this limitation may not apply to You. + + c. The disclaimer of warranties and limitation of liability provided above shall be interpreted in a manner that, to the extent possible, most closely approximates an absolute disclaimer and waiver of all liability. + +Section 6 – Term and Termination. + + a. This Public License applies for the term of the Copyright and Similar Rights licensed here. However, if You fail to comply with this Public License, then Your rights under this Public License terminate automatically. + + b. Where Your right to use the Licensed Material has terminated under Section 6(a), it reinstates: + + 1. automatically as of the date the violation is cured, provided it is cured within 30 days of Your discovery of the violation; or + + 2. upon express reinstatement by the Licensor. + + c. For the avoidance of doubt, this Section 6(b) does not affect any right the Licensor may have to seek remedies for Your violations of this Public License. + + d. For the avoidance of doubt, the Licensor may also offer the Licensed Material under separate terms or conditions or stop distributing the Licensed Material at any time; however, doing so will not terminate this Public License. + + e. Sections 1, 5, 6, 7, and 8 survive termination of this Public License. + +Section 7 – Other Terms and Conditions. + + a. The Licensor shall not be bound by any additional or different terms or conditions communicated by You unless expressly agreed. + + b. Any arrangements, understandings, or agreements regarding the Licensed Material not stated herein are separate from and independent of the terms and conditions of this Public License. + +Section 8 – Interpretation. + + a. For the avoidance of doubt, this Public License does not, and shall not be interpreted to, reduce, limit, restrict, or impose conditions on any use of the Licensed Material that could lawfully be made without permission under this Public License. + + b. To the extent possible, if any provision of this Public License is deemed unenforceable, it shall be automatically reformed to the minimum extent necessary to make it enforceable. If the provision cannot be reformed, it shall be severed from this Public License without affecting the enforceability of the remaining terms and conditions. + + c. No term or condition of this Public License will be waived and no failure to comply consented to unless expressly agreed to by the Licensor. + + d. Nothing in this Public License constitutes or may be interpreted as a limitation upon, or waiver of, any privileges and immunities that apply to the Licensor or You, including from the legal processes of any jurisdiction or authority. + +Creative Commons is not a party to its public licenses. Notwithstanding, Creative Commons may elect to apply one of its public licenses to material it publishes and in those instances will be considered the “Licensor.” Except for the limited purpose of indicating that material is shared under a Creative Commons public license or as otherwise permitted by the Creative Commons policies published at creativecommons.org/policies, Creative Commons does not authorize the use of the trademark “Creative Commons” or any other trademark or logo of Creative Commons without its prior written consent including, without limitation, in connection with any unauthorized modifications to any of its public licenses or any other arrangements, understandings, or agreements concerning use of licensed material. For the avoidance of doubt, this paragraph does not form part of the public licenses. + +Creative Commons may be contacted at creativecommons.org. diff --git a/LICENSES/README.adoc b/LICENSES/README.adoc index 1095c72f..6bf223da 100644 --- a/LICENSES/README.adoc +++ b/LICENSES/README.adoc @@ -1,10 +1,39 @@ -// SPDX-License-Identifier: MPL-2.0 -// Copyright (c) Jonathan D.A. Jewell -= Licensing Folder +// SPDX-License-Identifier: CC-BY-SA-4.0 +// SPDX-FileCopyrightText: 2026 Jonathan D.A. Jewell (hyperpolymath) += Licensing -Store repository licensing/supporting legal texts here. +boj-server uses exactly two licences. -Conventions: +[cols="1,1,2"] +|=== +| Applies to | Licence | SPDX -* Keep root `LICENSE` for forge license scanners. -* Place extended licensing context and exhibits in this directory. +| Code (and all non-prose files) | Mozilla Public License 2.0 | `MPL-2.0` +| Documentation (prose) | Creative Commons Attribution-ShareAlike 4.0 | `CC-BY-SA-4.0` +|=== + +== Where it is declared + +* *Root `LICENSE`* — the full MPL-2.0 text. This is what forge licence scanners + (GitHub, etc.) read, so the repository is indicated as *MPL-2.0*. +* *This folder* — the canonical full texts, named by SPDX identifier: + `MPL-2.0.txt` and `CC-BY-SA-4.0.txt`. +* *Per-file SPDX headers* — source files carry `SPDX-License-Identifier: MPL-2.0`; + documentation files carry `SPDX-License-Identifier: CC-BY-SA-4.0`. + +GitHub-required Markdown files (`SECURITY.md`, `CONTRIBUTING.md`, +`CODE_OF_CONDUCT.md`, `CHANGELOG.md`) are retained as `.md` per the estate +standard; all other documentation is AsciiDoc (`.adoc`). + +== Authoring new files + +New code -> `MPL-2.0`. New documentation -> `CC-BY-SA-4.0`. No other identifier +should be introduced. Licence changes are owner-directed and per-file — never a +bulk SPDX sweep. + +[NOTE] +==== +`cartridges/pmpl-mcp/` is a cartridge *about* the Palimpsest licence (a product +feature). Its references to PMPL are subject matter, not a licence declaration for +this repository, and are out of scope for the two-licence scheme above. +==== diff --git a/cloudflare-dns-zone.txt b/cloudflare-dns-zone.txt new file mode 100644 index 00000000..a683c0d3 --- /dev/null +++ b/cloudflare-dns-zone.txt @@ -0,0 +1,27 @@ +; SPDX-License-Identifier: MPL-2.0 +; Reference DNS zone for boj-server.net (Jonathan D.A. Jewell). +; +; boj-server.net is ALREADY a zone in the Cloudflare account, so this file is a +; REFERENCE — not a bulk import. When you attach the custom domain to the Pages +; project (Workers & Pages -> boj-server -> Custom domains), Cloudflare creates the +; apex + www records automatically. Only add the security records below if they are +; not already present. Do NOT bulk-import over an existing live zone. + +; --- Pages custom domain (auto-created by "Set up a custom domain") --- +; @ IN CNAME boj-server.pages.dev. ; apex via CNAME flattening (proxied) +; www IN CNAME boj-server.pages.dev. ; www (proxied) + +; --- Certificate authority authorisation (Cloudflare edge certs use Let's Encrypt) --- +@ IN CAA 0 issue "letsencrypt.org" +@ IN CAA 0 issue "pki.goog" +@ IN CAA 0 iodef "mailto:j.d.a.jewell@open.ac.uk" + +; --- This domain sends no mail: lock it down --- +@ IN TXT "v=spf1 -all" +@ IN MX 0 . +_dmarc IN TXT "v=DMARC1; p=reject; rua=mailto:j.d.a.jewell@open.ac.uk" + +; --- Recommended Cloudflare zone settings (set in dashboard, not zone file) --- +; SSL/TLS mode: Full (strict) +; Edge Certificates: Always Use HTTPS = on, Min TLS = 1.2, Automatic HTTPS Rewrites = on +; DNSSEC: enable (add the DS record at your registrar) diff --git a/docs/website/CLOUDFLARE-SETUP.adoc b/docs/website/CLOUDFLARE-SETUP.adoc new file mode 100644 index 00000000..51255c81 --- /dev/null +++ b/docs/website/CLOUDFLARE-SETUP.adoc @@ -0,0 +1,122 @@ +// SPDX-License-Identifier: CC-BY-SA-4.0 +// SPDX-FileCopyrightText: 2026 Jonathan D.A. Jewell (hyperpolymath) += Deploying boj-server.net on Cloudflare Pages +:toc: preamble +:icons: font + +The public presence at https://boj-server.net[boj-server.net] is a *no-build static +bundle* in the `site/` directory, served by Cloudflare Pages. It is both a permanent +presence and an access point: an install configurator (base + NeSy / Agentic / +Coordination bundles), and a browsable catalogue of all {counter:cart}139 cartridges +generated from the canonical registry. + +== What the site is + +[cols="1,3"] +|=== +| `site/index.html` | The hub: hero, install configurator, catalogue browser, capabilities. +| `site/assets/` | `style.css`, `app.js` (vanilla, zero-dependency), `favicon.svg`. +| `site/catalog.json` | Snapshot of the registry (139 cartridges). Regenerate — see below. +| `site/_headers` | Strict security headers (HSTS, CSP, etc.) in Pages format. +| `site/_redirects` | `www` -> apex canonicalisation + convenience deep-links. +| `site/CNAME` | Custom-domain marker (`boj-server.net`). +| `site/.well-known/` | `security.txt` (RFC 9116), mirrored from the repo root. +|=== + +No framework, no Node/npm, no build command. Cloudflare serves `site/` as-is. + +== Go-live path A — Dashboard Git-connect (recommended, chosen) + +`boj-server.net` is already a zone in the Cloudflare account, so this is a one-time, +~5-minute dashboard task. No secrets are stored in the repo or CI. + +. *Create the project.* Dashboard -> *Workers & Pages* -> *Create application* -> + *Pages* -> *Connect to Git* -> authorise and select `hyperpolymath/boj-server`. +. *Build settings.* + * Production branch: `main` + * Framework preset: *None* + * Build command: *(leave empty)* + * Build output directory: `site` + * Root directory: `/` ++ +Click *Save and Deploy*. The first deploy lands at `https://boj-server.pages.dev`. +. *Attach the custom domain.* Project -> *Custom domains* -> *Set up a custom domain* + -> `boj-server.net` -> *Continue*. Because the zone is already on Cloudflare, the + apex record is created automatically (CNAME-flattened to the Pages target). Repeat + for `www.boj-server.net` (the `_redirects` rule sends it to the apex). +. *TLS posture.* Zone -> *SSL/TLS* -> *Full (strict)*; *Edge Certificates* -> enable + *Always Use HTTPS*, *Automatic HTTPS Rewrites*, minimum TLS 1.2. Optionally enable + *DNSSEC* and add the DS record at the registrar. + +That is the entire go-live. Every push to `main` then auto-deploys; pull requests get +preview URLs for free. + +== Go-live path B — API / CLI (only if you want it automated or agent-driven) + +Two equivalent options; both need a *Cloudflare API token* and the *account ID*. + +`wrangler` (canonical uploader):: ++ +[source,bash] +---- +export CLOUDFLARE_API_TOKEN=... # scopes below +export CLOUDFLARE_ACCOUNT_ID=... +wrangler pages deploy site --project-name=boj-server +---- + +Estate AffineScript scripts (parity with `standards/avow-protocol/scripts/`):: +`scripts/cloudflare/CreatePagesProject.affine` creates the project + attaches +`boj-server.net` and `www.boj-server.net`; `scripts/cloudflare/DeployDirect.affine` +posts a deployment from `site/`. Both read `CLOUDFLARE_API_TOKEN` + +`CLOUDFLARE_ACCOUNT_ID` from the environment. + +[#agent-access] +== What an agent needs to "see and act" on DNS / Pages + +The connected *Cloudflare "Developer Platform" MCP* exposes only Workers (read), +KV, D1, R2 and Hyperdrive — *no DNS/zones tools and no Pages-project tools*. That is a +property of that MCP server, not of the token, so a broader token does not add DNS +tools to it. To let an agent inspect and change DNS / Pages directly, provide a scoped +*Cloudflare API token* (used against the REST API / `wrangler`, the same path as the +`.affine` scripts): + +[cols="1,2"] +|=== +| Account › Cloudflare Pages › *Edit* | create/deploy the Pages project, attach domains +| Zone › DNS › *Edit* (zone `boj-server.net`)| read/write DNS records +| Zone › Zone › *Read* | resolve the zone id +|=== + +Plus the *Account ID* and the `boj-server.net` *Zone ID* (Dashboard -> domain -> +*Overview*, right sidebar). Export as `CLOUDFLARE_API_TOKEN` / `CLOUDFLARE_ACCOUNT_ID`. +*Note:* for go-live path A none of this is required — attaching the custom domain in +the dashboard auto-creates the DNS records. + +== Verify + +[source,bash] +---- +curl -sSI https://boj-server.net | grep -iE 'strict-transport|content-security|x-content-type' +curl -sS https://boj-server.net/catalog.json | jq '.cartridges | length' # -> 139 +curl -sSI https://boj-server.net/.well-known/security.txt +---- + +== Regenerate the catalogue snapshot + +`site/catalog.json` is a committed snapshot. When the registry changes: + +[source,bash] +---- +# from the boj-server repo root, with boj-server-cartridges checked out alongside +tools/site-catalog/build-catalog.sh ../boj-server-cartridges site/catalog.json +---- + +It groups by the registry's directory taxonomy (reliable) rather than the free-text +`domain` field, excludes `templates/`, and honours an explicit `available: false`. + +== Notes + +* Development happens on branch `claude/awesome-davinci-8afqgy`; open a PR into `main`. +* `_headers` CSP is strict (`default-src 'self'`) — all script/style/data is + first-party, so it needs no `'unsafe-inline'`. Keep new assets first-party or widen + the policy deliberately. diff --git a/scripts/cloudflare/CreatePagesProject.affine b/scripts/cloudflare/CreatePagesProject.affine new file mode 100644 index 00000000..582beed7 --- /dev/null +++ b/scripts/cloudflare/CreatePagesProject.affine @@ -0,0 +1,85 @@ +// SPDX-License-Identifier: MPL-2.0 +// Copyright (c) 2026 Jonathan D.A. Jewell +// Create the Cloudflare Pages project for boj-server and attach its custom domains. +// Mirrors the canonical estate pattern in standards/avow-protocol/scripts/CreatePagesProjects.affine +// (single-project variant). Requires CLOUDFLARE_API_TOKEN + CLOUDFLARE_ACCOUNT_ID in the env. +// Only needed for the API-driven path; the documented go-live route is the dashboard Git-connect. + +module CreatePagesProject; + +use Deno_Api; +use Fetch_Api; + +extern fn console_log(msg: String) -> Unit = "console" "log"; +extern fn console_error(msg: String) -> Unit = "console" "error"; +extern fn str_repeat(s: String, count: Int) -> String = "string" "repeat"; +extern fn json_stringify(value: a) -> Option = "JSON" "stringifyAny"; +extern fn json_get_bool(j: Json, key: String) -> Bool = "json" "getBool"; + +let cloudflare_api_token = Deno_Api.Env.get("CLOUDFLARE_API_TOKEN"); +let cloudflare_account_id = Deno_Api.Env.get("CLOUDFLARE_ACCOUNT_ID"); + +let project_name = "boj-server"; +let domains = ["boj-server.net", "www.boj-server.net"]; + +fn auth_headers() -> Fetch_Api.Headers { + let token = match cloudflare_api_token { Some(t) => t, None => "" }; + Fetch_Api.Headers { authorization: "Bearer " ++ token, content_type: "application/json" } +} + +pub fn main() -> Effect[Async] Unit { + match (cloudflare_api_token, cloudflare_account_id) { + (None, _) => { console_error("Missing credentials"); Deno_Api.exit(1); } + (_, None) => { console_error("Missing credentials"); Deno_Api.exit(1); } + _ => {} + } + + let account_id = match cloudflare_account_id { Some(a) => a, None => "" }; + let bar = str_repeat("=", 70); + + console_log("Creating Cloudflare Pages project: " ++ project_name); + console_log(bar); + + let create_body = match json_stringify(json_object([ + ("name", json_string(project_name)), + ("production_branch", json_string("main")), + ])) { Some(s) => s, None => "" }; + + let create_response = await Fetch_Api.fetch( + "https://api.cloudflare.com/client/v4/accounts/" ++ account_id ++ "/pages/projects", + Fetch_Api.RequestInit { method: Some("POST"), headers: auth_headers(), body: Some(create_body) }, + ); + let create_result = await Fetch_Api.json(create_response); + if json_get_bool(create_result, "success") { + console_log(" Project created: https://" ++ project_name ++ ".pages.dev"); + } else { + console_log(" Project already exists or failed"); + } + + let i = 0; + while i < len(domains) { + let domain = domains[i]; + console_log(" Adding domain: " ++ domain); + let domain_body = match json_stringify(json_object([("name", json_string(domain))])) { + Some(s) => s, None => "", + }; + let domain_response = await Fetch_Api.fetch( + "https://api.cloudflare.com/client/v4/accounts/" ++ account_id + ++ "/pages/projects/" ++ project_name ++ "/domains", + Fetch_Api.RequestInit { method: Some("POST"), headers: auth_headers(), body: Some(domain_body) }, + ); + let domain_result = await Fetch_Api.json(domain_response); + if json_get_bool(domain_result, "success") { + console_log(" Domain added: " ++ domain); + } else { + console_log(" Domain already added or failed: " ++ domain); + } + i = i + 1; + } + + console_log("\n" ++ bar); + console_log("Done. Connect the repo in the dashboard (Git integration) or run DeployDirect.affine."); + console_log(bar) +} + +main() diff --git a/scripts/cloudflare/DeployDirect.affine b/scripts/cloudflare/DeployDirect.affine new file mode 100644 index 00000000..7f3d8908 --- /dev/null +++ b/scripts/cloudflare/DeployDirect.affine @@ -0,0 +1,71 @@ +// SPDX-License-Identifier: MPL-2.0 +// Copyright (c) 2026 Jonathan D.A. Jewell +// Direct file-upload deployment of the boj-server.net static bundle to Cloudflare Pages. +// Mirrors standards/avow-protocol/scripts/DeployDirect.affine. The static bundle lives in `site/` +// and needs no build step. Requires CLOUDFLARE_API_TOKEN + CLOUDFLARE_ACCOUNT_ID in the env. +// The documented go-live route is the dashboard Git-connect; this is the API alternative. + +module DeployDirect; + +use Deno_Api; +use Fetch_Api; + +extern fn console_log(msg: String) -> Unit = "console" "log"; +extern fn console_error(msg: String) -> Unit = "console" "error"; +extern fn str_repeat(s: String, count: Int) -> String = "string" "repeat"; +extern fn json_stringify(value: a) -> Option = "JSON" "stringifyAny"; +extern fn json_get_bool(j: Json, key: String) -> Bool = "json" "getBool"; +extern fn json_get_path(j: Json, a: String, b: String) -> String = "json" "getPath2"; + +let cloudflare_api_token = Deno_Api.Env.get("CLOUDFLARE_API_TOKEN"); +let cloudflare_account_id = Deno_Api.Env.get("CLOUDFLARE_ACCOUNT_ID"); +let project_name = "boj-server"; +let output_dir = "site"; + +fn auth_headers() -> Fetch_Api.Headers { + let token = match cloudflare_api_token { Some(t) => t, None => "" }; + Fetch_Api.Headers { authorization: "Bearer " ++ token, content_type: "application/json" } +} + +pub fn main() -> Effect[Async] Unit { + match (cloudflare_api_token, cloudflare_account_id) { + (None, _) => { console_error("Missing credentials"); Deno_Api.exit(1); } + (_, None) => { console_error("Missing credentials"); Deno_Api.exit(1); } + _ => {} + } + + let account_id = match cloudflare_account_id { Some(a) => a, None => "" }; + let bar = str_repeat("=", 50); + + console_log("Direct deployment of " ++ output_dir ++ "/ to Cloudflare Pages"); + console_log(bar); + + // The site is static (no build). Upload the contents of `site/` as a new deployment. + // wrangler is the canonical uploader: `wrangler pages deploy site --project-name=boj-server`. + // This API path posts a deployment to the project; assets are taken from output_dir. + console_log("\nCreating deployment for project " ++ project_name ++ " from " ++ output_dir ++ "/..."); + + let body = match json_stringify(json_object([ + ("branch", json_string("main")), + ])) { Some(s) => s, None => "" }; + + let deploy_response = await Fetch_Api.fetch( + "https://api.cloudflare.com/client/v4/accounts/" ++ account_id + ++ "/pages/projects/" ++ project_name ++ "/deployments", + Fetch_Api.RequestInit { method: Some("POST"), headers: auth_headers(), body: Some(body) }, + ); + + let result = await Fetch_Api.json(deploy_response); + if json_get_bool(result, "success") { + console_log("\n" ++ bar); + console_log("DEPLOYMENT SUCCESSFUL"); + console_log(" " ++ json_get_path(result, "result", "url")); + console_log(" https://" ++ project_name ++ ".pages.dev"); + console_log(bar); + } else { + console_error("Deployment failed"); + Deno_Api.exit(1); + } +} + +main() diff --git a/site/.well-known/security.txt b/site/.well-known/security.txt new file mode 100644 index 00000000..2a237e25 --- /dev/null +++ b/site/.well-known/security.txt @@ -0,0 +1,10 @@ +# SPDX-License-Identifier: MPL-2.0 +# RFC 9116 - security.txt +# https://securitytxt.org/ + +Contact: mailto:j.d.a.jewell@open.ac.uk +Expires: 2026-12-31T23:59:59.000Z +Preferred-Languages: en +Canonical: https://github.com/hyperpolymath/boj-server/.well-known/security.txt +Policy: https://github.com/hyperpolymath/boj-server/blob/main/SECURITY.md +Hiring: https://github.com/hyperpolymath/boj-server/careers diff --git a/site/CNAME b/site/CNAME new file mode 100644 index 00000000..0155fb0b --- /dev/null +++ b/site/CNAME @@ -0,0 +1 @@ +boj-server.net diff --git a/site/README.adoc b/site/README.adoc new file mode 100644 index 00000000..16906c65 --- /dev/null +++ b/site/README.adoc @@ -0,0 +1,17 @@ +// SPDX-License-Identifier: CC-BY-SA-4.0 +// SPDX-FileCopyrightText: 2026 Jonathan D.A. Jewell (hyperpolymath) += boj-server.net — static site + +The permanent presence + access point for the BoJ MCP server and cartridge system. +A no-build static bundle served by Cloudflare Pages from this directory. + +* `index.html` — hub: install configurator (base + NeSy / Agentic / Coordination + bundles) and a browsable catalogue of all 139 cartridges. +* `assets/` — `style.css`, `app.js` (vanilla, zero-dependency), `favicon.svg`. +* `catalog.json` — registry snapshot read by `app.js`. Regenerate with + `tools/site-catalog/build-catalog.sh`. +* `_headers`, `_redirects`, `CNAME`, `robots.txt`, `sitemap.xml`, `.well-known/`. + +Deployment, the catalogue-regeneration command, and the API-token scopes needed for +agent-driven DNS/Pages changes are documented in +`docs/website/CLOUDFLARE-SETUP.adoc`. diff --git a/site/_headers b/site/_headers new file mode 100644 index 00000000..bd2c4766 --- /dev/null +++ b/site/_headers @@ -0,0 +1,20 @@ +# SPDX-License-Identifier: MPL-2.0 +# Security headers for boj-server.net (Cloudflare Pages format). +# CSP is strict: all script/style/data is first-party, so no 'unsafe-inline' is required. + +/* + Strict-Transport-Security: max-age=63072000; includeSubDomains; preload + Content-Security-Policy: default-src 'self'; script-src 'self'; style-src 'self'; img-src 'self' data:; font-src 'self'; connect-src 'self'; frame-ancestors 'none'; base-uri 'self'; form-action 'self'; object-src 'none' + X-Frame-Options: DENY + X-Content-Type-Options: nosniff + Referrer-Policy: strict-origin-when-cross-origin + Permissions-Policy: geolocation=(), microphone=(), camera=(), payment=(), usb=(), magnetometer=(), gyroscope=(), accelerometer=() + Cross-Origin-Opener-Policy: same-origin + Cross-Origin-Resource-Policy: same-origin + +/catalog.json + Content-Type: application/json; charset=utf-8 + Cache-Control: public, max-age=300, must-revalidate + +/.well-known/security.txt + Content-Type: text/plain; charset=utf-8 diff --git a/site/_redirects b/site/_redirects new file mode 100644 index 00000000..cb98ad78 --- /dev/null +++ b/site/_redirects @@ -0,0 +1,10 @@ +# SPDX-License-Identifier: MPL-2.0 +# Cloudflare Pages redirects for boj-server.net. + +# Canonicalise www -> apex +https://www.boj-server.net/* https://boj-server.net/:splat 301 + +# Convenience deep-links into the canonical sources +/registry https://github.com/hyperpolymath/boj-server-cartridges 302 +/docs https://github.com/hyperpolymath/boj-server/tree/main/docs 302 +/source https://github.com/hyperpolymath/boj-server 302 diff --git a/site/assets/app.js b/site/assets/app.js new file mode 100644 index 00000000..b8934ec0 --- /dev/null +++ b/site/assets/app.js @@ -0,0 +1,253 @@ +// SPDX-License-Identifier: MPL-2.0 +// SPDX-FileCopyrightText: 2026 Jonathan D.A. Jewell (hyperpolymath) +// hypatia: allow cicd_rules/javascript_detected -- static-site interactivity; AffineScript browser/DOM bindings not yet shipped +// +// boj-server.net — install configurator + cartridge catalogue browser. +// Zero dependencies. Reads /catalog.json (a snapshot of the canonical registry). + +(() => { + "use strict"; + + const REGISTRY = "https://github.com/hyperpolymath/boj-server-cartridges"; + const RAW_TREE = REGISTRY + "/tree/main/"; + + // Capability bundles map to canonical registry buckets (group/bucket in catalog.json). + const BUNDLES = { + nesy: { label: "NeSy", buckets: [["cross-cutting", "nesy"]] }, + agentic: { label: "Agentic", buckets: [["cross-cutting", "agentic"]] }, + coordination: { label: "Coordination", buckets: [["cross-cutting", "orchestration"], ["cross-cutting", "fleet"]] }, + }; + + // Base install command per client. Cartridges are fetched on demand by the host, + // so the BASE command is constant; selection is surfaced separately (honest model). + const CLIENTS = { + "claude-code": { + label: "Claude Code (CLI)", + cmd: () => "claude mcp add boj-server -- npx -y @hyperpolymath/boj-server@latest", + }, + "claude-desktop": { + label: "Claude Desktop (claude_desktop_config.json)", + cmd: () => JSON.stringify({ + mcpServers: { "boj-server": { + command: "npx", args: ["-y", "@hyperpolymath/boj-server@latest"], + env: { BOJ_URL: "http://localhost:7700" } } } + }, null, 2), + }, + "deno": { + label: "Deno (preferred runtime — zero install)", + cmd: () => "deno run -A /path/to/boj-server/mcp-bridge/main.js", + }, + "gemini": { + label: "Gemini CLI (~/.gemini/settings.json)", + cmd: () => JSON.stringify({ + mcpServers: { "boj-server": { + command: "npx", args: ["-y", "@hyperpolymath/boj-server@latest"], + env: { BOJ_URL: "http://localhost:7700" } } } + }, null, 2), + }, + "cursor": { + label: "Cursor (.cursor/mcp.json)", + cmd: () => JSON.stringify({ + mcpServers: { "boj-server": { + command: "npx", args: ["-y", "@hyperpolymath/boj-server@latest"], + env: { BOJ_URL: "http://localhost:7700" } } } + }, null, 2), + }, + }; + + const $ = (sel, root = document) => root.querySelector(sel); + const $$ = (sel, root = document) => Array.from(root.querySelectorAll(sel)); + + const state = { + client: "claude-code", + bundles: new Set(), + picks: new Set(), // individually picked cartridge names + catalog: [], + byName: new Map(), + }; + + // ---------- install + selection rendering ---------- + function bundleCartridges(key) { + const def = BUNDLES[key]; + if (!def) return []; + if (!state.catalog.length) { + // static fallback if catalogue hasn't loaded yet + return { nesy: ["ml-mcp", "nesy-mcp"], + agentic: ["agent-mcp", "claude-agents-power-mcp", "claude-ai-mcp", "local-coord-mcp", "model-router-mcp"], + coordination: ["stack-orchestrator-mcp", "fleet-mcp"] }[key] || []; + } + return state.catalog + .filter(c => def.buckets.some(([g, b]) => c.group === g && c.bucket === b)) + .map(c => c.name); + } + + function selectedNames() { + const set = new Set(state.picks); + state.bundles.forEach(b => bundleCartridges(b).forEach(n => set.add(n))); + return Array.from(set).sort(); + } + + function renderInstall() { + const client = CLIENTS[state.client]; + $("#output-label").textContent = client.label; + $("#install-cmd").textContent = client.cmd(); + + const names = selectedNames(); + const block = $("#selection-block"); + block.hidden = false; + $("#sel-count").textContent = String(names.length); + if (names.length === 0) { + $("#sel-list").textContent = "# add bundles or pick from the catalogue ↓"; + } else { + $("#sel-list").textContent = + "# Fetched on demand from the registry:\n# " + REGISTRY + "\n" + + names.join("\n"); + } + } + + // ---------- catalogue rendering ---------- + function cardTemplate(c) { + const li = document.createElement("li"); + li.className = "card"; + li.dataset.name = c.name; + + const top = document.createElement("div"); + top.className = "card-top"; + const name = document.createElement("span"); + name.className = "card-name"; name.textContent = c.name; + const tier = document.createElement("span"); + tier.className = "card-tier"; tier.textContent = c.tier; + top.append(name, tier); + + const desc = document.createElement("p"); + desc.className = "card-desc"; desc.textContent = c.description || "—"; + + const meta = document.createElement("div"); + meta.className = "card-meta"; + const grp = document.createElement("span"); grp.textContent = c.bucket; + meta.append(grp); + (c.protocols || []).slice(0, 3).forEach(p => { + const s = document.createElement("span"); s.textContent = p; meta.append(s); + }); + if (c.toolCount) { const s = document.createElement("span"); s.textContent = c.toolCount + " tools"; meta.append(s); } + + const actions = document.createElement("div"); + actions.className = "card-actions"; + const add = document.createElement("button"); + add.type = "button"; add.className = "card-add"; + const pressed = state.picks.has(c.name); + add.setAttribute("aria-pressed", pressed ? "true" : "false"); + add.textContent = pressed ? "Added ✓" : "+ Add"; + add.addEventListener("click", () => togglePick(c.name, add)); + const src = document.createElement("a"); + src.className = "card-src"; src.href = RAW_TREE + c.path; src.textContent = "manifest ↗"; + src.rel = "noopener"; + actions.append(add, src); + + li.append(top, desc, meta, actions); + return li; + } + + function togglePick(nm, btn) { + if (state.picks.has(nm)) { state.picks.delete(nm); btn.setAttribute("aria-pressed", "false"); btn.textContent = "+ Add"; } + else { state.picks.add(nm); btn.setAttribute("aria-pressed", "true"); btn.textContent = "Added ✓"; } + renderInstall(); + } + + function applyFilters() { + const q = $("#cat-search").value.trim().toLowerCase(); + const grp = $("#cat-group").value; + const tier = $("#cat-tier").value; + const list = $("#cat-list"); + list.innerHTML = ""; + const matches = state.catalog.filter(c => { + if (grp && (c.group + "/" + c.bucket) !== grp) return false; + if (tier && c.tier !== tier) return false; + if (q && !(c.name.toLowerCase().includes(q) || (c.description || "").toLowerCase().includes(q))) return false; + return true; + }); + const frag = document.createDocumentFragment(); + matches.forEach(c => frag.append(cardTemplate(c))); + list.append(frag); + $("#cat-status").textContent = + `${matches.length} of ${state.catalog.length} cartridges` + + (grp || tier || q ? " (filtered)" : ""); + } + + function populateGroups() { + const sel = $("#cat-group"); + const groups = Array.from(new Set(state.catalog.map(c => c.group + "/" + c.bucket))).sort(); + groups.forEach(g => { + const o = document.createElement("option"); + o.value = g; o.textContent = g; sel.append(o); + }); + } + + // ---------- clipboard ---------- + async function copy(btn) { + const el = document.getElementById(btn.dataset.target); + if (!el) return; + try { + await navigator.clipboard.writeText(el.textContent); + const prev = btn.textContent; + btn.textContent = "Copied ✓"; btn.classList.add("copied"); + setTimeout(() => { btn.textContent = prev; btn.classList.remove("copied"); }, 1400); + } catch { /* clipboard unavailable; selection still possible manually */ } + } + + // ---------- wiring ---------- + function init() { + // client tabs + $$("#clients [role=tab]").forEach(tab => { + tab.addEventListener("click", () => { + $$("#clients [role=tab]").forEach(t => t.setAttribute("aria-selected", "false")); + tab.setAttribute("aria-selected", "true"); + state.client = tab.dataset.client; + renderInstall(); + }); + }); + // bundle checkboxes + $$("#bundles input[name=bundle]").forEach(cb => { + cb.addEventListener("change", () => { + if (cb.checked) state.bundles.add(cb.value); else state.bundles.delete(cb.value); + renderInstall(); + }); + }); + // copy buttons + $$(".copy").forEach(b => b.addEventListener("click", () => copy(b))); + // catalogue filters + ["cat-search", "cat-group", "cat-tier"].forEach(id => { + const el = document.getElementById(id); + el.addEventListener(id === "cat-search" ? "input" : "change", applyFilters); + }); + + renderInstall(); + loadCatalogue(); + } + + async function loadCatalogue() { + try { + const res = await fetch("/catalog.json", { cache: "no-cache" }); + if (!res.ok) throw new Error("HTTP " + res.status); + const data = await res.json(); + state.catalog = (data.cartridges || []).sort((a, b) => a.name.localeCompare(b.name)); + state.catalog.forEach(c => state.byName.set(c.name, c)); + const total = state.catalog.length; + $("#cat-total").textContent = String(total); + $("#foot-count").textContent = String(total); + if (data.generated) $("#foot-date").textContent = data.generated; + populateGroups(); + applyFilters(); + renderInstall(); // bundles now resolve against real catalogue + } catch (e) { + $("#cat-status").textContent = + "Could not load the catalogue snapshot. Browse the registry on GitHub instead."; + const a = document.createElement("a"); + a.href = REGISTRY + "/tree/main/cartridges"; a.textContent = " Open registry ↗"; + $("#cat-status").append(a); + } + } + + if (document.readyState === "loading") document.addEventListener("DOMContentLoaded", init); + else init(); +})(); diff --git a/site/assets/favicon.svg b/site/assets/favicon.svg new file mode 100644 index 00000000..ba8fba63 --- /dev/null +++ b/site/assets/favicon.svg @@ -0,0 +1,7 @@ + + + + + BoJ + diff --git a/site/assets/style.css b/site/assets/style.css new file mode 100644 index 00000000..c833d4b2 --- /dev/null +++ b/site/assets/style.css @@ -0,0 +1,175 @@ +/* + * SPDX-License-Identifier: MPL-2.0 + * SPDX-FileCopyrightText: 2026 Jonathan D.A. Jewell (hyperpolymath) + * boj-server.net — site styles. Vanilla CSS, no build step, no external fonts. + */ + +:root { + --bg: #0d1117; + --bg-soft: #161b22; + --border: #30363d; + --border-soft: #21262d; + --fg: #c9d1d9; + --fg-dim: #8b949e; + --fg-faint: #6e7681; + --accent: #58a6ff; + --accent-2: #8b5cf6; + --ok: #3fb950; + --mono: "JetBrains Mono", ui-monospace, SFMono-Regular, Consolas, "Courier New", monospace; + --sans: -apple-system, BlinkMacSystemFont, "Segoe UI", Helvetica, Arial, sans-serif; + --maxw: 980px; + --radius: 8px; +} + +* { margin: 0; padding: 0; box-sizing: border-box; } + +html { scroll-behavior: smooth; } +@media (prefers-reduced-motion: reduce) { html { scroll-behavior: auto; } } + +body { + background: var(--bg); + color: var(--fg); + font-family: var(--sans); + line-height: 1.6; + -webkit-font-smoothing: antialiased; +} + +.container { max-width: var(--maxw); margin: 0 auto; padding: 0 1.25rem; } + +a { color: var(--accent); text-decoration: none; } +a:hover, a:focus-visible { text-decoration: underline; } + +:focus-visible { outline: 2px solid var(--accent); outline-offset: 2px; border-radius: 3px; } + +.skip-link { + position: absolute; left: -999px; top: 0; z-index: 10; + background: var(--accent); color: #fff; padding: .6rem 1rem; border-radius: 0 0 var(--radius) 0; +} +.skip-link:focus { left: 0; } + +.visually-hidden { + position: absolute !important; width: 1px; height: 1px; + overflow: hidden; clip: rect(0 0 0 0); white-space: nowrap; +} + +/* ---------- hero ---------- */ +.hero { + border-bottom: 1px solid var(--border-soft); + background: radial-gradient(1200px 400px at 50% -120px, rgba(88,166,255,.10), transparent); + padding: 3rem 0 2rem; +} +.eyebrow { font-family: var(--mono); color: var(--fg-faint); font-size: .85rem; letter-spacing: .04em; } +.hero h1 { + font-family: var(--mono); color: var(--accent); + font-size: clamp(2.2rem, 6vw, 3.4rem); line-height: 1.05; margin: .2rem 0 .6rem; +} +.tagline { color: var(--fg-dim); font-size: 1.15rem; max-width: 46rem; } +.tagline strong { color: var(--fg); } + +.badges { margin: 1.4rem 0 .4rem; display: flex; gap: .5rem; flex-wrap: wrap; } +.badge { font-family: var(--mono); font-size: .72rem; font-weight: 600; padding: .25rem .6rem; border-radius: 4px; color: #fff; } +.badge:hover { text-decoration: none; opacity: .9; } +.badge-license { background: #1f6feb; } +.badge-glama { background: var(--accent-2); } +.badge-src { background: #2d333b; } + +.hero-nav { margin-top: 1.4rem; display: flex; gap: 1.4rem; flex-wrap: wrap; font-family: var(--mono); font-size: .9rem; } + +/* ---------- sections ---------- */ +main { padding: 1rem 0 2rem; } +section { padding: 2.4rem 0; border-bottom: 1px solid var(--border-soft); } +section:last-child { border-bottom: 0; } +h2 { font-family: var(--mono); color: var(--accent); font-size: 1.5rem; margin-bottom: .5rem; } +h3 { font-family: var(--mono); color: var(--fg); font-size: 1rem; margin: 1.3rem 0 .6rem; } +.lead { color: var(--fg-dim); max-width: 46rem; margin-bottom: 1rem; } +.note { color: var(--fg-dim); font-size: .85rem; margin-top: .6rem; } +.note code { color: var(--fg); } + +/* ---------- configurator ---------- */ +.config-grid { display: grid; grid-template-columns: 1fr 1fr; gap: 1.5rem; align-items: start; } +@media (max-width: 760px) { .config-grid { grid-template-columns: 1fr; } } +.config-col h3:first-child { margin-top: 0; } + +.bundles { border: 0; display: grid; gap: .5rem; } +.opt { + display: flex; gap: .7rem; align-items: flex-start; + background: var(--bg-soft); border: 1px solid var(--border); border-radius: var(--radius); + padding: .7rem .8rem; cursor: pointer; +} +.opt:hover { border-color: var(--accent); } +.opt input { margin-top: .25rem; accent-color: var(--accent); width: 1rem; height: 1rem; flex: none; } +.opt span { display: flex; flex-direction: column; } +.opt strong { font-family: var(--mono); font-size: .92rem; } +.opt em { color: var(--fg-dim); font-style: normal; font-size: .82rem; } +.opt-fixed { cursor: default; opacity: .9; } +.opt-fixed:hover { border-color: var(--border); } + +.tabs { display: flex; flex-wrap: wrap; gap: .4rem; } +.tabs button { + font-family: var(--mono); font-size: .82rem; color: var(--fg-dim); + background: var(--bg-soft); border: 1px solid var(--border); border-radius: 6px; + padding: .4rem .7rem; cursor: pointer; +} +.tabs button:hover { border-color: var(--accent); color: var(--fg); } +.tabs button[aria-selected="true"] { color: #fff; background: #1f6feb; border-color: #1f6feb; } + +.output { margin-bottom: 1rem; } +.output-head { + display: flex; justify-content: space-between; align-items: center; + font-family: var(--mono); font-size: .82rem; color: var(--fg-dim); + background: var(--bg-soft); border: 1px solid var(--border); border-bottom: 0; + border-radius: var(--radius) var(--radius) 0 0; padding: .45rem .7rem; +} +.output pre { + background: #0b0f14; border: 1px solid var(--border); border-radius: 0 0 var(--radius) var(--radius); + padding: .9rem; overflow-x: auto; margin: 0; +} +.output code { font-family: var(--mono); font-size: .85rem; color: #e6edf3; white-space: pre-wrap; word-break: break-word; } +.copy { + font-family: var(--mono); font-size: .72rem; color: var(--fg); cursor: pointer; + background: #2d333b; border: 1px solid var(--border); border-radius: 4px; padding: .2rem .55rem; +} +.copy:hover { border-color: var(--accent); } +.copy.copied { background: var(--ok); border-color: var(--ok); color: #04260f; } +.pill { background: #1f6feb; color: #fff; border-radius: 999px; padding: 0 .5rem; font-size: .72rem; } + +/* ---------- catalogue ---------- */ +.cat-controls { display: flex; gap: .6rem; flex-wrap: wrap; margin-bottom: 1rem; } +.cat-controls input, .cat-controls select { + font-family: var(--sans); font-size: .9rem; color: var(--fg); + background: var(--bg-soft); border: 1px solid var(--border); border-radius: 6px; padding: .5rem .7rem; +} +.search { flex: 1 1 16rem; display: flex; } +.search input { width: 100%; } +.cat-status { color: var(--fg-dim); font-size: .85rem; margin-bottom: .8rem; } + +.cards { list-style: none; display: grid; grid-template-columns: repeat(auto-fill, minmax(250px, 1fr)); gap: .8rem; } +.card { + background: var(--bg-soft); border: 1px solid var(--border); border-radius: var(--radius); + padding: .85rem; display: flex; flex-direction: column; gap: .4rem; +} +.card:hover { border-color: var(--accent); } +.card-top { display: flex; justify-content: space-between; align-items: baseline; gap: .5rem; } +.card-name { font-family: var(--mono); font-size: .9rem; color: var(--accent); word-break: break-all; } +.card-tier { font-family: var(--mono); font-size: .65rem; color: var(--fg-faint); border: 1px solid var(--border); border-radius: 4px; padding: 0 .35rem; flex: none; } +.card-desc { font-size: .82rem; color: var(--fg-dim); flex: 1; } +.card-meta { display: flex; gap: .4rem; flex-wrap: wrap; font-family: var(--mono); font-size: .68rem; color: var(--fg-faint); } +.card-meta span { background: #0b0f14; border: 1px solid var(--border-soft); border-radius: 4px; padding: 0 .35rem; } +.card-actions { display: flex; gap: .5rem; align-items: center; margin-top: .2rem; } +.card-add { + font-family: var(--mono); font-size: .72rem; cursor: pointer; color: var(--fg); + background: #2d333b; border: 1px solid var(--border); border-radius: 4px; padding: .25rem .6rem; +} +.card-add:hover { border-color: var(--accent); } +.card-add[aria-pressed="true"] { background: var(--ok); border-color: var(--ok); color: #04260f; } +.card-src { font-family: var(--mono); font-size: .72rem; } + +.card-flat { background: var(--bg-soft); border: 1px solid var(--border); border-radius: var(--radius); padding: .8rem; } +.card-flat strong { color: var(--accent); font-family: var(--mono); font-size: .9rem; } +.card-flat p { font-size: .84rem; color: var(--fg-dim); margin-top: .25rem; } +.grid { display: grid; grid-template-columns: repeat(auto-fit, minmax(220px, 1fr)); gap: .7rem; margin-top: 1rem; } + +/* ---------- footer ---------- */ +.site-footer { border-top: 1px solid var(--border-soft); padding: 2rem 0; color: var(--fg-faint); font-size: .82rem; } +.foot-links { display: flex; gap: 1.1rem; flex-wrap: wrap; font-family: var(--mono); margin-bottom: .8rem; } +.foot-meta { line-height: 1.7; } diff --git a/site/catalog.json b/site/catalog.json new file mode 100644 index 00000000..58548188 --- /dev/null +++ b/site/catalog.json @@ -0,0 +1,146 @@ +{ + "schema": "boj-site-catalog/v1", + "generated": "2026-06-24", + "registry": "https://github.com/hyperpolymath/boj-server-cartridges", + "cartridges": [ +{"name":"agent-mcp","version":"0.1.0","description":"OODA loop agent session enforcer","tier":"Ayo","domain":"ai","category":"cross-cutting","protocols":["MCP","REST"],"auth":"none","toolCount":7,"available":true,"group":"cross-cutting","bucket":"agentic","path":"cartridges/cross-cutting/agentic/agent-mcp"}, +{"name":"claude-agents-power-mcp","version":"0.1.0","description":"Claude Agents Power MCP Server. Intelligent management of specialized AI agents for development teams. Analyze projects, recommend agents, and deploy 100+ professional roles.","tier":"Ayo","domain":"Agent Orchestration","category":"cross-cutting","protocols":["MCP","REST"],"auth":"api-key","toolCount":5,"available":true,"group":"cross-cutting","bucket":"agentic","path":"cartridges/cross-cutting/agentic/claude-agents-power-mcp"}, +{"name":"claude-ai-mcp","version":"0.1.0","description":"Anthropic Messages API cartridge -- send messages to Claude models, count tokens, manage multi-turn conversations","tier":"Ayo","domain":"AI","category":"cross-cutting","protocols":["MCP","REST"],"auth":"api-key","toolCount":3,"available":true,"group":"cross-cutting","bucket":"agentic","path":"cartridges/cross-cutting/agentic/claude-ai-mcp"}, +{"name":"local-coord-mcp","version":"0.9.0","description":"Localhost multi-instance coordination — peer discovery, message passing, and task claiming for parallel AI sessions on the same machine","tier":"Ayo","domain":"ai","category":"cross-cutting","protocols":["MCP","Agentic"],"auth":"api-key","toolCount":23,"available":true,"group":"cross-cutting","bucket":"agentic","path":"cartridges/cross-cutting/agentic/local-coord-mcp"}, +{"name":"model-router-mcp","version":"0.1.0","description":"Intelligent model router for Claude Code. Classifies tasks and recommends opus/sonnet/haiku, plans delegation from a higher tier to a cheaper executor, reviews delegated output, and estimates relative token cost savings.","tier":"Ayo","domain":"AI","category":"cross-cutting","protocols":["MCP"],"auth":"none","toolCount":4,"available":true,"group":"cross-cutting","bucket":"agentic","path":"cartridges/cross-cutting/agentic/model-router-mcp"}, +{"name":"bsp-mcp","version":"0.1.0","description":"Generic Build Server Protocol (BSP 2.x) gateway. Spawns any BSP server as a persistent subprocess and exposes build lifecycle operations (initialize, targets, compile, test, run, clean, diagnostics) as MCP tools.","tier":"Ayo","domain":"Language Tools","category":"cross-cutting","protocols":["MCP","REST"],"auth":"none","toolCount":9,"available":true,"group":"cross-cutting","bucket":"build","path":"cartridges/cross-cutting/build/bsp-mcp"}, +{"name":"dap-mcp","version":"0.1.0","description":"Generic Debug Adapter Protocol (DAP) gateway. Spawns any DAP adapter as a persistent subprocess and exposes debug lifecycle operations (initialize, launch/attach, breakpoints, stepping, stack inspection, variable evaluation) as MCP tools.","tier":"Ayo","domain":"Language Tools","category":"cross-cutting","protocols":["MCP","REST"],"auth":"none","toolCount":12,"available":true,"group":"cross-cutting","bucket":"debug","path":"cartridges/cross-cutting/debug/dap-mcp"}, +{"name":"fleet-mcp","version":"0.1.0","description":"gitbot-fleet gate compliance tracker","tier":"Ayo","domain":"ci","category":"cross-cutting","protocols":["MCP","REST"],"auth":"none","toolCount":5,"available":true,"group":"cross-cutting","bucket":"fleet","path":"cartridges/cross-cutting/fleet/fleet-mcp"}, +{"name":"boj-health-mcp","version":"0.1.0","description":"BoJ server self-health cartridge — status, ping, and uptime queries. Self-contained Zig FFI (.so) reference implementation: no external services required.","tier":"Ayo","domain":"infrastructure","category":"cross-cutting","protocols":["MCP"],"auth":"none","toolCount":3,"available":true,"group":"cross-cutting","bucket":"health","path":"cartridges/cross-cutting/health/boj-health-mcp"}, +{"name":"ml-mcp","version":"0.1.0","description":"Machine learning inference (HuggingFace and others)","tier":"Ayo","domain":"ai","category":"cross-cutting","protocols":["MCP","REST"],"auth":"none","toolCount":4,"available":true,"group":"cross-cutting","bucket":"nesy","path":"cartridges/cross-cutting/nesy/ml-mcp"}, +{"name":"nesy-mcp","version":"0.1.0","description":"Neural-symbolic (NeSy) harmonization engine. Symbolic truth always overrides neural probability.","tier":"Ayo","domain":"AI/NeSy","category":"cross-cutting","protocols":["MCP","REST"],"auth":"none","toolCount":3,"available":true,"group":"cross-cutting","bucket":"nesy","path":"cartridges/cross-cutting/nesy/nesy-mcp"}, +{"name":"stack-orchestrator-mcp","version":"0.1.0","description":"Multi-stack execution orchestrator. Parses stack.compose.toml, builds dependency graphs, plans phased parallel execution, and dispatches steps to per-domain LSP cartridges (cloud-lsp, container-lsp, database-lsp, k8s-lsp, git-lsp, iac-lsp, observe-lsp, queues-lsp, secrets-lsp, ssg-lsp, proof-lsp). Replaces 'fleet-mcp redesign' working name per ADR-002.","tier":"Ayo","domain":"Orchestration","category":"cross-cutting","protocols":["MCP","REST"],"auth":"none","toolCount":5,"available":true,"group":"cross-cutting","bucket":"orchestration","path":"cartridges/cross-cutting/orchestration/stack-orchestrator-mcp"}, +{"name":"browser-mcp","version":"0.1.0","description":"Firefox browser automation via Marionette","tier":"Ayo","domain":"automation","category":"domain","protocols":["MCP","REST"],"auth":"none","toolCount":9,"available":true,"group":"domains","bucket":"automation","path":"cartridges/domains/automation/browser-mcp"}, +{"name":"origene-mcp","version":"0.1.0","description":"Biomedical MCP Server Platform. Integrates 600+ tools and databases (ChEMBL, PubChem, FDA, OpenTargets, NCBI, UniProt, PDB, Ensembl, UCSC, KEGG, STRING, TCGA, Monarch, ClinicalTrials) for multi-dimensional biomedical information retrieval.","tier":"Ayo","domain":"Bioinformatics","category":"domain","protocols":["MCP","REST"],"auth":"api-key","toolCount":5,"available":true,"group":"domains","bucket":"bioinformatics","path":"cartridges/domains/bioinformatics/origene-mcp"}, +{"name":"buildkite-mcp","version":"0.1.0","description":"Buildkite CI/CD cartridge -- pipeline listing, build management, job inspection, artifact retrieval, agent listing, annotation creation, build triggering, log retrieval, environment listing, and build cancellation via the Buildkite REST API","tier":"Ayo","domain":"CI/CD","category":"domain","protocols":["MCP","REST"],"auth":"api-key","toolCount":10,"available":true,"group":"domains","bucket":"ci-cd","path":"cartridges/domains/ci-cd/buildkite-mcp"}, +{"name":"circleci-mcp","version":"0.1.0","description":"CircleCI CI/CD cartridge -- pipeline listing, workflow management, job inspection, artifact retrieval, project listing, environment variable browsing, pipeline triggering, job cancellation, and insight queries via the CircleCI API v2","tier":"Ayo","domain":"CI/CD","category":"domain","protocols":["MCP","REST"],"auth":"api-key","toolCount":9,"available":true,"group":"domains","bucket":"ci-cd","path":"cartridges/domains/ci-cd/circleci-mcp"}, +{"name":"github-actions-mcp","version":"0.1.0","description":"GitHub Actions CI/CD cartridge -- workflow listing, run management, job/step inspection, artifact download, log retrieval, workflow dispatch, secret listing, environment browsing, cache management, runner listing, re-run, and cancellation via the GitHub Actions API","tier":"Ayo","domain":"CI/CD","category":"domain","protocols":["MCP","REST"],"auth":"api-key","toolCount":12,"available":true,"group":"domains","bucket":"ci-cd","path":"cartridges/domains/ci-cd/github-actions-mcp"}, +{"name":"hypatia-mcp","version":"0.1.0","description":"Hypatia neurosymbolic CI/CD intelligence. Scans repos for security, quality, and compliance issues using symbolic rules + neural pattern detection.","tier":"Ayo","domain":"CI/CD Intelligence","category":"domain","protocols":["MCP","REST"],"auth":"none","toolCount":4,"available":true,"group":"domains","bucket":"ci-cd","path":"cartridges/domains/ci-cd/hypatia-mcp"}, +{"name":"laminar-mcp","version":"0.1.0","description":"Laminar CI/CD pipeline management","tier":"Ayo","domain":"ci","category":"domain","protocols":["MCP","REST"],"auth":"none","toolCount":4,"available":true,"group":"domains","bucket":"ci-cd","path":"cartridges/domains/ci-cd/laminar-mcp"}, +{"name":"aws-mcp","version":"0.1.0","description":"AWS cloud gateway. Session-based authentication with per-region slots, throttle management, and multi-service action routing.","tier":"Ayo","domain":"Cloud","category":"domain","protocols":["MCP","REST"],"auth":"none","toolCount":8,"available":true,"group":"domains","bucket":"cloud","path":"cartridges/domains/cloud/aws-mcp"}, +{"name":"cloud-lsp","version":"0.1.0","description":"Language Server Protocol implementation for cloud-provider infrastructure. Provides IDE integration for resource validation, IAM lint, region/zone completion, and cost hints across AWS, Azure, GCP, and DigitalOcean.","tier":"Ayo","domain":"Cloud","category":"domain","protocols":["LSP"],"auth":"none","toolCount":5,"available":true,"group":"domains","bucket":"cloud","path":"cartridges/domains/cloud/cloud-lsp"}, +{"name":"cloud-mcp","version":"0.1.0","description":"Multi-cloud provider session manager (AWS/GCP/Azure/DO/Vercel)","tier":"Ayo","domain":"cloud","category":"domain","protocols":["MCP","REST"],"auth":"none","toolCount":4,"available":true,"group":"domains","bucket":"cloud","path":"cartridges/domains/cloud/cloud-mcp"}, +{"name":"cloudflare-mcp","version":"0.1.0","description":"Cloudflare API v4 cartridge -- DNS record management, zone settings, and SSL/TLS configuration","tier":"Ayo","domain":"Cloud","category":"domain","protocols":["MCP","REST"],"auth":"api-key","toolCount":11,"available":true,"group":"domains","bucket":"cloud","path":"cartridges/domains/cloud/cloudflare-mcp"}, +{"name":"digitalocean-mcp","version":"0.2.0","description":"DigitalOcean cloud infrastructure cartridge -- droplets, volumes, domains, SSH keys, snapshots, databases, Kubernetes, firewalls, load balancers, and account management","tier":"Ayo","domain":"Cloud","category":"domain","protocols":["MCP","REST"],"auth":"api-key","toolCount":18,"available":true,"group":"domains","bucket":"cloud","path":"cartridges/domains/cloud/digitalocean-mcp"}, +{"name":"fly-mcp","version":"0.1.0","description":"Fly.io Machines API v1 cartridge -- app, machine, volume, secret, region, IP, and certificate management","tier":"Ayo","domain":"Cloud","category":"domain","protocols":["MCP","REST"],"auth":"api-key","toolCount":21,"available":true,"group":"domains","bucket":"cloud","path":"cartridges/domains/cloud/fly-mcp"}, +{"name":"gcp-mcp","version":"0.1.0","description":"GCP cloud gateway. Project-scoped authentication with quota tracking and multi-service routing.","tier":"Ayo","domain":"Cloud","category":"domain","protocols":["MCP","REST"],"auth":"none","toolCount":7,"available":true,"group":"domains","bucket":"cloud","path":"cartridges/domains/cloud/gcp-mcp"}, +{"name":"hetzner-mcp","version":"0.2.0","description":"Hetzner Cloud API cartridge -- server, volume, firewall, network, SSH key, image, snapshot, floating IP, and load balancer management with per-second rate limiting","tier":"Ayo","domain":"Cloud","category":"domain","protocols":["MCP","REST"],"auth":"api-key","toolCount":20,"available":true,"group":"domains","bucket":"cloud","path":"cartridges/domains/cloud/hetzner-mcp"}, +{"name":"linode-mcp","version":"0.2.0","description":"Linode/Akamai cloud infrastructure cartridge -- instances, volumes, domains, NodeBalancers, StackScripts, images, regions, firewalls, and account management","tier":"Ayo","domain":"Cloud","category":"domain","protocols":["MCP","REST"],"auth":"api-key","toolCount":18,"available":true,"group":"domains","bucket":"cloud","path":"cartridges/domains/cloud/linode-mcp"}, +{"name":"railway-mcp","version":"0.1.0","description":"Railway GraphQL API v2 cartridge -- project, service, deployment, environment variable, domain, log, and metrics management","tier":"Ayo","domain":"Cloud","category":"domain","protocols":["MCP","GraphQL"],"auth":"api-key","toolCount":19,"available":true,"group":"domains","bucket":"cloud","path":"cartridges/domains/cloud/railway-mcp"}, +{"name":"render-mcp","version":"0.2.0","description":"Render REST API v1 cartridge -- services, deploys, env groups, custom domains, jobs, suspend/resume, and bandwidth monitoring","tier":"Ayo","domain":"Cloud","category":"domain","protocols":["MCP","REST"],"auth":"api-key","toolCount":16,"available":true,"group":"domains","bucket":"cloud","path":"cartridges/domains/cloud/render-mcp"}, +{"name":"coderag-mcp","version":"0.1.0","description":"Enterprise Code Intelligence Platform. Advanced graph-based code analysis for AI-assisted software development. Transforms complex software projects into searchable knowledge graphs using Neo4j.","tier":"Ayo","domain":"Code Analysis","category":"domain","protocols":["MCP","REST"],"auth":"none","toolCount":5,"available":true,"group":"domains","bucket":"code-quality","path":"cartridges/domains/code-quality/coderag-mcp"}, +{"name":"sanctify-mcp","version":"1.0.0","description":"Sanctify Cartridge — PHP lint and deviation detection tools","tier":"Ayo","domain":"Code Quality","category":"domain","protocols":["MCP"],"auth":"none","toolCount":5,"available":true,"group":"domains","bucket":"code-quality","path":"cartridges/domains/code-quality/sanctify-mcp"}, +{"name":"burble-admin-mcp","version":"0.1.0","description":"Burble WebRTC server administration","tier":"Ayo","domain":"communications","category":"domain","protocols":["MCP","REST"],"auth":"none","toolCount":10,"available":true,"group":"domains","bucket":"communications","path":"cartridges/domains/communications/burble-admin-mcp"}, +{"name":"comms-mcp","version":"0.1.0","description":"Multi-provider communications (Gmail, Google Calendar)","tier":"Ayo","domain":"communications","category":"domain","protocols":["MCP","REST"],"auth":"none","toolCount":4,"available":true,"group":"domains","bucket":"communications","path":"cartridges/domains/communications/comms-mcp"}, +{"name":"discord-mcp","version":"0.1.0","description":"Discord bot gateway. Send messages, read channel history, manage guilds, and react to messages.","tier":"Ayo","domain":"Communications","category":"domain","protocols":["MCP","REST"],"auth":"none","toolCount":7,"available":true,"group":"domains","bucket":"communications","path":"cartridges/domains/communications/discord-mcp"}, +{"name":"matrix-mcp","version":"0.1.0","description":"Matrix homeserver gateway. Send messages, join/leave rooms, read room history, and manage membership.","tier":"Ayo","domain":"Communications","category":"domain","protocols":["MCP","REST"],"auth":"none","toolCount":7,"available":true,"group":"domains","bucket":"communications","path":"cartridges/domains/communications/matrix-mcp"}, +{"name":"notifyhub-mcp","version":"0.1.0","description":"Unified notification platform. Send notifications via Email, SMS, WhatsApp, Slack, Telegram, Discord, Teams, Firebase Push, Webhooks, WebSocket, Google Chat, Twitter/X, LinkedIn, Notion, Twitch, YouTube, Instagram, SendGrid, TikTok Shop, Facebook, AWS SNS, Mailgun, PagerDuty, Kick.","tier":"Ayo","domain":"Communication","category":"domain","protocols":["MCP","REST"],"auth":"api-key","toolCount":5,"available":true,"group":"domains","bucket":"communications","path":"cartridges/domains/communications/notifyhub-mcp"}, +{"name":"slack-mcp","version":"0.1.0","description":"Slack workspace gateway. Send messages, list channels, read threads, search messages, and manage users.","tier":"Ayo","domain":"Communications","category":"domain","protocols":["MCP","REST"],"auth":"none","toolCount":7,"available":true,"group":"domains","bucket":"communications","path":"cartridges/domains/communications/slack-mcp"}, +{"name":"telegram-mcp","version":"0.1.0","description":"Telegram Bot API gateway. Send messages, manage chats, handle inline queries, and read updates.","tier":"Ayo","domain":"Communications","category":"domain","protocols":["MCP","REST"],"auth":"none","toolCount":6,"available":true,"group":"domains","bucket":"communications","path":"cartridges/domains/communications/telegram-mcp"}, +{"name":"civic-connect-mcp","version":"0.1.0","description":"CivicConnect community engagement platform","tier":"Ayo","domain":"community","category":"domain","protocols":["MCP","REST"],"auth":"none","toolCount":3,"available":true,"group":"domains","bucket":"community","path":"cartridges/domains/community/civic-connect-mcp"}, +{"name":"feedback-mcp","version":"0.1.0","description":"Feedback collection and sentiment analysis","tier":"Ayo","domain":"community","category":"domain","protocols":["MCP","REST"],"auth":"none","toolCount":4,"available":true,"group":"domains","bucket":"community","path":"cartridges/domains/community/feedback-mcp"}, +{"name":"conflow-mcp","version":"0.1.0","description":"Conflow configuration management","tier":"Ayo","domain":"configuration","category":"domain","protocols":["MCP","REST"],"auth":"none","toolCount":4,"available":true,"group":"domains","bucket":"config","path":"cartridges/domains/config/conflow-mcp"}, +{"name":"k9iser-mcp","version":"0.1.0","description":"Wrap configs into self-validating K9 contracts (k9iser generate/validate/apply)","tier":"Ayo","domain":"config","category":"domain","protocols":["MCP","REST"],"auth":"none","toolCount":5,"available":true,"group":"domains","bucket":"config","path":"cartridges/domains/config/k9iser-mcp"}, +{"name":"container-lsp","version":"0.1.0","description":"Language Server Protocol implementation for container runtimes. Provides IDE integration for Containerfile/Dockerfile linting, base-image hints, layer-size diagnostics, and security policy checks across Docker, Podman, and nerdctl.","tier":"Ayo","domain":"Container","category":"domain","protocols":["LSP"],"auth":"none","toolCount":5,"available":true,"group":"domains","bucket":"container","path":"cartridges/domains/container/container-lsp"}, +{"name":"container-mcp","version":"0.1.0","description":"Container lifecycle manager. Build, create, start, stop, and remove containers via Podman/Docker with state machine enforcement.","tier":"Ayo","domain":"Container Orchestration","category":"domain","protocols":["MCP","REST"],"auth":"none","toolCount":8,"available":true,"group":"domains","bucket":"container","path":"cartridges/domains/container/container-mcp"}, +{"name":"docker-hub-mcp","version":"0.2.0","description":"Docker Hub container registry cartridge -- image search, repository management, tag listing, manifest inspection, namespace browsing, and pull rate limit tracking with JWT auth","tier":"Ayo","domain":"Container","category":"domain","protocols":["MCP","REST"],"auth":"api-key","toolCount":16,"available":true,"group":"domains","bucket":"container","path":"cartridges/domains/container/docker-hub-mcp"}, +{"name":"k8s-lsp","version":"0.1.0","description":"Language Server Protocol implementation for Kubernetes manifests and orchestration tooling. Provides IDE integration for manifest validation, CRD-aware completion, Helm chart linting, and Kustomize overlay resolution across kubectl, helm, and kustomize.","tier":"Ayo","domain":"Container","category":"domain","protocols":["LSP"],"auth":"none","toolCount":5,"available":true,"group":"domains","bucket":"container","path":"cartridges/domains/container/k8s-lsp"}, +{"name":"k8s-mcp","version":"0.1.0","description":"Kubernetes cluster management. Namespace-scoped operations with connection lifecycle and resource CRUD.","tier":"Ayo","domain":"Container Orchestration","category":"domain","protocols":["MCP","REST"],"auth":"none","toolCount":8,"available":true,"group":"domains","bucket":"container","path":"cartridges/domains/container/k8s-mcp"}, +{"name":"stapeln-mcp","version":"0.1.0","description":"Stapeln container stack manager. Deploy, scale, and monitor container stacks using Chainguard base images.","tier":"Ayo","domain":"Container Orchestration","category":"domain","protocols":["MCP","REST"],"auth":"none","toolCount":4,"available":true,"group":"domains","bucket":"container","path":"cartridges/domains/container/stapeln-mcp"}, +{"name":"arango-mcp","version":"0.1.0","description":"ArangoDB multi-model database gateway. AQL queries, document operations, graph traversals, and collection management.","tier":"Ayo","domain":"Database","category":"domain","protocols":["MCP","REST"],"auth":"none","toolCount":9,"available":true,"group":"domains","bucket":"database","path":"cartridges/domains/database/arango-mcp"}, +{"name":"clickhouse-mcp","version":"0.1.0","description":"ClickHouse analytics database gateway. Columnar queries, bulk inserts, and real-time analytics via session management.","tier":"Ayo","domain":"Database","category":"domain","protocols":["MCP","REST"],"auth":"none","toolCount":7,"available":true,"group":"domains","bucket":"database","path":"cartridges/domains/database/clickhouse-mcp"}, +{"name":"database-lsp","version":"0.1.0","description":"Language Server Protocol implementation for database query languages and schemas. Provides IDE integration for SQL syntax, schema completion, query plan hints, and migration diagnostics across PostgreSQL, MySQL, SQLite, Redis, MongoDB, and Neo4j.","tier":"Ayo","domain":"Database","category":"domain","protocols":["LSP"],"auth":"none","toolCount":5,"available":true,"group":"domains","bucket":"database","path":"cartridges/domains/database/database-lsp"}, +{"name":"database-mcp","version":"0.1.0","description":"Universal database gateway. Connects to PostgreSQL, SQLite, VeriSimDB, QuandleDB, MongoDB, and other backends with unified query interface.","tier":"Ayo","domain":"Database","category":"domain","protocols":["MCP","REST"],"auth":"none","toolCount":6,"available":true,"group":"domains","bucket":"database","path":"cartridges/domains/database/database-mcp"}, +{"name":"duckdb-mcp","version":"0.1.0","description":"DuckDB in-process analytics gateway. SQL queries over Parquet, CSV, JSON, and Arrow files with export support.","tier":"Ayo","domain":"Database","category":"domain","protocols":["MCP","REST"],"auth":"none","toolCount":7,"available":true,"group":"domains","bucket":"database","path":"cartridges/domains/database/duckdb-mcp"}, +{"name":"mongodb-mcp","version":"0.1.0","description":"MongoDB gateway with collection-level CRUD, aggregation pipeline support, and session management.","tier":"Ayo","domain":"Database","category":"domain","protocols":["MCP","REST"],"auth":"none","toolCount":8,"available":true,"group":"domains","bucket":"database","path":"cartridges/domains/database/mongodb-mcp"}, +{"name":"neo4j-mcp","version":"0.1.0","description":"Neo4j graph database query and write","tier":"Ayo","domain":"database","category":"domain","protocols":["MCP","REST"],"auth":"none","toolCount":5,"available":true,"group":"domains","bucket":"database","path":"cartridges/domains/database/neo4j-mcp"}, +{"name":"neon-mcp","version":"0.1.0","description":"Neon serverless Postgres gateway. Branch management, query execution, and connection pooling for Neon projects.","tier":"Ayo","domain":"Database","category":"domain","protocols":["MCP","REST"],"auth":"none","toolCount":7,"available":true,"group":"domains","bucket":"database","path":"cartridges/domains/database/neon-mcp"}, +{"name":"postgresql-mcp","version":"0.1.0","description":"PostgreSQL gateway with full transaction support, connection pooling, and query lifecycle management.","tier":"Ayo","domain":"Database","category":"domain","protocols":["MCP","REST"],"auth":"none","toolCount":9,"available":true,"group":"domains","bucket":"database","path":"cartridges/domains/database/postgresql-mcp"}, +{"name":"redis-mcp","version":"0.1.0","description":"Redis gateway. Key-value operations, sorted sets, pub/sub, streams, and Lua scripting via session slots.","tier":"Ayo","domain":"Database","category":"domain","protocols":["MCP","REST"],"auth":"none","toolCount":9,"available":true,"group":"domains","bucket":"database","path":"cartridges/domains/database/redis-mcp"}, +{"name":"supabase-mcp","version":"0.1.0","description":"Supabase gateway. PostgreSQL queries, Auth user management, Storage file operations, and Edge Functions.","tier":"Ayo","domain":"Database","category":"domain","protocols":["MCP","REST"],"auth":"none","toolCount":7,"available":true,"group":"domains","bucket":"database","path":"cartridges/domains/database/supabase-mcp"}, +{"name":"turso-mcp","version":"0.1.0","description":"Turso libSQL gateway. Edge SQLite databases with multi-database support and embedded replica sync.","tier":"Ayo","domain":"Database","category":"domain","protocols":["MCP","REST"],"auth":"none","toolCount":7,"available":true,"group":"domains","bucket":"database","path":"cartridges/domains/database/turso-mcp"}, +{"name":"verisimdb-mcp","version":"0.1.0","description":"VeriSimDB verified simulation database. Stores octadic records with formal drift detection and full audit trail.","tier":"Ayo","domain":"Database","category":"domain","protocols":["MCP","REST"],"auth":"none","toolCount":4,"available":true,"group":"domains","bucket":"database","path":"cartridges/domains/database/verisimdb-mcp"}, +{"name":"codeseeker-mcp","version":"0.1.0","description":"CodeSeeker hybrid code search and graph RAG","tier":"Ayo","domain":"development","category":"domain","protocols":["MCP","REST"],"auth":"none","toolCount":5,"available":true,"group":"domains","bucket":"development","path":"cartridges/domains/development/codeseeker-mcp"}, +{"name":"fireflag-mcp","version":"1.0.0","description":"Fireflag Cartridge — Extension-to-MCP mapping and discovery tools","tier":"Ayo","domain":"Developer Tools","category":"domain","protocols":["MCP"],"auth":"none","toolCount":5,"available":true,"group":"domains","bucket":"development","path":"cartridges/domains/development/fireflag-mcp"}, +{"name":"git-lsp","version":"0.1.0","description":"Language Server Protocol implementation for git hosting platforms. Provides IDE integration for PR/MR description linting, issue cross-reference completion, branch name conventions, and CI workflow validation across GitHub, GitLab, Gitea, and Bitbucket.","tier":"Ayo","domain":"Development","category":"domain","protocols":["LSP"],"auth":"none","toolCount":5,"available":true,"group":"domains","bucket":"development","path":"cartridges/domains/development/git-lsp"}, +{"name":"git-mcp","version":"0.1.0","description":"Multi-forge git operations (GitHub, GitLab, Gitea, Bitbucket)","tier":"Ayo","domain":"development","category":"domain","protocols":["MCP","REST"],"auth":"none","toolCount":7,"available":true,"group":"domains","bucket":"development","path":"cartridges/domains/development/git-mcp"}, +{"name":"github-api-mcp","version":"0.1.0","description":"GitHub REST API — repos, issues, PRs, search","tier":"Ayo","domain":"development","category":"domain","protocols":["MCP","REST"],"auth":"none","toolCount":8,"available":true,"group":"domains","bucket":"development","path":"cartridges/domains/development/github-api-mcp"}, +{"name":"gitlab-api-mcp","version":"0.1.0","description":"GitLab REST API — projects, issues, MRs","tier":"Ayo","domain":"development","category":"domain","protocols":["MCP","REST"],"auth":"none","toolCount":7,"available":true,"group":"domains","bucket":"development","path":"cartridges/domains/development/gitlab-api-mcp"}, +{"name":"kategoria-mcp","version":"0.1.0","description":"Kategoria type-theory learning system. Classifies type-theory constructs and evaluates learner challenge responses.","tier":"Ayo","domain":"Education","category":"domain","protocols":["MCP","REST"],"auth":"none","toolCount":3,"available":true,"group":"domains","bucket":"education","path":"cartridges/domains/education/kategoria-mcp"}, +{"name":"echidna-llm-mcp","version":"0.1.0","description":"LLM advisor cartridge for the ECHIDNA formal verification engine. Provides free-form consultation (consult) and structured proof-tactic generation (suggest_tactics) by routing to Anthropic Claude via ANTHROPIC_API_KEY.","tier":"Ayo","domain":"Formal Verification","category":"domain","protocols":["REST"],"auth":"api-key","toolCount":2,"available":true,"group":"domains","bucket":"formal-verification","path":"cartridges/domains/formal-verification/echidna-llm-mcp"}, +{"name":"ephapax-mcp","version":"1.0.0","description":"Ephapax Cartridge — Proof-compiler query tools for formal verification workflows","tier":"Ayo","domain":"Formal Verification","category":"domain","protocols":["MCP"],"auth":"none","toolCount":5,"available":true,"group":"domains","bucket":"formal-verification","path":"cartridges/domains/formal-verification/ephapax-mcp"}, +{"name":"proof-lsp","version":"0.1.0","description":"Language Server Protocol implementation for proof assistants. Provides IDE integration for proof checking, goal display, tactic completion, theorem search, and hover documentation across Coq, Lean, Isabelle, and Agda.","tier":"Ayo","domain":"Formal Verification","category":"domain","protocols":["LSP"],"auth":"none","toolCount":5,"available":true,"group":"domains","bucket":"formal-verification","path":"cartridges/domains/formal-verification/proof-lsp"}, +{"name":"proof-mcp","version":"0.1.0","description":"Proof verification lifecycle manager. Manages sessions across Lean, Coq, Agda, Isabelle, Idris2, Z3, CVC5. State machine: idle -> loading -> verifying -> verified/failed.","tier":"Ayo","domain":"Formal Verification","category":"domain","protocols":["MCP","REST"],"auth":"none","toolCount":8,"available":true,"group":"domains","bucket":"formal-verification","path":"cartridges/domains/formal-verification/proof-mcp"}, +{"name":"game-admin-mcp","version":"0.1.0","description":"Game server administration and configuration drift","tier":"Ayo","domain":"gaming","category":"domain","protocols":["MCP","REST"],"auth":"none","toolCount":7,"available":true,"group":"domains","bucket":"gaming","path":"cartridges/domains/gaming/game-admin-mcp"}, +{"name":"idaptik-admin-mcp","version":"0.1.0","description":"IDApTIK game server administration","tier":"Ayo","domain":"gaming","category":"domain","protocols":["MCP","REST"],"auth":"none","toolCount":10,"available":true,"group":"domains","bucket":"gaming","path":"cartridges/domains/gaming/idaptik-admin-mcp"}, +{"name":"npc-mcp","version":"0.1.0","description":"Embeds an AI presence inside a Minecraft server via a Fabric mod companion. Exposes a layered perception stack and curated command tools so an MCP client can act as an unseen participant in the game world. The paired Fabric mod dials out to the host: it POSTs world events to npc_ingest_event and polls npc_drain_commands for queued actions, so the cartridge itself holds no socket.","tier":"Ayo","domain":"Game Servers","category":"domain","protocols":["MCP","REST"],"auth":"none","toolCount":9,"available":true,"group":"domains","bucket":"gaming","path":"cartridges/domains/gaming/npc-mcp"}, +{"name":"ums-mcp","version":"0.1.0","description":"Universal Map Specification — level editor and validator","tier":"Ayo","domain":"gaming","category":"domain","protocols":["MCP","REST"],"auth":"none","toolCount":7,"available":true,"group":"domains","bucket":"gaming","path":"cartridges/domains/gaming/ums-mcp"}, +{"name":"aerie-mcp","version":"0.1.0","description":"Aerie environment lifecycle manager","tier":"Ayo","domain":"infrastructure","category":"domain","protocols":["MCP","REST"],"auth":"none","toolCount":4,"available":true,"group":"domains","bucket":"infrastructure","path":"cartridges/domains/infrastructure/aerie-mcp"}, +{"name":"hesiod-mcp","version":"1.0.0","description":"DNS lookup cartridge — query DNS records via MCP tools","tier":"Ayo","domain":"Infrastructure","category":"domain","protocols":["MCP"],"auth":"none","toolCount":3,"available":true,"group":"domains","bucket":"infrastructure","path":"cartridges/domains/infrastructure/hesiod-mcp"}, +{"name":"iac-lsp","version":"0.1.0","description":"Language Server Protocol implementation for Infrastructure-as-Code tooling. Provides IDE integration for HCL/policy linting, resource graph diagnostics, plan-preview hovers, and state-drift hints across OpenTofu and Pulumi.","tier":"Ayo","domain":"Infrastructure","category":"domain","protocols":["LSP"],"auth":"none","toolCount":5,"available":true,"group":"domains","bucket":"infrastructure","path":"cartridges/domains/infrastructure/iac-lsp"}, +{"name":"iac-mcp","version":"0.1.0","description":"Infrastructure-as-Code gateway. Manages Terraform/OpenTofu plan→apply→destroy lifecycle with state machine enforcement.","tier":"Ayo","domain":"Infrastructure","category":"domain","protocols":["MCP","REST"],"auth":"none","toolCount":7,"available":true,"group":"domains","bucket":"infrastructure","path":"cartridges/domains/infrastructure/iac-mcp"}, +{"name":"librarian-mcp","version":"0.1.0","description":"Document RAG cartridge -- holds books and long-form text on BoJ and serves the most relevant passages to models. Extracts text (plain, Markdown, or pdftotext-extractable PDFs), chunks with overlap and page references, embeds (offline hash backend or delegated HuggingFace feature-extraction via ml-mcp), and answers semantic queries with brute-force cosine over a persistent, ownable on-disk index.","tier":"Ayo","domain":"Knowledge","category":"domain","protocols":["MCP","REST","gRPC","GraphQL"],"auth":"none","toolCount":5,"available":true,"group":"domains","bucket":"knowledge","path":"cartridges/domains/knowledge/librarian-mcp"}, +{"name":"local-memory-mcp","version":"0.1.0","description":"Persistent local memory for Claude, Cursor & Codex. 13 tools. No cloud. No API keys. Stores learnings, decisions, people, projects in a single SQLite file on your machine.","tier":"Ayo","domain":"Knowledge & Memory","category":"domain","protocols":["MCP","REST"],"auth":"none","toolCount":13,"available":true,"group":"domains","bucket":"knowledge","path":"cartridges/domains/knowledge/local-memory-mcp"}, +{"name":"obsidian-mcp","version":"0.2.0","description":"Obsidian vault cartridge -- note search, content retrieval, backlink navigation, tag browsing, graph analysis, dataview queries, frontmatter extraction, daily notes, template listing, and vault statistics via the Obsidian Local REST API","tier":"Ayo","domain":"Knowledge","category":"domain","protocols":["MCP","REST"],"auth":"api-key","toolCount":12,"available":true,"group":"domains","bucket":"knowledge","path":"cartridges/domains/knowledge/obsidian-mcp"}, +{"name":"007-mcp","version":"0.1.0","description":"007 agent meta-language cartridge — exposes the full oo7 CLI surface (parse/run/trace/build/test/lint/verify/contractile verbs/canonical-proof-suite/groove/self-assess) plus on-enter and on-exit lifecycle hooks that register the session as a coord peer, load the 6a2 methodology pack (STATE, META, ECOSYSTEM, AGENTIC, NEUROSYM, PLAYBOOK), and perform drift checks on exit.","tier":"Ayo","domain":"dezig","category":"domain","protocols":["MCP","Agentic"],"auth":"none","toolCount":73,"available":true,"group":"domains","bucket":"languages","path":"cartridges/domains/languages/007-mcp"}, +{"name":"affinescript-mcp","version":"0.1.0","description":"AffineScript language cartridge -- type checking, parsing, formatting, linting, compiling, hover/goto-def/completion queries, error explanation, stdlib browsing, and syntax reference for the AffineScript language (substructural type system with affine/linear types, algebraic effects)","tier":"Ayo","domain":"Languages","category":"domain","protocols":["MCP","REST"],"auth":"none","toolCount":12,"available":true,"group":"domains","bucket":"languages","path":"cartridges/domains/languages/affinescript-mcp"}, +{"name":"lang-mcp","version":"0.1.0","description":"Multi-language session manager for the nextgen-languages family: Eclexia, AffineScript, BetLang, Ephapax, MyLang, WokeLang, Anvomidav, Phronesis, Error-lang, Julia-the-Viper, Me-dialect, Oblibeny. Tracks per-language sessions, delegates type-checking and evaluation to each language's CLI tool, and provides a unified interface across all dialects.","tier":"Ayo","domain":"Languages","category":"domain","protocols":["MCP","REST"],"auth":"none","toolCount":9,"available":true,"group":"domains","bucket":"languages","path":"cartridges/domains/languages/lang-mcp"}, +{"name":"lsp-mcp","version":"0.1.0","description":"Generic Language Server Protocol (LSP 3.17) gateway. Spawns any LSP server as a persistent subprocess, manages the JSON-RPC 2.0 over stdio session, and exposes text document operations (open, change, hover, completion, goto-definition, references, diagnostics, formatting) as MCP tools.","tier":"Ayo","domain":"Language Tools","category":"domain","protocols":["MCP","REST"],"auth":"none","toolCount":12,"available":true,"group":"domains","bucket":"languages","path":"cartridges/domains/languages/lsp-mcp"}, +{"name":"orchestrator-lsp-mcp","version":"0.1.0","description":"Cross-domain LSP orchestrator. Routes LSP requests across all 12 poly-*-lsp servers (cloud, container, iac, k8s, db, queue, secret, git, ssg, proof, observability, browser) via a single GenLSP supervisor. Inspired by poly-orchestrator-lsp (polystack, archived). Wraps the 12 domain servers into one unified textDocument interface with domain-routing based on workspace root and file type.","tier":"Teranga","domain":"LSP","category":"domain","protocols":["MCP","LSP"],"auth":"none","toolCount":4,"available":true,"group":"domains","bucket":"languages","path":"cartridges/domains/languages/orchestrator-lsp-mcp"}, +{"name":"toolchain-mcp","version":"0.1.0","description":"Toolchain orchestrator. Mints, provisions, and configures language toolchains composed from lsp-mcp, dap-mcp, lang-mcp, and bsp-mcp. Integrates with PanLL panels via Groove and supports collaborative Burble sessions for pair-debugging and pair-programming workflows.","tier":"Ayo","domain":"Language Tools","category":"domain","protocols":["MCP","REST"],"auth":"none","toolCount":8,"available":true,"group":"domains","bucket":"languages","path":"cartridges/domains/languages/toolchain-mcp"}, +{"name":"typed-wasm-mcp","version":"0.2.0","description":"AffineScript typed-wasm gateway. Compiles .affine source to Wasm with the typed-wasm Level 7/10 ownership contract, runs the intra-module verifier, and runs the cross-module boundary verifier between two compiled modules.","tier":"Ayo","domain":"Compiler","category":"domain","protocols":["MCP","REST"],"auth":"none","toolCount":4,"available":true,"group":"domains","bucket":"languages","path":"cartridges/domains/languages/typed-wasm-mcp"}, +{"name":"pmpl-mcp","version":"0.1.0","description":"PMPL licence chain verification and artefact hashing","tier":"Ayo","domain":"legal","category":"domain","protocols":["MCP","REST"],"auth":"none","toolCount":5,"available":true,"group":"domains","bucket":"legal","path":"cartridges/domains/legal/pmpl-mcp"}, +{"name":"queues-lsp","version":"0.1.0","description":"Language Server Protocol implementation for message-queue configurations and subject/topic schemas. Provides IDE integration for routing-key linting, subject-pattern completion, dead-letter-queue hints, and consumer-group diagnostics across NATS, RabbitMQ, and Redis Streams.","tier":"Ayo","domain":"Messaging","category":"domain","protocols":["LSP"],"auth":"none","toolCount":5,"available":true,"group":"domains","bucket":"messaging","path":"cartridges/domains/messaging/queues-lsp"}, +{"name":"queues-mcp","version":"0.1.0","description":"Message queue bridge (Redis Streams, RabbitMQ, NATS)","tier":"Ayo","domain":"messaging","category":"domain","protocols":["MCP","REST"],"auth":"none","toolCount":6,"available":true,"group":"domains","bucket":"messaging","path":"cartridges/domains/messaging/queues-mcp"}, +{"name":"elevenlabs-mcp","version":"0.1.0","description":"Text-to-speech via ElevenLabs API — high-quality voices, multilingual, voice cloning (premium tier), streaming output.","tier":"Teranga","domain":"multimodal","category":"domain","protocols":["MCP","REST"],"auth":"api-key","toolCount":4,"available":true,"group":"domains","bucket":"multimodal","path":"cartridges/domains/multimodal/elevenlabs-mcp"}, +{"name":"ffmpeg-mcp","version":"0.1.0","description":"Local FFmpeg gateway — probe metadata, transcode formats, extract audio, extract frames, concatenate, trim. Glue between whisper / replicate / browser screenshots. Local-only — requires host ffmpeg binary; not Worker-compatible.","tier":"Teranga","domain":"multimodal","category":"domain","protocols":["MCP","REST"],"auth":"none","toolCount":6,"available":true,"group":"domains","bucket":"multimodal","path":"cartridges/domains/multimodal/ffmpeg-mcp"}, +{"name":"replicate-mcp","version":"0.1.0","description":"Replicate hosted ML models — image generation (Stable Diffusion, FLUX), video (Veo, Kling), upscaling, vision (LLaVA), audio (MusicGen). Async prediction model with polling.","tier":"Teranga","domain":"multimodal","category":"domain","protocols":["MCP","REST"],"auth":"api-key","toolCount":5,"available":true,"group":"domains","bucket":"multimodal","path":"cartridges/domains/multimodal/replicate-mcp"}, +{"name":"whisper-mcp","version":"0.1.0","description":"Speech-to-text via OpenAI Whisper API + local whisper.cpp fallback. Transcription, language detection, optional translation to English.","tier":"Teranga","domain":"multimodal","category":"domain","protocols":["MCP","REST"],"auth":"api-key","toolCount":4,"available":true,"group":"domains","bucket":"multimodal","path":"cartridges/domains/multimodal/whisper-mcp"}, +{"name":"grafana-mcp","version":"0.1.0","description":"Grafana monitoring cartridge -- dashboard CRUD, panel queries, alert rule management, annotation creation, datasource listing, folder browsing, org info, snapshot management, health checks, and search via the Grafana HTTP API","tier":"Ayo","domain":"Monitoring","category":"domain","protocols":["MCP","REST"],"auth":"api-key","toolCount":10,"available":true,"group":"domains","bucket":"observability","path":"cartridges/domains/observability/grafana-mcp"}, +{"name":"observe-lsp","version":"0.1.0","description":"Language Server Protocol implementation for observability query languages and dashboard definitions. Provides IDE integration for PromQL/LogQL completion, Grafana dashboard JSON validation, Jaeger trace queries, and SLO hints across Prometheus, Loki, Grafana, and Jaeger.","tier":"Ayo","domain":"Observability","category":"domain","protocols":["LSP"],"auth":"none","toolCount":5,"available":true,"group":"domains","bucket":"observability","path":"cartridges/domains/observability/observe-lsp"}, +{"name":"observe-mcp","version":"0.1.0","description":"Unified observability — metrics, logs, traces (Prometheus, Grafana, Loki, Jaeger)","tier":"Ayo","domain":"observability","category":"domain","protocols":["MCP","REST"],"auth":"none","toolCount":4,"available":true,"group":"domains","bucket":"observability","path":"cartridges/domains/observability/observe-mcp"}, +{"name":"prometheus-mcp","version":"0.1.0","description":"Prometheus monitoring cartridge -- instant and range queries (PromQL), target discovery, alert rule listing, label/value browsing, metric metadata, series listing, and runtime/build info via the Prometheus HTTP API v1","tier":"Ayo","domain":"Monitoring","category":"domain","protocols":["MCP","REST"],"auth":"api-key","toolCount":8,"available":true,"group":"domains","bucket":"observability","path":"cartridges/domains/observability/prometheus-mcp"}, +{"name":"sentry-mcp","version":"0.1.0","description":"Sentry error tracking cartridge -- issue listing, event retrieval, project browsing, release management, DSN lookup, team listing, tag search, error resolution, breadcrumb inspection, and performance transaction queries via the Sentry API","tier":"Ayo","domain":"Monitoring","category":"domain","protocols":["MCP","REST"],"auth":"api-key","toolCount":10,"available":true,"group":"domains","bucket":"observability","path":"cartridges/domains/observability/sentry-mcp"}, +{"name":"opendata-mcp","version":"0.1.0","description":"Open Data Model Context Protocol. Access public datasets from your LLM application. Publish and distribute your Open Data via MCP servers.","tier":"Ayo","domain":"Open Data","category":"domain","protocols":["MCP","REST"],"auth":"none","toolCount":5,"available":true,"group":"domains","bucket":"open-data","path":"cartridges/domains/open-data/opendata-mcp"}, +{"name":"airtable-mcp","version":"0.2.0","description":"Airtable cartridge -- base listing, table schema retrieval, record search, record creation, record update, field listing, view browsing, webhook management, comment access, and revision history via the Airtable REST API","tier":"Ayo","domain":"Productivity","category":"domain","protocols":["MCP","REST"],"auth":"api-key","toolCount":10,"available":true,"group":"domains","bucket":"productivity","path":"cartridges/domains/productivity/airtable-mcp"}, +{"name":"google-docs-mcp","version":"0.2.0","description":"Google Docs cartridge -- document retrieval, content reading, text search, heading extraction, comment listing, suggestion browsing, revision history, named range access, document creation, and text insertion via the Google Docs API v1","tier":"Ayo","domain":"Productivity","category":"domain","protocols":["MCP","REST"],"auth":"oauth2","toolCount":10,"available":true,"group":"domains","bucket":"productivity","path":"cartridges/domains/productivity/google-docs-mcp"}, +{"name":"google-sheets-mcp","version":"0.2.0","description":"Google Sheets cartridge -- spreadsheet metadata retrieval, cell range reading, sheet listing, named range access, cell value writing, row appending, sheet creation, formula evaluation, conditional format listing, and pivot table access via the Google Sheets API v4","tier":"Ayo","domain":"Productivity","category":"domain","protocols":["MCP","REST"],"auth":"oauth2","toolCount":10,"available":true,"group":"domains","bucket":"productivity","path":"cartridges/domains/productivity/google-sheets-mcp"}, +{"name":"notion-mcp","version":"0.1.0","description":"Notion workspace pages, databases, and blocks","tier":"Ayo","domain":"productivity","category":"domain","protocols":["MCP","REST"],"auth":"none","toolCount":7,"available":true,"group":"domains","bucket":"productivity","path":"cartridges/domains/productivity/notion-mcp"}, +{"name":"todoist-mcp","version":"0.2.0","description":"Todoist task manager cartridge -- task search, project listing, task creation, task completion, label management, comment retrieval, section browsing, filter queries, activity log access, and productivity stats via the Todoist REST API v2","tier":"Ayo","domain":"Productivity","category":"domain","protocols":["MCP","REST"],"auth":"api-key","toolCount":10,"available":true,"group":"domains","bucket":"productivity","path":"cartridges/domains/productivity/todoist-mcp"}, +{"name":"jira-mcp","version":"0.1.0","description":"Jira project management and issue tracking","tier":"Ayo","domain":"project-management","category":"domain","protocols":["MCP","REST"],"auth":"none","toolCount":8,"available":true,"group":"domains","bucket":"project-management","path":"cartridges/domains/project-management/jira-mcp"}, +{"name":"linear-mcp","version":"0.1.0","description":"Linear issue tracking and project management","tier":"Ayo","domain":"project-management","category":"domain","protocols":["MCP","REST"],"auth":"none","toolCount":7,"available":true,"group":"domains","bucket":"project-management","path":"cartridges/domains/project-management/linear-mcp"}, +{"name":"crates-mcp","version":"0.2.0","description":"crates.io registry cartridge -- Rust crate search, metadata retrieval, version listing, download stats, dependency analysis, owner management, category browsing, and reverse dependency lookup via the crates.io API","tier":"Ayo","domain":"Registry","category":"domain","protocols":["MCP","REST"],"auth":"api-key","toolCount":13,"available":true,"group":"domains","bucket":"registry","path":"cartridges/domains/registry/crates-mcp"}, +{"name":"hackage-mcp","version":"0.2.0","description":"Hackage registry cartridge -- Haskell package search, metadata retrieval, version listing, download stats, dependency analysis, reverse dependency lookup, maintainer listing, deprecated status, and cabal file retrieval via the Hackage API","tier":"Ayo","domain":"Registry","category":"domain","protocols":["MCP","REST"],"auth":"api-key","toolCount":12,"available":true,"group":"domains","bucket":"registry","path":"cartridges/domains/registry/hackage-mcp"}, +{"name":"hex-mcp","version":"0.2.0","description":"Hex.pm registry cartridge -- Elixir/Erlang package search, metadata retrieval, version listing, download stats, dependency analysis, owner listing, retirement status, and API key management via the Hex API","tier":"Ayo","domain":"Registry","category":"domain","protocols":["MCP","REST"],"auth":"api-key","toolCount":10,"available":true,"group":"domains","bucket":"registry","path":"cartridges/domains/registry/hex-mcp"}, +{"name":"npm-registry-mcp","version":"0.2.0","description":"npm registry cartridge -- package search, metadata retrieval, version listing, download stats, dependency analysis, maintainer lookup, and audit advisory queries via the npm registry API","tier":"Ayo","domain":"Registry","category":"domain","protocols":["MCP","REST"],"auth":"api-key","toolCount":12,"available":true,"group":"domains","bucket":"registry","path":"cartridges/domains/registry/npm-registry-mcp"}, +{"name":"opam-mcp","version":"0.2.0","description":"opam registry cartridge -- OCaml package search, metadata retrieval, version listing, dependency analysis, reverse dependency lookup, maintainer listing, and repository browsing via the opam.ocaml.org API","tier":"Ayo","domain":"Registry","category":"domain","protocols":["MCP","REST"],"auth":"none","toolCount":10,"available":true,"group":"domains","bucket":"registry","path":"cartridges/domains/registry/opam-mcp"}, +{"name":"opsm-mcp","version":"0.1.0","description":"Odds-and-Sods Package Manager (OPSM) gateway. Routes package search, install, dependency resolution (PubGrub), and registry management across 103 registry adapters (npm, cargo, hex, pypi, affinescript, rattlescript, eclexia, guix, nix, and more). State machine enforces valid registry slot lifecycle via Zig FFI.","tier":"Ayo","domain":"Package Management","category":"domain","protocols":["MCP","REST"],"auth":"none","toolCount":7,"available":true,"group":"domains","bucket":"registry","path":"cartridges/domains/registry/opsm-mcp"}, +{"name":"pypi-mcp","version":"0.2.0","description":"PyPI registry cartridge -- Python package search, metadata retrieval, version listing, download stats, dependency analysis, maintainer lookup, classifier browsing, and vulnerability advisory queries via the PyPI JSON API and Warehouse API","tier":"Ayo","domain":"Registry","category":"domain","protocols":["MCP","REST"],"auth":"api-key","toolCount":11,"available":true,"group":"domains","bucket":"registry","path":"cartridges/domains/registry/pypi-mcp"}, +{"name":"reposystem-mcp","version":"0.1.0","description":"Reposystem repository management. Lists managed repos, checks health, syncs mirrors, and runs RSR compliance audits.","tier":"Ayo","domain":"Repository Management","category":"domain","protocols":["MCP","REST"],"auth":"none","toolCount":4,"available":true,"group":"domains","bucket":"repository-management","path":"cartridges/domains/repository-management/reposystem-mcp"}, +{"name":"academic-workflow-mcp","version":"1.0.0","description":"Academic workflow — Zotero integration, citations, paper review","tier":"Ayo","domain":"Research","category":"domain","protocols":["MCP"],"auth":"none","toolCount":6,"available":true,"group":"domains","bucket":"research","path":"cartridges/domains/research/academic-workflow-mcp"}, +{"name":"bofig-mcp","version":"1.0.0","description":"Bofig Cartridge — Evidence graph query tools for investigative workflows","tier":"Ayo","domain":"Research","category":"domain","protocols":["MCP"],"auth":"none","toolCount":6,"available":true,"group":"domains","bucket":"research","path":"cartridges/domains/research/bofig-mcp"}, +{"name":"research-mcp","version":"0.1.0","description":"Academic paper search (Semantic Scholar, OpenAlex)","tier":"Ayo","domain":"research","category":"domain","protocols":["MCP","REST"],"auth":"none","toolCount":4,"available":true,"group":"domains","bucket":"research","path":"cartridges/domains/research/research-mcp"}, +{"name":"search-mcp","version":"0.1.0","description":"Web search across multiple providers (Tavily, Brave, Exa, Perplexity) behind one cartridge.","tier":"Teranga","domain":"research","category":"domain","protocols":["MCP","REST"],"auth":"api-key","toolCount":4,"available":true,"group":"domains","bucket":"research","path":"cartridges/domains/research/search-mcp"}, +{"name":"zotero-mcp","version":"0.2.0","description":"Zotero reference manager cartridge -- library search, item retrieval, collection browsing, tag management, attachment access, citation export, note extraction, saved search execution, group library access, and bibliography generation via the Zotero Web API v3","tier":"Ayo","domain":"Research","category":"domain","protocols":["MCP","REST"],"auth":"api-key","toolCount":12,"available":true,"group":"domains","bucket":"research","path":"cartridges/domains/research/zotero-mcp"}, +{"name":"dns-shield-mcp","version":"0.1.0","description":"DNS security shield — DoQ, DoH, DNSSEC, CAA","tier":"Ayo","domain":"security","category":"domain","protocols":["MCP","REST"],"auth":"none","toolCount":5,"available":true,"group":"domains","bucket":"security","path":"cartridges/domains/security/dns-shield-mcp"}, +{"name":"panic-attack-mcp","version":"0.1.0","description":"panic-attacker static analysis. Scans codebases for dangerous patterns, banned constructs, proof drift, and OWASP-class vulnerabilities across 49 languages.","tier":"Ayo","domain":"Security","category":"domain","protocols":["MCP","REST"],"auth":"none","toolCount":3,"available":true,"group":"domains","bucket":"security","path":"cartridges/domains/security/panic-attack-mcp"}, +{"name":"rokur-mcp","version":"0.1.0","description":"Rokur — Svalinn secrets GUI authorisation layer","tier":"Ayo","domain":"security","category":"domain","protocols":["MCP","REST"],"auth":"none","toolCount":4,"available":true,"group":"domains","bucket":"security","path":"cartridges/domains/security/rokur-mcp"}, +{"name":"secrets-lsp","version":"0.1.0","description":"Language Server Protocol implementation for secrets-management tools. Provides IDE integration for SOPS-encrypted file detection, Vault path completion, key rotation hints, and policy-document validation across Vault and SOPS.","tier":"Ayo","domain":"Security","category":"domain","protocols":["LSP"],"auth":"none","toolCount":5,"available":true,"group":"domains","bucket":"security","path":"cartridges/domains/security/secrets-lsp"}, +{"name":"secrets-mcp","version":"0.1.0","description":"Secrets management (Vault, SOPS, env-vault)","tier":"Ayo","domain":"security","category":"domain","protocols":["MCP","REST"],"auth":"none","toolCount":5,"available":true,"group":"domains","bucket":"security","path":"cartridges/domains/security/secrets-mcp"}, +{"name":"vault-mcp","version":"0.1.0","description":"Vault CLI credential broker (execute, list, verify, rotate)","tier":"Ayo","domain":"security","category":"domain","protocols":["MCP","REST"],"auth":"none","toolCount":5,"available":true,"group":"domains","bucket":"security","path":"cartridges/domains/security/vault-mcp"}, +{"name":"vext-mcp","version":"0.1.0","description":"Vext message verification and attestation chain. Verifies signed messages, checks attestation chains, and appends verified payloads.","tier":"Ayo","domain":"Security","category":"domain","protocols":["MCP","REST"],"auth":"none","toolCount":3,"available":true,"group":"domains","bucket":"security","path":"cartridges/domains/security/vext-mcp"}, +{"name":"vordr-mcp","version":"0.1.0","description":"Vordr container integrity monitor. BLAKE3 hashing to detect tampering and drift in container images.","tier":"Ayo","domain":"Security","category":"domain","protocols":["MCP","REST"],"auth":"none","toolCount":4,"available":true,"group":"domains","bucket":"security","path":"cartridges/domains/security/vordr-mcp"}, +{"name":"textkit-mcp","version":"0.1.0","description":"Pure-computation text utilities (base64 encode/decode, etc.). No network, no filesystem, no credentials.","tier":"Ayo","domain":"utilities","category":"domain","protocols":["MCP"],"auth":"none","toolCount":1,"available":true,"group":"domains","bucket":"utilities","path":"cartridges/domains/utilities/textkit-mcp"}, +{"name":"chromadb-mcp","version":"0.1.0","description":"Chroma vector DB — embedded (local persistent) or client/server; LLM-app-focused; metadata + document storage alongside vectors.","tier":"Teranga","domain":"vector","category":"domain","protocols":["MCP","REST"],"auth":"api-key","toolCount":7,"available":true,"group":"domains","bucket":"vector","path":"cartridges/domains/vector/chromadb-mcp"}, +{"name":"pinecone-mcp","version":"0.1.0","description":"Pinecone hosted vector DB — serverless indexes, upsert, similarity search, namespaces, metadata filtering.","tier":"Teranga","domain":"vector","category":"domain","protocols":["MCP","REST"],"auth":"api-key","toolCount":7,"available":true,"group":"domains","bucket":"vector","path":"cartridges/domains/vector/pinecone-mcp"}, +{"name":"qdrant-mcp","version":"0.1.0","description":"Qdrant vector DB — Rust-native; payloads + filtering; sparse + dense vectors; self-host or Qdrant Cloud.","tier":"Teranga","domain":"vector","category":"domain","protocols":["MCP","REST","gRPC"],"auth":"api-key","toolCount":7,"available":true,"group":"domains","bucket":"vector","path":"cartridges/domains/vector/qdrant-mcp"}, +{"name":"weaviate-mcp","version":"0.1.0","description":"Weaviate vector DB — hybrid (vector + BM25 + filter) search, schema-driven classes, modular vectorisers; self-host or cloud.","tier":"Teranga","domain":"vector","category":"domain","protocols":["MCP","REST","gRPC","GraphQL"],"auth":"api-key","toolCount":7,"available":true,"group":"domains","bucket":"vector","path":"cartridges/domains/vector/weaviate-mcp"}, +{"name":"ssg-lsp","version":"0.1.0","description":"Language Server Protocol implementation for static-site-generator content and templates. Provides IDE integration for shortcode/templating completion, frontmatter validation, broken-link diagnostics, and template-syntax hints across Hugo, mdbook, Zola, Hakyll, Franklin, and casket-ssg (Jekyll replacement per estate policy).","tier":"Ayo","domain":"Web","category":"domain","protocols":["LSP"],"auth":"none","toolCount":5,"available":true,"group":"domains","bucket":"web","path":"cartridges/domains/web/ssg-lsp"}, +{"name":"ssg-mcp","version":"0.1.0","description":"Static site generator (Hugo, Zola, Astro, Casket)","tier":"Ayo","domain":"web","category":"domain","protocols":["MCP","REST"],"auth":"none","toolCount":5,"available":true,"group":"domains","bucket":"web","path":"cartridges/domains/web/ssg-mcp"} + ] +} diff --git a/site/index.html b/site/index.html new file mode 100644 index 00000000..84942549 --- /dev/null +++ b/site/index.html @@ -0,0 +1,186 @@ + + + + + + + boj-server — one MCP endpoint for all your tooling + + + + + + + + + + + + + +
+
+

boj-server.net

+

Bundle of Joy

+

One MCP endpoint for all your tooling — GitHub, GitLab, Cloudflare, Vercel, Gmail, + browser automation, research, ML, and 139 open-source cartridges.

+ + +
+
+ +
+ + +
+

Get BoJ

+

Install the base server, then add capability bundles or pick individual cartridges. + Everything below updates the commands live.

+ +
+
+

1 · Base

+ + +

2 · Capability bundles

+
+ Optional capability bundles + + + + +
+ +

3 · Client

+
+ + + + + +
+
+ +
+

Your install

+
+
+ Claude Code (CLI) + +
+
claude mcp add boj-server -- npx -y @hyperpolymath/boj-server@latest
+
+ + +
+
+
+ + +
+

Cartridge catalogue

+

139 open-source cartridges. Filter by group, search by name, + or add individual cartridges to your selection above.

+ +
+ + + +
+ +

Loading catalogue…

+
    + + +
    + + +
    +

    What BoJ does

    +

    BoJ (Bundle of Joy) consolidates your service integrations into a single MCP server endpoint for + AI assistants. The bridge has zero runtime dependencies and runs on Deno, Bun, or Node.

    +
    +
    Forge

    GitHub, GitLab, Bitbucket — repos, issues, PRs, code search, mirroring

    +
    Cloud

    Cloudflare (DNS, Workers, KV, R2, D1), Vercel, Verpex

    +
    Comms

    Gmail, Google Calendar, Slack, Discord, Telegram, Matrix

    +
    Browser

    Headless navigation, screenshots, JS execution

    +
    Research / ML

    Web search, deep research, HuggingFace models & datasets

    +
    Verified

    Constructive proofs over the catalogue, dispatch, and credential isolation

    +
    +
    +
    + + + + + + diff --git a/site/index.md b/site/index.md deleted file mode 100644 index 2955b831..00000000 --- a/site/index.md +++ /dev/null @@ -1,23 +0,0 @@ - ---- -title: boj-server -date: 2026-03-31 ---- - -# boj-server - -The public web home for this project is [boj-server.net](https://boj-server.net). - -BoJ (Bundle of Joy) is a unified MCP server that consolidates all hyperpolymath tooling into a single endpoint — GitHub, GitLab, Cloudflare, Vercel, Verpex, Gmail, Calendar, browser automation, research, ML, and 50+ open-source cartridges. - -## Project Links - -- Website: [boj-server.net](https://boj-server.net) -- Source: [https://github.com/hyperpolymath/boj-server](https://github.com/hyperpolymath/boj-server) -- README: [project overview](https://github.com/hyperpolymath/boj-server/blob/main/README.adoc) -- Docs: [documentation directory](https://github.com/hyperpolymath/boj-server/tree/main/docs) - -This page is a lightweight landing point for the repository and will grow with the project. diff --git a/site/robots.txt b/site/robots.txt new file mode 100644 index 00000000..8522ca99 --- /dev/null +++ b/site/robots.txt @@ -0,0 +1,5 @@ +# SPDX-License-Identifier: MPL-2.0 +User-agent: * +Allow: / + +Sitemap: https://boj-server.net/sitemap.xml diff --git a/site/sitemap.xml b/site/sitemap.xml new file mode 100644 index 00000000..d66b2b61 --- /dev/null +++ b/site/sitemap.xml @@ -0,0 +1,10 @@ + + + + + https://boj-server.net/ + 2026-06-24 + weekly + 1.0 + + diff --git a/tools/site-catalog/build-catalog.sh b/tools/site-catalog/build-catalog.sh new file mode 100755 index 00000000..71122890 --- /dev/null +++ b/tools/site-catalog/build-catalog.sh @@ -0,0 +1,53 @@ +#!/usr/bin/env bash +# SPDX-License-Identifier: MPL-2.0 +# Copyright (c) 2026 Jonathan D.A. Jewell (hyperpolymath) +# +# Regenerate site/catalog.json from the canonical cartridge registry. +# The site serves a committed snapshot; run this when the registry changes. +# +# Usage: +# tools/site-catalog/build-catalog.sh [CARTRIDGES_REPO] [OUT] +# Defaults: +# CARTRIDGES_REPO=../boj-server-cartridges OUT=site/catalog.json +# +# Requires: jq. Groups by the registry's directory taxonomy (reliable), not the +# free-text `domain` field. Excludes templates/. Honours an explicit `available:false`. + +set -euo pipefail + +CARTRIDGES_REPO="${1:-../boj-server-cartridges}" +OUT="${2:-site/catalog.json}" +GEN_DATE="$(date -u +%Y-%m-%d)" +REGISTRY="https://github.com/hyperpolymath/boj-server-cartridges" + +command -v jq >/dev/null || { echo "error: jq is required" >&2; exit 1; } +[ -d "$CARTRIDGES_REPO/cartridges" ] || { echo "error: no cartridges/ under $CARTRIDGES_REPO" >&2; exit 1; } + +cd "$CARTRIDGES_REPO" +tmp="$(mktemp)" +{ + printf '{\n "schema": "boj-site-catalog/v1",\n' + printf ' "generated": "%s",\n "registry": "%s",\n "cartridges": [\n' "$GEN_DATE" "$REGISTRY" + first=1 + while IFS= read -r f; do + rel="${f#./}" + case "$rel" in cartridges/templates/*) continue;; esac + IFS='/' read -r _c grp bucket _name _rest <<<"$rel" + dir="$(dirname "$rel")" + if [ $first -eq 1 ]; then first=0; else printf ',\n'; fi + jq -c --arg group "$grp" --arg bucket "$bucket" --arg path "$dir" '{ + name, version: (.version // "0.0.0"), description: (.description // ""), + tier: (.tier // "Ayo"), domain: (.domain // ""), category: (.category // ""), + protocols: (.protocols // []), auth: (.auth.method // "none"), + toolCount: ((.tools // []) | length), + available: (if has("available") then .available else true end), + group: $group, bucket: $bucket, path: $path + }' "$f" | tr -d '\n' + done < <(find cartridges -name cartridge.json | sort) + printf '\n ]\n}\n' +} >"$tmp" + +jq -e . "$tmp" >/dev/null || { echo "error: produced invalid JSON" >&2; rm -f "$tmp"; exit 1; } +cd - >/dev/null +mv "$tmp" "$OUT" +echo "wrote $OUT ($(jq '.cartridges|length' "$OUT") cartridges)" diff --git a/wrangler.toml b/wrangler.toml new file mode 100644 index 00000000..c515d103 --- /dev/null +++ b/wrangler.toml @@ -0,0 +1,7 @@ +# SPDX-License-Identifier: MPL-2.0 +# Cloudflare Pages configuration for boj-server.net. +# The site is a no-build static bundle; Pages serves the `site/` directory as-is. + +name = "boj-server" +compatibility_date = "2026-06-24" +pages_build_output_dir = "site" From 1c53c209c6ad69ec7e31f3d2767bc56177a86288 Mon Sep 17 00:00:00 2001 From: Claude Date: Wed, 24 Jun 2026 07:37:51 +0000 Subject: [PATCH 2/2] site: resolve Hypatia code_safety alerts in app.js - js_innerhtml (CWE-79): replace `list.innerHTML = ""` with `list.replaceChildren()` (the list was only being cleared; no markup was ever assigned). - js_deno_all_perms (CWE-250): the displayed Deno install command now uses the bridge's declared least-privilege flags (`--allow-net --allow-env --allow-read`, per mcp-bridge/main.js + mcp-bridge/deno.json) instead of `-A`. Co-Authored-By: Claude Opus 4.8 Claude-Session: https://claude.ai/code/session_01XrPAh7eBSUcVKauTVdXH9Y --- site/assets/app.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/site/assets/app.js b/site/assets/app.js index b8934ec0..a507a5c2 100644 --- a/site/assets/app.js +++ b/site/assets/app.js @@ -35,7 +35,7 @@ }, "deno": { label: "Deno (preferred runtime — zero install)", - cmd: () => "deno run -A /path/to/boj-server/mcp-bridge/main.js", + cmd: () => "deno run --allow-net --allow-env --allow-read /path/to/boj-server/mcp-bridge/main.js", }, "gemini": { label: "Gemini CLI (~/.gemini/settings.json)", @@ -159,7 +159,7 @@ const grp = $("#cat-group").value; const tier = $("#cat-tier").value; const list = $("#cat-list"); - list.innerHTML = ""; + list.replaceChildren(); const matches = state.catalog.filter(c => { if (grp && (c.group + "/" + c.bucket) !== grp) return false; if (tier && c.tier !== tier) return false;