@cavuno/board 4.64.0 → 4.65.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 +26 -0
- package/dist/{_spec-D1Qg_Twd.d.mts → _spec-CIufstif.d.mts} +57 -1
- package/dist/{_spec-D1Qg_Twd.d.ts → _spec-CIufstif.d.ts} +57 -1
- package/dist/{blog-Dp2jAVVM.d.ts → blog-DuNJLfIh.d.ts} +1 -1
- package/dist/{blog-e0YbZBjg.d.mts → blog-teDJ9KaO.d.mts} +1 -1
- package/dist/{board-Cc3wbTKI.d.mts → board-DZNCHGgl.d.mts} +2 -2
- package/dist/{board-BeNZLOYC.d.ts → board-iCHYuNhr.d.ts} +2 -2
- package/dist/{breadcrumbs-C5WjB8jm.d.mts → breadcrumbs-Bt3oNIAx.d.mts} +2 -2
- package/dist/{breadcrumbs-BOFeIYEX.d.ts → breadcrumbs-DYGo0yB9.d.ts} +2 -2
- package/dist/browser/cavuno-board.global.min.js +1 -1
- package/dist/chunk-RDHHRDKN.mjs +6 -0
- package/dist/doctor.js +1 -1
- package/dist/filters.d.mts +2 -2
- package/dist/filters.d.ts +2 -2
- package/dist/format.d.mts +4 -4
- package/dist/format.d.ts +4 -4
- package/dist/index.d.mts +15 -14
- package/dist/index.d.ts +15 -14
- package/dist/index.js +1 -1
- package/dist/index.mjs +4 -4
- package/dist/{jobs-CClqlUld.d.mts → jobs-CbXbDBij.d.mts} +1 -1
- package/dist/{jobs-D04ngjCP.d.ts → jobs-DM_QMccX.d.ts} +1 -1
- package/dist/mcp.d.mts +52 -0
- package/dist/mcp.d.ts +52 -0
- package/dist/mcp.js +150 -0
- package/dist/mcp.mjs +128 -0
- package/dist/{search-DZeNdYN6.d.ts → search-B7x4qt9A.d.ts} +1 -1
- package/dist/{search-BtrwcLkc.d.mts → search-PrqcJMft.d.mts} +1 -1
- package/dist/{seo-DLoyZRTo.d.ts → seo-C1Br7ygq.d.ts} +1 -1
- package/dist/seo-files.d.mts +2 -2
- package/dist/seo-files.d.ts +2 -2
- package/dist/{seo-LfpgbdnO.d.mts → seo-ohehUCzN.d.mts} +1 -1
- package/dist/seo.d.mts +22 -7
- package/dist/seo.d.ts +22 -7
- package/dist/seo.js +12 -3
- package/dist/seo.mjs +12 -3
- package/dist/server.d.mts +6 -6
- package/dist/server.d.ts +6 -6
- package/dist/sitemap.d.mts +6 -6
- package/dist/sitemap.d.ts +6 -6
- package/dist/skills.js +1 -1
- package/dist/suggest.d.mts +2 -2
- package/dist/suggest.d.ts +2 -2
- package/package.json +13 -2
- package/skills/cavuno-board-mcp/SKILL.md +80 -0
- package/skills/cavuno-board-seo/BLOG.md +13 -8
- package/skills/manifest.json +8 -1
package/dist/seo.js
CHANGED
|
@@ -50,7 +50,8 @@ function createBlogArticleJsonLd({
|
|
|
50
50
|
post,
|
|
51
51
|
boardName,
|
|
52
52
|
permalink,
|
|
53
|
-
ogImageUrl
|
|
53
|
+
ogImageUrl,
|
|
54
|
+
authorProfileUrl
|
|
54
55
|
}) {
|
|
55
56
|
const article = {
|
|
56
57
|
"@context": "https://schema.org",
|
|
@@ -66,7 +67,12 @@ function createBlogArticleJsonLd({
|
|
|
66
67
|
if (image) article.image = image;
|
|
67
68
|
const author = post.authors[0];
|
|
68
69
|
if (author) {
|
|
69
|
-
article.author = {
|
|
70
|
+
article.author = authorProfileUrl ? {
|
|
71
|
+
"@type": "Person",
|
|
72
|
+
"@id": authorProfileId(authorProfileUrl),
|
|
73
|
+
name: author.name,
|
|
74
|
+
url: authorProfileUrl
|
|
75
|
+
} : {
|
|
70
76
|
"@type": "Person",
|
|
71
77
|
name: author.name,
|
|
72
78
|
...author.websiteUrl ? { url: author.websiteUrl } : {}
|
|
@@ -92,7 +98,7 @@ function createAuthorProfileJsonLd({
|
|
|
92
98
|
normalizeUrl(author.linkedinUrl),
|
|
93
99
|
normalizeUrl(author.githubUrl)
|
|
94
100
|
].filter((value) => Boolean(value));
|
|
95
|
-
const authorId =
|
|
101
|
+
const authorId = authorProfileId(canonical);
|
|
96
102
|
const hasPart = posts.slice(0, 5).map((post) => {
|
|
97
103
|
const postUrl = buildAbsoluteUrl(origin, `/blog/${post.slug}`);
|
|
98
104
|
if (!postUrl) {
|
|
@@ -134,6 +140,9 @@ function createAuthorProfileJsonLd({
|
|
|
134
140
|
}
|
|
135
141
|
return profilePage;
|
|
136
142
|
}
|
|
143
|
+
function authorProfileId(authorCanonical) {
|
|
144
|
+
return `${authorCanonical}#profile`;
|
|
145
|
+
}
|
|
137
146
|
function normalizeUrl(value) {
|
|
138
147
|
if (!value) {
|
|
139
148
|
return null;
|
package/dist/seo.mjs
CHANGED
|
@@ -28,7 +28,8 @@ function createBlogArticleJsonLd({
|
|
|
28
28
|
post,
|
|
29
29
|
boardName,
|
|
30
30
|
permalink,
|
|
31
|
-
ogImageUrl
|
|
31
|
+
ogImageUrl,
|
|
32
|
+
authorProfileUrl
|
|
32
33
|
}) {
|
|
33
34
|
const article = {
|
|
34
35
|
"@context": "https://schema.org",
|
|
@@ -44,7 +45,12 @@ function createBlogArticleJsonLd({
|
|
|
44
45
|
if (image) article.image = image;
|
|
45
46
|
const author = post.authors[0];
|
|
46
47
|
if (author) {
|
|
47
|
-
article.author = {
|
|
48
|
+
article.author = authorProfileUrl ? {
|
|
49
|
+
"@type": "Person",
|
|
50
|
+
"@id": authorProfileId(authorProfileUrl),
|
|
51
|
+
name: author.name,
|
|
52
|
+
url: authorProfileUrl
|
|
53
|
+
} : {
|
|
48
54
|
"@type": "Person",
|
|
49
55
|
name: author.name,
|
|
50
56
|
...author.websiteUrl ? { url: author.websiteUrl } : {}
|
|
@@ -70,7 +76,7 @@ function createAuthorProfileJsonLd({
|
|
|
70
76
|
normalizeUrl(author.linkedinUrl),
|
|
71
77
|
normalizeUrl(author.githubUrl)
|
|
72
78
|
].filter((value) => Boolean(value));
|
|
73
|
-
const authorId =
|
|
79
|
+
const authorId = authorProfileId(canonical);
|
|
74
80
|
const hasPart = posts.slice(0, 5).map((post) => {
|
|
75
81
|
const postUrl = buildAbsoluteUrl(origin, `/blog/${post.slug}`);
|
|
76
82
|
if (!postUrl) {
|
|
@@ -112,6 +118,9 @@ function createAuthorProfileJsonLd({
|
|
|
112
118
|
}
|
|
113
119
|
return profilePage;
|
|
114
120
|
}
|
|
121
|
+
function authorProfileId(authorCanonical) {
|
|
122
|
+
return `${authorCanonical}#profile`;
|
|
123
|
+
}
|
|
115
124
|
function normalizeUrl(value) {
|
|
116
125
|
if (!value) {
|
|
117
126
|
return null;
|
package/dist/server.d.mts
CHANGED
|
@@ -1,10 +1,10 @@
|
|
|
1
1
|
import { BoardSdk } from './index.mjs';
|
|
2
|
-
import './_spec-
|
|
3
|
-
import './search-
|
|
4
|
-
import './jobs-
|
|
5
|
-
import './board-
|
|
6
|
-
import './seo-
|
|
7
|
-
import './blog-
|
|
2
|
+
import './_spec-CIufstif.mjs';
|
|
3
|
+
import './search-PrqcJMft.mjs';
|
|
4
|
+
import './jobs-CbXbDBij.mjs';
|
|
5
|
+
import './board-DZNCHGgl.mjs';
|
|
6
|
+
import './seo-ohehUCzN.mjs';
|
|
7
|
+
import './blog-teDJ9KaO.mjs';
|
|
8
8
|
|
|
9
9
|
/**
|
|
10
10
|
* Session cookie codec — pure (no framework imports, no node imports) so it
|
package/dist/server.d.ts
CHANGED
|
@@ -1,10 +1,10 @@
|
|
|
1
1
|
import { BoardSdk } from './index.js';
|
|
2
|
-
import './_spec-
|
|
3
|
-
import './search-
|
|
4
|
-
import './jobs-
|
|
5
|
-
import './board-
|
|
6
|
-
import './seo-
|
|
7
|
-
import './blog-
|
|
2
|
+
import './_spec-CIufstif.js';
|
|
3
|
+
import './search-B7x4qt9A.js';
|
|
4
|
+
import './jobs-DM_QMccX.js';
|
|
5
|
+
import './board-iCHYuNhr.js';
|
|
6
|
+
import './seo-C1Br7ygq.js';
|
|
7
|
+
import './blog-DuNJLfIh.js';
|
|
8
8
|
|
|
9
9
|
/**
|
|
10
10
|
* Session cookie codec — pure (no framework imports, no node imports) so it
|
package/dist/sitemap.d.mts
CHANGED
|
@@ -1,10 +1,10 @@
|
|
|
1
1
|
import { BoardSdk } from './index.mjs';
|
|
2
|
-
import './_spec-
|
|
3
|
-
import './search-
|
|
4
|
-
import './jobs-
|
|
5
|
-
import './board-
|
|
6
|
-
import './seo-
|
|
7
|
-
import './blog-
|
|
2
|
+
import './_spec-CIufstif.mjs';
|
|
3
|
+
import './search-PrqcJMft.mjs';
|
|
4
|
+
import './jobs-CbXbDBij.mjs';
|
|
5
|
+
import './board-DZNCHGgl.mjs';
|
|
6
|
+
import './seo-ohehUCzN.mjs';
|
|
7
|
+
import './blog-teDJ9KaO.mjs';
|
|
8
8
|
|
|
9
9
|
/**
|
|
10
10
|
* Sitemap primitives — the pure XML + bucket-filename logic behind a board
|
package/dist/sitemap.d.ts
CHANGED
|
@@ -1,10 +1,10 @@
|
|
|
1
1
|
import { BoardSdk } from './index.js';
|
|
2
|
-
import './_spec-
|
|
3
|
-
import './search-
|
|
4
|
-
import './jobs-
|
|
5
|
-
import './board-
|
|
6
|
-
import './seo-
|
|
7
|
-
import './blog-
|
|
2
|
+
import './_spec-CIufstif.js';
|
|
3
|
+
import './search-B7x4qt9A.js';
|
|
4
|
+
import './jobs-DM_QMccX.js';
|
|
5
|
+
import './board-iCHYuNhr.js';
|
|
6
|
+
import './seo-C1Br7ygq.js';
|
|
7
|
+
import './blog-DuNJLfIh.js';
|
|
8
8
|
|
|
9
9
|
/**
|
|
10
10
|
* Sitemap primitives — the pure XML + bucket-filename logic behind a board
|
package/dist/skills.js
CHANGED
|
@@ -27,7 +27,7 @@ __export(skills_exports, {
|
|
|
27
27
|
});
|
|
28
28
|
module.exports = __toCommonJS(skills_exports);
|
|
29
29
|
|
|
30
|
-
// node_modules/.pnpm/tsup@8.5.1_postcss@8.5.
|
|
30
|
+
// node_modules/.pnpm/tsup@8.5.1_postcss@8.5.32_tsx@4.23.1_typescript@5.9.3/node_modules/tsup/assets/cjs_shims.js
|
|
31
31
|
var getImportMetaUrl = () => typeof document === "undefined" ? new URL(`file:${__filename}`).href : document.currentScript && document.currentScript.tagName.toUpperCase() === "SCRIPT" ? document.currentScript.src : new URL("main.js", document.baseURI).href;
|
|
32
32
|
var importMetaUrl = /* @__PURE__ */ getImportMetaUrl();
|
|
33
33
|
|
package/dist/suggest.d.mts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import { h as SuggestionItem, b as SearchSuggestQuery, F as FetchOptions, g as SuggestResult } from './search-
|
|
2
|
-
import './_spec-
|
|
1
|
+
import { h as SuggestionItem, b as SearchSuggestQuery, F as FetchOptions, g as SuggestResult } from './search-PrqcJMft.mjs';
|
|
2
|
+
import './_spec-CIufstif.mjs';
|
|
3
3
|
|
|
4
4
|
/**
|
|
5
5
|
* `@cavuno/board/suggest` — framework-agnostic headless search-suggest
|
package/dist/suggest.d.ts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import { h as SuggestionItem, b as SearchSuggestQuery, F as FetchOptions, g as SuggestResult } from './search-
|
|
2
|
-
import './_spec-
|
|
1
|
+
import { h as SuggestionItem, b as SearchSuggestQuery, F as FetchOptions, g as SuggestResult } from './search-B7x4qt9A.js';
|
|
2
|
+
import './_spec-CIufstif.js';
|
|
3
3
|
|
|
4
4
|
/**
|
|
5
5
|
* `@cavuno/board/suggest` — framework-agnostic headless search-suggest
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@cavuno/board",
|
|
3
|
-
"version": "4.
|
|
3
|
+
"version": "4.65.0",
|
|
4
4
|
"description": "Build custom job boards and careers pages with Cavuno’s TypeScript SDK.",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"api-client",
|
|
@@ -134,6 +134,16 @@
|
|
|
134
134
|
"default": "./dist/go.js"
|
|
135
135
|
}
|
|
136
136
|
},
|
|
137
|
+
"./mcp": {
|
|
138
|
+
"import": {
|
|
139
|
+
"types": "./dist/mcp.d.mts",
|
|
140
|
+
"default": "./dist/mcp.mjs"
|
|
141
|
+
},
|
|
142
|
+
"require": {
|
|
143
|
+
"types": "./dist/mcp.d.ts",
|
|
144
|
+
"default": "./dist/mcp.js"
|
|
145
|
+
}
|
|
146
|
+
},
|
|
137
147
|
"./route-contract": {
|
|
138
148
|
"import": {
|
|
139
149
|
"types": "./dist/route-contract.d.mts",
|
|
@@ -240,7 +250,8 @@
|
|
|
240
250
|
"publint": "^0.3.12",
|
|
241
251
|
"tsup": "^8.4.0",
|
|
242
252
|
"tsx": "^4.19.2",
|
|
243
|
-
"
|
|
253
|
+
"vite": "^8.3.6",
|
|
254
|
+
"vitest": "^5.1.0",
|
|
244
255
|
"typescript": "^5.9.3",
|
|
245
256
|
"@typescript/native-preview": "7.0.0-dev.20260707.2"
|
|
246
257
|
},
|
|
@@ -0,0 +1,80 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: cavuno-board-mcp
|
|
3
|
+
description: Serve the board's public MCP server at /mcp with @cavuno/board/mcp. Use when connecting a self-hosted board to Claude, ChatGPT, Cursor or another MCP client, or when /mcp or /mcp/docs returns 404 on the board's host.
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
# Board MCP server
|
|
7
|
+
|
|
8
|
+
Every paid Cavuno board has a public, read-only MCP server: AI assistants can
|
|
9
|
+
search its jobs, read job and company pages, and look up salaries. Boards that
|
|
10
|
+
Cavuno hosts serve it at `/mcp` on their own domain already. A self-hosted
|
|
11
|
+
board serves it by mounting `createMcpHandler` from `@cavuno/board/mcp`, which
|
|
12
|
+
forwards to the Board API, so the tools, limits and setup page match every
|
|
13
|
+
other Cavuno board.
|
|
14
|
+
|
|
15
|
+
## Mount the handler
|
|
16
|
+
|
|
17
|
+
Mount one handler at `/mcp`, `/mcp/*` and `/.well-known/ai-catalog.json`, for
|
|
18
|
+
GET, HEAD and POST. Pass
|
|
19
|
+
the board's publishable key: job and company links in tool results then point
|
|
20
|
+
at the key's own origin.
|
|
21
|
+
|
|
22
|
+
```ts snippet
|
|
23
|
+
import { createMcpHandler } from '@cavuno/board/mcp';
|
|
24
|
+
|
|
25
|
+
// app/mcp/[[...path]]/route.ts, and the same lines in
|
|
26
|
+
// app/.well-known/ai-catalog.json/route.ts
|
|
27
|
+
const handler = createMcpHandler({
|
|
28
|
+
board: process.env.NEXT_PUBLIC_CAVUNO_BOARD_KEY!,
|
|
29
|
+
});
|
|
30
|
+
export const GET = handler;
|
|
31
|
+
export const HEAD = handler;
|
|
32
|
+
export const POST = handler;
|
|
33
|
+
```
|
|
34
|
+
|
|
35
|
+
Other frameworks mount the same `(request: Request) => Promise<Response>`
|
|
36
|
+
function on each path. Do not add authentication, cookies or caching in front
|
|
37
|
+
of `/mcp`: every tool is an anonymous read, and MCP clients POST without
|
|
38
|
+
credentials.
|
|
39
|
+
|
|
40
|
+
## What each path answers
|
|
41
|
+
|
|
42
|
+
- `POST /mcp`: the stateless Streamable HTTP transport.
|
|
43
|
+
- `GET /mcp` from a browser: a redirect to `/mcp/docs`. Any other non-POST
|
|
44
|
+
request answers 405.
|
|
45
|
+
- `GET /mcp/docs`: an HTML page listing the tools and how to add the server
|
|
46
|
+
to each assistant. Use this URL as the documentation link in a Claude or
|
|
47
|
+
ChatGPT directory submission.
|
|
48
|
+
- `GET /mcp/server-card`: the MCP Server Card, the server's name, version,
|
|
49
|
+
title, icons and URL as `application/mcp-server-card+json`, for an
|
|
50
|
+
assistant to read before it connects.
|
|
51
|
+
- `GET /.well-known/ai-catalog.json`: the AI Catalog, which lists the Server
|
|
52
|
+
Card so an assistant that knows only the board's domain can find the server.
|
|
53
|
+
|
|
54
|
+
A free-plan board, a password-protected board, or a board whose operator has
|
|
55
|
+
switched the server off answers 404 on every path.
|
|
56
|
+
|
|
57
|
+
## Limits
|
|
58
|
+
|
|
59
|
+
The Board API allows 1,000 MCP requests a minute per visitor address. Requests
|
|
60
|
+
forwarded from a self-hosted server arrive from that server's address, so the
|
|
61
|
+
limit applies to the board's MCP traffic as a whole. Over the limit, `/mcp`
|
|
62
|
+
answers 429 with `Retry-After`.
|
|
63
|
+
|
|
64
|
+
## Completion gate
|
|
65
|
+
|
|
66
|
+
Finish only after every check passes against the deployed board:
|
|
67
|
+
|
|
68
|
+
- `POST /mcp` with `{"jsonrpc":"2.0","id":1,"method":"tools/list"}`,
|
|
69
|
+
`Content-Type: application/json` and
|
|
70
|
+
`Accept: application/json, text/event-stream` returns the tool list.
|
|
71
|
+
- Opening `/mcp` in a browser lands on `/mcp/docs`, and that page names the
|
|
72
|
+
board and shows `https://<board-host>/mcp` as the server URL.
|
|
73
|
+
- `GET /.well-known/ai-catalog.json` returns an entry whose `url` is
|
|
74
|
+
`https://<board-host>/mcp/server-card`, and that card's `remotes` URL is
|
|
75
|
+
`https://<board-host>/mcp`.
|
|
76
|
+
- A job URL in a `search_jobs` result opens on the board's own host.
|
|
77
|
+
|
|
78
|
+
## Cavuno SDK reference
|
|
79
|
+
|
|
80
|
+
For setup and API details beyond this workflow, use the [Cavuno Board SDK documentation](https://cavuno.com/docs/sdk).
|
|
@@ -10,17 +10,19 @@ import {
|
|
|
10
10
|
|
|
11
11
|
const { name } = await board.context();
|
|
12
12
|
const post = await board.blog.posts.retrieve('hello-world');
|
|
13
|
+
const [firstAuthor] = post.authors;
|
|
13
14
|
const article = createBlogArticleJsonLd({
|
|
14
15
|
post,
|
|
15
16
|
boardName: name,
|
|
16
17
|
permalink: `https://jobs.example.com/blog/${post.slug}`,
|
|
17
18
|
ogImageUrl: `https://jobs.example.com/blog/${post.slug}/og`,
|
|
19
|
+
authorProfileUrl: firstAuthor
|
|
20
|
+
? `https://jobs.example.com/blog/author/${firstAuthor.slug}`
|
|
21
|
+
: null,
|
|
18
22
|
});
|
|
19
23
|
|
|
20
24
|
const author = await board.blog.authors.retrieve('jane');
|
|
21
|
-
const
|
|
22
|
-
authorSlug: 'jane',
|
|
23
|
-
});
|
|
25
|
+
const authorPosts = await board.blog.posts.list({ authorSlug: 'jane' });
|
|
24
26
|
// Profile description is application-owned. Prefer author.bio; otherwise
|
|
25
27
|
// compose from the board catalog (shape only — not an English sentence).
|
|
26
28
|
const profile = createAuthorProfileJsonLd({
|
|
@@ -29,14 +31,17 @@ const profile = createAuthorProfileJsonLd({
|
|
|
29
31
|
description:
|
|
30
32
|
author.bio ?? messages.authorProfileDescription({ name: author.name }),
|
|
31
33
|
origin: 'https://jobs.example.com',
|
|
32
|
-
posts: authorPosts,
|
|
33
|
-
|
|
34
|
+
posts: authorPosts.data,
|
|
35
|
+
// The author's total, not this page's length.
|
|
36
|
+
totalPosts: authorPosts.count ?? authorPosts.data.length,
|
|
34
37
|
});
|
|
35
38
|
```
|
|
36
39
|
|
|
37
|
-
The article `ogImageUrl` is the fallback when the post has no cover.
|
|
38
|
-
|
|
39
|
-
`
|
|
40
|
+
The article `ogImageUrl` is the fallback when the post has no cover. Pass
|
|
41
|
+
`authorProfileUrl` as the same URL you give the profile's `canonical`, so the
|
|
42
|
+
post's author and the profile's `Person` share one `@id`. Supply author posts
|
|
43
|
+
newest-first; the profile builder keeps the first five as `hasPart`. The list's
|
|
44
|
+
`count` is the author's total published posts; `data` is one page.
|
|
40
45
|
|
|
41
46
|
This branch is complete when the post emits an `Article`, the author emits a
|
|
42
47
|
`ProfilePage`, every URL is absolute and canonical, and a null builder result
|
package/skills/manifest.json
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
{
|
|
2
|
-
"version": "4.
|
|
2
|
+
"version": "4.65.0",
|
|
3
3
|
"skills": [
|
|
4
4
|
{
|
|
5
5
|
"name": "cavuno-board-account",
|
|
@@ -92,6 +92,13 @@
|
|
|
92
92
|
"framework": null,
|
|
93
93
|
"category": "core"
|
|
94
94
|
},
|
|
95
|
+
{
|
|
96
|
+
"name": "cavuno-board-mcp",
|
|
97
|
+
"description": "Serve the board's public MCP server at /mcp with @cavuno/board/mcp. Use when connecting a self-hosted board to Claude, ChatGPT, Cursor or another MCP client, or when /mcp or /mcp/docs returns 404 on the board's host.",
|
|
98
|
+
"path": "skills/cavuno-board-mcp/SKILL.md",
|
|
99
|
+
"framework": null,
|
|
100
|
+
"category": "core"
|
|
101
|
+
},
|
|
95
102
|
{
|
|
96
103
|
"name": "cavuno-board-messaging",
|
|
97
104
|
"description": "Polled messaging contract with @cavuno/board. Use for inboxes, unread badges, threads, read receipts, message moderation, or user blocks.",
|