@goodfellow-cms/mcp 0.0.0-stage → 0.3.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 Goodfellow contributors
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
package/README.md CHANGED
@@ -1,3 +1,39 @@
1
- # Temporary Holding Version
1
+ # @goodfellow-cms/mcp
2
2
 
3
- This version is a temporary placeholder for this package. An operational version to replace this has been submitted for review and is awaiting a staged release.
3
+ Work on a [Goodfellow](https://goodfellow-cms.github.io/goodfellow-cms/) site from Claude. An [MCP](https://modelcontextprotocol.io) server with Goodfellow's tools: Claude reads a site's pages, items and settings, sees what blocks it has, makes changes in a draft, takes screenshots, and publishes the draft or submits it for review.
4
+
5
+ Most editors use Goodfellow's hosted connector instead; see [Work with Claude](https://goodfellow-cms.github.io/goodfellow-cms/docs/claude). This package runs the same tools on your own computer, signed in with a GitHub or GitLab token that stays there.
6
+
7
+ ## Claude Code
8
+
9
+ ```sh
10
+ claude mcp add goodfellow --env GOODFELLOW_SITE=github:your-name/your-site --env GOODFELLOW_TOKEN=your-token -- npx -y @goodfellow-cms/mcp
11
+ ```
12
+
13
+ - `GOODFELLOW_SITE`: the site's repository, `github:owner/name` or `gitlab:group/name`.
14
+ - `GOODFELLOW_TOKEN`: a token that can change the site's files and open pull requests or merge requests.
15
+ - `GITLAB_URL`: for a GitLab of your own.
16
+ - `GOODFELLOW_BROWSER`: a Chromium-based browser for screenshots, if not Google Chrome or Microsoft Edge.
17
+
18
+ ## Claude Desktop
19
+
20
+ Install the [Goodfellow extension](https://goodfellow-cms.github.io/goodfellow-cms/goodfellow.mcpb), which `pnpm pack-extension` builds from this package.
21
+
22
+ ## In your own server
23
+
24
+ `createGoodfellowServer()` gives an `McpServer` with the tools, for any transport:
25
+
26
+ ```ts
27
+ import { createGoodfellowServer } from "@goodfellow-cms/mcp";
28
+
29
+ const server = createGoodfellowServer({
30
+ sites: async () => [{ id: "github:your-name/your-site" }],
31
+ backend: async (site) => signInSomehow(site), // a GitBackend from @goodfellow-cms/github or @goodfellow-cms/gitlab
32
+ });
33
+ ```
34
+
35
+ Goodfellow's hosted connector (`packages/connector` in the repository) is built this way.
36
+
37
+ ## License
38
+
39
+ MIT
@@ -0,0 +1,68 @@
1
+ import { ContentSource, GitBackend } from "@goodfellow-cms/core";
2
+ import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
3
+ import "@puckeditor/core";
4
+ //#region src/site.d.ts
5
+ /** Where the tools find the sites they may edit, and sign in to them. */
6
+ interface ConnectorContext {
7
+ /** The sites this connection may edit, such as `github:parish/site`. */
8
+ sites(): Promise<Array<{
9
+ id: string;
10
+ label?: string;
11
+ }>>;
12
+ /** Signs in to a site's repository. Throws `ToolError` for a site this connection may not edit. */
13
+ backend(site: string): Promise<GitBackend>;
14
+ /** Fetches the live site's description. Defaults to the global `fetch`. */
15
+ fetch?: typeof fetch;
16
+ /** Takes screenshots, where this server can. */
17
+ screenshots?: Screenshotter;
18
+ /** For tests. */
19
+ now?: () => Date;
20
+ }
21
+ interface Screenshotter {
22
+ /**
23
+ * A PNG of a page at `url`, `width` pixels wide and as tall as the page. With
24
+ * `preview`, `url` is the site's preview page (`/admin/#/preview`), which is
25
+ * handed a draft's content files and shows the page at `preview.path`.
26
+ */
27
+ take(options: {
28
+ url: string;
29
+ width: number;
30
+ preview?: {
31
+ files: Record<string, string>;
32
+ path: string;
33
+ dark?: boolean;
34
+ };
35
+ /** `url` is an image's, shown on a page of its own (`imagePage()`), no wider than `width`. */
36
+ image?: boolean;
37
+ /** Shows the page as a computer set to dark sees it, for sites with dark mode. */
38
+ dark?: boolean;
39
+ }): Promise<Uint8Array>;
40
+ }
41
+ //#endregion
42
+ //#region src/content.d.ts
43
+ /** Thrown with a message Claude can pass on to the editor as it is. */
44
+ export declare class ToolError extends Error {
45
+ name: string;
46
+ }
47
+ /** Every content file, as text: what the preview page needs to show a draft as the site would. */
48
+ export declare function contentFiles(source: ContentSource): Promise<Record<string, string>>;
49
+ //#endregion
50
+ //#region src/image-page.d.ts
51
+ export declare function imagePage(url: string): string;
52
+ //#endregion
53
+ //#region src/tools.d.ts
54
+ /** What Claude is told about working with Goodfellow sites. */
55
+ export declare const INSTRUCTIONS = "These tools edit websites built with Goodfellow, for people who aren't developers.\n\n- Start with get_site, which lists the site's pages, collections and blocks.\n- Changes are saved in a draft, never straight to the live site. The first change starts one and returns its name: pass that name as \"draft\" to every later change and read, so they build on each other.\n- Pages, the header and the footer are made of blocks. get_blocks says which blocks the site has and what each one's props are. Blocks are written as a flat list in page order: a block inside another names it as \"parent\", and which of its places it goes in as \"slot\".\n- Show the editor what a draft looks like with screenshot before anything goes live.\n- Only publish when the editor says to. If they'd like someone to check it first, use submit_for_review instead.\n- Use the site's own words for things: say \"publish\", not \"commit\" or \"merge\".";
56
+ //#endregion
57
+ //#region src/index.d.ts
58
+ /** A site's id for the tools: its host, then its repository, such as `github:parish/site`. */
59
+ export type SiteId = `github:${string}` | `gitlab:${string}`;
60
+ /** Splits a site's id into its host and repository, or `undefined` if it isn't one. */
61
+ export declare function parseSiteId(id: string): {
62
+ host: "github" | "gitlab";
63
+ repo: string;
64
+ } | undefined;
65
+ /** An MCP server with Goodfellow's tools. Connect it to a transport. */
66
+ export declare function createGoodfellowServer(context: ConnectorContext): McpServer;
67
+ //#endregion
68
+ export type { ConnectorContext, Screenshotter };