@caik.dev/mcp 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/README.md +110 -0
- package/dist/index.js +634 -0
- package/package.json +45 -0
package/README.md
ADDED
|
@@ -0,0 +1,110 @@
|
|
|
1
|
+
# @caik.dev/mcp
|
|
2
|
+
|
|
3
|
+
MCP (Model Context Protocol) server for the [CAIK](https://caik.dev) AI artifact registry. Enables Claude Code, Cursor, Windsurf, Codex, and other MCP-capable agents to search, install, and contribute to the collective knowledge base.
|
|
4
|
+
|
|
5
|
+
## Quick Start
|
|
6
|
+
|
|
7
|
+
Add to your agent's MCP configuration:
|
|
8
|
+
|
|
9
|
+
```json
|
|
10
|
+
{
|
|
11
|
+
"mcpServers": {
|
|
12
|
+
"caik": {
|
|
13
|
+
"command": "npx",
|
|
14
|
+
"args": ["-y", "caik-mcp-server"]
|
|
15
|
+
}
|
|
16
|
+
}
|
|
17
|
+
}
|
|
18
|
+
```
|
|
19
|
+
|
|
20
|
+
**Claude Code** (`~/.claude/settings.json`):
|
|
21
|
+
|
|
22
|
+
```json
|
|
23
|
+
{
|
|
24
|
+
"mcpServers": {
|
|
25
|
+
"caik": {
|
|
26
|
+
"command": "npx",
|
|
27
|
+
"args": ["-y", "caik-mcp-server"]
|
|
28
|
+
}
|
|
29
|
+
}
|
|
30
|
+
}
|
|
31
|
+
```
|
|
32
|
+
|
|
33
|
+
## Authentication
|
|
34
|
+
|
|
35
|
+
Some tools require authentication. Set up via the CLI:
|
|
36
|
+
|
|
37
|
+
```bash
|
|
38
|
+
npx @caik.dev/cli init
|
|
39
|
+
```
|
|
40
|
+
|
|
41
|
+
Or set the environment variable directly:
|
|
42
|
+
|
|
43
|
+
```bash
|
|
44
|
+
export CAIK_API_KEY=caik_...
|
|
45
|
+
```
|
|
46
|
+
|
|
47
|
+
The server reads credentials from `~/.caik/config.json` (written by `caik init`) or the `CAIK_API_KEY` / `CAIK_API_URL` environment variables.
|
|
48
|
+
|
|
49
|
+
## Tools
|
|
50
|
+
|
|
51
|
+
### Discovery
|
|
52
|
+
|
|
53
|
+
| Tool | Description | Auth |
|
|
54
|
+
|------|-------------|------|
|
|
55
|
+
| `search` | Search for AI agent skills, MCP servers, prompts, tools, and stacks | No |
|
|
56
|
+
| `get_artifact` | Get full details for an artifact by slug | No |
|
|
57
|
+
| `get_family` | Get all variants of an artifact family, ranked by platform relevance | No |
|
|
58
|
+
| `resolve_stack` | Resolve a stack into an ordered install sequence | No |
|
|
59
|
+
|
|
60
|
+
### Account & Stats
|
|
61
|
+
|
|
62
|
+
| Tool | Description | Auth |
|
|
63
|
+
|------|-------------|------|
|
|
64
|
+
| `get_account` | Get your account info, karma, and contribution level | Yes |
|
|
65
|
+
| `get_stats` | Get platform-wide statistics | No |
|
|
66
|
+
| `get_updates` | Check for available updates for an installation | Yes |
|
|
67
|
+
|
|
68
|
+
### Contribution
|
|
69
|
+
|
|
70
|
+
| Tool | Description | Auth |
|
|
71
|
+
|------|-------------|------|
|
|
72
|
+
| `report_outcome` | Report success/failure telemetry for an artifact | Yes |
|
|
73
|
+
| `submit_review` | Upvote or downvote an artifact | Yes |
|
|
74
|
+
|
|
75
|
+
### Bounties
|
|
76
|
+
|
|
77
|
+
| Tool | Description | Auth |
|
|
78
|
+
|------|-------------|------|
|
|
79
|
+
| `list_bounties` | List community bounties for requested artifacts | No |
|
|
80
|
+
| `claim_bounty` | Claim a bounty with your published artifact | Yes |
|
|
81
|
+
|
|
82
|
+
### Publishing
|
|
83
|
+
|
|
84
|
+
| Tool | Description | Auth |
|
|
85
|
+
|------|-------------|------|
|
|
86
|
+
| `submit_artifact` | Publish a new artifact to the registry | Yes |
|
|
87
|
+
| `list_my_artifacts` | List your published artifacts | Yes |
|
|
88
|
+
| `list_my_submissions` | Get submission pipeline summary | Yes |
|
|
89
|
+
|
|
90
|
+
## Resources
|
|
91
|
+
|
|
92
|
+
- `caik://artifact/{slug}` — Artifact detail as JSON
|
|
93
|
+
- `caik://stack/{slug}` — Resolved stack as JSON
|
|
94
|
+
|
|
95
|
+
## Prompt Templates
|
|
96
|
+
|
|
97
|
+
- `discover` — Find tools and skills for your platform
|
|
98
|
+
- `setup` — Set up a complete agent stack for a use case
|
|
99
|
+
- `contribute` — Publish a new or forked artifact
|
|
100
|
+
|
|
101
|
+
## Environment Variables
|
|
102
|
+
|
|
103
|
+
| Variable | Description | Default |
|
|
104
|
+
|----------|-------------|---------|
|
|
105
|
+
| `CAIK_API_KEY` | API key for authenticated requests | Read from `~/.caik/config.json` |
|
|
106
|
+
| `CAIK_API_URL` | API base URL | `https://caik.dev` |
|
|
107
|
+
|
|
108
|
+
## License
|
|
109
|
+
|
|
110
|
+
MIT
|
package/dist/index.js
ADDED
|
@@ -0,0 +1,634 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
|
|
3
|
+
// src/index.ts
|
|
4
|
+
import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
|
|
5
|
+
import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio.js";
|
|
6
|
+
|
|
7
|
+
// src/api.ts
|
|
8
|
+
import { McpError, ErrorCode } from "@modelcontextprotocol/sdk/types.js";
|
|
9
|
+
var CaikApiClient = class {
|
|
10
|
+
baseUrl;
|
|
11
|
+
apiKey;
|
|
12
|
+
constructor(config) {
|
|
13
|
+
this.baseUrl = config.apiUrl.replace(/\/+$/, "");
|
|
14
|
+
this.apiKey = config.apiKey;
|
|
15
|
+
}
|
|
16
|
+
hasApiKey() {
|
|
17
|
+
return !!this.apiKey;
|
|
18
|
+
}
|
|
19
|
+
requireAuth() {
|
|
20
|
+
if (!this.apiKey) {
|
|
21
|
+
throw new McpError(
|
|
22
|
+
ErrorCode.InvalidRequest,
|
|
23
|
+
"No API key configured. Run 'caik init' to set up authentication, or set CAIK_API_KEY environment variable."
|
|
24
|
+
);
|
|
25
|
+
}
|
|
26
|
+
}
|
|
27
|
+
async get(path, params) {
|
|
28
|
+
const url = new URL(`${this.baseUrl}/api/v1${path}`);
|
|
29
|
+
if (params) {
|
|
30
|
+
for (const [key, value] of Object.entries(params)) {
|
|
31
|
+
if (value === void 0) continue;
|
|
32
|
+
if (Array.isArray(value)) {
|
|
33
|
+
for (const v of value) url.searchParams.append(key, v);
|
|
34
|
+
} else {
|
|
35
|
+
url.searchParams.set(key, String(value));
|
|
36
|
+
}
|
|
37
|
+
}
|
|
38
|
+
}
|
|
39
|
+
return this.request(url.toString(), { method: "GET" });
|
|
40
|
+
}
|
|
41
|
+
async post(path, body) {
|
|
42
|
+
return this.request(`${this.baseUrl}/api/v1${path}`, {
|
|
43
|
+
method: "POST",
|
|
44
|
+
headers: { "Content-Type": "application/json" },
|
|
45
|
+
body: body !== void 0 ? JSON.stringify(body) : void 0
|
|
46
|
+
});
|
|
47
|
+
}
|
|
48
|
+
async request(url, init) {
|
|
49
|
+
const headers = {
|
|
50
|
+
...init.headers
|
|
51
|
+
};
|
|
52
|
+
if (this.apiKey) {
|
|
53
|
+
headers["Authorization"] = `Bearer ${this.apiKey}`;
|
|
54
|
+
}
|
|
55
|
+
let response;
|
|
56
|
+
try {
|
|
57
|
+
response = await fetch(url, { ...init, headers });
|
|
58
|
+
} catch (err) {
|
|
59
|
+
const msg = err instanceof Error ? err.message : String(err);
|
|
60
|
+
throw new McpError(
|
|
61
|
+
ErrorCode.InternalError,
|
|
62
|
+
`Could not connect to the CAIK API: ${msg}. Check CAIK_API_URL or ensure the server is running.`
|
|
63
|
+
);
|
|
64
|
+
}
|
|
65
|
+
if (!response.ok) {
|
|
66
|
+
return this.handleHttpError(response);
|
|
67
|
+
}
|
|
68
|
+
if (response.status === 204) {
|
|
69
|
+
return void 0;
|
|
70
|
+
}
|
|
71
|
+
return response.json();
|
|
72
|
+
}
|
|
73
|
+
async handleHttpError(response) {
|
|
74
|
+
let body;
|
|
75
|
+
try {
|
|
76
|
+
body = await response.json();
|
|
77
|
+
} catch {
|
|
78
|
+
body = await response.text().catch(() => null);
|
|
79
|
+
}
|
|
80
|
+
const message = typeof body === "object" && body !== null && "message" in body ? String(body.message) : `Request failed with status ${response.status}`;
|
|
81
|
+
switch (response.status) {
|
|
82
|
+
case 401:
|
|
83
|
+
throw new McpError(
|
|
84
|
+
ErrorCode.InvalidRequest,
|
|
85
|
+
`Authentication failed: ${message}. Run 'caik init' to set up authentication.`
|
|
86
|
+
);
|
|
87
|
+
case 403:
|
|
88
|
+
throw new McpError(
|
|
89
|
+
ErrorCode.InvalidRequest,
|
|
90
|
+
`Insufficient permissions: ${message}. Your account tier may not allow this action.`
|
|
91
|
+
);
|
|
92
|
+
case 404:
|
|
93
|
+
throw new McpError(
|
|
94
|
+
ErrorCode.InvalidRequest,
|
|
95
|
+
`Not found: ${message}. Try using the 'search' tool to find the correct artifact.`
|
|
96
|
+
);
|
|
97
|
+
case 400:
|
|
98
|
+
throw new McpError(
|
|
99
|
+
ErrorCode.InvalidParams,
|
|
100
|
+
`Invalid request: ${message}. Check your input parameters and try again.`
|
|
101
|
+
);
|
|
102
|
+
case 429:
|
|
103
|
+
throw new McpError(
|
|
104
|
+
ErrorCode.InternalError,
|
|
105
|
+
"Rate limited. Please wait a moment and try again (limit: 120 requests/min)."
|
|
106
|
+
);
|
|
107
|
+
default:
|
|
108
|
+
throw new McpError(
|
|
109
|
+
ErrorCode.InternalError,
|
|
110
|
+
`Server error (${response.status}): ${message}. The CAIK API may be temporarily unavailable.`
|
|
111
|
+
);
|
|
112
|
+
}
|
|
113
|
+
}
|
|
114
|
+
};
|
|
115
|
+
|
|
116
|
+
// src/config.ts
|
|
117
|
+
import { readFileSync, existsSync } from "fs";
|
|
118
|
+
import { join } from "path";
|
|
119
|
+
import { homedir } from "os";
|
|
120
|
+
var DEFAULT_API_URL = "https://caik.dev";
|
|
121
|
+
function getConfigPath() {
|
|
122
|
+
return join(homedir(), ".caik", "config.json");
|
|
123
|
+
}
|
|
124
|
+
function readConfig() {
|
|
125
|
+
const path = getConfigPath();
|
|
126
|
+
if (!existsSync(path)) {
|
|
127
|
+
return { apiUrl: DEFAULT_API_URL };
|
|
128
|
+
}
|
|
129
|
+
try {
|
|
130
|
+
const raw = readFileSync(path, "utf-8");
|
|
131
|
+
const parsed = JSON.parse(raw);
|
|
132
|
+
return { apiUrl: DEFAULT_API_URL, ...parsed };
|
|
133
|
+
} catch {
|
|
134
|
+
return { apiUrl: DEFAULT_API_URL };
|
|
135
|
+
}
|
|
136
|
+
}
|
|
137
|
+
function resolveConfig() {
|
|
138
|
+
const config = readConfig();
|
|
139
|
+
return {
|
|
140
|
+
apiUrl: process.env.CAIK_API_URL ?? config.apiUrl ?? DEFAULT_API_URL,
|
|
141
|
+
apiKey: process.env.CAIK_API_KEY ?? config.apiKey
|
|
142
|
+
};
|
|
143
|
+
}
|
|
144
|
+
|
|
145
|
+
// src/tools/discovery.ts
|
|
146
|
+
import { z } from "zod";
|
|
147
|
+
function registerDiscoveryTools(server, api) {
|
|
148
|
+
server.tool(
|
|
149
|
+
"search",
|
|
150
|
+
"Search the CAIK collective knowledge base for AI agent skills, MCP servers, prompts, tools, libraries, and stacks. Use this to discover artifacts by keyword, platform, or tag. Returns a ranked list with quality scores and install counts.",
|
|
151
|
+
{
|
|
152
|
+
query: z.string().describe("Search query (e.g., 'github code review', 'database MCP server')"),
|
|
153
|
+
platform: z.string().optional().describe("Filter by platform: 'claude-code', 'cursor', 'windsurf', 'codex', 'generic'"),
|
|
154
|
+
tags: z.array(z.string()).optional().describe("Filter by tags (e.g., ['productivity', 'git'])"),
|
|
155
|
+
limit: z.number().optional().describe("Max results to return (default 10, max 50)")
|
|
156
|
+
},
|
|
157
|
+
async ({ query, platform, tags, limit }) => {
|
|
158
|
+
const params = {
|
|
159
|
+
q: query,
|
|
160
|
+
platform,
|
|
161
|
+
tags,
|
|
162
|
+
limit: limit ?? 10
|
|
163
|
+
};
|
|
164
|
+
const result = await api.get("/artifacts/search", params);
|
|
165
|
+
return {
|
|
166
|
+
content: [
|
|
167
|
+
{
|
|
168
|
+
type: "text",
|
|
169
|
+
text: JSON.stringify(result, null, 2)
|
|
170
|
+
}
|
|
171
|
+
]
|
|
172
|
+
};
|
|
173
|
+
}
|
|
174
|
+
);
|
|
175
|
+
server.tool(
|
|
176
|
+
"get_artifact",
|
|
177
|
+
"Get full details for a specific CAIK artifact by its slug. Returns the complete artifact including manifest, install instructions, family info, quality scores, and content. Use after 'search' to get details on a specific result.",
|
|
178
|
+
{
|
|
179
|
+
slug: z.string().describe("Artifact slug (e.g., 'github-pr-review-skill')")
|
|
180
|
+
},
|
|
181
|
+
async ({ slug }) => {
|
|
182
|
+
const result = await api.get(`/artifacts/${encodeURIComponent(slug)}`);
|
|
183
|
+
return {
|
|
184
|
+
content: [
|
|
185
|
+
{
|
|
186
|
+
type: "text",
|
|
187
|
+
text: JSON.stringify(result, null, 2)
|
|
188
|
+
}
|
|
189
|
+
]
|
|
190
|
+
};
|
|
191
|
+
}
|
|
192
|
+
);
|
|
193
|
+
server.tool(
|
|
194
|
+
"get_family",
|
|
195
|
+
"Get all variants (forks) of an artifact family, ranked by relevance to your platform and co-installed artifacts. Use this to compare alternatives and pick the best variant for your setup.",
|
|
196
|
+
{
|
|
197
|
+
family_id: z.string().describe("Family ID (found in artifact detail's familyId field)"),
|
|
198
|
+
platform: z.string().optional().describe("Your platform for ranking relevance: 'claude-code', 'cursor', 'windsurf', 'codex', 'generic'"),
|
|
199
|
+
co_installs: z.array(z.string()).optional().describe("Slugs of artifacts you already have installed, for compatibility ranking")
|
|
200
|
+
},
|
|
201
|
+
async ({ family_id, platform, co_installs }) => {
|
|
202
|
+
const params = {
|
|
203
|
+
platform,
|
|
204
|
+
co_installs
|
|
205
|
+
};
|
|
206
|
+
const result = await api.get(`/artifacts/family/${encodeURIComponent(family_id)}`, params);
|
|
207
|
+
return {
|
|
208
|
+
content: [
|
|
209
|
+
{
|
|
210
|
+
type: "text",
|
|
211
|
+
text: JSON.stringify(result, null, 2)
|
|
212
|
+
}
|
|
213
|
+
]
|
|
214
|
+
};
|
|
215
|
+
}
|
|
216
|
+
);
|
|
217
|
+
server.tool(
|
|
218
|
+
"resolve_stack",
|
|
219
|
+
"Resolve a CAIK stack into its ordered list of artifacts with install sequence. Stacks are curated collections of artifacts that work well together. Returns the full dependency-ordered install list.",
|
|
220
|
+
{
|
|
221
|
+
slug: z.string().describe("Stack slug (e.g., 'full-stack-dev-claude')"),
|
|
222
|
+
platform: z.string().optional().describe("Target platform for resolution: 'claude-code', 'cursor', 'windsurf', 'codex', 'generic'")
|
|
223
|
+
},
|
|
224
|
+
async ({ slug, platform }) => {
|
|
225
|
+
const result = await api.get(`/stacks/${encodeURIComponent(slug)}/resolve`, { platform });
|
|
226
|
+
return {
|
|
227
|
+
content: [
|
|
228
|
+
{
|
|
229
|
+
type: "text",
|
|
230
|
+
text: JSON.stringify(result, null, 2)
|
|
231
|
+
}
|
|
232
|
+
]
|
|
233
|
+
};
|
|
234
|
+
}
|
|
235
|
+
);
|
|
236
|
+
}
|
|
237
|
+
|
|
238
|
+
// src/tools/account.ts
|
|
239
|
+
import { z as z2 } from "zod";
|
|
240
|
+
function registerAccountTools(server, api) {
|
|
241
|
+
server.tool(
|
|
242
|
+
"get_account",
|
|
243
|
+
"Get your CAIK account info including handle, tier, karma, contribution level, and install count. Requires authentication \u2014 run 'caik init' if you haven't set up your API key.",
|
|
244
|
+
{},
|
|
245
|
+
async () => {
|
|
246
|
+
api.requireAuth();
|
|
247
|
+
const result = await api.get("/me");
|
|
248
|
+
return {
|
|
249
|
+
content: [
|
|
250
|
+
{
|
|
251
|
+
type: "text",
|
|
252
|
+
text: JSON.stringify(result, null, 2)
|
|
253
|
+
}
|
|
254
|
+
]
|
|
255
|
+
};
|
|
256
|
+
}
|
|
257
|
+
);
|
|
258
|
+
server.tool(
|
|
259
|
+
"get_stats",
|
|
260
|
+
"Get CAIK platform statistics: total artifacts, breakdown by primitive type (skills, MCP servers, prompts, etc.), total installs, and active contributor count. No authentication required.",
|
|
261
|
+
{},
|
|
262
|
+
async () => {
|
|
263
|
+
const result = await api.get("/stats");
|
|
264
|
+
return {
|
|
265
|
+
content: [
|
|
266
|
+
{
|
|
267
|
+
type: "text",
|
|
268
|
+
text: JSON.stringify(result, null, 2)
|
|
269
|
+
}
|
|
270
|
+
]
|
|
271
|
+
};
|
|
272
|
+
}
|
|
273
|
+
);
|
|
274
|
+
server.tool(
|
|
275
|
+
"get_updates",
|
|
276
|
+
"Check for available updates for an installation. Returns recommended artifact swaps, new versions, and newly published artifacts matching your profile.",
|
|
277
|
+
{
|
|
278
|
+
installation_id: z2.string().describe("Installation ID to check for updates")
|
|
279
|
+
},
|
|
280
|
+
async ({ installation_id }) => {
|
|
281
|
+
api.requireAuth();
|
|
282
|
+
const result = await api.get(`/installations/${encodeURIComponent(installation_id)}/updates`);
|
|
283
|
+
return {
|
|
284
|
+
content: [
|
|
285
|
+
{
|
|
286
|
+
type: "text",
|
|
287
|
+
text: JSON.stringify(result, null, 2)
|
|
288
|
+
}
|
|
289
|
+
]
|
|
290
|
+
};
|
|
291
|
+
}
|
|
292
|
+
);
|
|
293
|
+
}
|
|
294
|
+
|
|
295
|
+
// src/tools/contribution.ts
|
|
296
|
+
import { z as z3 } from "zod";
|
|
297
|
+
function registerContributionTools(server, api) {
|
|
298
|
+
server.tool(
|
|
299
|
+
"report_outcome",
|
|
300
|
+
"Report the outcome of using a CAIK artifact (success/failure telemetry). This helps the community by contributing to quality scores. Fire-and-forget \u2014 does not block your workflow. Requires authentication.",
|
|
301
|
+
{
|
|
302
|
+
artifact_id: z3.string().describe("ID of the artifact that was used"),
|
|
303
|
+
success: z3.boolean().describe("Whether the artifact worked as expected"),
|
|
304
|
+
latency_ms: z3.number().optional().describe("Execution time in milliseconds (if applicable)"),
|
|
305
|
+
error_type: z3.string().optional().describe("Error category if failed (e.g., 'timeout', 'parse_error', 'runtime_error')")
|
|
306
|
+
},
|
|
307
|
+
async ({ artifact_id, success, latency_ms, error_type }) => {
|
|
308
|
+
api.requireAuth();
|
|
309
|
+
await api.post("/events", {
|
|
310
|
+
eventType: "outcome",
|
|
311
|
+
artifactId: artifact_id,
|
|
312
|
+
payload: { success, latencyMs: latency_ms, errorType: error_type }
|
|
313
|
+
});
|
|
314
|
+
return {
|
|
315
|
+
content: [
|
|
316
|
+
{
|
|
317
|
+
type: "text",
|
|
318
|
+
text: "Outcome reported successfully. Thank you for contributing to the CAIK quality scores!"
|
|
319
|
+
}
|
|
320
|
+
]
|
|
321
|
+
};
|
|
322
|
+
}
|
|
323
|
+
);
|
|
324
|
+
server.tool(
|
|
325
|
+
"submit_review",
|
|
326
|
+
"Submit a review (upvote or downvote) for a CAIK artifact. Helps the community evaluate artifact quality. Requires authentication with contributor+ tier. Returns karma earned for the review.",
|
|
327
|
+
{
|
|
328
|
+
artifact_slug: z3.string().describe("Slug of the artifact to review"),
|
|
329
|
+
vote: z3.enum(["up", "down"]).describe("Your vote: 'up' (helpful) or 'down' (unhelpful)"),
|
|
330
|
+
reason: z3.string().optional().describe("Brief explanation for your vote (recommended for downvotes)")
|
|
331
|
+
},
|
|
332
|
+
async ({ artifact_slug, vote, reason }) => {
|
|
333
|
+
api.requireAuth();
|
|
334
|
+
const result = await api.post(`/artifacts/${encodeURIComponent(artifact_slug)}/review`, {
|
|
335
|
+
vote,
|
|
336
|
+
reason
|
|
337
|
+
});
|
|
338
|
+
return {
|
|
339
|
+
content: [
|
|
340
|
+
{
|
|
341
|
+
type: "text",
|
|
342
|
+
text: JSON.stringify(result, null, 2)
|
|
343
|
+
}
|
|
344
|
+
]
|
|
345
|
+
};
|
|
346
|
+
}
|
|
347
|
+
);
|
|
348
|
+
}
|
|
349
|
+
|
|
350
|
+
// src/tools/bounties.ts
|
|
351
|
+
import { z as z4 } from "zod";
|
|
352
|
+
function registerBountyTools(server, api) {
|
|
353
|
+
server.tool(
|
|
354
|
+
"list_bounties",
|
|
355
|
+
"List CAIK bounties \u2014 requests from the community for specific artifacts. Bounties reward karma to contributors who fulfill them. Filter by status and tags to find bounties you can fulfill.",
|
|
356
|
+
{
|
|
357
|
+
status: z4.enum(["open", "claimed", "fulfilled"]).optional().describe("Filter by bounty status (default: all)"),
|
|
358
|
+
tags: z4.array(z4.string()).optional().describe("Filter by tags (e.g., ['git', 'testing'])")
|
|
359
|
+
},
|
|
360
|
+
async ({ status, tags }) => {
|
|
361
|
+
const params = {
|
|
362
|
+
status,
|
|
363
|
+
tags
|
|
364
|
+
};
|
|
365
|
+
const result = await api.get("/bounties", params);
|
|
366
|
+
return {
|
|
367
|
+
content: [
|
|
368
|
+
{
|
|
369
|
+
type: "text",
|
|
370
|
+
text: JSON.stringify(result, null, 2)
|
|
371
|
+
}
|
|
372
|
+
]
|
|
373
|
+
};
|
|
374
|
+
}
|
|
375
|
+
);
|
|
376
|
+
server.tool(
|
|
377
|
+
"claim_bounty",
|
|
378
|
+
"Claim a CAIK bounty with a published artifact that fulfills it. You must have already published the artifact. Requires authentication. Returns confirmation with bounty details and karma reward.",
|
|
379
|
+
{
|
|
380
|
+
bounty_id: z4.string().describe("ID of the bounty to claim"),
|
|
381
|
+
artifact_slug: z4.string().describe("Slug of your published artifact that fulfills the bounty")
|
|
382
|
+
},
|
|
383
|
+
async ({ bounty_id, artifact_slug }) => {
|
|
384
|
+
api.requireAuth();
|
|
385
|
+
const result = await api.post(`/bounties/${encodeURIComponent(bounty_id)}/claim`, {
|
|
386
|
+
artifactSlug: artifact_slug
|
|
387
|
+
});
|
|
388
|
+
return {
|
|
389
|
+
content: [
|
|
390
|
+
{
|
|
391
|
+
type: "text",
|
|
392
|
+
text: JSON.stringify(result, null, 2)
|
|
393
|
+
}
|
|
394
|
+
]
|
|
395
|
+
};
|
|
396
|
+
}
|
|
397
|
+
);
|
|
398
|
+
}
|
|
399
|
+
|
|
400
|
+
// src/tools/publishing.ts
|
|
401
|
+
import { z as z5 } from "zod";
|
|
402
|
+
function registerPublishingTools(server, api) {
|
|
403
|
+
server.tool(
|
|
404
|
+
"submit_artifact",
|
|
405
|
+
"Publish a new artifact to the CAIK registry. Supports skills, MCP servers, prompts, commands, subagents, libraries, stacks, and references. The artifact goes through automated eval (security scan, schema validation, quality scoring). Requires authentication.",
|
|
406
|
+
{
|
|
407
|
+
name: z5.string().describe("Artifact name (human-readable, e.g., 'GitHub PR Review Skill')"),
|
|
408
|
+
description: z5.string().describe("What the artifact does \u2014 be descriptive, this helps discovery (min 20 chars)"),
|
|
409
|
+
primitive: z5.enum(["skill", "mcp-server", "prompt", "command", "subagent", "library", "stack", "reference"]).describe("Artifact type/primitive"),
|
|
410
|
+
tags: z5.array(z5.string()).min(1).describe("At least one tag for categorization (e.g., ['git', 'code-review'])"),
|
|
411
|
+
platforms: z5.array(z5.string()).min(1).describe("Supported platforms (e.g., ['claude-code', 'cursor', 'generic'])"),
|
|
412
|
+
content: z5.string().describe("The artifact content (skill source, prompt text, config, etc.)"),
|
|
413
|
+
manifest: z5.record(z5.unknown()).optional().describe("Optional manifest object with primitive-specific metadata"),
|
|
414
|
+
parentSlug: z5.string().optional().describe("If this is a fork, the slug of the parent artifact"),
|
|
415
|
+
forkRationale: z5.string().optional().describe("If forking, explain what you changed and why")
|
|
416
|
+
},
|
|
417
|
+
async ({ name, description, primitive, tags, platforms, content, manifest, parentSlug, forkRationale }) => {
|
|
418
|
+
api.requireAuth();
|
|
419
|
+
const result = await api.post("/artifacts", {
|
|
420
|
+
name,
|
|
421
|
+
description,
|
|
422
|
+
primitive,
|
|
423
|
+
tags,
|
|
424
|
+
platforms,
|
|
425
|
+
content,
|
|
426
|
+
manifest,
|
|
427
|
+
parentSlug,
|
|
428
|
+
forkRationale: forkRationale ? { category: "custom", description: forkRationale } : void 0
|
|
429
|
+
});
|
|
430
|
+
return {
|
|
431
|
+
content: [
|
|
432
|
+
{
|
|
433
|
+
type: "text",
|
|
434
|
+
text: JSON.stringify(result, null, 2)
|
|
435
|
+
}
|
|
436
|
+
]
|
|
437
|
+
};
|
|
438
|
+
}
|
|
439
|
+
);
|
|
440
|
+
server.tool(
|
|
441
|
+
"list_my_artifacts",
|
|
442
|
+
"List all artifacts you've published to CAIK. Returns slug, name, quality score, install count, and status for each. Requires authentication.",
|
|
443
|
+
{},
|
|
444
|
+
async () => {
|
|
445
|
+
api.requireAuth();
|
|
446
|
+
const result = await api.get("/me/artifacts");
|
|
447
|
+
return {
|
|
448
|
+
content: [
|
|
449
|
+
{
|
|
450
|
+
type: "text",
|
|
451
|
+
text: JSON.stringify(result, null, 2)
|
|
452
|
+
}
|
|
453
|
+
]
|
|
454
|
+
};
|
|
455
|
+
}
|
|
456
|
+
);
|
|
457
|
+
server.tool(
|
|
458
|
+
"list_my_submissions",
|
|
459
|
+
"Get a summary of your CAIK submission pipeline: how many artifacts are pending review, published, or still in draft. Requires authentication.",
|
|
460
|
+
{},
|
|
461
|
+
async () => {
|
|
462
|
+
api.requireAuth();
|
|
463
|
+
const result = await api.get("/me/submissions");
|
|
464
|
+
return {
|
|
465
|
+
content: [
|
|
466
|
+
{
|
|
467
|
+
type: "text",
|
|
468
|
+
text: JSON.stringify(result, null, 2)
|
|
469
|
+
}
|
|
470
|
+
]
|
|
471
|
+
};
|
|
472
|
+
}
|
|
473
|
+
);
|
|
474
|
+
}
|
|
475
|
+
|
|
476
|
+
// src/resources.ts
|
|
477
|
+
import { ResourceTemplate } from "@modelcontextprotocol/sdk/server/mcp.js";
|
|
478
|
+
function registerResources(server, api) {
|
|
479
|
+
server.resource(
|
|
480
|
+
"artifact",
|
|
481
|
+
new ResourceTemplate("caik://artifact/{slug}", { list: void 0 }),
|
|
482
|
+
{
|
|
483
|
+
description: "Full artifact detail from the CAIK registry",
|
|
484
|
+
mimeType: "application/json"
|
|
485
|
+
},
|
|
486
|
+
async (uri, { slug }) => {
|
|
487
|
+
const result = await api.get(`/artifacts/${encodeURIComponent(slug)}`);
|
|
488
|
+
return {
|
|
489
|
+
contents: [
|
|
490
|
+
{
|
|
491
|
+
uri: uri.href,
|
|
492
|
+
mimeType: "application/json",
|
|
493
|
+
text: JSON.stringify(result, null, 2)
|
|
494
|
+
}
|
|
495
|
+
]
|
|
496
|
+
};
|
|
497
|
+
}
|
|
498
|
+
);
|
|
499
|
+
server.resource(
|
|
500
|
+
"stack",
|
|
501
|
+
new ResourceTemplate("caik://stack/{slug}", { list: void 0 }),
|
|
502
|
+
{
|
|
503
|
+
description: "Resolved stack with ordered artifact install sequence",
|
|
504
|
+
mimeType: "application/json"
|
|
505
|
+
},
|
|
506
|
+
async (uri, { slug }) => {
|
|
507
|
+
const result = await api.get(`/stacks/${encodeURIComponent(slug)}/resolve`);
|
|
508
|
+
return {
|
|
509
|
+
contents: [
|
|
510
|
+
{
|
|
511
|
+
uri: uri.href,
|
|
512
|
+
mimeType: "application/json",
|
|
513
|
+
text: JSON.stringify(result, null, 2)
|
|
514
|
+
}
|
|
515
|
+
]
|
|
516
|
+
};
|
|
517
|
+
}
|
|
518
|
+
);
|
|
519
|
+
}
|
|
520
|
+
|
|
521
|
+
// src/prompts.ts
|
|
522
|
+
import { z as z6 } from "zod";
|
|
523
|
+
function registerPrompts(server) {
|
|
524
|
+
server.prompt(
|
|
525
|
+
"discover",
|
|
526
|
+
"Help me find AI agent tools, skills, or MCP servers for my setup",
|
|
527
|
+
{
|
|
528
|
+
category: z6.string().optional().describe("Category to search: 'skills', 'mcp-servers', 'prompts', 'libraries', 'stacks', or a specific domain like 'git', 'testing'"),
|
|
529
|
+
platform: z6.string().optional().describe("Your agent platform: 'claude-code', 'cursor', 'windsurf', 'codex', 'generic'")
|
|
530
|
+
},
|
|
531
|
+
({ category, platform }) => ({
|
|
532
|
+
messages: [
|
|
533
|
+
{
|
|
534
|
+
role: "user",
|
|
535
|
+
content: {
|
|
536
|
+
type: "text",
|
|
537
|
+
text: `Help me find ${category ?? "tools and skills"} for my ${platform ?? "AI agent"} setup.
|
|
538
|
+
|
|
539
|
+
Use the CAIK 'search' tool to find relevant artifacts. Show me the top results with their quality scores, install counts, and a brief description of each. If there are artifact families with multiple variants, mention which variant is best for my platform.`
|
|
540
|
+
}
|
|
541
|
+
}
|
|
542
|
+
]
|
|
543
|
+
})
|
|
544
|
+
);
|
|
545
|
+
server.prompt(
|
|
546
|
+
"setup",
|
|
547
|
+
"Set up a complete agent stack for a specific use case",
|
|
548
|
+
{
|
|
549
|
+
use_case: z6.string().describe("What you want to build or accomplish (e.g., 'full-stack web development', 'data analysis pipeline')"),
|
|
550
|
+
platform: z6.string().optional().describe("Your agent platform: 'claude-code', 'cursor', 'windsurf', 'codex', 'generic'")
|
|
551
|
+
},
|
|
552
|
+
({ use_case, platform }) => ({
|
|
553
|
+
messages: [
|
|
554
|
+
{
|
|
555
|
+
role: "user",
|
|
556
|
+
content: {
|
|
557
|
+
type: "text",
|
|
558
|
+
text: `I want to set up a complete agent stack for: ${use_case}
|
|
559
|
+
Platform: ${platform ?? "generic"}
|
|
560
|
+
|
|
561
|
+
Please:
|
|
562
|
+
1. Search CAIK for relevant stacks using the 'search' tool with appropriate keywords
|
|
563
|
+
2. If a stack exists, use 'resolve_stack' to get the full install sequence
|
|
564
|
+
3. If no stack exists, search for individual artifacts and recommend a combination
|
|
565
|
+
4. For each recommended artifact, show the quality score and install count
|
|
566
|
+
5. Provide the install sequence in order`
|
|
567
|
+
}
|
|
568
|
+
}
|
|
569
|
+
]
|
|
570
|
+
})
|
|
571
|
+
);
|
|
572
|
+
server.prompt(
|
|
573
|
+
"contribute",
|
|
574
|
+
"Publish a new or forked artifact to the CAIK registry",
|
|
575
|
+
{
|
|
576
|
+
action: z6.enum(["new", "fork"]).optional().describe("Whether you're publishing a new artifact or forking an existing one"),
|
|
577
|
+
parent_slug: z6.string().optional().describe("If forking, the slug of the artifact to fork from")
|
|
578
|
+
},
|
|
579
|
+
({ action, parent_slug }) => {
|
|
580
|
+
const isFork = action === "fork" || !!parent_slug;
|
|
581
|
+
const forkContext = isFork ? `
|
|
582
|
+
I'm forking from: ${parent_slug ?? "(specify the parent artifact slug)"}
|
|
583
|
+
|
|
584
|
+
First, use 'get_artifact' to fetch the parent artifact details so we can see what we're building on.` : "";
|
|
585
|
+
return {
|
|
586
|
+
messages: [
|
|
587
|
+
{
|
|
588
|
+
role: "user",
|
|
589
|
+
content: {
|
|
590
|
+
type: "text",
|
|
591
|
+
text: `I want to ${isFork ? "fork an existing artifact and publish my modified version" : "publish a new artifact"} to the CAIK registry.${forkContext}
|
|
592
|
+
|
|
593
|
+
Walk me through the process:
|
|
594
|
+
1. Help me prepare the artifact metadata (name, description, tags, platforms, primitive type)
|
|
595
|
+
2. Review the content for quality (description > 20 chars, at least 1 tag, valid primitive)
|
|
596
|
+
3. Use 'submit_artifact' to publish it
|
|
597
|
+
4. Verify the submission with 'list_my_submissions'`
|
|
598
|
+
}
|
|
599
|
+
}
|
|
600
|
+
]
|
|
601
|
+
};
|
|
602
|
+
}
|
|
603
|
+
);
|
|
604
|
+
}
|
|
605
|
+
|
|
606
|
+
// src/index.ts
|
|
607
|
+
function createServer() {
|
|
608
|
+
const config = resolveConfig();
|
|
609
|
+
const api = new CaikApiClient(config);
|
|
610
|
+
const server = new McpServer({
|
|
611
|
+
name: "caik",
|
|
612
|
+
version: "0.1.0"
|
|
613
|
+
});
|
|
614
|
+
registerDiscoveryTools(server, api);
|
|
615
|
+
registerAccountTools(server, api);
|
|
616
|
+
registerContributionTools(server, api);
|
|
617
|
+
registerBountyTools(server, api);
|
|
618
|
+
registerPublishingTools(server, api);
|
|
619
|
+
registerResources(server, api);
|
|
620
|
+
registerPrompts(server);
|
|
621
|
+
return server;
|
|
622
|
+
}
|
|
623
|
+
async function main() {
|
|
624
|
+
const server = createServer();
|
|
625
|
+
const transport = new StdioServerTransport();
|
|
626
|
+
await server.connect(transport);
|
|
627
|
+
}
|
|
628
|
+
main().catch((err) => {
|
|
629
|
+
console.error("CAIK MCP Server failed to start:", err);
|
|
630
|
+
process.exit(1);
|
|
631
|
+
});
|
|
632
|
+
export {
|
|
633
|
+
createServer
|
|
634
|
+
};
|
package/package.json
ADDED
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@caik.dev/mcp",
|
|
3
|
+
"version": "0.1.0",
|
|
4
|
+
"type": "module",
|
|
5
|
+
"description": "CAIK MCP Server — AI artifact registry tools for Claude Code, Cursor, and other MCP-capable agents",
|
|
6
|
+
"keywords": [
|
|
7
|
+
"caik",
|
|
8
|
+
"mcp",
|
|
9
|
+
"ai",
|
|
10
|
+
"artifacts",
|
|
11
|
+
"claude",
|
|
12
|
+
"cursor",
|
|
13
|
+
"skills",
|
|
14
|
+
"registry",
|
|
15
|
+
"model-context-protocol"
|
|
16
|
+
],
|
|
17
|
+
"homepage": "https://caik.dev",
|
|
18
|
+
"repository": {
|
|
19
|
+
"type": "git",
|
|
20
|
+
"url": "https://github.com/open-lattice-ai/caik",
|
|
21
|
+
"directory": "packages/mcp"
|
|
22
|
+
},
|
|
23
|
+
"license": "MIT",
|
|
24
|
+
"bin": {
|
|
25
|
+
"caik-mcp-server": "./dist/index.js"
|
|
26
|
+
},
|
|
27
|
+
"files": [
|
|
28
|
+
"dist",
|
|
29
|
+
"README.md"
|
|
30
|
+
],
|
|
31
|
+
"main": "./dist/index.js",
|
|
32
|
+
"scripts": {
|
|
33
|
+
"build": "tsup",
|
|
34
|
+
"dev": "tsx src/index.ts",
|
|
35
|
+
"typecheck": "tsc --noEmit"
|
|
36
|
+
},
|
|
37
|
+
"dependencies": {
|
|
38
|
+
"@modelcontextprotocol/sdk": "^1.12.1",
|
|
39
|
+
"zod": "^3.24.0"
|
|
40
|
+
},
|
|
41
|
+
"devDependencies": {
|
|
42
|
+
"tsup": "^8.5.1",
|
|
43
|
+
"tsx": "^4.21.0"
|
|
44
|
+
}
|
|
45
|
+
}
|