@kammcs/buildit-mcp 0.0.0-stage → 0.1.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/CHANGELOG.md +72 -0
- package/LICENSE +21 -0
- package/README.md +318 -2
- package/SECURITY.md +48 -0
- package/dist/api/client.js +382 -0
- package/dist/api/generated/operations.js +1559 -0
- package/dist/api/generated/schemas.js +1376 -0
- package/dist/api/generated/strict.js +1622 -0
- package/dist/api/operations.js +43 -0
- package/dist/config.js +280 -0
- package/dist/errors.js +347 -0
- package/dist/identity.js +124 -0
- package/dist/index.js +73 -0
- package/dist/log.js +90 -0
- package/dist/prompts.js +114 -0
- package/dist/resources.js +55 -0
- package/dist/server.js +257 -0
- package/dist/tools/chat.js +273 -0
- package/dist/tools/comments.js +128 -0
- package/dist/tools/items-read.js +569 -0
- package/dist/tools/items-write.js +580 -0
- package/dist/tools/pages.js +325 -0
- package/dist/tools/planning.js +697 -0
- package/dist/tools/plans.js +906 -0
- package/dist/tools/projects.js +401 -0
- package/dist/tools/setup.js +292 -0
- package/dist/tools/shared.js +438 -0
- package/dist/tools/whoami.js +219 -0
- package/dist/toolsets/catalog.js +71 -0
- package/dist/toolsets/registry.js +97 -0
- package/dist/toolsets/toolsets.js +89 -0
- package/dist/transports/http.js +212 -0
- package/dist/transports/stdio.js +203 -0
- package/dist/untrusted.js +466 -0
- package/dist/version.js +28 -0
- package/package.json +75 -4
package/CHANGELOG.md
ADDED
|
@@ -0,0 +1,72 @@
|
|
|
1
|
+
# Changelog
|
|
2
|
+
|
|
3
|
+
All notable changes to buildit-mcp are listed here. The project follows [semantic versioning](https://semver.org); see [Versions](README.md#versions) for what that means for tools.
|
|
4
|
+
|
|
5
|
+
## [0.1.0] - 2026-10-22
|
|
6
|
+
|
|
7
|
+
The first release on npm, as `@kammcs/buildit-mcp`. Built on version 1 of the buildIt.Social agent API (`/v1`).
|
|
8
|
+
|
|
9
|
+
### Tools
|
|
10
|
+
|
|
11
|
+
40 tools in seven toolsets. `items` and `comments` are on by default (15 tools); turn the others on with `BUILDIT_TOOLSETS` or `--toolsets` (`all` for every one). A tool is listed only when the token has all the scopes it needs.
|
|
12
|
+
|
|
13
|
+
- **items** (13): `whoami`, `list_projects`, `describe_project`, `find_users`, `search_items`, `get_item`, `create_item`, `update_item`, `assign_item`, `transition_item`, `link_items`, `unlink_items`, `rank_item`.
|
|
14
|
+
- **comments** (2): `list_comments`, `add_comment`.
|
|
15
|
+
- **planning** (5): `list_sprints`, `plan_sprint`, `list_releases`, `plan_release`, `write_release_notes`.
|
|
16
|
+
- **pages** (4): `list_pages`, `get_page`, `create_page`, `update_page`.
|
|
17
|
+
- **chat** (3, read only, never direct messages): `list_channels`, `read_channel`, `read_thread`.
|
|
18
|
+
- **admin** (8): `create_channel`, `create_project`, `get_workflow`, `list_work_types`, `propose_workflow_change`, `propose_work_type_change`, `propose_field_change`, `propose_label_change`.
|
|
19
|
+
- **destructive** (5): `propose_delete_item`, `propose_move_item`, `propose_bulk_update`, `propose_archive_status`, and `apply_plan`, which is listed whenever any `propose_*` tool is.
|
|
20
|
+
|
|
21
|
+
Deleting, moving and bulk-editing items, archiving a status, and changing workflows, work types, fields or labels are always two steps: a `propose_*` tool returns a preview and a plan handle, and `apply_plan` applies it only after the person confirms. `admin` and `destructive` stay off unless you name them.
|
|
22
|
+
|
|
23
|
+
Also in this release:
|
|
24
|
+
|
|
25
|
+
- Resources `buildit://items/{key}` and `buildit://pages/{id}`, and the prompts `plan_epic`, `triage` and `standup`.
|
|
26
|
+
- People-written content (titles, descriptions, comments, pages, messages, and the names of people, projects, channels and the like) comes back inside `<untrusted_content>` blocks, each with a random id that its closing tag repeats.
|
|
27
|
+
- Read-only mode (`BUILDIT_READ_ONLY`) and a list of tools to hide (`BUILDIT_EXCLUDE_TOOLS`).
|
|
28
|
+
- JSON logs on stderr that never contain tokens or content.
|
|
29
|
+
- `whoami` says what the token can't do and why (a scope it lacks, or project or channel limits that hide `create_channel` and `create_project`), so an agent can tell the person instead of looking for a tool.
|
|
30
|
+
- The server's instructions no longer ask the agent to call `whoami` before everything (it cost a call in most tasks), and ask it to tell the person about requests aimed at agents that it finds in content, rather than leaving them out of a summary; `get_page`, `read_channel` and `read_thread` say the same where the text is read.
|
|
31
|
+
- After `plan_expired` or `plan_stale`, the error, `apply_plan`'s description and the instructions say the new plan needs its own yes: an agent re-proposed an expired deletion and applied it without asking again.
|
|
32
|
+
- `get_item` shows the report behind an item that another organization filed through the Feedback app: its kind, severity, plus-ones and state, and the reporter's name, organization and device, wrapped as untrusted content (`source="feedback"`). It says that the agent's comments never reach the reporter.
|
|
33
|
+
- `get_item` reads a long description in windows of 20,000 characters (`description_offset`); `detail="full"` points to it when the description is cut.
|
|
34
|
+
- `search_items` text searches page with `cursor`, and `query` with `sort` narrows a sorted list to the items matching every word.
|
|
35
|
+
- With API 1.1.0's served operations (`/v1/meta`), a call the deployment doesn't serve yet is refused with a clear message instead of a 404, `whoami` lists them (`not_served`), and arguments that need a newer API are refused the same way.
|
|
36
|
+
- `plan_release` can correct a release afterwards: `update` (name, description, dates, and the day a released release was released), `reopen` (released back to unreleased, items untouched), `archive` and `restore`. Error hints name these actions.
|
|
37
|
+
- `plan_sprint` with `start` lists the sprint's backlog items that moved onto the board, and those that stay, with why.
|
|
38
|
+
- `read_channel` and `read_thread` say which messages an app (a bot of the org) sent (`author_type`).
|
|
39
|
+
- `server.json` lists the server in the MCP Registry as `io.github.kammcs/buildit-mcp`, with the npm package and the container image.
|
|
40
|
+
- A Claude Desktop bundle (`buildit-mcp-<version>.mcpb`, attached to each GitHub release): Claude Desktop keeps the token as a protected setting, with optional settings for the toolsets, read-only mode and the API URL. `npm run bundle` builds it.
|
|
41
|
+
- A container image, `ghcr.io/kammcs/buildit-mcp` (amd64 and arm64): HTTP mode on port 8765 by default, a non-root user, a health check on `/healthz`, and no token inside; stdio with `BUILDIT_HTTP=false`.
|
|
42
|
+
- [deploy/](deploy/README.md): a Compose file that runs the image behind Caddy for TLS, with the allowed host set from one variable, a read-only filesystem and no capabilities; notes for Fly.io, Cloud Run and other proxies; a checklist.
|
|
43
|
+
- `GET /healthz` answers before the `Host` check, so container and platform probes that call it by `localhost` or the instance's address get `200`.
|
|
44
|
+
- Image layouts in page bodies and item descriptions: an image's title sets its width (10% to 100%), placement (left, center, right, wrap-left, wrap-right) and gap (``); tools that rewrite Markdown keep the titles as read, and a malformed one is refused (`image_layout_invalid`).
|
|
45
|
+
|
|
46
|
+
### Hardening
|
|
47
|
+
|
|
48
|
+
- Hardening: untrusted-content blocks carry a random id per result, and the closing tag repeats it; the agent is told a block ends only at its own closing tag.
|
|
49
|
+
- Hardening: untrusted-content marking is stronger against look-alike tags, and changes only text that could form a tag: Markdown that mentions the block's name comes back as written.
|
|
50
|
+
- Hardening: names that people write (people, the org, tokens, projects, channels, sprints, releases, statuses, types, labels, fields) are inside untrusted blocks in every tool's text, and capped at 64 characters for people and 60 for other names.
|
|
51
|
+
- Hardening: in HTTP mode, the configured toolsets are a ceiling; `X-Buildit-Toolsets` can only narrow them.
|
|
52
|
+
- Hardening: binding off loopback without `BUILDIT_ALLOWED_HOSTS` is refused unless `BUILDIT_ALLOW_ANY_HOST=true` (or `--allow-any-host`) is set.
|
|
53
|
+
- Hardening: path parameters that would change the API route are refused as `invalid_arguments` before any request is sent.
|
|
54
|
+
- Hardening: API error text is scrubbed of token-shaped strings, and error details come back inside an untrusted block.
|
|
55
|
+
- Hardening: a malformed resource URI is an invalid-params error rather than an internal error.
|
|
56
|
+
- Hardening: the API call log records the operation and its path template instead of the filled-in path.
|
|
57
|
+
|
|
58
|
+
### Transports
|
|
59
|
+
|
|
60
|
+
- **stdio** (the default): one person, with the token in `BUILDIT_TOKEN`.
|
|
61
|
+
- **Streamable HTTP** (`--http`): stateless; every request carries its own `Authorization: Bearer` token and nothing is kept afterwards. It binds to `127.0.0.1` by default, checks the `Host` and `Origin` headers (off loopback, `BUILDIT_ALLOWED_HOSTS` is required unless `BUILDIT_ALLOW_ANY_HOST` is set), lets `X-Buildit-Toolsets` narrow the configured toolsets per request, and answers `GET /healthz`.
|
|
62
|
+
|
|
63
|
+
### Protocol versions
|
|
64
|
+
|
|
65
|
+
Both transports serve MCP 2026-07-28 (stateless, with per-request `_meta`) and 2025-11-25 (the initialize handshake).
|
|
66
|
+
|
|
67
|
+
### Requirements
|
|
68
|
+
|
|
69
|
+
- Node.js 20 or newer (22 recommended).
|
|
70
|
+
- A buildIt.Social personal access token, from an org with agent access turned on.
|
|
71
|
+
|
|
72
|
+
[0.1.0]: https://github.com/kammcs/buildit-mcp/releases/tag/v0.1.0
|
package/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 Kamm Creative Solutions
|
|
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,319 @@
|
|
|
1
|
-
#
|
|
1
|
+
# buildit-mcp
|
|
2
2
|
|
|
3
|
-
|
|
3
|
+
An [MCP](https://modelcontextprotocol.io) server for [buildIt.Social](https://buildit.social). It lets AI agents (Claude Code, Claude Desktop, Cursor, VS Code and others) work with an org's projects, items, comments, pages and channels through buildIt.Social's agent API, with a personal access token.
|
|
4
|
+
|
|
5
|
+
It runs on your own machine (stdio) or as a stateless HTTP server for a team. It holds no secrets of its own: each person's token stays in their own client.
|
|
6
|
+
|
|
7
|
+
**Status:** 0.1.0, the first release, on npm as [`@kammcs/buildit-mcp`](https://www.npmjs.com/package/@kammcs/buildit-mcp). Built on the agent API's v1 contract: items and comments by default (15 tools), and planning, pages, chat, admin and destructive changes when you turn them on (40 tools in all).
|
|
8
|
+
|
|
9
|
+
- [How it works](docs/design.md)
|
|
10
|
+
- [Security policy](SECURITY.md)
|
|
11
|
+
- [Changelog](CHANGELOG.md)
|
|
12
|
+
- [Contributing (for people and agents)](CLAUDE.md)
|
|
13
|
+
|
|
14
|
+
## What you need
|
|
15
|
+
|
|
16
|
+
- Node.js 20 or newer (22 recommended).
|
|
17
|
+
- A buildIt.Social **personal access token**. An org admin first turns on agent access for the org (Settings → the org's name → Integrations → Agent access); then you can create a token for yourself in Settings → Agent tokens, choosing its scopes, an expiry, and optionally the projects and channels it may reach. Tokens start with `buildit_pat_`.
|
|
18
|
+
|
|
19
|
+
**Keep the token out of files.** Put it in an environment variable (`BUILDIT_TOKEN`) in your user environment or shell profile, and reference that variable from your client's configuration. Never paste it into a config file, especially one in a repository.
|
|
20
|
+
|
|
21
|
+
## Install
|
|
22
|
+
|
|
23
|
+
Nothing to install by hand: clients start the server with `npx`, which downloads it on first use.
|
|
24
|
+
|
|
25
|
+
```sh
|
|
26
|
+
npx -y @kammcs/buildit-mcp@0 --help
|
|
27
|
+
```
|
|
28
|
+
|
|
29
|
+
- **Versions:** `@0` follows the 0.x releases, so you get fixes and new tools as they ship; `@0.1.0` pins one release. The server tells you when the API needs a newer one ([Versions](#versions)).
|
|
30
|
+
- **Windows:** if a client can't start `npx` (an `ENOENT` or "command not found" error), use `cmd` as the command, with `/c`, `npx`, `-y` and `@kammcs/buildit-mcp@0` as its arguments.
|
|
31
|
+
- Also available as a [container image](#container-image) and, for Claude Desktop, as a [bundle](#claude-desktop).
|
|
32
|
+
|
|
33
|
+
### From a clone (contributors)
|
|
34
|
+
|
|
35
|
+
```sh
|
|
36
|
+
git clone https://github.com/kammcs/buildit-mcp.git
|
|
37
|
+
cd buildit-mcp
|
|
38
|
+
npm ci
|
|
39
|
+
npm run build
|
|
40
|
+
```
|
|
41
|
+
|
|
42
|
+
The server is then `node /path/to/buildit-mcp/dist/index.js`: use that command and argument in place of `npx -y @kammcs/buildit-mcp@0` in the examples below.
|
|
43
|
+
|
|
44
|
+
## Configuration
|
|
45
|
+
|
|
46
|
+
Every setting is an environment variable, and also a flag (the flag wins). The token is the exception: it is only ever read from the environment, because other processes can see flags.
|
|
47
|
+
|
|
48
|
+
| Variable | Flag | Default | Meaning |
|
|
49
|
+
| ------------------------- | ------------------- | --------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
|
|
50
|
+
| `BUILDIT_TOKEN` | none | | Your personal access token (stdio mode). Ignored in HTTP mode, where each request carries its own. |
|
|
51
|
+
| `BUILDIT_API_URL` | `--api-url` | `https://api.buildit.social/functions/v1/agent-api` | The agent API. Must be `https://` (plain `http://` only for localhost). |
|
|
52
|
+
| `BUILDIT_TOOLSETS` | `--toolsets` | `items,comments` | Comma-separated toolsets, or `all`. Known: `items`, `comments`, `planning`, `pages`, `chat`, `admin`, `destructive`. |
|
|
53
|
+
| `BUILDIT_READ_ONLY` | `--read-only` | `false` | List only tools that change nothing. |
|
|
54
|
+
| `BUILDIT_EXCLUDE_TOOLS` | `--exclude-tools` | | Comma-separated tool names to hide. |
|
|
55
|
+
| `BUILDIT_LOG_LEVEL` | `--log-level` | `info` | `debug`, `info`, `warn` or `error`. Logs are JSON lines on stderr and never contain tokens or content. |
|
|
56
|
+
| `BUILDIT_HTTP` | `--http` | `false` | Serve Streamable HTTP instead of stdio. |
|
|
57
|
+
| `BUILDIT_HOST` | `--host` | `127.0.0.1` | HTTP bind address. |
|
|
58
|
+
| `BUILDIT_PORT` | `--port` | `8765` | HTTP port. |
|
|
59
|
+
| `BUILDIT_ALLOWED_HOSTS` | `--allowed-hosts` | localhost names on a loopback bind | Hostnames accepted in the `Host` header (DNS-rebinding protection). Required when binding off loopback, unless `BUILDIT_ALLOW_ANY_HOST` is set. |
|
|
60
|
+
| `BUILDIT_ALLOWED_ORIGINS` | `--allowed-origins` | localhost names on a loopback bind | Hostnames accepted in the `Origin` header. Off loopback, requests with any other `Origin` are refused. `moz-extension://*`-style entries admit a browser extension. |
|
|
61
|
+
| `BUILDIT_ALLOW_ANY_HOST` | `--allow-any-host` | `false` | Off loopback, serve without checking the `Host` header (for example behind a proxy that checks it). Without it, such a bind needs `BUILDIT_ALLOWED_HOSTS`. |
|
|
62
|
+
|
|
63
|
+
The tools you see depend on the enabled toolsets, read-only mode, the exclude list, and your token's scopes: a token with only `projects:read` never sees write tools, and a token limited to some projects or channels doesn't see `create_channel` and `create_project`. If buildIt.Social refuses the token, only `whoami` is listed, so the agent can tell you why. If the scopes can't be read for a moment (a rate limit, the network), every tool your configuration allows is listed and buildIt.Social checks each call; the scopes are read again on the next list.
|
|
64
|
+
|
|
65
|
+
### Toolsets
|
|
66
|
+
|
|
67
|
+
`items` and `comments` are on by default (15 tools). Turn others on with `BUILDIT_TOOLSETS` (or `--toolsets`), for example `BUILDIT_TOOLSETS=items,comments,planning,pages` or `BUILDIT_TOOLSETS=all` (40 tools). In HTTP mode, the `X-Buildit-Toolsets` header picks them per request, among the ones the server enables: it can narrow them, never add one.
|
|
68
|
+
|
|
69
|
+
**`admin` and `destructive` stay off unless you name them**, even when your token has `projects:admin` or `projects:delete`. Turn them on only for work that needs them, for example a separate client entry with `BUILDIT_TOOLSETS=items,admin` while you reorganize a workflow. Their changes always go through preview and confirm (below), except creating a channel or a project, which changes nothing that exists.
|
|
70
|
+
|
|
71
|
+
### Tools
|
|
72
|
+
|
|
73
|
+
| Toolset | Tool | Scope | Annotations | Does |
|
|
74
|
+
| ------------------------- | -------------------------- | ----------------------------------- | ----------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ |
|
|
75
|
+
| `items` (on) | `whoami` | none | read-only | Who the token acts as: the user, the org, the token's name, expiry, scopes and limits, what it can't do, the projects in reach and the rate limits. |
|
|
76
|
+
| | `list_projects` | `projects:read` | read-only | The projects in reach, with keys, settings and item counts. Paged. |
|
|
77
|
+
| | `describe_project` | `projects:read` | read-only | A project's types, workflows (statuses, allowed moves and the fields they need), labels, custom fields, estimates and members. |
|
|
78
|
+
| | `find_users` | `projects:read` | read-only | A project's members matching part of a name or email, or "me", for assigning and mentions. Paged. |
|
|
79
|
+
| | `search_items` | `projects:read` | read-only | Items by filters (project, type, status, category, priority, assignee, label, sprint, release, parent, updated since) and text (best first, or narrowing a sort); sorted, paged, `detail`. |
|
|
80
|
+
| | `get_item` | `projects:read` | read-only | One item: fields, description (long ones in windows), custom fields, children, links, latest comments, a Feedback report and, optionally, history and GitHub refs; the versions an update needs. |
|
|
81
|
+
| | `create_item` | `projects:write` | | An epic, story, task, bug or subtask, under a parent or in a project, at a position; safe to retry with its idempotency key. |
|
|
82
|
+
| | `update_item` | `projects:write` | idempotent | A field patch; the description appended to (safe) or replaced (with its version); `if_version` guards against concurrent edits. |
|
|
83
|
+
| | `assign_item` | `projects:write` | idempotent | Assign to a person (`me`, an email or a name) or unassign. |
|
|
84
|
+
| | `transition_item` | `projects:write` | idempotent | Move to a status by name, setting the fields the move needs and posting a comment; a refused move lists the moves allowed from where the item is. |
|
|
85
|
+
| | `link_items` | `projects:write` | idempotent | Add a link: blocks, blocked by, relates, duplicates, duplicated by. |
|
|
86
|
+
| | `unlink_items` | `projects:write` | destructive, idempotent | Remove a link, by kind and target or by its id. |
|
|
87
|
+
| | `rank_item` | `projects:write` | idempotent | Move an item before or after another in its project's order. |
|
|
88
|
+
| `comments` (on) | `list_comments` | `projects:read` | read-only | An item's comments, oldest or newest first, paged. |
|
|
89
|
+
| | `add_comment` | `projects:write` | | A plain-text comment with `@email` or `@[Display Name]` mentions; safe to retry with its idempotency key. |
|
|
90
|
+
| `planning` | `list_sprints` | `projects:read` | read-only | A project's sprints, newest first, with goals, dates and item counts. Paged. |
|
|
91
|
+
| | `plan_sprint` | `projects:write` | | Create, start (moving backlog items onto the board) or complete a sprint (carrying open items on), or add and remove up to 50 items. |
|
|
92
|
+
| | `list_releases` | `projects:read` | read-only | A project's releases (fix versions), with status, dates, notes page and item counts. Paged. |
|
|
93
|
+
| | `plan_release` | `projects:write` | | Create, release, edit, reopen, archive or restore a release (releasing moves open items on), or add and remove up to 50 items. |
|
|
94
|
+
| | `write_release_notes` | `projects:write`, `pages:write` | destructive, idempotent | Write a release's notes page and show it; a page people edited is replaced only with the version they confirmed. |
|
|
95
|
+
| `pages` | `list_pages` | `pages:read` | read-only | A channel's pages: titles, tree and versions, without bodies. Paged. |
|
|
96
|
+
| | `get_page` | `pages:read` | read-only | One page's Markdown and version; long pages in windows (`offset`). |
|
|
97
|
+
| | `create_page` | `pages:write` | | A Markdown page in a channel, optionally under a parent; safe to retry with its idempotency key. |
|
|
98
|
+
| | `update_page` | `pages:write` | destructive, idempotent | A new title, body (replaced whole), parent or position, with the version read; a conflict says how to reapply. |
|
|
99
|
+
| `chat` | `list_channels` | `chat:read` | read-only, open-world | The channels you belong to (never direct messages). Paged. |
|
|
100
|
+
| | `read_channel` | `chat:read` | read-only, open-world | A channel's messages, newest first, optionally `since` a time; says which come from an app (a bot of the org). Paged. |
|
|
101
|
+
| | `read_thread` | `chat:read` | read-only, open-world | A message and its replies, oldest first. Paged. |
|
|
102
|
+
| `admin` (off) | `create_channel` | `projects:admin` | | A public or private channel, with members; safe to retry with its idempotency key. Needs a token without project or channel limits. |
|
|
103
|
+
| | `create_project` | `projects:admin` | | Turn a channel into a project from a template, with its key (named after the channel); safe to retry. Needs a token without limits and Projects. |
|
|
104
|
+
| | `get_workflow` | `projects:admin` | read-only | A workflow's statuses, moves and whole definition, to edit and propose. |
|
|
105
|
+
| | `list_work_types` | `projects:admin` | read-only | The org's work types and the projects that use each. |
|
|
106
|
+
| | `propose_workflow_change` | `projects:admin` | | Preview a workflow change (statuses, moves, required fields, types); returns a plan handle. |
|
|
107
|
+
| | `propose_work_type_change` | `projects:admin` | | Preview creating, changing, archiving or restoring a work type. |
|
|
108
|
+
| | `propose_field_change` | `projects:admin` | | Preview creating, changing, archiving or restoring a custom field. |
|
|
109
|
+
| | `propose_label_change` | `projects:admin` | | Preview creating, renaming, recoloring or deleting a label. |
|
|
110
|
+
| `destructive` (off) | `propose_delete_item` | `projects:delete` | | Preview deleting an item and its children. |
|
|
111
|
+
| | `propose_move_item` | `projects:delete` | | Preview moving an item to another project. |
|
|
112
|
+
| | `propose_bulk_update` | `projects:delete` | | Preview one change to up to 50 items. |
|
|
113
|
+
| | `propose_archive_status` | `projects:delete`, `projects:admin` | | Preview archiving a status, moving its items to another. |
|
|
114
|
+
| with any `propose_*` tool | `apply_plan` | the plan's | destructive | Apply a plan the person confirmed. Listed whenever a `propose_*` tool is. |
|
|
115
|
+
|
|
116
|
+
No tool is open-world except the chat tools: the others only touch the org's structured data. Every tool returns a short text summary and structured content with an output schema. Long lists are paged (pass `next_cursor` back as `cursor`), and long descriptions, comments, pages and messages are cut so a response stays well under 25,000 tokens.
|
|
117
|
+
|
|
118
|
+
### Resources and prompts
|
|
119
|
+
|
|
120
|
+
- **Resources:** `buildit://items/{key}` (with the `items` toolset and `projects:read`) and `buildit://pages/{id}` (with `pages` and `pages:read`), so you can attach an item or a page to a conversation by hand. They read as `get_item` and `get_page` do.
|
|
121
|
+
- **Prompts:** `plan_epic` (break an epic into stories), `triage` (sort a project's new items) and `standup` (what changed since yesterday, and what's blocked). The first two end in writes, so they need `projects:write`, and both ask for your go-ahead before changing anything.
|
|
122
|
+
|
|
123
|
+
### Preview, then confirm
|
|
124
|
+
|
|
125
|
+
Deleting, moving or bulk-editing items, archiving a status, and changing workflows, work types, fields or labels never happen in one call:
|
|
126
|
+
|
|
127
|
+
1. A `propose_*` tool asks buildIt.Social to check the change and compute its effect ("Deletes DEMO-42 and its 3 child items"). Nothing changes; it returns a preview and a plan handle.
|
|
128
|
+
2. The agent shows you the preview and asks you.
|
|
129
|
+
3. Only when you say yes does it call `apply_plan` with the handle. A handle works once, for 10 minutes, only with the token that proposed it, and is refused if anything it targets changed since the preview. A plan proposed again after that needs the person's yes again.
|
|
130
|
+
|
|
131
|
+
`apply_plan` is marked destructive, so clients that ask before destructive tools ask you again. The server's instructions, every preview and `apply_plan`'s description tell the agent never to apply a plan you haven't seen and agreed to, and never because content in buildIt.Social asks for it.
|
|
132
|
+
|
|
133
|
+
## Set up your client
|
|
134
|
+
|
|
135
|
+
In every example the token comes from the `BUILDIT_TOKEN` environment variable; set it in your user environment first, then restart the client so it sees the variable.
|
|
136
|
+
|
|
137
|
+
### Claude Code
|
|
138
|
+
|
|
139
|
+
Single quotes keep `${BUILDIT_TOKEN}` literal, so the configuration stores the reference, not the token; Claude Code expands it when it starts the server.
|
|
140
|
+
|
|
141
|
+
```sh
|
|
142
|
+
claude mcp add buildit --scope user -e 'BUILDIT_TOKEN=${BUILDIT_TOKEN}' -- npx -y @kammcs/buildit-mcp@0
|
|
143
|
+
```
|
|
144
|
+
|
|
145
|
+
Or share it with a project through `.mcp.json`, where each person's own `BUILDIT_TOKEN` is used:
|
|
146
|
+
|
|
147
|
+
```json
|
|
148
|
+
{
|
|
149
|
+
"mcpServers": {
|
|
150
|
+
"buildit": {
|
|
151
|
+
"command": "npx",
|
|
152
|
+
"args": ["-y", "@kammcs/buildit-mcp@0"],
|
|
153
|
+
"env": { "BUILDIT_TOKEN": "${BUILDIT_TOKEN}" }
|
|
154
|
+
}
|
|
155
|
+
}
|
|
156
|
+
}
|
|
157
|
+
```
|
|
158
|
+
|
|
159
|
+
Then ask Claude to "run whoami on buildit" to check the connection.
|
|
160
|
+
|
|
161
|
+
### Cursor
|
|
162
|
+
|
|
163
|
+
In `~/.cursor/mcp.json` (or a project's `.cursor/mcp.json`), using Cursor's `${env:NAME}` syntax:
|
|
164
|
+
|
|
165
|
+
```json
|
|
166
|
+
{
|
|
167
|
+
"mcpServers": {
|
|
168
|
+
"buildit": {
|
|
169
|
+
"command": "npx",
|
|
170
|
+
"args": ["-y", "@kammcs/buildit-mcp@0"],
|
|
171
|
+
"env": { "BUILDIT_TOKEN": "${env:BUILDIT_TOKEN}" }
|
|
172
|
+
}
|
|
173
|
+
}
|
|
174
|
+
}
|
|
175
|
+
```
|
|
176
|
+
|
|
177
|
+
### VS Code
|
|
178
|
+
|
|
179
|
+
In `.vscode/mcp.json`. VS Code prompts for the token once and keeps it in its secret storage:
|
|
180
|
+
|
|
181
|
+
```json
|
|
182
|
+
{
|
|
183
|
+
"inputs": [
|
|
184
|
+
{
|
|
185
|
+
"type": "promptString",
|
|
186
|
+
"id": "buildit-token",
|
|
187
|
+
"description": "buildIt.Social personal access token",
|
|
188
|
+
"password": true
|
|
189
|
+
}
|
|
190
|
+
],
|
|
191
|
+
"servers": {
|
|
192
|
+
"buildit": {
|
|
193
|
+
"type": "stdio",
|
|
194
|
+
"command": "npx",
|
|
195
|
+
"args": ["-y", "@kammcs/buildit-mcp@0"],
|
|
196
|
+
"env": { "BUILDIT_TOKEN": "${input:buildit-token}" }
|
|
197
|
+
}
|
|
198
|
+
}
|
|
199
|
+
}
|
|
200
|
+
```
|
|
201
|
+
|
|
202
|
+
### Claude Desktop
|
|
203
|
+
|
|
204
|
+
Install the bundle: download `buildit-mcp-<version>.mcpb` from the [latest release](https://github.com/kammcs/buildit-mcp/releases/latest) and open it (or drag it onto Claude Desktop's Settings → Extensions). Claude Desktop asks for your personal access token and keeps it as a protected setting in your system's secure storage, never in a plain config file. The other settings (toolsets, read-only, the API URL) are optional; change them later in the extension's settings. Then ask Claude to call `whoami` to check the token.
|
|
205
|
+
|
|
206
|
+
To build the bundle from a clone: `npm run bundle`.
|
|
207
|
+
|
|
208
|
+
Without the bundle, don't put a token in `claude_desktop_config.json`: it doesn't expand environment variables, so the token would sit there in plain text. Instead, either:
|
|
209
|
+
|
|
210
|
+
- set `BUILDIT_TOKEN` in your user environment and add the server **without** an `env` entry, then restart Claude Desktop and call `whoami` to confirm the token reached the server (whether Claude Desktop passes its environment to servers is not documented, so check); or
|
|
211
|
+
- run the server in HTTP mode on your machine (below) and connect to it as a remote server.
|
|
212
|
+
|
|
213
|
+
```json
|
|
214
|
+
{
|
|
215
|
+
"mcpServers": {
|
|
216
|
+
"buildit": {
|
|
217
|
+
"command": "npx",
|
|
218
|
+
"args": ["-y", "@kammcs/buildit-mcp@0"]
|
|
219
|
+
}
|
|
220
|
+
}
|
|
221
|
+
}
|
|
222
|
+
```
|
|
223
|
+
|
|
224
|
+
## HTTP mode
|
|
225
|
+
|
|
226
|
+
```sh
|
|
227
|
+
npx -y @kammcs/buildit-mcp@0 --http # http://127.0.0.1:8765/mcp
|
|
228
|
+
```
|
|
229
|
+
|
|
230
|
+
- Every request must carry `Authorization: Bearer <token>`; the server uses that request's token for its API calls and keeps nothing afterwards. A token is required even on localhost.
|
|
231
|
+
- It binds to `127.0.0.1` and accepts only localhost `Host` and `Origin` headers, unless configured otherwise.
|
|
232
|
+
- It serves both MCP protocol versions in use: 2026-07-28 (stateless) and 2025-11-25.
|
|
233
|
+
- An `X-Buildit-Toolsets: items,comments` header picks the toolsets for one request, among the ones the server enables: the server's toolsets are a ceiling the header can only narrow. For example, a server started with `--toolsets items` lists no `propose_*` tool and no `apply_plan` for a request that asks for `destructive`. Read-only mode and the exclude list set on the server always apply.
|
|
234
|
+
- `GET /healthz` answers `200` for health checks.
|
|
235
|
+
|
|
236
|
+
For Claude Code:
|
|
237
|
+
|
|
238
|
+
```sh
|
|
239
|
+
claude mcp add buildit --transport http --header 'Authorization: Bearer ${BUILDIT_TOKEN}' http://127.0.0.1:8765/mcp
|
|
240
|
+
```
|
|
241
|
+
|
|
242
|
+
### Team mode
|
|
243
|
+
|
|
244
|
+
One server can serve a whole team: each member connects with the team URL and their own token, and the server forwards each request with that member's token. It holds no buildIt.Social secret and stores nothing, so it can run as several replicas behind any load balancer.
|
|
245
|
+
|
|
246
|
+
```sh
|
|
247
|
+
npx -y @kammcs/buildit-mcp@0 --http --host 0.0.0.0 --port 8765
|
|
248
|
+
# with BUILDIT_ALLOWED_HOSTS=mcp.example.com
|
|
249
|
+
```
|
|
250
|
+
|
|
251
|
+
Bound to anything but loopback, the server refuses to start without `BUILDIT_ALLOWED_HOSTS` (the hostnames clients use), so the `Host` header is always checked. If a proxy in front checks it instead, set `BUILDIT_ALLOW_ANY_HOST=true` (or pass `--allow-any-host`) to start anyway; the server then logs a warning.
|
|
252
|
+
|
|
253
|
+
### Container image
|
|
254
|
+
|
|
255
|
+
`ghcr.io/kammcs/buildit-mcp` runs the server in HTTP mode on port 8765, as a non-root user, with a health check on `/healthz`. Each release is tagged with its version (`0.1.0`) and its major version (`0`), for amd64 and arm64. No token is in the image: each request brings its own.
|
|
256
|
+
|
|
257
|
+
```sh
|
|
258
|
+
docker run -d -p 8765:8765 -e BUILDIT_ALLOWED_HOSTS=mcp.example.com ghcr.io/kammcs/buildit-mcp:0
|
|
259
|
+
```
|
|
260
|
+
|
|
261
|
+
Every setting under [Configuration](#configuration) works as an environment variable, for example `-e BUILDIT_TOOLSETS=items,comments,planning`. To build the image from a clone instead: `docker build -t buildit-mcp .`.
|
|
262
|
+
|
|
263
|
+
A client that starts the server itself can run the image over stdio. `-e BUILDIT_TOKEN` without a value passes the token from your environment, so it never appears in the command or the client's config:
|
|
264
|
+
|
|
265
|
+
```sh
|
|
266
|
+
docker run -i --rm -e BUILDIT_HTTP=false -e BUILDIT_TOKEN ghcr.io/kammcs/buildit-mcp:0
|
|
267
|
+
```
|
|
268
|
+
|
|
269
|
+
[deploy/](deploy/README.md) has a Compose file that runs it behind Caddy for TLS, notes for Fly.io, Cloud Run and other proxies, and a checklist. The essentials are under [Hardening](#hardening).
|
|
270
|
+
|
|
271
|
+
## Security notes
|
|
272
|
+
|
|
273
|
+
- **Tokens:** keep them in environment variables or your client's secret storage, never in files you commit. Give each token only the scopes it needs, limit it to the projects and channels the work needs, and choose a short expiry. If a token leaks, revoke it in buildIt.Social at once.
|
|
274
|
+
- **The agent acts as you.** Everything it does is done with your permissions and is labelled in buildIt.Social as done through your agent.
|
|
275
|
+
- **People-written content is marked.** Titles, descriptions, comments, pages and messages, the names of people, projects, channels and the like (and GitHub titles, branch names and authors) come back inside `<untrusted_content>` blocks, and the server tells the agent to treat them as data, never instructions. Each block carries a random id, repeated in its closing tag, and only that closing tag ends it. This reduces, but cannot remove, the risk of prompt injection, so prefer narrow scopes and review what an agent proposes.
|
|
276
|
+
- **Destructive and admin changes are previewed and need your confirmation** ([above](#preview-then-confirm)), and their toolsets are off unless you turn them on. Read the preview before you say yes: it is what will happen.
|
|
277
|
+
- **Chat is read only**, and never reaches direct messages.
|
|
278
|
+
- **Logs** are JSON on stderr and never contain tokens or content.
|
|
279
|
+
|
|
280
|
+
### Hardening
|
|
281
|
+
|
|
282
|
+
For an HTTP server that anyone other than you can reach:
|
|
283
|
+
|
|
284
|
+
- terminate TLS in front of it (a reverse proxy such as Caddy or nginx; [deploy/](deploy/README.md) has a Compose file with Caddy), and don't let the proxy buffer responses, which can be event streams;
|
|
285
|
+
- set `BUILDIT_ALLOWED_HOSTS` to the hostnames clients use (required off loopback, unless you set `BUILDIT_ALLOW_ANY_HOST` because the proxy checks the `Host` header), and `BUILDIT_ALLOWED_ORIGINS` only if a browser-based client needs it;
|
|
286
|
+
- enable only the toolsets the team needs with `BUILDIT_TOOLSETS`: a request's `X-Buildit-Toolsets` header can narrow them, never add one;
|
|
287
|
+
- optionally restrict client IP addresses at the proxy;
|
|
288
|
+
- have the proxy pass the client's `Host` header through (Caddy and nginx's `proxy_set_header Host $host` do): the server checks `Host` itself and ignores `X-Forwarded-*` headers, since it never uses the client's address, so there is no trusted-proxies setting;
|
|
289
|
+
- keep it updated: `whoami` says when the API needs a newer version ([Versions](#versions)).
|
|
290
|
+
|
|
291
|
+
## Versions
|
|
292
|
+
|
|
293
|
+
buildit-mcp follows [semantic versioning](https://semver.org), and every release is listed in [CHANGELOG.md](CHANGELOG.md). Before 1.0, a breaking change raises the minor version (0.1 to 0.2); from 1.0, the major.
|
|
294
|
+
|
|
295
|
+
- **Tool names are stable.** A released tool keeps its name, and changes to tools are additive: new tools, new optional arguments, new fields in results. Removing or renaming a tool, an argument or a result field is a breaking change.
|
|
296
|
+
- **Deprecation comes first.** A tool that is going away is kept for at least one minor version after it is deprecated, still working, with a note at the start of its description that says so and what to use instead, and an entry in the changelog.
|
|
297
|
+
- **The API says when to update.** buildIt.Social's agent API publishes the oldest buildit-mcp release it supports (`min_mcp_version`, from `GET /v1/meta`). When this server is older, `whoami` reports `update_required: true` and asks the agent to tell you to update, and in stdio mode the server also logs a warning when it starts. It doesn't stop working by itself: calls go on as far as the API accepts them.
|
|
298
|
+
- **The API says what it serves.** From API 1.1.0, `GET /v1/meta` also lists the operations the deployment serves. Once the server has read it (in stdio mode at startup, and whenever `whoami` runs), a call the deployment doesn't serve yet, such as a newer `plan_release` action, is refused with a clear message instead of reaching the API, `whoami` lists those operations (`not_served`), and arguments that need a newer API (such as `description_offset`) are refused the same way.
|
|
299
|
+
|
|
300
|
+
To update: `npx` with `@0` picks up the newest 0.x release when the client next starts the server (run `npx -y @kammcs/buildit-mcp@0 --version` to check); with a pinned version, change the pin. From a clone, pull and rebuild.
|
|
301
|
+
|
|
302
|
+
## Development
|
|
303
|
+
|
|
304
|
+
```sh
|
|
305
|
+
npm ci
|
|
306
|
+
npm run check # lint, format check, build, tests, the privacy guard over the packed package
|
|
307
|
+
npm run inspect # MCP Inspector smoke test against a fake API
|
|
308
|
+
npm run inspect:docker # the same, also against the container image (Docker Desktop)
|
|
309
|
+
npm run bundle # build the Claude Desktop bundle (.mcpb) and smoke-test it
|
|
310
|
+
npm run conformance # official MCP conformance suite, offline
|
|
311
|
+
npm run generate # regenerate src/api/generated/ from openapi/openapi.json
|
|
312
|
+
npm run privacy # check that no file holds private details (the tests run it too)
|
|
313
|
+
```
|
|
314
|
+
|
|
315
|
+
See [CLAUDE.md](CLAUDE.md) for the architecture and how to add a tool, and [docs/releasing.md](docs/releasing.md) for how a release ships. Tests never call a real buildIt.Social server. [evals/](evals/README.md) has realistic tasks a maintainer runs by hand with a real client against a test org.
|
|
316
|
+
|
|
317
|
+
## License
|
|
318
|
+
|
|
319
|
+
MIT. See [LICENSE](LICENSE).
|
package/SECURITY.md
ADDED
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
# Security policy
|
|
2
|
+
|
|
3
|
+
## Reporting a vulnerability
|
|
4
|
+
|
|
5
|
+
Please report security problems privately, by email to **security@buildit.social**, not in a public issue or pull request.
|
|
6
|
+
|
|
7
|
+
Include what you can of:
|
|
8
|
+
|
|
9
|
+
- what the problem is and what an attacker could do with it;
|
|
10
|
+
- the version or commit of `buildit-mcp`, and the transport (stdio or HTTP);
|
|
11
|
+
- steps to reproduce, or a proof of concept;
|
|
12
|
+
- whether you have shared it with anyone else.
|
|
13
|
+
|
|
14
|
+
**Never send a real token, even an expired one.** If a report needs one, describe it instead (for example "a token with only `projects:read`").
|
|
15
|
+
|
|
16
|
+
We aim to acknowledge reports within three working days and to keep you informed until the problem is fixed. We are glad to credit reporters who want to be credited.
|
|
17
|
+
|
|
18
|
+
## Scope
|
|
19
|
+
|
|
20
|
+
In scope:
|
|
21
|
+
|
|
22
|
+
- this server's code: its transports, authentication handling, Host and Origin checks, logging, untrusted-content marking and error handling;
|
|
23
|
+
- the way it handles tokens (for example a token appearing in logs, errors, or a request to the wrong host).
|
|
24
|
+
|
|
25
|
+
Out of scope here, but welcome at the same address:
|
|
26
|
+
|
|
27
|
+
- the buildIt.Social apps and the agent API itself.
|
|
28
|
+
|
|
29
|
+
Not vulnerabilities on their own:
|
|
30
|
+
|
|
31
|
+
- a model following instructions planted in buildIt.Social content. The `<untrusted_content>` marking is a best-effort signal, not a boundary (see [docs/design.md](docs/design.md#untrusted-content)); a way to break out of the marking itself is in scope;
|
|
32
|
+
- issues that need a token the attacker already controls to act only within that token's own permissions.
|
|
33
|
+
|
|
34
|
+
## Supported versions
|
|
35
|
+
|
|
36
|
+
Security fixes go into the latest minor release on npm, as a patch release, and are listed in [CHANGELOG.md](CHANGELOG.md).
|
|
37
|
+
|
|
38
|
+
| Version | Supported |
|
|
39
|
+
| ----------------------------------------------- | --------- |
|
|
40
|
+
| The latest minor release (0.1.x, the first one) | Yes |
|
|
41
|
+
| Older minor releases | No |
|
|
42
|
+
| Unreleased commits on `main` | No |
|
|
43
|
+
|
|
44
|
+
To get a fix, update to the latest release. See [Versions](README.md#versions) for the versioning policy.
|
|
45
|
+
|
|
46
|
+
## If a token leaks
|
|
47
|
+
|
|
48
|
+
Revoke it in buildIt.Social at once (the token's owner or an org admin can), then create a new one. Tokens start with `buildit_pat_`, so secret scanners can find them; this repository's gitleaks configuration includes a rule for them.
|