band-mcp-server 1.0.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.
- checksums.yaml +7 -0
- data/API_DISCREPANCIES.md +119 -0
- data/CHANGELOG.md +12 -0
- data/LICENSE +674 -0
- data/README.md +192 -0
- data/exe/band-mcp-server +6 -0
- data/lib/band_mcp/client.rb +103 -0
- data/lib/band_mcp/config.rb +40 -0
- data/lib/band_mcp/error.rb +28 -0
- data/lib/band_mcp/tools/check_permissions.rb +56 -0
- data/lib/band_mcp/tools/create_comment.rb +44 -0
- data/lib/band_mcp/tools/create_post.rb +43 -0
- data/lib/band_mcp/tools/get_post.rb +40 -0
- data/lib/band_mcp/tools/helpers.rb +103 -0
- data/lib/band_mcp/tools/list_bands.rb +31 -0
- data/lib/band_mcp/tools/list_comments.rb +69 -0
- data/lib/band_mcp/tools/list_posts.rb +41 -0
- data/lib/band_mcp/tools/ping.rb +21 -0
- data/lib/band_mcp/tools/remove_comment.rb +46 -0
- data/lib/band_mcp/tools/remove_post.rb +42 -0
- data/lib/band_mcp/version.rb +7 -0
- data/lib/band_mcp.rb +39 -0
- metadata +95 -0
checksums.yaml
ADDED
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
---
|
|
2
|
+
SHA256:
|
|
3
|
+
metadata.gz: 92d5b0a1a544030076c6acdb2033c098849fe94c9f040d5dc24f2a1530f4c14c
|
|
4
|
+
data.tar.gz: ba627213dd57c1036dbda49815552e96ce7b182c1a8c6efec86fc57c06955b4c
|
|
5
|
+
SHA512:
|
|
6
|
+
metadata.gz: cae177a91d106006f43c94b8e9adceaafb6940351d105ab7188d1e5ecc54ac9dba5e2e6876a5df28e94f84d46bf64cd4a75613ea33714f69b960b8883a67435f
|
|
7
|
+
data.tar.gz: ae8e01b5f488591b6f1aacfec1ba03772b34585715f1417356c05cb32e67eb316c63ed05c3a7a6f29c875451ebabd1a2673a23928041427dee6c66bfa55c1a77
|
|
@@ -0,0 +1,119 @@
|
|
|
1
|
+
# BAND API discrepancies
|
|
2
|
+
|
|
3
|
+
Places where the live BAND Open API did not match [its documentation](https://developers.band.us/develop/guide/api),
|
|
4
|
+
or where the docs say nothing and we found out the hard way. Everything here was observed through this server against
|
|
5
|
+
the real API unless an entry says otherwise. The PR numbers point to the discussion and the live checks.
|
|
6
|
+
|
|
7
|
+
When you find another difference, add it here in the same commit as the code that works around it.
|
|
8
|
+
|
|
9
|
+
## Where the docs and the API disagree
|
|
10
|
+
|
|
11
|
+
### Authentication goes in a header, not a parameter
|
|
12
|
+
|
|
13
|
+
- **Docs**: every endpoint lists `access_token` as a request parameter.
|
|
14
|
+
- **Live**: `Authorization: Bearer <token>` works on every endpoint we use.
|
|
15
|
+
- **We do**: send the header, which keeps the token out of URLs and logs. (#3)
|
|
16
|
+
|
|
17
|
+
### `next_params` hands back the access token
|
|
18
|
+
|
|
19
|
+
- **Docs**: paged responses return `next_params`, to be passed back as query parameters. The docs' own example
|
|
20
|
+
includes `access_token`.
|
|
21
|
+
- **Live**: it does, in plain text, next to the cursor.
|
|
22
|
+
- **We do**: pass on only the cursor, as `next_after`, from both paged tools (`list_posts` and `list_comments`). Each
|
|
23
|
+
has a spec asserting the token never appears in the output. (#4, #9)
|
|
24
|
+
|
|
25
|
+
### `get_posts` ignores `limit` and sends no `latest_comments`
|
|
26
|
+
|
|
27
|
+
- **Docs**: a `limit` parameter, and a `latest_comments` list on each post.
|
|
28
|
+
- **Live**: the page size is a fixed 20 whatever `limit` says, and `latest_comments` never appears.
|
|
29
|
+
- **We do**: offer neither. Use `list_comments` for a post's comments. (#4)
|
|
30
|
+
|
|
31
|
+
### Comment `sort` is not what the docs describe
|
|
32
|
+
|
|
33
|
+
- **Docs**: `+created_at` sorts by creation date and `-created_at` by last modification date; the default is creation
|
|
34
|
+
date.
|
|
35
|
+
- **Live**: with no `sort`, comments come oldest first. With `+created_at` or `-created_at`, both come newest first,
|
|
36
|
+
identical to each other.
|
|
37
|
+
- **We do**: `list_comments` offers a `newest_first` flag that sends `-created_at`, instead of two values that do the
|
|
38
|
+
same thing. (#9)
|
|
39
|
+
|
|
40
|
+
### The comments docs cite the posts endpoint for paging
|
|
41
|
+
|
|
42
|
+
- **Docs**: the paging example on the "Get Comments" page calls `https://openapi.band.us/v2/band/posts?...`. This is
|
|
43
|
+
a copy-paste slip in the docs, not something we saw the API do.
|
|
44
|
+
- **Live**: `/v2/band/post/comments` pages with the same cursor shape as posts, 20 comments a page when tested. A post with 45
|
|
45
|
+
comments came back as pages of 20, 20 and 5 in both orders, with no duplicates or gaps.
|
|
46
|
+
- **We do**: page that endpoint. (#9, and the paging runs of 2026-10-21 on Keith's Test Band: 45 comments, then 23 through the final tool)
|
|
47
|
+
|
|
48
|
+
### A comment cursor only works with the sort it came from
|
|
49
|
+
|
|
50
|
+
- **Docs**: say nothing about it. `next_params` carries the cursor, and everything needed to repeat the request.
|
|
51
|
+
- **Live**: a cursor from a `-created_at` listing, followed without the sort, returned 19 comments in ascending order
|
|
52
|
+
starting partway through the post. That skips comments and repeats others, with no error.
|
|
53
|
+
- **We do**: `list_comments` puts the order into the `next_after` it returns (`oldest:<cursor>` or `newest:<cursor>`)
|
|
54
|
+
and takes the order from `after`, so it cannot be mismatched. A bare cursor is refused.
|
|
55
|
+
|
|
56
|
+
### The permissions response shows two key names
|
|
57
|
+
|
|
58
|
+
- **Docs**: the field table names the result key `permissions`; the example response shows `permission`.
|
|
59
|
+
- **Live**: `permissions`, a list of the granted names. Only a band where all three were granted has been read, so
|
|
60
|
+
what BAND sends for partial or empty grants is not known (see "Not verified").
|
|
61
|
+
- **We do**: `check_permissions` reads only `permissions`. A response with just `permission` is reported as an
|
|
62
|
+
unexpected format instead of as everything denied. (#6)
|
|
63
|
+
|
|
64
|
+
## What the docs leave out
|
|
65
|
+
|
|
66
|
+
### Writes are rate limited ("Cool down time restriction")
|
|
67
|
+
|
|
68
|
+
- **Live**: some writes are refused with `result_code` 1003, "Cool down time restriction":
|
|
69
|
+
- `remove_post` a few seconds after `create_post`;
|
|
70
|
+
- `remove_comment` immediately after another `remove_comment`;
|
|
71
|
+
- `create_comment` two seconds after another `create_comment`. All 45 comments of a bulk run were refused once
|
|
72
|
+
this way, and each went through after a 30-second wait.
|
|
73
|
+
|
|
74
|
+
The `remove_post` retry worked about 90 seconds later; the `remove_comment` repeat was not retried. A 10-second gap
|
|
75
|
+
between `create_comment` calls was enough: 23 in a row were never refused. A 20-second gap was enough between
|
|
76
|
+
`create_post` and `create_comment`, and between `create_comment` and `remove_comment`. So for repeated
|
|
77
|
+
`create_comment` calls the window is between 2 and 10 seconds; for other pairs of writes it is unknown.
|
|
78
|
+
- **We do**: say so in the `remove_post`, `remove_comment` and `create_comment` descriptions, so a model waits and
|
|
79
|
+
retries instead of giving up. (#7, #11, and the live paging runs)
|
|
80
|
+
|
|
81
|
+
### A deleted post is an error, not an empty result
|
|
82
|
+
|
|
83
|
+
- **Live**: `get_post` on a removed post fails with `result_code` 1000, "Deleted or cannot be found".
|
|
84
|
+
- **We do**: `remove_post` tells the model, after a dropped connection, that this answer means the removal worked.
|
|
85
|
+
(#7)
|
|
86
|
+
|
|
87
|
+
### `comment_key` is only unique within a post
|
|
88
|
+
|
|
89
|
+
- **Docs**: call it the "Comment ID".
|
|
90
|
+
- **Live**: the same `comment_key` (the first comment's) turned up on three different posts.
|
|
91
|
+
- **We do**: every comment tool takes `post_key` as well, and `remove_comment`'s description says the key only means
|
|
92
|
+
something together with it. (#11)
|
|
93
|
+
|
|
94
|
+
### Creating a comment returns no key
|
|
95
|
+
|
|
96
|
+
- **Docs**: the response is just `{"message": "success"}`, and so it is.
|
|
97
|
+
- **Consequence**: there is no `comment_key` to hand back. Find the new comment with `list_comments`.
|
|
98
|
+
- **We do**: say so in the `create_comment` description and the README. (#10)
|
|
99
|
+
|
|
100
|
+
### `get_posts` requires a `locale`
|
|
101
|
+
|
|
102
|
+
- **Live**: the request fails without one.
|
|
103
|
+
- **We do**: `list_posts` defaults it to `en_US` and rejects an empty value. (#4)
|
|
104
|
+
|
|
105
|
+
### Endpoint versions differ
|
|
106
|
+
|
|
107
|
+
- `/v2/…`, `/v2.1/…` and `/v2.2/…` are mixed (for example `GET /v2.1/band/post` but `GET /v2/band/posts`, and
|
|
108
|
+
`POST /v2.2/band/post/create`). The client takes a full versioned path per call.
|
|
109
|
+
|
|
110
|
+
## Not verified
|
|
111
|
+
|
|
112
|
+
These come from the docs only. Do not rely on them without trying.
|
|
113
|
+
|
|
114
|
+
- **Permissions when none are granted**: we only saw bands where everything is granted. If BAND omits the list in that
|
|
115
|
+
case, `check_permissions` reports an error. (#6)
|
|
116
|
+
- **Authorship**: the docs say `contents_deletion` does not check who wrote a post or comment, and that
|
|
117
|
+
`remove_comment` only works on comments made through the same app. The test band has one member, so neither was
|
|
118
|
+
tried. The tools pass BAND's refusal on. (#7, #11)
|
|
119
|
+
- **Removing something already removed**: the one attempt hit the cool-down instead. (#11)
|
data/CHANGELOG.md
ADDED
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
# Changelog
|
|
2
|
+
|
|
3
|
+
## v1.0.0
|
|
4
|
+
|
|
5
|
+
First stable release.
|
|
6
|
+
|
|
7
|
+
- Serve ten tools over stdio for the BAND Open API: `ping`, `list_bands`, `create_post`, `get_post`, `list_posts`,
|
|
8
|
+
`check_permissions`, `remove_post`, `list_comments`, `create_comment` and `remove_comment`.
|
|
9
|
+
- Write tools report an uncertain outcome (dropped connection, or a 5xx that isn't BAND's own JSON) with advice on how
|
|
10
|
+
to check before retrying.
|
|
11
|
+
- Package as the `band-mcp-server` gem with a `band-mcp-server` executable.
|
|
12
|
+
- Read `BAND_ACCESS_TOKEN` from `~/.config/band-mcp-server/config` when it is not in the environment.
|