@buygit/mcp-server 0.4.1 → 0.5.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/CLIENTS.md +303 -0
- package/README.md +6 -0
- package/dist/index.js +17 -17
- package/package.json +3 -2
package/CLIENTS.md
ADDED
|
@@ -0,0 +1,303 @@
|
|
|
1
|
+
# MCP client install matrix — `@buygit/mcp-server`
|
|
2
|
+
|
|
3
|
+
This file is the canonical, copy-pasteable install reference for every
|
|
4
|
+
MCP-capable client we test. The MCP protocol itself is universal (the
|
|
5
|
+
2025-11-25 spec is what every client targets), so any client that speaks
|
|
6
|
+
MCP works with this server — the table below pins the *config file
|
|
7
|
+
location* for the popular ones so you don't have to dig.
|
|
8
|
+
|
|
9
|
+
For everything else, the universal stdio config object is:
|
|
10
|
+
|
|
11
|
+
```json
|
|
12
|
+
{
|
|
13
|
+
"mcpServers": {
|
|
14
|
+
"buygit": {
|
|
15
|
+
"command": "npx",
|
|
16
|
+
"args": ["-y", "@buygit/mcp-server@latest"]
|
|
17
|
+
}
|
|
18
|
+
}
|
|
19
|
+
}
|
|
20
|
+
```
|
|
21
|
+
|
|
22
|
+
If your client is not listed and you find the right config path, please
|
|
23
|
+
PR an entry to this file.
|
|
24
|
+
|
|
25
|
+
---
|
|
26
|
+
|
|
27
|
+
## Quick reference
|
|
28
|
+
|
|
29
|
+
| Client | Transport | Config location |
|
|
30
|
+
|---|---|---|
|
|
31
|
+
| [Antigravity](#antigravity-google) | stdio | settings → MCP Servers (Google, Nov 2025+) |
|
|
32
|
+
| [Claude Desktop](#claude-desktop-anthropic) | stdio | `claude_desktop_config.json` |
|
|
33
|
+
| [Claude Code](#claude-code-anthropic-cli) | stdio | `~/.claude/settings.json` or `claude mcp add` |
|
|
34
|
+
| [Cursor](#cursor) | stdio + HTTP | `~/.cursor/mcp.json` + one-click deeplink |
|
|
35
|
+
| [Cline](#cline-vs-code) | stdio | command palette → "Cline: Open MCP Servers" |
|
|
36
|
+
| [Codex CLI](#codex-cli-openai) | stdio | `~/.codex/mcp.json` |
|
|
37
|
+
| [Continue](#continue-vs-code--jetbrains) | stdio | `~/.continue/config.json` |
|
|
38
|
+
| [Gemini CLI](#gemini-cli-google) | stdio | `~/.gemini/mcp.json` |
|
|
39
|
+
| [OpenCode](#opencode-sst) | stdio | `~/.opencode/config.json` |
|
|
40
|
+
| [Roo Code](#roo-code-vs-code) | stdio | settings → MCP Servers |
|
|
41
|
+
| [Windsurf](#windsurf-codeium) | stdio | `~/.codeium/windsurf/mcp_config.json` |
|
|
42
|
+
| [Zed](#zed) | stdio | `settings.json` → `context_servers` |
|
|
43
|
+
| [Self-hosted (Docker / HTTP)](#self-hosted-streamable-http) | HTTP | any MCP 2025-03-26+ client |
|
|
44
|
+
|
|
45
|
+
---
|
|
46
|
+
|
|
47
|
+
## Antigravity (Google)
|
|
48
|
+
|
|
49
|
+
Google's agentic IDE/CLI announced 2025-11-18. MCP support shipped at
|
|
50
|
+
launch — the config lives in Settings → MCP Servers (UI) or in the
|
|
51
|
+
on-disk settings file.
|
|
52
|
+
|
|
53
|
+
```json
|
|
54
|
+
{
|
|
55
|
+
"mcpServers": {
|
|
56
|
+
"buygit": {
|
|
57
|
+
"command": "npx",
|
|
58
|
+
"args": ["-y", "@buygit/mcp-server@latest"]
|
|
59
|
+
}
|
|
60
|
+
}
|
|
61
|
+
}
|
|
62
|
+
```
|
|
63
|
+
|
|
64
|
+
After saving, restart Antigravity. Tools appear under the agent's
|
|
65
|
+
"Available tools" panel; ask the agent literally `use buygit to find an
|
|
66
|
+
MIT-licensed react form library`.
|
|
67
|
+
|
|
68
|
+
> For the remote (Streamable HTTP) transport — useful for team-wide
|
|
69
|
+
> deployments — once `mcp.buygit.com` is operational, you'll be able to
|
|
70
|
+
> use `{ "url": "https://mcp.buygit.com/mcp" }` instead of `command`.
|
|
71
|
+
|
|
72
|
+
## Claude Desktop (Anthropic)
|
|
73
|
+
|
|
74
|
+
Edit:
|
|
75
|
+
|
|
76
|
+
- macOS: `~/Library/Application Support/Claude/claude_desktop_config.json`
|
|
77
|
+
- Windows: `%APPDATA%\Claude\claude_desktop_config.json`
|
|
78
|
+
- Linux: `~/.config/Claude/claude_desktop_config.json`
|
|
79
|
+
|
|
80
|
+
```json
|
|
81
|
+
{
|
|
82
|
+
"mcpServers": {
|
|
83
|
+
"buygit": {
|
|
84
|
+
"command": "npx",
|
|
85
|
+
"args": ["-y", "@buygit/mcp-server@latest"]
|
|
86
|
+
}
|
|
87
|
+
}
|
|
88
|
+
}
|
|
89
|
+
```
|
|
90
|
+
|
|
91
|
+
Restart Claude Desktop. The first call may take a few seconds while
|
|
92
|
+
`npx` resolves the package on disk.
|
|
93
|
+
|
|
94
|
+
## Claude Code (Anthropic CLI)
|
|
95
|
+
|
|
96
|
+
Two ways. Either edit `~/.claude/settings.json`:
|
|
97
|
+
|
|
98
|
+
```json
|
|
99
|
+
{
|
|
100
|
+
"mcpServers": {
|
|
101
|
+
"buygit": {
|
|
102
|
+
"command": "npx",
|
|
103
|
+
"args": ["-y", "@buygit/mcp-server@latest"]
|
|
104
|
+
}
|
|
105
|
+
}
|
|
106
|
+
}
|
|
107
|
+
```
|
|
108
|
+
|
|
109
|
+
…or use the bundled `claude mcp add` command:
|
|
110
|
+
|
|
111
|
+
```bash
|
|
112
|
+
claude mcp add buygit -- npx -y @buygit/mcp-server@latest
|
|
113
|
+
```
|
|
114
|
+
|
|
115
|
+
Claude Code v2.1.76+ supports our `instructions` field, structuredContent,
|
|
116
|
+
icons, and the Tool Search Tool optimization that `search_tools` plugs
|
|
117
|
+
into.
|
|
118
|
+
|
|
119
|
+
## Cursor
|
|
120
|
+
|
|
121
|
+
Edit `~/.cursor/mcp.json`:
|
|
122
|
+
|
|
123
|
+
```json
|
|
124
|
+
{
|
|
125
|
+
"mcpServers": {
|
|
126
|
+
"buygit": {
|
|
127
|
+
"command": "npx",
|
|
128
|
+
"args": ["-y", "@buygit/mcp-server@latest"]
|
|
129
|
+
}
|
|
130
|
+
}
|
|
131
|
+
}
|
|
132
|
+
```
|
|
133
|
+
|
|
134
|
+
Or use the **one-click deeplink** (Cursor 0.45+):
|
|
135
|
+
|
|
136
|
+
```
|
|
137
|
+
cursor://anysphere.cursor-deeplink/mcp/install?name=buygit&config=eyJjb21tYW5kIjoibnB4IiwiYXJncyI6WyIteSIsIkBidXlnaXQvbWNwLXNlcnZlckBsYXRlc3QiXX0=
|
|
138
|
+
```
|
|
139
|
+
|
|
140
|
+
Click it from any browser; Cursor will pop the install confirmation.
|
|
141
|
+
|
|
142
|
+
## Cline (VS Code)
|
|
143
|
+
|
|
144
|
+
Command palette → `Cline: Open MCP Servers` → paste under the top-level
|
|
145
|
+
`mcpServers` key:
|
|
146
|
+
|
|
147
|
+
```json
|
|
148
|
+
{
|
|
149
|
+
"mcpServers": {
|
|
150
|
+
"buygit": {
|
|
151
|
+
"command": "npx",
|
|
152
|
+
"args": ["-y", "@buygit/mcp-server@latest"]
|
|
153
|
+
}
|
|
154
|
+
}
|
|
155
|
+
}
|
|
156
|
+
```
|
|
157
|
+
|
|
158
|
+
## Codex CLI (OpenAI)
|
|
159
|
+
|
|
160
|
+
```bash
|
|
161
|
+
codex mcp add buygit "npx -y @buygit/mcp-server@latest"
|
|
162
|
+
```
|
|
163
|
+
|
|
164
|
+
Or edit `~/.codex/mcp.json` directly with the same object shape.
|
|
165
|
+
|
|
166
|
+
## Continue (VS Code / JetBrains)
|
|
167
|
+
|
|
168
|
+
Edit `~/.continue/config.json`. Continue uses the standard MCP key:
|
|
169
|
+
|
|
170
|
+
```json
|
|
171
|
+
{
|
|
172
|
+
"mcpServers": {
|
|
173
|
+
"buygit": {
|
|
174
|
+
"command": "npx",
|
|
175
|
+
"args": ["-y", "@buygit/mcp-server@latest"]
|
|
176
|
+
}
|
|
177
|
+
}
|
|
178
|
+
}
|
|
179
|
+
```
|
|
180
|
+
|
|
181
|
+
## Gemini CLI (Google)
|
|
182
|
+
|
|
183
|
+
Edit `~/.gemini/mcp.json`:
|
|
184
|
+
|
|
185
|
+
```json
|
|
186
|
+
{
|
|
187
|
+
"mcpServers": {
|
|
188
|
+
"buygit": {
|
|
189
|
+
"command": "npx",
|
|
190
|
+
"args": ["-y", "@buygit/mcp-server@latest"]
|
|
191
|
+
}
|
|
192
|
+
}
|
|
193
|
+
}
|
|
194
|
+
```
|
|
195
|
+
|
|
196
|
+
Verify with `gemini --list-mcp` (lists registered servers).
|
|
197
|
+
|
|
198
|
+
## OpenCode (SST)
|
|
199
|
+
|
|
200
|
+
Edit `~/.opencode/config.json`. OpenCode wraps Anthropic Claude under
|
|
201
|
+
a MCP-capable terminal UI:
|
|
202
|
+
|
|
203
|
+
```json
|
|
204
|
+
{
|
|
205
|
+
"mcp": {
|
|
206
|
+
"buygit": {
|
|
207
|
+
"type": "local",
|
|
208
|
+
"command": ["npx", "-y", "@buygit/mcp-server@latest"]
|
|
209
|
+
}
|
|
210
|
+
}
|
|
211
|
+
}
|
|
212
|
+
```
|
|
213
|
+
|
|
214
|
+
Note the `type: "local"` key — OpenCode uses a slightly different shape
|
|
215
|
+
than the standard `mcpServers` object.
|
|
216
|
+
|
|
217
|
+
## Roo Code (VS Code)
|
|
218
|
+
|
|
219
|
+
Fork of Cline. Same config location:
|
|
220
|
+
|
|
221
|
+
Command palette → `Roo Code: MCP Servers` → paste:
|
|
222
|
+
|
|
223
|
+
```json
|
|
224
|
+
{
|
|
225
|
+
"mcpServers": {
|
|
226
|
+
"buygit": {
|
|
227
|
+
"command": "npx",
|
|
228
|
+
"args": ["-y", "@buygit/mcp-server@latest"]
|
|
229
|
+
}
|
|
230
|
+
}
|
|
231
|
+
}
|
|
232
|
+
```
|
|
233
|
+
|
|
234
|
+
## Windsurf (Codeium)
|
|
235
|
+
|
|
236
|
+
Edit `~/.codeium/windsurf/mcp_config.json`:
|
|
237
|
+
|
|
238
|
+
```json
|
|
239
|
+
{
|
|
240
|
+
"mcpServers": {
|
|
241
|
+
"buygit": {
|
|
242
|
+
"command": "npx",
|
|
243
|
+
"args": ["-y", "@buygit/mcp-server@latest"]
|
|
244
|
+
}
|
|
245
|
+
}
|
|
246
|
+
}
|
|
247
|
+
```
|
|
248
|
+
|
|
249
|
+
## Zed
|
|
250
|
+
|
|
251
|
+
Edit Zed's `settings.json` (CMD/Ctrl+,):
|
|
252
|
+
|
|
253
|
+
```json
|
|
254
|
+
{
|
|
255
|
+
"context_servers": {
|
|
256
|
+
"buygit": {
|
|
257
|
+
"source": "custom",
|
|
258
|
+
"command": "npx",
|
|
259
|
+
"args": ["-y", "@buygit/mcp-server@latest"]
|
|
260
|
+
}
|
|
261
|
+
}
|
|
262
|
+
}
|
|
263
|
+
```
|
|
264
|
+
|
|
265
|
+
Zed surfaces MCP tools as `/buygit_*` slash commands in chat.
|
|
266
|
+
|
|
267
|
+
## Self-hosted (Streamable HTTP)
|
|
268
|
+
|
|
269
|
+
For team-wide deployment behind a load balancer:
|
|
270
|
+
|
|
271
|
+
```bash
|
|
272
|
+
# bare metal / pm2
|
|
273
|
+
BUYGIT_MCP_TRANSPORT=http BUYGIT_MCP_PORT=3030 \
|
|
274
|
+
npx -y @buygit/mcp-server@latest
|
|
275
|
+
|
|
276
|
+
# Docker (one-liner)
|
|
277
|
+
docker run --rm -p 3030:3030 \
|
|
278
|
+
-e BUYGIT_MCP_TRANSPORT=http \
|
|
279
|
+
-e BUYGIT_MCP_PORT=3030 \
|
|
280
|
+
node:20-alpine sh -c "npx -y @buygit/mcp-server@latest"
|
|
281
|
+
```
|
|
282
|
+
|
|
283
|
+
Then in any MCP 2025-03-26+ client config:
|
|
284
|
+
|
|
285
|
+
```json
|
|
286
|
+
{
|
|
287
|
+
"mcpServers": {
|
|
288
|
+
"buygit": {
|
|
289
|
+
"url": "http://your-internal-host:3030/mcp"
|
|
290
|
+
}
|
|
291
|
+
}
|
|
292
|
+
}
|
|
293
|
+
```
|
|
294
|
+
|
|
295
|
+
`/healthz` returns `{ok:true, version}` for orchestrator probes.
|
|
296
|
+
|
|
297
|
+
## Anything else
|
|
298
|
+
|
|
299
|
+
The universal stdio object at the top of this file works for any client
|
|
300
|
+
that follows the MCP spec. If you find the config path for a client not
|
|
301
|
+
listed here, please open a PR adding it.
|
|
302
|
+
|
|
303
|
+
> Issues: https://github.com/genoxdeveloper/Buygit/issues
|
package/README.md
CHANGED
|
@@ -8,6 +8,12 @@ MCP server for the **BuyGit Open Index** — 78,094 curated, deduplicated, licen
|
|
|
8
8
|
[](https://github.com/genoxdeveloper/Buygit/blob/main/packages/mcp-server/LICENSE)
|
|
9
9
|
|
|
10
10
|
> Companion: **[`@buygit/cli`](https://www.npmjs.com/package/@buygit/cli)** — same answers from your shell. `npx @buygit/cli search "react form" --license MIT`.
|
|
11
|
+
>
|
|
12
|
+
> Companion: **`buygit-vscode` extension** — license-compat + audit from the VS Code command palette + explorer right-click. See [`packages/vscode-extension`](../vscode-extension).
|
|
13
|
+
>
|
|
14
|
+
> Works in **Antigravity, Claude Desktop, Claude Code, Cursor, Cline, Codex CLI, Continue, Gemini CLI, OpenCode, Roo Code, Windsurf, Zed**, and any MCP 2025-11-25 client. Full install matrix in **[CLIENTS.md](./CLIENTS.md)**.
|
|
15
|
+
>
|
|
16
|
+
> **Cursor one-click install:** [`cursor://anysphere.cursor-deeplink/mcp/install?name=buygit&config=eyJjb21tYW5kIjoibnB4IiwiYXJncyI6WyIteSIsIkBidXlnaXQvbWNwLXNlcnZlckBsYXRlc3QiXX0=`](cursor://anysphere.cursor-deeplink/mcp/install?name=buygit&config=eyJjb21tYW5kIjoibnB4IiwiYXJncyI6WyIteSIsIkBidXlnaXQvbWNwLXNlcnZlckBsYXRlc3QiXX0=)
|
|
11
17
|
|
|
12
18
|
## Why BuyGit over raw GitHub search?
|
|
13
19
|
|
package/dist/index.js
CHANGED
|
@@ -1,27 +1,27 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
|
-
import{createServer as xe}from"http";import{StdioServerTransport as ve}from"@modelcontextprotocol/sdk/server/stdio.js";import{StreamableHTTPServerTransport as Se}from"@modelcontextprotocol/sdk/server/streamableHttp.js";import{Server as me}from"@modelcontextprotocol/sdk/server/index.js";import{CallToolRequestSchema as de,ListToolsRequestSchema as ye,ListResourceTemplatesRequestSchema as he,ListResourcesRequestSchema as fe,ReadResourceRequestSchema as _e,ListPromptsRequestSchema as be,GetPromptRequestSchema as we}from"@modelcontextprotocol/sdk/types.js";import{z as
|
|
3
|
-
`)}function
|
|
2
|
+
import{createServer as xe}from"http";import{StdioServerTransport as ve}from"@modelcontextprotocol/sdk/server/stdio.js";import{StreamableHTTPServerTransport as Se}from"@modelcontextprotocol/sdk/server/streamableHttp.js";import{Server as me}from"@modelcontextprotocol/sdk/server/index.js";import{CallToolRequestSchema as de,ListToolsRequestSchema as ye,ListResourceTemplatesRequestSchema as he,ListResourcesRequestSchema as fe,ReadResourceRequestSchema as _e,ListPromptsRequestSchema as be,GetPromptRequestSchema as we}from"@modelcontextprotocol/sdk/types.js";import{z as g}from"zod";import{Pool as O}from"undici";var f="0.5.0",w="@buygit/mcp-server";var A=process.env.BUYGIT_API_BASE||"https://buygit.com",D=`@buygit/mcp-server/${f} (+https://buygit.com/mcp)`,L=null;function N(e){return L===null&&(L=new O(e,{connections:4,keepAliveTimeout:6e4,keepAliveMaxTimeout:6e5})),L}var v=class extends Error{constructor(n,s,r){super(n);this.status=s;this.code=r;this.name="BuygitApiError"}status;code};async function m(e,t={},n={}){let r=N(A),i=Object.entries(t).filter(([,p])=>p!=null&&p!=="").map(([p,h])=>`${encodeURIComponent(p)}=${encodeURIComponent(String(h))}`).join("&"),a=i?`${e}?${i}`:e,c=await r.request({method:"GET",path:a,headers:{"user-agent":D,accept:"application/json"},headersTimeout:n.timeoutMs??12e3,bodyTimeout:n.timeoutMs??12e3}),o=c.statusCode,l=await c.body.text(),u=null;try{u=JSON.parse(l)}catch{throw new v(`upstream returned non-JSON (status ${o})`,o)}if(o>=400||u.ok===!1)throw new v(u.error??`upstream returned HTTP ${o}`,o,u.code);return u.data!==void 0?u.data:u}function M(e){if(!e)return null;let t=[];return t.push(e.license_category),t.push(`pop ${e.popularity}`),t.push(`risk ${e.risk}${e.risk>=40?" \u26A0":""}`),t.push(e.pricing_tier),`[${t.join(" \xB7 ")}]`}var U="\xA0";function R(e){return e>=1e3?`${(e/1e3).toFixed(1)}k`:String(e)}function P(e){return e.filter(t=>!!(t&&t.length>0)).join(" \xB7 ")}function H(e,t){let n=t!==void 0?`${t}. **${e.title}**`:`**${e.title}**`,s=P([e.stars>0?`\u2605${U}${R(e.stars)}`:null,e.license||null,e.language||null,e.category?e.category.name:null]),r=M(e.signals),i=e.signals?.license_warning;return[n,s?` ${s}`:null,r?` ${r}`:null,` ${e.short_description}`,i?` \u26A0 ${i}`:null,` ${e.url}`].filter(a=>a!==null).join(`
|
|
3
|
+
`)}function $(e,t){let n=t?.header?`${t.header}
|
|
4
4
|
|
|
5
5
|
`:"",s=t?.footer?`
|
|
6
6
|
|
|
7
7
|
${t.footer}`:"";return e.length===0?`${n}_No results._${s}`:n+e.map((r,i)=>H(r,i+1)).join(`
|
|
8
8
|
|
|
9
|
-
`)+s}function
|
|
9
|
+
`)+s}function k(e){let t=[];t.push(`# ${e.title}`),t.push(""),t.push(P([e.repo_signals.stars>0?`\u2605 ${R(e.repo_signals.stars)}`:null,e.license,e.repo_signals.language,e.category?.name??null,e.source])),t.push(""),t.push(e.short_description),t.push(""),e.tags&&e.tags.length>0&&(t.push(`**Tags:** ${e.tags.slice(0,12).map(i=>`\`${i}\``).join(" ")}`),t.push(""));let n=[];e.safety_signals.secret_scan==="clean"?n.push("secret-scan: clean \u2713"):e.safety_signals.secret_scan==="flagged"?n.push("secret-scan: **flagged** \u26A0"):n.push("secret-scan: not run"),e.safety_signals.malware_flag&&n.push("**malware flag set** \u26A0"),e.repo_signals.upstream_status==="removed"&&n.push("**upstream removed** \u26A0"),t.push(`**Safety:** ${n.join(" \xB7 ")}`),t.push("");let s=e.signals;t.push(`**Signals:** license: ${s.license_category} \xB7 popularity: ${s.popularity}/100 \xB7 risk: ${s.risk}/100 \xB7 pricing: ${s.pricing_tier}`),s.license_warning&&t.push(`> \u26A0 ${s.license_warning}`),t.push("");let r=[];if(e.repo_signals.repo_url&&r.push(`repo: ${e.repo_signals.repo_url}`),e.repo_signals.default_branch&&r.push(`branch: \`${e.repo_signals.default_branch}\``),e.repo_signals.last_commit_at&&r.push(`last commit: ${e.repo_signals.last_commit_at.slice(0,10)}`),e.repo_signals.good_first_issues>0&&r.push(`good-first-issues: ${e.repo_signals.good_first_issues}`),r.length>0&&(t.push(`**Repo:** ${r.join(" \xB7 ")}`),t.push("")),e.full_description_md&&e.full_description_md.trim().length>0){let i=e.full_description_md.slice(0,1200);t.push("## Description"),t.push(i+(e.full_description_md.length>1200?`
|
|
10
10
|
|
|
11
11
|
_(truncated \u2014 see canonical page for full text)_`:"")),t.push("")}if(t.push(`**BuyGit listing:** ${e.url}`),e.attribution&&(t.push(""),t.push(`_Attribution:_ ${e.attribution}`)),e.similar&&e.similar.length>0){t.push(""),t.push("## Similar listings");for(let i of e.similar.slice(0,5))t.push(`- **${i.title}** \xB7 ${i.url}`)}return t.join(`
|
|
12
|
-
`)}function
|
|
13
|
-
`)}function
|
|
14
|
-
`),{categories:t.categories})}catch(t){return
|
|
15
|
-
`),{total_listings:e.total_listings,last_indexed_at:e.last_indexed_at,by_license:e.by_license,by_category:e.by_category,by_source:e.by_source})}catch(e){return
|
|
16
|
-
`);return
|
|
12
|
+
`)}function T(e){let t=["# Side-by-side comparison",""];for(let n of e){if("error"in n){t.push(`## \`${n.slug}\``),t.push("_not found in the crawler index_"),t.push("");continue}t.push(`## ${n.title}`),t.push(P([n.repo_signals.stars>0?`\u2605 ${R(n.repo_signals.stars)}`:null,n.license,n.repo_signals.language,n.category?.name??null])),t.push(""),t.push(n.short_description),t.push(""),t.push(`\u2192 ${n.url}`),t.push("")}return t.join(`
|
|
13
|
+
`)}function b(e,t){let n={content:[{type:"text",text:e}]};return t&&(n.structuredContent=t),n}function d(e){return{content:[{type:"text",text:e instanceof v?`BuyGit API error (${e.status}${e.code?` / ${e.code}`:""}): ${e.message}`:e instanceof Error?`Tool error: ${e.message}`:`Tool error: ${String(e)}`}],isError:!0}}var C={type:"object",description:"4-axis signals (license, popularity, risk, pricing). The defining BuyGit MCP differentiator \u2014 no other MCP returns license + supply-chain risk + popularity + pricing in a single call.",properties:{license_category:{type:"string",enum:["permissive","weak-copyleft","strong-copyleft","public-domain","proprietary","unknown"]},license_warning:{type:["string","null"],description:"Plain-English warning when the license needs attention; null when safe."},popularity:{type:"integer",minimum:0,maximum:100,description:"Log-scaled star score 0-100."},risk:{type:"integer",minimum:0,maximum:100,description:"Supply-chain risk score 0-100. 0 = clean. \u226540 = warn user before bundling."},price_usd:{type:"number",minimum:0},pricing_tier:{type:"string",enum:["free","paid"]}}},F=g.object({query:g.string().max(200).optional(),category:g.string().max(80).optional(),language:g.string().max(40).optional(),license:g.string().max(40).optional(),min_stars:g.number().int().min(0).optional(),limit:g.number().int().min(1).max(50).default(10),sort:g.enum(["relevance","newest","stars","health"]).default("relevance")}),X={name:"buygit_search",description:"Search 78,094 curated, deduplicated, license-tagged Git assets \u2014 not raw GitHub search. Every result carries license + popularity + supply-chain risk + pricing in one shot. Filters: category slug, language, SPDX license, min stars. Sort: relevance | newest | stars | health. Prefer this when the user wants to *use* or *buy* a project, compare alternatives, or check license compatibility. Use github-mcp for private repos / Issues / commits.",inputSchema:{type:"object",properties:{query:{type:"string",maxLength:200,description:"Free text query."},category:{type:"string",maxLength:80,description:"Category slug from buygit_list_categories."},language:{type:"string",maxLength:40,description:'Primary language e.g. "TypeScript".'},license:{type:"string",maxLength:40,description:'SPDX id e.g. "MIT".'},min_stars:{type:"integer",minimum:0},limit:{type:"integer",minimum:1,maximum:50,default:10},sort:{type:"string",enum:["relevance","newest","stars","health"],default:"relevance"}}},outputSchema:{type:"object",required:["count","has_more","results"],properties:{count:{type:"integer"},has_more:{type:"boolean"},results:{type:"array",items:{type:"object",properties:{slug:{type:"string"},title:{type:"string"},url:{type:"string"},license:{type:["string","null"]},stars:{type:"integer"},signals:C}}}}},handler:async(e,t)=>{let n=F.safeParse(e??{});if(!n.success)return d(`invalid arguments: ${n.error.message}`);let{query:s,category:r,language:i,license:a,min_stars:c,limit:o,sort:l}=n.data;try{let u=await m("/api/v1/crawler/search",{q:s,category:r,language:i,license:a,min_stars:c,limit:o,sort:l});if(t.elicit&&!a&&u.has_more&&u.results.length>=o){let y=await t.elicit(`Found ${u.results.length}+ matches${s?` for "${s}"`:""}. Narrow by license?`,{type:"object",properties:{license:{type:"string",enum:["","MIT","Apache-2.0","BSD-3-Clause","ISC","GPL-3.0","AGPL-3.0","MPL-2.0","LGPL-3.0"],description:"SPDX id, or blank to skip narrowing."}}});if(y?.license&&y.license.length>0){a=y.license;let _=await m("/api/v1/crawler/search",{q:s,category:r,language:i,license:a,min_stars:c,limit:o,sort:l});u.results=_.results,u.has_more=_.has_more,u.next_cursor=_.next_cursor}}let p=[`**${u.results.length} result(s)**`,s?`for "${s}"`:null,r?`\xB7 category: ${r}`:null,i?`\xB7 lang: ${i}`:null,a?`\xB7 license: ${a}`:null,c?`\xB7 \u2265${c}\u2605`:null,`\xB7 sort: ${l}`].filter(Boolean).join(" "),h=u.has_more?"_More results available. Call again with a narrower filter, or use buygit_get_listing(slug) on any of these for full detail._":"_Call buygit_get_listing(slug) on any result for full detail._";return b($(u.results,{header:p,footer:h}),{count:u.results.length,has_more:u.has_more,results:u.results.map(y=>({slug:y.slug,title:y.title,url:y.url,license:y.license,stars:y.stars,signals:y.signals}))})}catch(u){return d(u)}}},z=g.object({slug:g.string().regex(/^[a-z0-9\-]+$/i).max(200)}),Y={name:"buygit_get_listing",description:"Full detail for one BuyGit listing \u2014 replaces 3 separate MCP calls (license + supply-chain risk + popularity in one response). Includes secret-scan status, malware flag, upstream health, repo signals (stars, forks, last commit, language), full description, license classification with compatibility warning, pricing, and up to 5 similar listings. Slug must come from a prior buygit_search / trending / random / compare result.",inputSchema:{type:"object",required:["slug"],properties:{slug:{type:"string",pattern:"^[a-z0-9\\-]+$",maxLength:200,description:"Listing slug from a previous tool call."}}},outputSchema:{type:"object",required:["slug","title","url","signals"],properties:{slug:{type:"string"},title:{type:"string"},url:{type:"string"},license:{type:["string","null"]},signals:C}},handler:async e=>{let t=z.safeParse(e??{});if(!t.success)return d(`invalid slug: ${t.error.message}`);try{let n=await m(`/api/v1/crawler/listings/${encodeURIComponent(t.data.slug)}`),s={...n,rating_block:n.rating??{avg:null,count:0}};return b(k(s),{slug:s.slug,title:s.title,url:s.url,license:s.license,signals:s.signals,safety:s.safety_signals,repo:{stars:s.repo_signals.stars,forks:s.repo_signals.forks,language:s.repo_signals.language,last_commit_at:s.repo_signals.last_commit_at,upstream_status:s.repo_signals.upstream_status}})}catch(n){return d(n)}}},J={name:"buygit_list_categories",description:"Full BuyGit Open Index taxonomy with per-category crawler listing counts. Use this to find a category slug for buygit_search, or to discover what is in the catalog. Counts are accurate to the last crawl (typically <24h).",inputSchema:{type:"object",properties:{}},outputSchema:{type:"object",required:["categories"],properties:{categories:{type:"array",items:{type:"object"}}}},handler:async()=>{try{let s=function(r,i){let a=" ".repeat(i);n.push(`${a}- **${r.name}** \`${r.slug}\` \xB7 ${r.crawler_listing_count}`);for(let c of r.children)s(c,i+1)};var e=s;let t=await m("/api/v1/crawler/categories"),n=["**BuyGit category tree** (crawler listings only)",""];for(let r of t.categories)s(r,0);return n.push(""),n.push("_Pick a slug and pass it as `category` to `buygit_search` to filter._"),b(n.join(`
|
|
14
|
+
`),{categories:t.categories})}catch(t){return d(t)}}},V=g.object({period:g.enum(["day","week","month"]).default("week"),category:g.string().max(80).optional(),limit:g.number().int().min(1).max(50).default(10)}),W={name:"buygit_trending",description:'Top crawler listings ranked by recent activity (day | week | month), each carrying license + risk + popularity + pricing. Optionally narrow to a category. Use for "what is hot right now in <category>" \u2014 agent gets a curated, license-aware shortlist instead of GitHub trending noise.',inputSchema:{type:"object",properties:{period:{type:"string",enum:["day","week","month"],default:"week"},category:{type:"string",maxLength:80},limit:{type:"integer",minimum:1,maximum:50,default:10}}},outputSchema:{type:"object",required:["period","count","results"],properties:{period:{type:"string"},count:{type:"integer"},results:{type:"array"}}},handler:async e=>{let t=V.safeParse(e??{});if(!t.success)return d(t.error.message);let{period:n,category:s,limit:r}=t.data;try{let i=await m("/api/v1/crawler/trending",{period:n,category:s,limit:r}),a=`**Trending (${n}${s?` \xB7 ${s}`:""})** \u2014 ${i.count} listing(s)`;return b($(i.results,{header:a,footer:"_Call buygit_get_listing(slug) for full detail._"}),{period:i.period,count:i.count,results:i.results.map(c=>({slug:c.slug,title:c.title,url:c.url,license:c.license,stars:c.stars,signals:c.signals}))})}catch(i){return d(i)}}},Z=g.object({slugs:g.array(g.string().regex(/^[a-z0-9\-]+$/i)).min(2).max(5)}),K={name:"buygit_compare",description:"Single-call side-by-side of 2-5 listings: license category, license_warning, popularity score, risk score, pricing, repo signals. Equivalent github-mcp / Smithery workflows need 4+ calls and do not return license compatibility. Pass slugs from prior tool results; unknown slugs come back as `not found` entries instead of erroring.",inputSchema:{type:"object",required:["slugs"],properties:{slugs:{type:"array",items:{type:"string",pattern:"^[a-z0-9\\-]+$"},minItems:2,maxItems:5}}},outputSchema:{type:"object",required:["items"],properties:{items:{type:"array"}}},handler:async e=>{let t=Z.safeParse(e??{});if(!t.success)return d(t.error.message);try{let s=(await m("/api/v1/crawler/compare",{slugs:t.data.slugs.join(",")})).items.map(r=>{if("error"in r)return r;let i=r;return{...i,rating_block:i.rating??{avg:null,count:0}}});return b(T(s),{items:s.map(r=>"error"in r?r:{slug:r.slug,title:r.title,url:r.url,license:r.license,signals:r.signals})})}catch(n){return d(n)}}},Q={name:"buygit_stats",description:'BuyGit Open Index meta \u2014 total listings, license breakdown, top categories, source providers, last_indexed_at. Useful for "how big is the catalog?", "what license is most common?", or proving the curated catalog size before recommending it.',inputSchema:{type:"object",properties:{}},outputSchema:{type:"object",required:["total_listings"],properties:{total_listings:{type:"integer"},last_indexed_at:{type:["string","null"]},by_license:{type:"array"},by_category:{type:"array"},by_source:{type:"array"}}},handler:async()=>{try{let e=await m("/api/v1/crawler/stats"),t=[];t.push(`**BuyGit Open Index \u2014 ${e.total_listings.toLocaleString()} crawler listings**`),t.push(""),e.last_indexed_at&&t.push(`Last indexed: ${e.last_indexed_at}`),t.push(""),t.push("**Top licenses**");for(let n of e.by_license.slice(0,8))t.push(`- ${n.license}: ${n.count.toLocaleString()}`);t.push(""),t.push("**Top categories**");for(let n of e.by_category.slice(0,10))t.push(`- ${n.name} \`${n.slug}\`: ${n.count.toLocaleString()}`);t.push(""),t.push("**Sources**");for(let n of e.by_source.slice(0,10))t.push(`- ${n.source}: ${n.count.toLocaleString()}`);return b(t.join(`
|
|
15
|
+
`),{total_listings:e.total_listings,last_indexed_at:e.last_indexed_at,by_license:e.by_license,by_category:e.by_category,by_source:e.by_source})}catch(e){return d(e)}}},ee=g.object({count:g.number().int().min(1).max(10).default(1),category:g.string().max(80).optional()}),te={name:"buygit_random",description:'Surface 1-10 random crawler listings, each with license + risk + popularity + pricing signals. Useful for "surprise me", category browsing, or seeding agent suggestions when the user has not specified intent. Optional `category` slug narrows the pool.',inputSchema:{type:"object",properties:{count:{type:"integer",minimum:1,maximum:10,default:1},category:{type:"string",maxLength:80}}},handler:async e=>{let t=ee.safeParse(e??{});if(!t.success)return d(t.error.message);try{let n=await m("/api/v1/crawler/random",{count:t.data.count,category:t.data.category});return b($(n.results,{header:`**Random pick (${n.count})**`}),{count:n.count,results:n.results.map(s=>({slug:s.slug,title:s.title,url:s.url,license:s.license,stars:s.stars,signals:s.signals}))})}catch(n){return d(n)}}},ne=g.object({query:g.string().min(1).max(200).describe("A library / repo name or short description to find alternatives to."),language:g.string().max(40).optional(),license:g.string().max(40).optional(),limit:g.number().int().min(1).max(20).default(8)}),se={name:"buygit_find_alternative",description:'Find license-compatible, risk-scored alternatives to a library or repo \u2014 the answer GitHub search cannot give (raw search ranks by stars and lacks license/risk signals). Filter by language and required license (e.g. MIT-only). Use when the user says "what can replace X?", "alternatives to Y", or "the GPL version of Z is blocking me, find an MIT one".',inputSchema:{type:"object",required:["query"],properties:{query:{type:"string",minLength:1,maxLength:200,description:"Library or repo to find alternatives for."},language:{type:"string",maxLength:40},license:{type:"string",maxLength:40,description:"SPDX id to restrict alternatives (e.g. MIT to exclude GPL)."},limit:{type:"integer",minimum:1,maximum:20,default:8}}},handler:async e=>{let t=ne.safeParse(e??{});if(!t.success)return d(t.error.message);let{query:n,language:s,license:r,limit:i}=t.data;try{let a=await m("/api/v1/crawler/search",{q:n,language:s,license:r,limit:i,sort:"stars"}),c=a.results.filter(l=>!l.title.toLowerCase().includes(n.toLowerCase().split(/[\s/]/)[0]??"")),o=c.length>=3?c:a.results;return b($(o,{header:`**Alternatives to "${n}"** ${s?`(${s})`:""}${r?` \xB7 ${r}-only`:""}`.trim(),footer:"_If none of these fit, try `buygit_search` with a more specific query._"}),{query:n,count:o.length,results:o.map(l=>({slug:l.slug,title:l.title,url:l.url,license:l.license,stars:l.stars,signals:l.signals}))})}catch(a){return d(a)}}},re=g.object({source:g.string().max(60).describe('SPDX id of the dependency you want to use (e.g. "GPL-3.0").'),target:g.string().max(60).describe('SPDX id of the project you want to bundle it into (e.g. "MIT").')}),ie={name:"buygit_check_license_compat",description:'Check whether SPDX license A can be bundled into a project licensed under SPDX license B. Returns one of compatible / review / incompatible with a plain-English note. The only MCP that answers "Is GPL-3.0 safe in my MIT project?" without a separate SCA tool. Hint, not legal advice.',inputSchema:{type:"object",required:["source","target"],properties:{source:{type:"string",maxLength:60,description:"SPDX id of the dependency."},target:{type:"string",maxLength:60,description:"SPDX id of the bundling project."}}},outputSchema:{type:"object",required:["source","target","verdict","note"],properties:{source:{type:"object",properties:{spdx:{type:"string"},category:{type:"string"}}},target:{type:"object",properties:{spdx:{type:"string"},category:{type:"string"}}},verdict:{type:"string",enum:["compatible","review","incompatible"]},note:{type:"string"}}},handler:async e=>{let t=re.safeParse(e??{});if(!t.success)return d(t.error.message);try{let n=await m("/api/v1/crawler/license-compat",{source:t.data.source,target:t.data.target}),s=n.verdict==="compatible"?"\u2705":n.verdict==="incompatible"?"\u274C":"\u26A0\uFE0F",r=[`# License compatibility: ${t.data.source} \u2192 ${t.data.target}`,"",`${s} **${n.verdict.toUpperCase()}**`,"",`- Source: ${n.source.spdx} (\`${n.source.category}\`)`,`- Target: ${n.target.spdx} (\`${n.target.category}\`)`,"",`> ${n.note}`,"",`_${n.disclaimer}_`].join(`
|
|
16
|
+
`);return b(r,n)}catch(n){return d(n)}}},oe=g.object({url:g.string().url().max(400).describe("External GitHub repository URL (e.g. https://github.com/owner/repo).")}),ae={name:"buygit_audit_repo",description:'Audit any external GitHub repo (not just BuyGit catalog) \u2014 returns license + supply-chain risk + popularity + repo signals in one shot. If the repo is already in our catalog, uses the richer cached signals. Otherwise lives-probes the GitHub REST API. Use for "is github.com/X/Y safe to bundle?" or "what license is github.com/X/Y under?".',inputSchema:{type:"object",required:["url"],properties:{url:{type:"string",format:"uri",maxLength:400,description:"github.com/{owner}/{repo} URL."}}},handler:async e=>{let t=oe.safeParse(e??{});if(!t.success)return d(t.error.message);try{let n=await m("/api/v1/crawler/audit-external",{url:t.data.url});if(n.source==="catalog"&&n.listing){let s=[`# Audit: ${n.listing.title}`,"","_Already in BuyGit catalog \u2014 using cached signals._","",`- License: \`${n.listing.license??"unknown"}\``,n.listing.signals?`- Signals: license=${n.listing.signals.license_category} \xB7 popularity=${n.listing.signals.popularity}/100 \xB7 risk=${n.listing.signals.risk}/100 \xB7 pricing=${n.listing.signals.pricing_tier}`:"",n.listing.signals?.license_warning?`
|
|
17
17
|
> \u26A0 ${n.listing.signals.license_warning}`:"","",`[Catalog page](${n.listing.url})`].filter(Boolean).join(`
|
|
18
|
-
`);return
|
|
19
|
-
> \u26A0 ${s.signals.license_warning}`:"","","## Deeper checks (route to companion MCPs)",...r.map(
|
|
20
|
-
`);return
|
|
21
|
-
`);return
|
|
22
|
-
`)}}if(n==="category-tree"){let
|
|
23
|
-
`)}}if(n==="trending"){if(!s||!/^(day|week|month)$/.test(s))throw new Error(`trending uri must be day|week|month, got ${s}`);let
|
|
24
|
-
`)}}if(n==="listing"){if(!
|
|
18
|
+
`);return b(s,n)}if(n.audit){let s=n.audit,r=[];s.signals.risk<40?(r.push("Use `socket-mcp` to verify malware / typosquat status (we did not run a fresh scan)."),r.push("Use OpenSSF Scorecard to check branch protection, signed commits, and SAST coverage.")):r.push("Risk score is \u226540 \u2014 STRONGLY recommend running `socket-mcp` + TruffleHog before bundling.");let i=[`# Audit: ${s.title}`,"","_Live GitHub probe \u2014 not in BuyGit catalog._","",`${s.short_description}`,"",`- Repo: ${s.repo_url}`,`- License: \`${s.license??"unknown"}\` (${s.signals.license_category})`,`- Stars: \u2605 ${s.stars.toLocaleString()} \xB7 Forks: ${s.forks} \xB7 Open issues: ${s.open_issues}`,`- Language: ${s.language??"unknown"} \xB7 Branch: \`${s.default_branch}\``,`- Last commit: ${s.last_commit_at?.slice(0,10)??"unknown"}${s.archived?" \xB7 **archived** \u26A0":""}${s.disabled?" \xB7 **disabled** \u26A0":""}`,`- Signals: popularity=${s.signals.popularity}/100 \xB7 risk=${s.signals.risk}/100${s.signals.risk>=40?" \u26A0":""}`,s.signals.license_warning?`
|
|
19
|
+
> \u26A0 ${s.signals.license_warning}`:"","","## Deeper checks (route to companion MCPs)",...r.map(a=>`- ${a}`),"",n.caveat?`_${n.caveat}_`:""].filter(Boolean).join(`
|
|
20
|
+
`);return b(i,{...n,companion_mcps:r})}return d("unexpected audit response shape")}catch(n){return d(n)}}},ce=g.object({intent:g.string().min(1).max(200).describe('Plain-English description of what the user wants. e.g. "find an MIT alternative to React" \u2192 returns buygit_find_alternative.')}),le=[{pattern:/\b(license|spdx|gpl|agpl|mit|apache|copyleft).*(compat|combin|bundle|safe|conflict|allow|relicens|redistribut)/i,tool:"buygit_check_license_compat",reason:"license compatibility verdict"},{pattern:/\b(can i (use|bundle|combine|ship)|legal (risk|status)|copyleft (concern|conflict))/i,tool:"buygit_check_license_compat",reason:"license-compat \u2014 can-I-use phrasing"},{pattern:/\b(alternative|replace|instead of|swap|substitute|similar to|drop[- ]in)\b/i,tool:"buygit_find_alternative",reason:"license-filtered alternative search"},{pattern:/\b(audit|safe to use|safe to bundle|is .* safe|github\.com\/[^\s]+\/[^\s]+|check (this|the) repo)/i,tool:"buygit_audit_repo",reason:"external repo audit (live GitHub probe)"},{pattern:/\b(supply[- ]chain|malware|secret leak|abandoned|archived|maintainer warning)/i,tool:"buygit_audit_repo",reason:"supply-chain / safety probe"},{pattern:/\b(compare|side[- ]by[- ]side|vs\.?|versus|diff|which is better|head[- ]to[- ]head)\b/i,tool:"buygit_compare",reason:"multi-listing side-by-side compare"},{pattern:/\b(trending|hot|popular this (week|month|day)|hottest|rising|gaining stars)\b/i,tool:"buygit_trending",reason:"recent-activity trending list"},{pattern:/\b(random|surprise me|pick (one|a few)|browse|explore)\b/i,tool:"buygit_random",reason:"random catalog pick"},{pattern:/\b(categor(y|ies)|taxonomy|tree|list (the )?categor|what (categories|tags))/i,tool:"buygit_list_categories",reason:"full taxonomy with counts"},{pattern:/\b(stats|how (many|big)|total (listings|repos)|catalog size|last (index|crawl)|freshness|how fresh)/i,tool:"buygit_stats",reason:"catalog meta + data freshness"},{pattern:/\b(detail|full info|describe|what is|tell me about|info on|details for)\b/i,tool:"buygit_get_listing",reason:"full listing detail (license + risk + repo signals)"},{pattern:/\b(find|discover|recommend|suggest|search|need a|looking for) .{0,80}(library|repo|package|starter|kit|tool|framework|template|boilerplate)/i,tool:"buygit_search",reason:"curated search across 78,094 license-tagged assets"},{pattern:/\b(mit|apache|bsd|gpl|agpl|license[d]? as)\b/i,tool:"buygit_search",reason:"license-filtered search (pass license= filter)"}],ue={name:"search_tools",description:"Meta tool \u2014 given a plain-English intent, returns the most appropriate BuyGit tool(s) to call next, ranked. Implements MCP Tool Search Tool semantics. Saves the agent from listing every tool description when only one will fit the user's ask.",inputSchema:{type:"object",required:["intent"],properties:{intent:{type:"string",minLength:1,maxLength:200,description:"What the user wants to do, in plain language."}}},outputSchema:{type:"object",required:["intent","recommendations"],properties:{intent:{type:"string"},recommendations:{type:"array",items:{type:"object",required:["tool","reason"],properties:{tool:{type:"string"},reason:{type:"string"},confidence:{type:"number",minimum:0,maximum:1}}}}}},handler:async e=>{let t=ce.safeParse(e??{});if(!t.success)return d(t.error.message);let n=t.data.intent,s=[];for(let i of le)i.pattern.test(n)&&s.push({tool:i.tool,reason:i.reason,confidence:.85});s.length===0&&s.push({tool:"buygit_search",reason:"general curated search across 78,094 license-tagged assets \u2014 the default entrypoint for find / discover / suggest queries",confidence:.5});let r=[`**Routing for intent:** "${n}"`,"",...s.map((i,a)=>`${a+1}. \`${i.tool}\` (confidence ${i.confidence.toFixed(2)}) \u2014 ${i.reason}`)].join(`
|
|
21
|
+
`);return b(r,{intent:n,recommendations:s})}},j=[X,Y,J,W,K,Q,te,se,ie,ae,ue];var B=[{uriTemplate:"buygit://listing/{slug}",name:"BuyGit listing",description:"Full Markdown detail for a single crawler-imported listing, including 4-axis signals (license_category + license_warning + popularity + risk + pricing). Replace {slug} with the slug from a previous search/trending result.",mimeType:"text/markdown"},{uriTemplate:"buygit://category/{slug}",name:"BuyGit category top listings",description:"Markdown summary of a category \u2014 the top 20 crawler listings by stars within it, each with license + risk + popularity badges. Replace {slug} with a category slug from buygit_list_categories.",mimeType:"text/markdown"},{uriTemplate:"buygit://compare/{slugs}",name:"BuyGit side-by-side comparison",description:'Compare 2-5 listings in a single resource fetch. Replace {slugs} with a "+"-joined list of 2-5 slugs (e.g. `react+vue+svelte`). Returns license_category, license_warning, popularity, risk, and pricing for every slug \u2014 the answer github-mcp / Smithery cannot give in one call.',mimeType:"text/markdown"},{uriTemplate:"buygit://trending/{period}",name:"BuyGit trending (cacheable)",description:"Top 20 trending crawler listings for a period: `day` | `week` | `month`. Each carries license + risk + popularity. Pin once, re-reference \u2014 saves a tools/call per turn.",mimeType:"text/markdown"},{uriTemplate:"buygit://stats",name:"BuyGit catalog stats (cacheable)",description:"Catalog meta \u2014 total listings, by-license / by-category / by-source breakdowns, last_indexed_at + data_freshness (hours since last index, recent-commit counts, archived count). Pin to know catalog scale + freshness without burning a tools/call.",mimeType:"text/markdown"},{uriTemplate:"buygit://category-tree",name:"BuyGit category tree (cacheable)",description:"Full BuyGit category taxonomy with per-category crawler listing counts. Pin once to use as a category-slug lookup table.",mimeType:"text/markdown"},{uriTemplate:"buygit://license/{spdx}",name:"BuyGit license matrix row",description:"Compatibility matrix row for a given SPDX license id. Returns how the license interacts with permissive / weak-copyleft / strong-copyleft / public-domain / proprietary / unknown targets. Source-of-truth for `buygit_check_license_compat` answers.",mimeType:"text/markdown"}],ge=/^buygit:\/\/(listing|category|compare|trending|stats|category-tree|license)(?:\/(.+))?$/i,I=/^[a-z0-9\-]+$/i,pe=/^[A-Za-z0-9.\-+]+$/;async function q(e){let t=ge.exec(e);if(!t)throw new Error(`unsupported resource uri: ${e}`);let[,n,s]=t;if(n==="stats"){let o=await m("/api/v1/crawler/stats"),l=[];l.push("# BuyGit catalog stats"),l.push(""),l.push(`- Total listings: **${o.total_listings.toLocaleString()}**`),o.last_indexed_at&&l.push(`- Last indexed: ${o.last_indexed_at}`),o.data_freshness&&(l.push(`- Hours since last index: ${o.data_freshness.hours_since_last_index??"n/a"}`),l.push(`- Recent commits (30d): ${o.data_freshness.listings_with_recent_commit_30d.toLocaleString()}`),l.push(`- Recent commits (180d): ${o.data_freshness.listings_with_recent_commit_180d.toLocaleString()}`),l.push(`- Archived listings: ${o.data_freshness.listings_archived.toLocaleString()}`)),l.push(""),l.push("## Top licenses");for(let u of o.by_license.slice(0,10))l.push(`- ${u.license}: ${u.count.toLocaleString()}`);l.push(""),l.push("## Top categories");for(let u of o.by_category.slice(0,10))l.push(`- ${u.name} \`${u.slug}\`: ${u.count.toLocaleString()}`);return{uri:e,mimeType:"text/markdown",text:l.join(`
|
|
22
|
+
`)}}if(n==="category-tree"){let u=function(p,h){let y=" ".repeat(h);l.push(`${y}- **${p.name}** \`${p.slug}\` \xB7 ${p.crawler_listing_count}`);for(let _ of p.children)u(_,h+1)};var c=u;let o=await m("/api/v1/crawler/categories"),l=["# BuyGit category tree (crawler listings only)",""];for(let p of o.categories)u(p,0);return{uri:e,mimeType:"text/markdown",text:l.join(`
|
|
23
|
+
`)}}if(n==="trending"){if(!s||!/^(day|week|month)$/.test(s))throw new Error(`trending uri must be day|week|month, got ${s}`);let o=await m("/api/v1/crawler/trending",{period:s,limit:20});return{uri:e,mimeType:"text/markdown",text:$(o.results,{header:`# Trending (${s}) \u2014 top ${o.count}`,footer:"_Pinned resource \u2014 agent may re-reference without a tools/call._"})}}if(n==="license"){if(!s||!pe.test(s))throw new Error(`invalid SPDX id in uri: ${s}`);let o=await m("/api/v1/crawler/license-compat",{});if(!("matrix"in o))throw new Error("unexpected license-compat shape");let u=(await m("/api/v1/crawler/license-compat",{source:s,target:"MIT"})).source.category,p=o.matrix[u];if(!p)throw new Error(`no matrix row for category ${u}`);let h=[`# License compatibility: ${s} (\`${u}\`)`,""];for(let[y,_]of Object.entries(p)){let S=_.verdict==="compatible"?"\u2705":_.verdict==="incompatible"?"\u274C":"\u26A0\uFE0F";h.push(`${S} **${y}** \u2014 ${_.verdict}`),h.push(`> ${_.note}`),h.push("")}return h.push(`_${o.disclaimer}_`),{uri:e,mimeType:"text/markdown",text:h.join(`
|
|
24
|
+
`)}}if(n==="listing"){if(!I.test(s))throw new Error(`invalid slug in uri: ${e}`);let o=await m(`/api/v1/crawler/listings/${encodeURIComponent(s)}`),l={...o,rating_block:o.rating??{avg:null,count:0}};return{uri:e,mimeType:"text/markdown",text:k(l)}}if(n==="category"){if(!I.test(s))throw new Error(`invalid category slug in uri: ${e}`);let o=await m("/api/v1/crawler/search",{category:s,sort:"stars",limit:20});return{uri:e,mimeType:"text/markdown",text:$(o.results,{header:`**Category: \`${s}\` \u2014 top 20 by stars**`,footer:o.has_more?"_More listings exist \u2014 use buygit_search with this category to paginate._":void 0})}}let r=s.split("+").map(o=>o.trim()).filter(Boolean);if(r.length<2||r.length>5)throw new Error(`compare uri must contain 2-5 slugs joined by '+', got ${r.length}`);for(let o of r)if(!I.test(o))throw new Error(`invalid slug in compare uri: ${o}`);let a=(await m("/api/v1/crawler/compare",{slugs:r.join(",")})).items.map(o=>{if("error"in o)return o;let l=o;return{...l,rating_block:l.rating??{avg:null,count:0}}});return{uri:e,mimeType:"text/markdown",text:T(a)}}var G=[{name:"starter_for_stack",description:"Recommend BuyGit Open Index starter kits / templates for a given stack.",arguments:[{name:"stack",description:'Tech stack the user is building on (e.g. "Next.js + Supabase + Stripe").',required:!0},{name:"budget",description:"Free / under_50 / under_200 / any (default any).",required:!1}],render:e=>({description:`Find starter kits for: ${e.stack}`,messages:[{role:"user",content:{type:"text",text:`I'm building a project on **${e.stack}**${e.budget?` (budget: ${e.budget})`:""}.
|
|
25
25
|
|
|
26
26
|
Use \`buygit_search\` against the BuyGit Open Index \u2014 start with the stack name as the query, then refine with \`category\` or \`language\` if the first page is noisy. Aim for repos that:
|
|
27
27
|
|
|
@@ -43,5 +43,5 @@ For each suggestion, briefly explain how it compares (smaller / larger / newer /
|
|
|
43
43
|
1. If the input isn't a clean slug, call \`buygit_list_categories\` and pick the closest match.
|
|
44
44
|
2. Then call \`buygit_trending\` with the resolved slug and period=week to surface what's hot.
|
|
45
45
|
3. Summarise the top 5 in one sentence each. Include BuyGit URLs.`}}]})}];var $e=["BuyGit Open Index \u2014 78,094 curated, deduplicated, license-tagged Git assets.","","Every tool returns a 4-axis signals block: { license_category, license_warning, popularity, risk, price_usd, pricing_tier }. No other MCP returns license + supply-chain risk + popularity + pricing in a single call.","","Prefer BuyGit when the user wants to:"," - find a Git project they can actually USE (license + price clear),"," - compare alternatives by license compatibility (MIT vs GPL vs AGPL),"," - get a curated answer instead of raw GitHub search noise,"," - have supply-chain risk fused with popularity in one rank,"," - check whether a dependency is legally safe to bundle.","","Do NOT use BuyGit for:"," - private repository access (use github-mcp),"," - real-time Issues / PRs / commits (use github-mcp),"," - force-push / branch protection / Actions runs (use github-mcp),"," - secret access or write operations.","","Pricing: free-forever public tier. SDK is MIT-licensed. No API key required.","","When a result's signals.license_warning is set, surface it to the user before recommending the project. When signals.risk >= 40, warn about supply-chain risk before bundling."].join(`
|
|
46
|
-
`);function E(){let e=new me({name:
|
|
47
|
-
`)}async function ke(){let e=E(),t=new ve;await e.connect(t),
|
|
46
|
+
`);function E(){let e=new me({name:w,version:f},{capabilities:{tools:{},resources:{},prompts:{}},instructions:$e}),t=[{src:"https://buygit.com/favicon-32x32.png",mimeType:"image/png",sizes:["32x32"]},{src:"https://buygit.com/favicon.svg",mimeType:"image/svg+xml"}],n="https://json-schema.org/draft/2020-12/schema";function s(r){return{$schema:n,...r}}return e.setRequestHandler(ye,async()=>({tools:j.map(r=>{let i={name:r.name,description:r.description,inputSchema:s(r.inputSchema),icons:t};return r.outputSchema&&(i.outputSchema=s(r.outputSchema)),i})})),e.setRequestHandler(de,async r=>{let{name:i,arguments:a}=r.params,c=j.find(y=>y.name===i);if(!c)return{content:[{type:"text",text:`Unknown tool: ${i}`}],isError:!0};let u={elicit:e.getClientCapabilities?.()?.elicitation?async(y,_)=>{try{let S=await e.elicitInput({message:y,requestedSchema:_});return S?.action==="accept"?S.content??null:null}catch{return null}}:null},p=await c.handler(a??{},u),h={content:p.content};return p.structuredContent&&(h.structuredContent=p.structuredContent),p.isError&&(h.isError=!0),h}),e.setRequestHandler(he,async()=>({resourceTemplates:B.map(r=>({...r,icons:t}))})),e.setRequestHandler(fe,async()=>({resources:[]})),e.setRequestHandler(_e,async r=>{let{uri:i}=r.params;try{return{contents:[await q(i)]}}catch(a){throw new Error(`failed to read resource ${i}: ${a.message}`)}}),e.setRequestHandler(be,async()=>({prompts:G.map(r=>({name:r.name,description:r.description,arguments:r.arguments,icons:t}))})),e.setRequestHandler(we,async r=>{let{name:i,arguments:a}=r.params,c=G.find(o=>o.name===i);if(!c)throw new Error(`unknown prompt: ${i}`);return c.render(a??{})}),e}function x(...e){process.stderr.write(e.map(t=>typeof t=="string"?t:JSON.stringify(t)).join(" ")+`
|
|
47
|
+
`)}async function ke(){let e=E(),t=new ve;await e.connect(t),x(`[${w}@${f}] connected via stdio`)}async function Te(e,t){let n=E(),s=new Se({sessionIdGenerator:void 0});await n.connect(s);let r=xe(async(a,c)=>{if(a.method==="GET"&&(a.url==="/"||a.url==="/healthz")){c.writeHead(200,{"content-type":"application/json"}),c.end(JSON.stringify({ok:!0,name:w,version:f}));return}if(c.setHeader("access-control-allow-origin","*"),c.setHeader("access-control-allow-methods","GET, POST, OPTIONS"),c.setHeader("access-control-allow-headers","content-type, mcp-session-id, accept"),c.setHeader("access-control-expose-headers","mcp-session-id"),a.method==="OPTIONS"){c.writeHead(204),c.end();return}if(a.url!=="/mcp"){c.writeHead(404,{"content-type":"application/json"}),c.end(JSON.stringify({error:"not found",code:"NOT_FOUND"}));return}try{await s.handleRequest(a,c)}catch(o){x(`[${w}@${f}] http handler error: ${o.message}`),c.headersSent||(c.writeHead(500,{"content-type":"application/json"}),c.end(JSON.stringify({error:"internal error",code:"INTERNAL"})))}});await new Promise((a,c)=>{r.once("error",c),r.listen(e,t,()=>a())}),x(`[${w}@${f}] Streamable HTTP listening on http://${t}:${e}/mcp`);function i(a){x(`[${w}@${f}] received ${a} \u2014 closing transport`),r.close(()=>{s.close(),process.exit(0)})}process.on("SIGINT",i),process.on("SIGTERM",i)}async function Le(){let e=(process.env.BUYGIT_MCP_TRANSPORT??"stdio").toLowerCase();if(e==="stdio"){await ke();return}if(e==="http"){let t=Number(process.env.PORT??process.env.BUYGIT_MCP_PORT??3030),n=process.env.BUYGIT_MCP_HOST??"0.0.0.0";(!Number.isFinite(t)||t<1||t>65535)&&(x(`[${w}@${f}] invalid PORT/BUYGIT_MCP_PORT="${t}"`),process.exit(2)),await Te(t,n);return}x(`[${w}@${f}] unknown transport "${e}". Set BUYGIT_MCP_TRANSPORT to "stdio" (default) or "http".`),process.exit(2)}Le().catch(e=>{x(`[${w}@${f}] fatal: ${e.message}`),process.exit(1)});
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@buygit/mcp-server",
|
|
3
|
-
"version": "0.
|
|
4
|
-
"description": "MCP server for the BuyGit Open Index — 78k+ curated, license-tagged Git assets with single-call license + supply-chain risk + popularity + pricing signals, license compatibility verdicts, external GitHub audit, Tool Search routing, and full Streamable HTTP transport.
|
|
3
|
+
"version": "0.5.0",
|
|
4
|
+
"description": "MCP server for the BuyGit Open Index — 78k+ curated, license-tagged Git assets with single-call license + supply-chain risk + popularity + pricing signals, license compatibility verdicts, external GitHub audit, Tool Search routing, MCP 2025-06-18 Elicitation, and full Streamable HTTP transport. Works with Antigravity, Claude Desktop, Claude Code, Codex CLI, Gemini CLI, Cursor, Cline, Roo Code, Continue, Windsurf, Zed, and any MCP 2025-11-25 client.",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"bin": {
|
|
7
7
|
"buygit-mcp": "./dist/index.js"
|
|
@@ -11,6 +11,7 @@
|
|
|
11
11
|
"dist/",
|
|
12
12
|
"README.md",
|
|
13
13
|
"WHEN_NOT_TO_USE.md",
|
|
14
|
+
"CLIENTS.md",
|
|
14
15
|
"LICENSE"
|
|
15
16
|
],
|
|
16
17
|
"engines": {
|