@buygit/mcp-server 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/LICENSE +21 -0
- package/README.md +158 -0
- package/dist/index.js +37 -0
- package/package.json +68 -0
package/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 BuyGit / Genox
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
package/README.md
ADDED
|
@@ -0,0 +1,158 @@
|
|
|
1
|
+
# @buygit/mcp-server
|
|
2
|
+
|
|
3
|
+
MCP server exposing the **BuyGit Open Index** — 76,000+ verified Git projects from GitHub, Codeberg, WordPress, npm, HuggingFace and more — to Claude Desktop, Cursor, Cline, Continue, and any other MCP-capable client.
|
|
4
|
+
|
|
5
|
+
> Search, compare, and audit production-ready repositories without leaving your IDE.
|
|
6
|
+
|
|
7
|
+
[](https://www.npmjs.com/package/@buygit/mcp-server)
|
|
8
|
+
[](https://github.com/genoxdeveloper/Buygit/blob/main/packages/mcp-server/LICENSE)
|
|
9
|
+
|
|
10
|
+
## What you get
|
|
11
|
+
|
|
12
|
+
8 tools, 2 resource templates, 4 prompts — all backed by the public read-only [BuyGit Open Index API](https://buygit.com/api/v1/crawler/openapi.json).
|
|
13
|
+
|
|
14
|
+
| Tool | What it does |
|
|
15
|
+
|---|---|
|
|
16
|
+
| `buygit_search` | Free text + filters (category, language, license, min_stars) + 4 sort modes |
|
|
17
|
+
| `buygit_get_listing` | Full detail for one slug — repo signals, safety signals, similar listings |
|
|
18
|
+
| `buygit_list_categories` | The full taxonomy with crawler-listing counts per branch |
|
|
19
|
+
| `buygit_trending` | Top-N by recent activity within day / week / month |
|
|
20
|
+
| `buygit_compare` | Side-by-side detail for 2-5 slugs |
|
|
21
|
+
| `buygit_stats` | Catalog meta — totals by license / category / source |
|
|
22
|
+
| `buygit_random` | Surprise me — 1-10 random picks, optional category filter |
|
|
23
|
+
| `buygit_find_alternative` | Conceptual alternatives to a given library or repo |
|
|
24
|
+
|
|
25
|
+
Resources let you @-mention a listing or category and have the full Markdown attached to the conversation:
|
|
26
|
+
- `buygit://listing/{slug}`
|
|
27
|
+
- `buygit://category/{slug}`
|
|
28
|
+
|
|
29
|
+
Prompts (slash-menu in Claude Desktop):
|
|
30
|
+
- `starter_for_stack` — "Find me a starter kit for {stack}"
|
|
31
|
+
- `alternative_to` — "Alternatives to {repo}"
|
|
32
|
+
- `audit_my_dependency` — "Is {slug} safe to ship?"
|
|
33
|
+
- `explore_category` — "What's hot in {category}?"
|
|
34
|
+
|
|
35
|
+
## Install
|
|
36
|
+
|
|
37
|
+
### Claude Desktop
|
|
38
|
+
|
|
39
|
+
Edit `~/Library/Application Support/Claude/claude_desktop_config.json` on macOS or `%APPDATA%\Claude\claude_desktop_config.json` on Windows:
|
|
40
|
+
|
|
41
|
+
```jsonc
|
|
42
|
+
{
|
|
43
|
+
"mcpServers": {
|
|
44
|
+
"buygit": {
|
|
45
|
+
"command": "npx",
|
|
46
|
+
"args": ["-y", "@buygit/mcp-server@latest"]
|
|
47
|
+
}
|
|
48
|
+
}
|
|
49
|
+
}
|
|
50
|
+
```
|
|
51
|
+
|
|
52
|
+
Restart Claude Desktop. The first tool call may take a few seconds while `npx` resolves the package.
|
|
53
|
+
|
|
54
|
+
### Cursor
|
|
55
|
+
|
|
56
|
+
Edit `~/.cursor/mcp.json`:
|
|
57
|
+
|
|
58
|
+
```jsonc
|
|
59
|
+
{
|
|
60
|
+
"mcpServers": {
|
|
61
|
+
"buygit": {
|
|
62
|
+
"command": "npx",
|
|
63
|
+
"args": ["-y", "@buygit/mcp-server@latest"]
|
|
64
|
+
}
|
|
65
|
+
}
|
|
66
|
+
}
|
|
67
|
+
```
|
|
68
|
+
|
|
69
|
+
### Cline (VS Code extension)
|
|
70
|
+
|
|
71
|
+
Open the Cline MCP settings (`Cline: Open MCP Servers` from the command palette) and add:
|
|
72
|
+
|
|
73
|
+
```jsonc
|
|
74
|
+
{
|
|
75
|
+
"buygit": {
|
|
76
|
+
"command": "npx",
|
|
77
|
+
"args": ["-y", "@buygit/mcp-server@latest"]
|
|
78
|
+
}
|
|
79
|
+
}
|
|
80
|
+
```
|
|
81
|
+
|
|
82
|
+
### Continue
|
|
83
|
+
|
|
84
|
+
Continue picks up MCP servers from `~/.continue/config.json`:
|
|
85
|
+
|
|
86
|
+
```jsonc
|
|
87
|
+
{
|
|
88
|
+
"mcpServers": {
|
|
89
|
+
"buygit": {
|
|
90
|
+
"command": "npx",
|
|
91
|
+
"args": ["-y", "@buygit/mcp-server@latest"]
|
|
92
|
+
}
|
|
93
|
+
}
|
|
94
|
+
}
|
|
95
|
+
```
|
|
96
|
+
|
|
97
|
+
### Self-hosted via Docker
|
|
98
|
+
|
|
99
|
+
```bash
|
|
100
|
+
docker run -i --rm ghcr.io/buygit/mcp-server:latest
|
|
101
|
+
```
|
|
102
|
+
|
|
103
|
+
The container runs stdio MCP. Pipe stdin/stdout from your client.
|
|
104
|
+
|
|
105
|
+
## Try it
|
|
106
|
+
|
|
107
|
+
After you've added the config and restarted your client, ask:
|
|
108
|
+
|
|
109
|
+
- _"Find me a Next.js SaaS starter under MIT with more than 500 stars."_
|
|
110
|
+
- _"What's trending in AI agents this week on BuyGit?"_
|
|
111
|
+
- _"Tell me about `next-saas-starter-pro` — is the secret scan clean?"_
|
|
112
|
+
- _"Compare `react-saas-template` and `nextjs-stripe-starter`."_
|
|
113
|
+
|
|
114
|
+
The model will call the right tools, attach the canonical BuyGit links, and let you click through.
|
|
115
|
+
|
|
116
|
+
## Configuration
|
|
117
|
+
|
|
118
|
+
| Env var | Default | Purpose |
|
|
119
|
+
|---|---|---|
|
|
120
|
+
| `BUYGIT_API_BASE` | `https://buygit.com` | Override for staging / self-hosted mirror |
|
|
121
|
+
| `BUYGIT_MCP_TRANSPORT` | `stdio` | `stdio` (default, all clients) · `http` (Phase 4) |
|
|
122
|
+
|
|
123
|
+
## Privacy & licensing
|
|
124
|
+
|
|
125
|
+
The BuyGit Open Index API is **public, read-only, no auth**. There is no key to install. Requests are not personally identifiable (the server doesn't log the queries you make).
|
|
126
|
+
|
|
127
|
+
The catalog excludes seller-curated listings — only crawler-imported public-repo metadata is exposed. Each result includes a `url` field linking back to the canonical BuyGit page; please surface that link when redistributing.
|
|
128
|
+
|
|
129
|
+
This package is MIT licensed. The API responses are licensed for indexing + attribution per the [BuyGit API terms](https://buygit.com/api-docs/crawler).
|
|
130
|
+
|
|
131
|
+
## Links
|
|
132
|
+
|
|
133
|
+
- BuyGit MCP landing page: <https://buygit.com/mcp>
|
|
134
|
+
- OpenAPI 3.1 spec: <https://buygit.com/api/v1/crawler/openapi.json>
|
|
135
|
+
- Source: <https://github.com/genoxdeveloper/Buygit/tree/main/packages/mcp-server>
|
|
136
|
+
- Issues: <https://github.com/genoxdeveloper/Buygit/issues>
|
|
137
|
+
|
|
138
|
+
## Develop
|
|
139
|
+
|
|
140
|
+
```bash
|
|
141
|
+
cd packages/mcp-server
|
|
142
|
+
pnpm install
|
|
143
|
+
pnpm build
|
|
144
|
+
node dist/index.js # connects on stdio — feed it MCP JSON-RPC over stdin
|
|
145
|
+
```
|
|
146
|
+
|
|
147
|
+
Or run the watch build while developing:
|
|
148
|
+
|
|
149
|
+
```bash
|
|
150
|
+
pnpm dev
|
|
151
|
+
```
|
|
152
|
+
|
|
153
|
+
To smoke-test against the live API:
|
|
154
|
+
|
|
155
|
+
```bash
|
|
156
|
+
BUYGIT_API_BASE=https://buygit.com node dist/index.js
|
|
157
|
+
# then in another process, send a `tools/list` JSON-RPC frame
|
|
158
|
+
```
|
package/dist/index.js
ADDED
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
import{StdioServerTransport as ae}from"@modelcontextprotocol/sdk/server/stdio.js";import{Server as Q}from"@modelcontextprotocol/sdk/server/index.js";import{CallToolRequestSchema as Z,ListToolsRequestSchema as ee,ListResourceTemplatesRequestSchema as te,ListResourcesRequestSchema as re,ReadResourceRequestSchema as ne,ListPromptsRequestSchema as se,GetPromptRequestSchema as ie}from"@modelcontextprotocol/sdk/types.js";import{z as a}from"zod";import{request as E,Pool as I}from"undici";var d="0.1.0",f="@buygit/mcp-server";var A=process.env.BUYGIT_API_BASE||"https://buygit.com",j=`@buygit/mcp-server/${d} (+https://buygit.com/mcp)`,$=null;function G(e){return $===null&&($=new I(e,{connections:4,keepAliveTimeout:6e4,keepAliveMaxTimeout:6e5})),$}var b=class extends Error{constructor(r,n,s){super(r);this.status=n;this.code=s;this.name="BuygitApiError"}status;code};async function u(e,t={},r={}){let s=G(A),i=Object.entries(t).filter(([,h])=>h!=null&&h!=="").map(([h,B])=>`${encodeURIComponent(h)}=${encodeURIComponent(String(B))}`).join("&"),o=i?`${e}?${i}`:e,g=await E(o,{method:"GET",headers:{"user-agent":j,accept:"application/json"},headersTimeout:r.timeoutMs??12e3,bodyTimeout:r.timeoutMs??12e3,dispatcher:s}),c=g.statusCode,p=await g.body.text(),m=null;try{m=JSON.parse(p)}catch{throw new b(`upstream returned non-JSON (status ${c})`,c)}if(c>=400||m.ok===!1)throw new b(m.error??`upstream returned HTTP ${c}`,c,m.code);return m.data!==void 0?m.data:m}function S(e){return e>=1e3?`${(e/1e3).toFixed(1)}k`:String(e)}function T(e){return e.filter(t=>!!(t&&t.length>0)).join(" \xB7 ")}function O(e,t){let r=t!==void 0?`${t}. **${e.title}**`:`**${e.title}**`,n=T([e.stars>0?`\u2605\xA0${S(e.stars)}`:null,e.license||null,e.language||null,e.category?e.category.name:null]);return[r,n?` ${n}`:null,` ${e.short_description}`,` ${e.url}`].filter(s=>s!==null).join(`
|
|
3
|
+
`)}function _(e,t){let r=t?.header?`${t.header}
|
|
4
|
+
|
|
5
|
+
`:"",n=t?.footer?`
|
|
6
|
+
|
|
7
|
+
${t.footer}`:"";return e.length===0?`${r}_No results._${n}`:r+e.map((s,i)=>O(s,i+1)).join(`
|
|
8
|
+
|
|
9
|
+
`)+n}function w(e){let t=[];t.push(`# ${e.title}`),t.push(""),t.push(T([e.repo_signals.stars>0?`\u2605 ${S(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(s=>`\`${s}\``).join(" ")}`),t.push(""));let r=[];e.safety_signals.secret_scan==="clean"?r.push("secret-scan: clean \u2713"):e.safety_signals.secret_scan==="flagged"?r.push("secret-scan: **flagged** \u26A0"):r.push("secret-scan: not run"),e.safety_signals.malware_flag&&r.push("**malware flag set** \u26A0"),e.repo_signals.upstream_status==="removed"&&r.push("**upstream removed** \u26A0"),t.push(`**Safety:** ${r.join(" \xB7 ")}`),t.push("");let n=[];if(e.repo_signals.repo_url&&n.push(`repo: ${e.repo_signals.repo_url}`),e.repo_signals.default_branch&&n.push(`branch: \`${e.repo_signals.default_branch}\``),e.repo_signals.last_commit_at&&n.push(`last commit: ${e.repo_signals.last_commit_at.slice(0,10)}`),e.repo_signals.good_first_issues>0&&n.push(`good-first-issues: ${e.repo_signals.good_first_issues}`),n.length>0&&(t.push(`**Repo:** ${n.join(" \xB7 ")}`),t.push("")),e.full_description_md&&e.full_description_md.trim().length>0){let s=e.full_description_md.slice(0,1200);t.push("## Description"),t.push(s+(e.full_description_md.length>1200?`
|
|
10
|
+
|
|
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 s of e.similar.slice(0,5))t.push(`- **${s.title}** \xB7 ${s.url}`)}return t.join(`
|
|
12
|
+
`)}function R(e){let t=["# Side-by-side comparison",""];for(let r of e){if("error"in r){t.push(`## \`${r.slug}\``),t.push("_not found in the crawler index_"),t.push("");continue}t.push(`## ${r.title}`),t.push(T([r.repo_signals.stars>0?`\u2605 ${S(r.repo_signals.stars)}`:null,r.license,r.repo_signals.language,r.category?.name??null])),t.push(""),t.push(r.short_description),t.push(""),t.push(`\u2192 ${r.url}`),t.push("")}return t.join(`
|
|
13
|
+
`)}function y(e){return{content:[{type:"text",text:e}]}}function l(e){return{content:[{type:"text",text:e instanceof b?`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 D=a.object({query:a.string().max(200).optional(),category:a.string().max(80).optional(),language:a.string().max(40).optional(),license:a.string().max(40).optional(),min_stars:a.number().int().min(0).optional(),limit:a.number().int().min(1).max(50).default(10),sort:a.enum(["relevance","newest","stars","health"]).default("relevance")}),C={name:"buygit_search",description:'Search the BuyGit Open Index (76k+ crawler-imported Git projects). Supports free-text query plus filters (category slug, language, SPDX license, min stars) and four sort modes (relevance / newest / stars / health). Returns up to 50 compact Markdown summaries, each with a canonical BuyGit URL the user can click. Use this first when the user asks "find me a repo for ...".',inputSchema:{type:"object",properties:{query:{type:"string",maxLength:200,description:"Free text query."},category:{type:"string",maxLength:80,description:"Category slug."},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"}}},handler:async e=>{let t=D.safeParse(e??{});if(!t.success)return l(`invalid arguments: ${t.error.message}`);let{query:r,category:n,language:s,license:i,min_stars:o,limit:g,sort:c}=t.data;try{let p=await u("/api/v1/crawler/search",{q:r,category:n,language:s,license:i,min_stars:o,limit:g,sort:c}),m=[`**${p.results.length} result(s)**`,r?`for "${r}"`:null,n?`\xB7 category: ${n}`:null,s?`\xB7 lang: ${s}`:null,i?`\xB7 license: ${i}`:null,o?`\xB7 \u2265${o}\u2605`:null,`\xB7 sort: ${c}`].filter(Boolean).join(" "),h=p.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 y(_(p.results,{header:m,footer:h}))}catch(p){return l(p)}}},U=a.object({slug:a.string().regex(/^[a-z0-9\-]+$/i).max(200)}),M={name:"buygit_get_listing",description:"Retrieve the full BuyGit Open Index detail for one listing by slug. Includes safety signals (secret scan status, malware flag, upstream health), repo signals (stars, forks, language, last commit), license + attribution, and up to 5 similar listings. Slug must come from a previous 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."}}},handler:async e=>{let t=U.safeParse(e??{});if(!t.success)return l(`invalid slug: ${t.error.message}`);try{let r=await u(`/api/v1/crawler/listings/${encodeURIComponent(t.data.slug)}`),n={...r,rating_block:r.rating??{avg:null,count:0}};return y(w(n))}catch(r){return l(r)}}},N={name:"buygit_list_categories",description:"List the BuyGit Open Index category taxonomy. Each node carries the count of crawler listings in that branch \u2014 useful for narrowing a search or picking a category slug for `buygit_search`.",inputSchema:{type:"object",properties:{}},handler:async()=>{try{let n=function(s,i){let o=" ".repeat(i);r.push(`${o}- **${s.name}** \`${s.slug}\` \xB7 ${s.crawler_listing_count}`);for(let g of s.children)n(g,i+1)};var e=n;let t=await u("/api/v1/crawler/categories"),r=["**BuyGit category tree** (crawler listings only)",""];for(let s of t.categories)n(s,0);return r.push(""),r.push("_Pick a slug and pass it as `category` to `buygit_search` to filter._"),y(r.join(`
|
|
14
|
+
`))}catch(t){return l(t)}}},F=a.object({period:a.enum(["day","week","month"]).default("week"),category:a.string().max(80).optional(),limit:a.number().int().min(1).max(50).default(10)}),H={name:"buygit_trending",description:"Top crawler listings by recent repository activity within a period (day / week / month). Optionally narrow to a single category. Ranked primarily by current stars among recently-committed repos.",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}}},handler:async e=>{let t=F.safeParse(e??{});if(!t.success)return l(t.error.message);let{period:r,category:n,limit:s}=t.data;try{let i=await u("/api/v1/crawler/trending",{period:r,category:n,limit:s}),o=`**Trending (${r}${n?` \xB7 ${n}`:""})** \u2014 ${i.count} listing(s)`;return y(_(i.results,{header:o,footer:"_Call buygit_get_listing(slug) for full detail._"}))}catch(i){return l(i)}}},z=a.object({slugs:a.array(a.string().regex(/^[a-z0-9\-]+$/i)).min(2).max(5)}),Y={name:"buygit_compare",description:"Side-by-side comparison of 2-5 crawler listings. Pass slugs you got from a previous tool call. Slugs that don't exist appear as `not found` entries.",inputSchema:{type:"object",required:["slugs"],properties:{slugs:{type:"array",items:{type:"string",pattern:"^[a-z0-9\\-]+$"},minItems:2,maxItems:5}}},handler:async e=>{let t=z.safeParse(e??{});if(!t.success)return l(t.error.message);try{let n=(await u("/api/v1/crawler/compare",{slugs:t.data.slugs.join(",")})).items.map(s=>{if("error"in s)return s;let i=s;return{...i,rating_block:i.rating??{avg:null,count:0}}});return y(R(n))}catch(r){return l(r)}}},V={name:"buygit_stats",description:'BuyGit Open Index meta \u2014 total listings, breakdown by license / category / source, last_indexed_at. Useful for "how big is the catalog?" questions.',inputSchema:{type:"object",properties:{}},handler:async()=>{try{let e=await u("/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 r of e.by_license.slice(0,8))t.push(`- ${r.license}: ${r.count.toLocaleString()}`);t.push(""),t.push("**Top categories**");for(let r of e.by_category.slice(0,10))t.push(`- ${r.name} \`${r.slug}\`: ${r.count.toLocaleString()}`);t.push(""),t.push("**Sources**");for(let r of e.by_source.slice(0,10))t.push(`- ${r.source}: ${r.count.toLocaleString()}`);return y(t.join(`
|
|
15
|
+
`))}catch(e){return l(e)}}},J=a.object({count:a.number().int().min(1).max(10).default(1),category:a.string().max(80).optional()}),X={name:"buygit_random",description:'Surface 1-10 random crawler listings \u2014 useful for "surprise me" prompts or browsing a category casually. 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=J.safeParse(e??{});if(!t.success)return l(t.error.message);try{let r=await u("/api/v1/crawler/random",{count:t.data.count,category:t.data.category});return y(_(r.results,{header:`**Random pick (${r.count})**`}))}catch(r){return l(r)}}},W=a.object({query:a.string().min(1).max(200).describe("A library / repo name or short description of what you want an alternative to."),language:a.string().max(40).optional(),license:a.string().max(40).optional(),limit:a.number().int().min(1).max(20).default(8)}),K={name:"buygit_find_alternative",description:'Find BuyGit Open Index listings that are conceptual alternatives to a library, repo, or short description. Wraps `buygit_search` with sensible defaults (sort by stars, exclude the input name from matches if obvious). Use when the user says "what can replace X?" or "alternatives to Y?".',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},limit:{type:"integer",minimum:1,maximum:20,default:8}}},handler:async e=>{let t=W.safeParse(e??{});if(!t.success)return l(t.error.message);let{query:r,language:n,license:s,limit:i}=t.data;try{let o=await u("/api/v1/crawler/search",{q:r,language:n,license:s,limit:i,sort:"stars"}),g=o.results.filter(p=>!p.title.toLowerCase().includes(r.toLowerCase().split(/[\s/]/)[0]??"")),c=g.length>=3?g:o.results;return y(_(c,{header:`**Alternatives to "${r}"** ${n?`(${n})`:""}`.trim(),footer:"_If none of these fit, try `buygit_search` with a more specific query._"}))}catch(o){return l(o)}}},L=[C,M,N,H,Y,V,X,K];var k=[{uriTemplate:"buygit://listing/{slug}",name:"BuyGit listing",description:"Full Markdown detail for a single crawler-imported listing. 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. Replace {slug} with a category slug from buygit_list_categories.",mimeType:"text/markdown"}];async function P(e){let t=/^buygit:\/\/(listing|category)\/([a-z0-9\-]+)$/i.exec(e);if(!t)throw new Error(`unsupported resource uri: ${e}`);let[,r,n]=t;if(r==="listing"){let i=await u(`/api/v1/crawler/listings/${encodeURIComponent(n)}`),o={...i,rating_block:i.rating??{avg:null,count:0}};return{uri:e,mimeType:"text/markdown",text:w(o)}}let s=await u("/api/v1/crawler/search",{category:n,sort:"stars",limit:20});return{uri:e,mimeType:"text/markdown",text:_(s.results,{header:`**Category: \`${n}\` \u2014 top 20 by stars**`,footer:s.has_more?"_More listings exist \u2014 use buygit_search with this category to paginate._":void 0})}}var v=[{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})`:""}.
|
|
16
|
+
|
|
17
|
+
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:
|
|
18
|
+
|
|
19
|
+
1. Match the stack closely (not "kind of related").
|
|
20
|
+
2. Are actively maintained \u2014 check \`last_commit_at\` in the result.
|
|
21
|
+
3. Have a permissive license (MIT / Apache-2.0).
|
|
22
|
+
|
|
23
|
+
Recommend the top 3-5 with one sentence each on why they fit. Always include the BuyGit listing URL.`}}]})},{name:"alternative_to",description:"Find BuyGit Open Index alternatives to a known library or repo.",arguments:[{name:"target",description:"Library or repo URL to find alternatives for.",required:!0}],render:e=>({description:`Find alternatives to ${e.target}`,messages:[{role:"user",content:{type:"text",text:`Find alternatives to **${e.target}** in the BuyGit Open Index.
|
|
24
|
+
|
|
25
|
+
Use \`buygit_find_alternative\` with the target name as the query. If the result list looks weak, fall back to \`buygit_search\` with the same query and sort=stars.
|
|
26
|
+
|
|
27
|
+
For each suggestion, briefly explain how it compares (smaller / larger / newer / older / different license / different language).`}}]})},{name:"audit_my_dependency",description:"Pull the safety signals (secret scan, malware flag, upstream status, license) for a BuyGit-indexed repo.",arguments:[{name:"slug_or_url",description:"BuyGit slug or canonical buygit.com/asset/* URL.",required:!0}],render:e=>({description:`Audit ${e.slug_or_url}`,messages:[{role:"user",content:{type:"text",text:`Audit this BuyGit-indexed dependency: **${e.slug_or_url}**.
|
|
28
|
+
|
|
29
|
+
1. Extract the slug (last path segment if a URL was given).
|
|
30
|
+
2. Call \`buygit_get_listing(slug)\`.
|
|
31
|
+
3. Surface the safety_signals block (secret scan, malware flag, upstream status) clearly. Flag anything that's not "clean" in plain English.
|
|
32
|
+
4. Note the license and whether it's compatible with a typical commercial closed-source project.`}}]})},{name:"explore_category",description:"Browse the top crawler listings in a BuyGit category.",arguments:[{name:"category",description:"Category slug or partial name. Use buygit_list_categories first if unsure.",required:!0}],render:e=>({description:`Explore category: ${e.category}`,messages:[{role:"user",content:{type:"text",text:`Show me what's in the BuyGit category **${e.category}**.
|
|
33
|
+
|
|
34
|
+
1. If the input isn't a clean slug, call \`buygit_list_categories\` and pick the closest match.
|
|
35
|
+
2. Then call \`buygit_trending\` with the resolved slug and period=week to surface what's hot.
|
|
36
|
+
3. Summarise the top 5 in one sentence each. Include BuyGit URLs.`}}]})}];function q(){let e=new Q({name:f,version:d},{capabilities:{tools:{},resources:{},prompts:{}}});return e.setRequestHandler(ee,async()=>({tools:L.map(t=>({name:t.name,description:t.description,inputSchema:t.inputSchema}))})),e.setRequestHandler(Z,async t=>{let{name:r,arguments:n}=t.params,s=L.find(i=>i.name===r);return s?s.handler(n??{}):{content:[{type:"text",text:`Unknown tool: ${r}`}],isError:!0}}),e.setRequestHandler(te,async()=>({resourceTemplates:k})),e.setRequestHandler(re,async()=>({resources:[]})),e.setRequestHandler(ne,async t=>{let{uri:r}=t.params;try{return{contents:[await P(r)]}}catch(n){throw new Error(`failed to read resource ${r}: ${n.message}`)}}),e.setRequestHandler(se,async()=>({prompts:v.map(t=>({name:t.name,description:t.description,arguments:t.arguments}))})),e.setRequestHandler(ie,async t=>{let{name:r,arguments:n}=t.params,s=v.find(i=>i.name===r);if(!s)throw new Error(`unknown prompt: ${r}`);return s.render(n??{})}),e}function x(...e){process.stderr.write(e.map(t=>typeof t=="string"?t:JSON.stringify(t)).join(" ")+`
|
|
37
|
+
`)}async function oe(){let e=(process.env.BUYGIT_MCP_TRANSPORT??"stdio").toLowerCase(),t=q();if(e==="stdio"){let r=new ae;await t.connect(r),x(`[${f}@${d}] connected via stdio`);return}e==="http"&&(x(`[${f}@${d}] HTTP transport not yet implemented in v0.1; stdio is the supported mode. Set BUYGIT_MCP_TRANSPORT=stdio.`),process.exit(2)),x(`[${f}@${d}] unknown transport "${e}". Set BUYGIT_MCP_TRANSPORT to "stdio" (default) or "http".`),process.exit(2)}oe().catch(e=>{x(`[${f}@${d}] fatal: ${e.message}`),process.exit(1)});
|
package/package.json
ADDED
|
@@ -0,0 +1,68 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@buygit/mcp-server",
|
|
3
|
+
"version": "0.1.0",
|
|
4
|
+
"description": "MCP server exposing the BuyGit Open Index — 76k+ verified Git projects, searchable from Claude Desktop, Cursor, Cline, and any MCP client.",
|
|
5
|
+
"type": "module",
|
|
6
|
+
"bin": {
|
|
7
|
+
"buygit-mcp": "./dist/index.js"
|
|
8
|
+
},
|
|
9
|
+
"main": "./dist/index.js",
|
|
10
|
+
"files": [
|
|
11
|
+
"dist/",
|
|
12
|
+
"README.md",
|
|
13
|
+
"LICENSE"
|
|
14
|
+
],
|
|
15
|
+
"engines": {
|
|
16
|
+
"node": ">=20"
|
|
17
|
+
},
|
|
18
|
+
"license": "MIT",
|
|
19
|
+
"author": {
|
|
20
|
+
"name": "BuyGit",
|
|
21
|
+
"email": "support@buygit.com",
|
|
22
|
+
"url": "https://buygit.com"
|
|
23
|
+
},
|
|
24
|
+
"homepage": "https://buygit.com/mcp",
|
|
25
|
+
"repository": {
|
|
26
|
+
"type": "git",
|
|
27
|
+
"url": "git+https://github.com/genoxdeveloper/Buygit.git",
|
|
28
|
+
"directory": "packages/mcp-server"
|
|
29
|
+
},
|
|
30
|
+
"bugs": {
|
|
31
|
+
"url": "https://github.com/genoxdeveloper/Buygit/issues"
|
|
32
|
+
},
|
|
33
|
+
"keywords": [
|
|
34
|
+
"mcp",
|
|
35
|
+
"model-context-protocol",
|
|
36
|
+
"buygit",
|
|
37
|
+
"git",
|
|
38
|
+
"discovery",
|
|
39
|
+
"anthropic",
|
|
40
|
+
"claude",
|
|
41
|
+
"cursor",
|
|
42
|
+
"cline",
|
|
43
|
+
"ai",
|
|
44
|
+
"agent"
|
|
45
|
+
],
|
|
46
|
+
"dependencies": {
|
|
47
|
+
"@modelcontextprotocol/sdk": "^1.0.0",
|
|
48
|
+
"undici": "^6.20.0",
|
|
49
|
+
"zod": "^3.23.8"
|
|
50
|
+
},
|
|
51
|
+
"devDependencies": {
|
|
52
|
+
"@types/node": "^20.14.0",
|
|
53
|
+
"tsup": "^8.3.0",
|
|
54
|
+
"typescript": "^5.6.0",
|
|
55
|
+
"vitest": "^2.1.0"
|
|
56
|
+
},
|
|
57
|
+
"publishConfig": {
|
|
58
|
+
"access": "public",
|
|
59
|
+
"registry": "https://registry.npmjs.org/"
|
|
60
|
+
},
|
|
61
|
+
"scripts": {
|
|
62
|
+
"build": "tsup",
|
|
63
|
+
"dev": "tsup --watch",
|
|
64
|
+
"start": "node dist/index.js",
|
|
65
|
+
"test": "vitest run",
|
|
66
|
+
"typecheck": "tsc --noEmit"
|
|
67
|
+
}
|
|
68
|
+
}
|