├── .gitignore ├── package.json ├── introspect.mjs ├── README.md └── github-stars-contributions-mcp.mjs /.gitignore: -------------------------------------------------------------------------------- 1 | node_modules 2 | dist -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "github-stars-contributions-mcp", 3 | "version": "1.0.2", 4 | "description": "MCP server for managing GitHub Stars contributions and profile links", 5 | "main": "dist/index.mjs", 6 | "bin": { 7 | "github-stars-contributions-mcp": "./dist/index.mjs" 8 | }, 9 | "files": [ 10 | "dist" 11 | ], 12 | "scripts": { 13 | "build": "ncc build github-stars-contributions-mcp.mjs -o dist", 14 | "prepublishOnly": "npm run build", 15 | "start": "node github-stars-contributions-mcp.mjs", 16 | "start:dist": "node dist/index.mjs" 17 | }, 18 | "repository": { 19 | "type": "git", 20 | "url": "git+https://github.com/AnandChowdhary/github-stars-contributions-mcp.git" 21 | }, 22 | "keywords": [ 23 | "mcp", 24 | "model-context-protocol", 25 | "github-stars", 26 | "claude", 27 | "cursor", 28 | "ai-assistant" 29 | ], 30 | "author": "Anand Chowdhary", 31 | "license": "ISC", 32 | "type": "module", 33 | "bugs": { 34 | "url": "https://github.com/AnandChowdhary/github-stars-contributions-mcp/issues" 35 | }, 36 | "homepage": "https://github.com/AnandChowdhary/github-stars-contributions-mcp#readme", 37 | "dependencies": { 38 | "@modelcontextprotocol/sdk": "^1.23.0", 39 | "zod": "^4.1.13" 40 | }, 41 | "devDependencies": { 42 | "@vercel/ncc": "^0.38.4" 43 | } 44 | } 45 | -------------------------------------------------------------------------------- /introspect.mjs: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env node 2 | 3 | // Get the GitHub Stars token from environment variables 4 | const GITHUB_STARS_TOKEN = process.env.GITHUB_STARS_TOKEN; 5 | 6 | if (!GITHUB_STARS_TOKEN) { 7 | console.error("Error: GITHUB_STARS_TOKEN environment variable is required"); 8 | process.exit(1); 9 | } 10 | 11 | const API_URL = "https://api-stars.github.com/"; 12 | 13 | // Introspection query to get the schema 14 | const introspectionQuery = ` 15 | query IntrospectionQuery { 16 | __schema { 17 | types { 18 | name 19 | kind 20 | fields { 21 | name 22 | type { 23 | name 24 | kind 25 | ofType { 26 | name 27 | kind 28 | } 29 | } 30 | } 31 | } 32 | } 33 | } 34 | `; 35 | 36 | async function introspect() { 37 | const response = await fetch(API_URL, { 38 | method: "POST", 39 | headers: { 40 | Authorization: `Bearer ${GITHUB_STARS_TOKEN}`, 41 | "Content-Type": "application/json", 42 | }, 43 | body: JSON.stringify({ query: introspectionQuery }), 44 | }); 45 | 46 | const result = await response.json(); 47 | 48 | if (result.errors) { 49 | console.error("Errors:", result.errors); 50 | return; 51 | } 52 | 53 | // Filter to show only relevant types 54 | const relevantTypes = ["User", "StarPublicData", "Contribution", "Link", "Query", "Mutation"]; 55 | 56 | const types = result.data.__schema.types.filter(t => 57 | relevantTypes.includes(t.name) || 58 | t.name.toLowerCase().includes("star") || 59 | t.name.toLowerCase().includes("profile") || 60 | t.name.toLowerCase().includes("user") 61 | ); 62 | 63 | for (const type of types) { 64 | if (type.fields) { 65 | console.log(`\n=== ${type.name} (${type.kind}) ===`); 66 | for (const field of type.fields) { 67 | const fieldType = field.type.name || 68 | (field.type.ofType ? `${field.type.kind}<${field.type.ofType.name}>` : field.type.kind); 69 | console.log(` ${field.name}: ${fieldType}`); 70 | } 71 | } 72 | } 73 | } 74 | 75 | introspect(); 76 | 77 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # ⭐ GitHub Stars Contributions MCP 2 | 3 | An MCP (Model Context Protocol) server for managing your [GitHub Stars](https://stars.github.com) contributions and profile - so AI assistants like Claude Desktop and Cursor can help you track your community contributions through natural language. 4 | 5 | ## ✨ Features 6 | 7 | ### Contribution management 8 | 9 | - **Add contribution** — Add talks, blog posts, videos, and other contributions 10 | - **Update contribution** — Modify existing contributions 11 | - **Remove contribution** — Delete contributions from your profile 12 | - **List contributions** — Retrieve all your contributions with pagination 13 | 14 | ### Profile links 15 | 16 | - **Add link** — Add social/platform links to your profile 17 | - **Remove link** — Delete profile links 18 | - **List links** — Get all your profile links 19 | 20 | ### Query tools 21 | 22 | - **Get public profile** — View any GitHub Star's public profile 23 | - **Search Stars** — Browse GitHub Stars directory 24 | - **Get logged user** — View your own profile information 25 | 26 | ## 📋 Prerequisites 27 | 28 | - **Node.js** v18 or later 29 | - **GitHub Stars API token** — Get yours from [stars.github.com/profile](https://stars.github.com/profile) under the "Token" tab 30 | 31 | ## 🚀 Quick start 32 | 33 | Add the server to your MCP config: 34 | 35 | ### Cursor IDE 36 | 37 | Add to your `~/.cursor/mcp.json`: 38 | 39 | ```json 40 | { 41 | "mcpServers": { 42 | "github-stars": { 43 | "command": "npx", 44 | "args": ["-y", "github-stars-contributions-mcp"], 45 | "env": { 46 | "GITHUB_STARS_TOKEN": "your-api-token-here" 47 | } 48 | } 49 | } 50 | } 51 | ``` 52 | 53 | ### Claude Desktop 54 | 55 | Add to your Claude Desktop config file: 56 | 57 | - **macOS**: `~/Library/Application Support/Claude/claude_desktop_config.json` 58 | - **Windows**: `%APPDATA%\Claude\claude_desktop_config.json` 59 | 60 | ```json 61 | { 62 | "mcpServers": { 63 | "github-stars": { 64 | "command": "npx", 65 | "args": ["-y", "github-stars-contributions-mcp"], 66 | "env": { 67 | "GITHUB_STARS_TOKEN": "your-api-token-here" 68 | } 69 | } 70 | } 71 | } 72 | ``` 73 | 74 | ### Get your API token 75 | 76 | 1. Go to [stars.github.com/profile](https://stars.github.com/profile) 77 | 2. Navigate to the **Token** tab 78 | 3. Copy your API token and replace `your-api-token-here` in the config above 79 | 80 | ## ⚙️ Alternative installation 81 | 82 | ### From source 83 | 84 | If you prefer to run from source: 85 | 86 | ```bash 87 | git clone https://github.com/AnandChowdhary/github-stars-contributions-mcp.git 88 | cd github-stars-contributions-mcp 89 | npm install 90 | ``` 91 | 92 | Then use this config: 93 | 94 | ```json 95 | { 96 | "mcpServers": { 97 | "github-stars": { 98 | "command": "node", 99 | "args": [ 100 | "/absolute/path/to/github-stars-contributions-mcp/github-stars-contributions-mcp.mjs" 101 | ], 102 | "env": { 103 | "GITHUB_STARS_TOKEN": "your-api-token-here" 104 | } 105 | } 106 | } 107 | } 108 | ``` 109 | 110 | ### Running standalone 111 | 112 | ```bash 113 | export GITHUB_STARS_TOKEN="your-api-token-here" 114 | npx github-stars-contributions-mcp 115 | ``` 116 | 117 | ## 🎯 Available tools 118 | 119 | ### `add_contribution` 120 | 121 | Add a new contribution to your GitHub Stars profile. 122 | 123 | | Parameter | Type | Required | Description | 124 | | ------------- | ------ | -------- | ------------------------------------------------------------------------------------------------------------------------------------------ | 125 | | `type` | enum | ✅ | `SPEAKING`, `BLOGPOST`, `ARTICLE_PUBLICATION`, `EVENT_ORGANIZATION`, `HACKATHON`, `OPEN_SOURCE_PROJECT`, `VIDEO_PODCAST`, `FORUM`, `OTHER` | 126 | | `title` | string | ✅ | Title of the contribution | 127 | | `description` | string | ✅ | Description of the contribution | 128 | | `date` | string | ✅ | Date in `YYYY-MM-DD` or ISO format | 129 | | `url` | string | ❌ | URL related to the contribution | 130 | 131 | ### `update_contribution` 132 | 133 | Update an existing contribution. 134 | 135 | | Parameter | Type | Required | Description | 136 | | ------------- | ------ | -------- | -------------------------------- | 137 | | `id` | string | ✅ | ID of the contribution to update | 138 | | `type` | enum | ❌ | Contribution type | 139 | | `title` | string | ❌ | Title | 140 | | `description` | string | ❌ | Description | 141 | | `date` | string | ❌ | Date | 142 | | `url` | string | ❌ | URL | 143 | 144 | ### `remove_contribution` 145 | 146 | Delete a contribution from your profile. 147 | 148 | | Parameter | Type | Required | Description | 149 | | --------- | ------ | -------- | -------------------------------- | 150 | | `id` | string | ✅ | ID of the contribution to delete | 151 | 152 | ### `list_contributions` 153 | 154 | Get all your contributions. 155 | 156 | | Parameter | Type | Required | Description | 157 | | --------- | ------ | -------- | ------------------------ | 158 | | `first` | number | ❌ | Number of items to fetch | 159 | | `offset` | number | ❌ | Pagination offset | 160 | 161 | ### `add_link` 162 | 163 | Add a profile link. 164 | 165 | | Parameter | Type | Required | Description | 166 | | ---------- | ------ | -------- | ------------------------------------------------------------------------------------------ | 167 | | `link` | string | ✅ | URL of the link | 168 | | `platform` | enum | ✅ | `TWITTER`, `MEDIUM`, `LINKEDIN`, `README`, `STACK_OVERFLOW`, `DEV_TO`, `MASTODON`, `OTHER` | 169 | 170 | ### `remove_link` 171 | 172 | Delete a profile link. 173 | 174 | | Parameter | Type | Required | Description | 175 | | --------- | ------ | -------- | ------------------------ | 176 | | `id` | string | ✅ | ID of the link to delete | 177 | 178 | ### `list_links` 179 | 180 | Get all your profile links. No parameters required. 181 | 182 | ### `get_public_profile` 183 | 184 | Get a GitHub Star's public profile. 185 | 186 | | Parameter | Type | Required | Description | 187 | | ---------- | ------ | -------- | --------------- | 188 | | `username` | string | ✅ | GitHub username | 189 | 190 | ### `search_stars` 191 | 192 | Search GitHub Stars. 193 | 194 | | Parameter | Type | Required | Description | 195 | | ---------- | ------- | -------- | ----------------------------- | 196 | | `featured` | boolean | ❌ | Filter to featured Stars only | 197 | 198 | ### `get_logged_user` 199 | 200 | Get your own profile information. No parameters required. 201 | 202 | ## 📝 Example usage 203 | 204 | Once configured with your AI assistant, you can use natural language: 205 | 206 | - _"Add my talk at GitHub Universe as a speaking contribution"_ 207 | - _"List all my contributions from this year"_ 208 | - _"Add my Twitter profile link"_ 209 | - _"Show me the public profile of octocat"_ 210 | - _"Remove the contribution with ID abc123"_ 211 | 212 | ## 📊 Contribution types 213 | 214 | | Type | Description | 215 | | --------------------- | ---------------------------------------- | 216 | | `SPEAKING` | Conference talks, meetups, webinars | 217 | | `BLOGPOST` | Blog posts and tutorials | 218 | | `ARTICLE_PUBLICATION` | Published articles in magazines/journals | 219 | | `EVENT_ORGANIZATION` | Organizing events, meetups, conferences | 220 | | `HACKATHON` | Hackathon participation or mentoring | 221 | | `OPEN_SOURCE_PROJECT` | Open source contributions | 222 | | `VIDEO_PODCAST` | YouTube videos, podcasts | 223 | | `FORUM` | Forum contributions, Q&A | 224 | | `OTHER` | Any other contribution type | 225 | 226 | ## 🔗 Platform types 227 | 228 | | Type | Description | 229 | | ---------------- | ---------------------- | 230 | | `TWITTER` | Twitter/X profile | 231 | | `MEDIUM` | Medium blog | 232 | | `LINKEDIN` | LinkedIn profile | 233 | | `README` | README profile | 234 | | `STACK_OVERFLOW` | Stack Overflow profile | 235 | | `DEV_TO` | DEV Community profile | 236 | | `MASTODON` | Mastodon profile | 237 | | `OTHER` | Any other platform | 238 | 239 | ## 🔧 Troubleshooting 240 | 241 | ### "GITHUB_STARS_TOKEN environment variable is required" 242 | 243 | Make sure you've set the `GITHUB_STARS_TOKEN` in your MCP configuration or exported it in your shell. 244 | 245 | ### "Unauthorized" errors 246 | 247 | Your API token may have expired. Generate a new one from [stars.github.com/profile](https://stars.github.com/profile). 248 | 249 | ### Server not connecting 250 | 251 | 1. Ensure Node.js v18+ is installed 252 | 2. Check that the `GITHUB_STARS_TOKEN` is set correctly 253 | 3. Restart your AI assistant after config changes 254 | 255 | ## 🔗 Related projects 256 | 257 | - [github-stars-contributions CLI](https://github.com/ahmadawais/github-stars-contributions) — CLI tool by Ahmad Awais 258 | - [GitHub Stars Program](https://stars.github.com) — Official GitHub Stars website 259 | 260 | ## 📃 License 261 | 262 | ISC © [Anand Chowdhary](https://anandchowdhary.com) 263 | -------------------------------------------------------------------------------- /github-stars-contributions-mcp.mjs: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env node 2 | 3 | import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js"; 4 | import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio.js"; 5 | import { z } from "zod"; 6 | 7 | // Get the GitHub Stars token from environment variables 8 | const GITHUB_STARS_TOKEN = process.env.GITHUB_STARS_TOKEN; 9 | 10 | if (!GITHUB_STARS_TOKEN) { 11 | console.error("Error: GITHUB_STARS_TOKEN environment variable is required"); 12 | process.exit(1); 13 | } 14 | 15 | const API_URL = "https://api-stars.github.com/"; 16 | 17 | // GraphQL request helper 18 | async function graphqlRequest(query, variables = {}) { 19 | const response = await fetch(API_URL, { 20 | method: "POST", 21 | headers: { 22 | Authorization: `Bearer ${GITHUB_STARS_TOKEN}`, 23 | "Content-Type": "application/json", 24 | }, 25 | body: JSON.stringify({ query, variables }), 26 | }); 27 | 28 | const result = await response.json(); 29 | 30 | if (result.errors) { 31 | throw new Error(result.errors.map((e) => e.message).join(", ")); 32 | } 33 | 34 | return result.data; 35 | } 36 | 37 | // Enums 38 | const ContributionType = z.enum([ 39 | "SPEAKING", 40 | "BLOGPOST", 41 | "ARTICLE_PUBLICATION", 42 | "EVENT_ORGANIZATION", 43 | "HACKATHON", 44 | "OPEN_SOURCE_PROJECT", 45 | "VIDEO_PODCAST", 46 | "FORUM", 47 | "OTHER", 48 | ]); 49 | 50 | const PlatformType = z.enum([ 51 | "TWITTER", 52 | "MEDIUM", 53 | "LINKEDIN", 54 | "README", 55 | "STACK_OVERFLOW", 56 | "DEV_TO", 57 | "MASTODON", 58 | "OTHER", 59 | ]); 60 | 61 | const server = new McpServer( 62 | { name: "github-stars-contributions-mcp", version: "1.0.0" }, 63 | { 64 | instructions: 65 | "Use this server to manage GitHub Stars contributions, profile links, and query public profiles.", 66 | } 67 | ); 68 | 69 | // ============================================ 70 | // CONTRIBUTION MANAGEMENT TOOLS 71 | // ============================================ 72 | 73 | server.tool( 74 | "add_contribution", 75 | "Add a new contribution to your GitHub Stars profile.", 76 | z.object({ 77 | type: ContributionType.describe("Type of contribution"), 78 | title: z.string().min(1).describe("Title of the contribution"), 79 | description: z.string().min(1).describe("Description of the contribution"), 80 | url: z 81 | .string() 82 | .url() 83 | .optional() 84 | .describe("URL related to the contribution"), 85 | date: z 86 | .string() 87 | .describe("Date of the contribution (YYYY-MM-DD or ISO format)"), 88 | }), 89 | async ({ type, title, description, url, date }) => { 90 | const query = ` 91 | mutation AddContribution( 92 | $type: ContributionType! 93 | $date: GraphQLDateTime! 94 | $title: String! 95 | $url: URL 96 | $description: String! 97 | ) { 98 | createContribution( 99 | data: { 100 | date: $date 101 | url: $url 102 | type: $type 103 | title: $title 104 | description: $description 105 | } 106 | ) { 107 | id 108 | title 109 | type 110 | date 111 | url 112 | description 113 | } 114 | } 115 | `; 116 | 117 | const variables = { 118 | type, 119 | title, 120 | description, 121 | url: url || null, 122 | date: new Date(date).toISOString(), 123 | }; 124 | 125 | const data = await graphqlRequest(query, variables); 126 | 127 | return { 128 | content: [ 129 | { 130 | type: "text", 131 | text: JSON.stringify(data.createContribution, null, 2), 132 | }, 133 | ], 134 | }; 135 | } 136 | ); 137 | 138 | server.tool( 139 | "remove_contribution", 140 | "Delete a contribution from your GitHub Stars profile.", 141 | z.object({ 142 | id: z.string().min(1).describe("ID of the contribution to delete"), 143 | }), 144 | async ({ id }) => { 145 | const query = ` 146 | mutation DeleteContribution($id: String!) { 147 | deleteContribution(id: $id) { 148 | id 149 | } 150 | } 151 | `; 152 | 153 | const data = await graphqlRequest(query, { id }); 154 | 155 | return { 156 | content: [ 157 | { 158 | type: "text", 159 | text: `Successfully deleted contribution with ID: ${data.deleteContribution.id}`, 160 | }, 161 | ], 162 | }; 163 | } 164 | ); 165 | 166 | server.tool( 167 | "update_contribution", 168 | "Update an existing contribution on your GitHub Stars profile.", 169 | z.object({ 170 | id: z.string().min(1).describe("ID of the contribution to update"), 171 | type: ContributionType.optional().describe("Type of contribution"), 172 | title: z.string().min(1).optional().describe("Title of the contribution"), 173 | description: z 174 | .string() 175 | .min(1) 176 | .optional() 177 | .describe("Description of the contribution"), 178 | url: z 179 | .string() 180 | .url() 181 | .optional() 182 | .describe("URL related to the contribution"), 183 | date: z 184 | .string() 185 | .optional() 186 | .describe("Date of the contribution (YYYY-MM-DD or ISO format)"), 187 | }), 188 | async ({ id, type, title, description, url, date }) => { 189 | const query = ` 190 | mutation UpdateContribution( 191 | $id: String! 192 | $type: ContributionType 193 | $date: GraphQLDateTime 194 | $title: String 195 | $url: URL 196 | $description: String 197 | ) { 198 | updateContribution( 199 | id: $id 200 | data: { 201 | date: $date 202 | url: $url 203 | type: $type 204 | title: $title 205 | description: $description 206 | } 207 | ) { 208 | id 209 | title 210 | type 211 | date 212 | url 213 | description 214 | } 215 | } 216 | `; 217 | 218 | const variables = { 219 | id, 220 | type: type || null, 221 | title: title || null, 222 | description: description || null, 223 | url: url || null, 224 | date: date ? new Date(date).toISOString() : null, 225 | }; 226 | 227 | const data = await graphqlRequest(query, variables); 228 | 229 | return { 230 | content: [ 231 | { 232 | type: "text", 233 | text: JSON.stringify(data.updateContribution, null, 2), 234 | }, 235 | ], 236 | }; 237 | } 238 | ); 239 | 240 | server.tool( 241 | "list_contributions", 242 | "Get all your contributions from your GitHub Stars profile.", 243 | z.object({ 244 | first: z.number().optional().describe("Number of contributions to fetch"), 245 | offset: z.number().optional().describe("Offset for pagination"), 246 | }), 247 | async ({ first, offset }) => { 248 | const query = ` 249 | query AllContributions($pagination: ContributionOffsetPaginationInput) { 250 | allContributions(pagination: $pagination) { 251 | id 252 | title 253 | type 254 | date 255 | url 256 | description 257 | } 258 | } 259 | `; 260 | 261 | const variables = { 262 | pagination: first || offset ? { first, offset } : null, 263 | }; 264 | 265 | const data = await graphqlRequest(query, variables); 266 | 267 | return { 268 | content: [ 269 | { 270 | type: "text", 271 | text: JSON.stringify(data.allContributions, null, 2), 272 | }, 273 | ], 274 | }; 275 | } 276 | ); 277 | 278 | // ============================================ 279 | // PROFILE LINKS TOOLS 280 | // ============================================ 281 | 282 | server.tool( 283 | "add_link", 284 | "Add a profile link to your GitHub Stars profile.", 285 | z.object({ 286 | link: z.string().url().describe("URL of the profile link"), 287 | platform: PlatformType.describe("Platform type for the link"), 288 | }), 289 | async ({ link, platform }) => { 290 | const query = ` 291 | mutation CreateLink($link: URL, $platform: PlatformType) { 292 | createLink(data: { link: $link, platform: $platform }) { 293 | id 294 | link 295 | platform 296 | } 297 | } 298 | `; 299 | 300 | const data = await graphqlRequest(query, { link, platform }); 301 | 302 | return { 303 | content: [ 304 | { 305 | type: "text", 306 | text: JSON.stringify(data.createLink, null, 2), 307 | }, 308 | ], 309 | }; 310 | } 311 | ); 312 | 313 | server.tool( 314 | "remove_link", 315 | "Delete a profile link from your GitHub Stars profile.", 316 | z.object({ 317 | id: z.string().min(1).describe("ID of the link to delete"), 318 | }), 319 | async ({ id }) => { 320 | const query = ` 321 | mutation DeleteLink($id: String!) { 322 | deleteLink(id: $id) { 323 | id 324 | } 325 | } 326 | `; 327 | 328 | const data = await graphqlRequest(query, { id }); 329 | 330 | return { 331 | content: [ 332 | { 333 | type: "text", 334 | text: `Successfully deleted link with ID: ${data.deleteLink.id}`, 335 | }, 336 | ], 337 | }; 338 | } 339 | ); 340 | 341 | server.tool( 342 | "list_links", 343 | "Get all profile links from your GitHub Stars profile.", 344 | z.object({}), 345 | async () => { 346 | const query = ` 347 | query { 348 | links { 349 | id 350 | link 351 | platform 352 | } 353 | } 354 | `; 355 | 356 | const data = await graphqlRequest(query); 357 | 358 | return { 359 | content: [ 360 | { 361 | type: "text", 362 | text: JSON.stringify(data.links, null, 2), 363 | }, 364 | ], 365 | }; 366 | } 367 | ); 368 | 369 | // ============================================ 370 | // QUERY TOOLS 371 | // ============================================ 372 | 373 | server.tool( 374 | "get_public_profile", 375 | "Get a GitHub Star's public profile by username.", 376 | z.object({ 377 | username: z.string().min(1).describe("GitHub username of the Star"), 378 | }), 379 | async ({ username }) => { 380 | const query = ` 381 | query PublicProfile($username: String!) { 382 | publicProfile(username: $username) { 383 | id 384 | username 385 | name 386 | bio 387 | avatar 388 | status 389 | featured 390 | country 391 | contributions { 392 | id 393 | title 394 | type 395 | date 396 | url 397 | description 398 | } 399 | links { 400 | id 401 | link 402 | platform 403 | } 404 | } 405 | } 406 | `; 407 | 408 | const data = await graphqlRequest(query, { username }); 409 | 410 | return { 411 | content: [ 412 | { 413 | type: "text", 414 | text: JSON.stringify(data.publicProfile, null, 2), 415 | }, 416 | ], 417 | }; 418 | } 419 | ); 420 | 421 | server.tool( 422 | "search_stars", 423 | "Search and list GitHub Stars public data.", 424 | z.object({ 425 | featured: z.boolean().optional().describe("Filter to only featured Stars"), 426 | }), 427 | async ({ featured }) => { 428 | const query = ` 429 | query StarsPublicData($featured: Boolean) { 430 | starsPublicData(featured: $featured) { 431 | id 432 | username 433 | name 434 | bio 435 | avatar 436 | status 437 | featured 438 | country 439 | } 440 | } 441 | `; 442 | 443 | const data = await graphqlRequest(query, { featured: featured ?? null }); 444 | 445 | return { 446 | content: [ 447 | { 448 | type: "text", 449 | text: JSON.stringify(data.starsPublicData, null, 2), 450 | }, 451 | ], 452 | }; 453 | } 454 | ); 455 | 456 | server.tool( 457 | "get_logged_user", 458 | "Get information about the currently logged-in user.", 459 | z.object({}), 460 | async () => { 461 | const query = ` 462 | query { 463 | loggedUser { 464 | id 465 | username 466 | avatar 467 | email 468 | nominee { 469 | status 470 | name 471 | bio 472 | featured 473 | country 474 | jobTitle 475 | company 476 | } 477 | } 478 | } 479 | `; 480 | 481 | const data = await graphqlRequest(query); 482 | 483 | return { 484 | content: [ 485 | { 486 | type: "text", 487 | text: JSON.stringify(data.loggedUser, null, 2), 488 | }, 489 | ], 490 | }; 491 | } 492 | ); 493 | 494 | const transport = new StdioServerTransport(); 495 | 496 | await server.connect(transport); 497 | --------------------------------------------------------------------------------