@gitstar-ai/mcp 0.2.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md ADDED
@@ -0,0 +1,85 @@
1
+ # @gitstar-ai/mcp
2
+
3
+ GitHub actions inside any AI tool, powered by [Gitstar](https://tinkling.vercel.app).
4
+
5
+ ## Setup
6
+
7
+ ### Claude Desktop
8
+
9
+ Add to `claude_desktop_config.json`:
10
+
11
+ ```json
12
+ {
13
+ "mcpServers": {
14
+ "gitstar": {
15
+ "command": "npx",
16
+ "args": ["-y", "@gitstar-ai/mcp"]
17
+ }
18
+ }
19
+ }
20
+ ```
21
+
22
+ ### Claude Code (CLI)
23
+
24
+ Add to `.claude/settings.json`:
25
+
26
+ ```json
27
+ {
28
+ "mcpServers": {
29
+ "gitstar": {
30
+ "command": "npx",
31
+ "args": ["-y", "@gitstar-ai/mcp"]
32
+ }
33
+ }
34
+ }
35
+ ```
36
+
37
+ ### Cursor
38
+
39
+ Add to `.cursor/mcp.json`:
40
+
41
+ ```json
42
+ {
43
+ "mcpServers": {
44
+ "gitstar": {
45
+ "command": "npx",
46
+ "args": ["-y", "@gitstar-ai/mcp"]
47
+ }
48
+ }
49
+ }
50
+ ```
51
+
52
+ ### Login
53
+
54
+ ```bash
55
+ npx @gitstar-ai/mcp login
56
+ ```
57
+
58
+ This opens your browser to authenticate with GitHub via Gitstar. One-time setup.
59
+
60
+ ## Tools
61
+
62
+ | Tool | Description |
63
+ |------|-------------|
64
+ | `gitstar_get_feed` | Narrated activity feed for a repo |
65
+ | `gitstar_get_repo` | Repo metadata and stats |
66
+ | `gitstar_get_pr` | PR details, diff, and files |
67
+ | `gitstar_get_pr_checks` | CI/CD check statuses |
68
+ | `gitstar_get_issue` | Issue details and timeline |
69
+ | `gitstar_comment_pr` | Comment on a PR |
70
+ | `gitstar_comment_issue` | Comment on an issue |
71
+ | `gitstar_review_pr` | Approve or request changes on a PR |
72
+ | `gitstar_merge_pr` | Merge a PR |
73
+ | `gitstar_close_pr` | Close a PR |
74
+ | `gitstar_close_issue` | Close an issue |
75
+ | `gitstar_search` | Search repos and users |
76
+ | `gitstar_trending` | Trending repos |
77
+
78
+ ## Example Prompts
79
+
80
+ - "Show me what's happening in facebook/react"
81
+ - "Review PR #42 in vercel/next.js for security issues"
82
+ - "What's the CI status on PR #15?"
83
+ - "Merge PR #10 using squash"
84
+ - "Close issue #33, it's a duplicate"
85
+ - "What repos are trending?"
package/dist/auth.d.ts ADDED
@@ -0,0 +1,5 @@
1
+ import type { AuthData } from './types.js';
2
+ export declare function getApiUrl(): string;
3
+ export declare function getToken(): AuthData | null;
4
+ export declare function saveToken(data: AuthData): void;
5
+ export declare function login(): Promise<void>;
package/dist/auth.js ADDED
@@ -0,0 +1,87 @@
1
+ import { createServer } from 'http';
2
+ import { readFileSync, writeFileSync, mkdirSync, existsSync } from 'fs';
3
+ import { join } from 'path';
4
+ import { homedir } from 'os';
5
+ const GITSTAR_DIR = join(homedir(), '.gitstar');
6
+ const AUTH_FILE = join(GITSTAR_DIR, 'auth.json');
7
+ const CONFIG_FILE = join(GITSTAR_DIR, 'config.json');
8
+ const DEFAULT_API_URL = 'https://www.gitstar.ai';
9
+ function ensureDir() {
10
+ if (!existsSync(GITSTAR_DIR)) {
11
+ mkdirSync(GITSTAR_DIR, { recursive: true, mode: 0o700 });
12
+ }
13
+ }
14
+ export function getApiUrl() {
15
+ try {
16
+ const config = JSON.parse(readFileSync(CONFIG_FILE, 'utf-8'));
17
+ return config.api_url || DEFAULT_API_URL;
18
+ }
19
+ catch {
20
+ return DEFAULT_API_URL;
21
+ }
22
+ }
23
+ export function getToken() {
24
+ try {
25
+ const data = JSON.parse(readFileSync(AUTH_FILE, 'utf-8'));
26
+ if (!data.key || !data.login)
27
+ return null;
28
+ return data;
29
+ }
30
+ catch {
31
+ return null;
32
+ }
33
+ }
34
+ export function saveToken(data) {
35
+ ensureDir();
36
+ writeFileSync(AUTH_FILE, JSON.stringify(data, null, 2), { mode: 0o600 });
37
+ }
38
+ export async function login() {
39
+ const apiUrl = getApiUrl();
40
+ return new Promise((resolve, reject) => {
41
+ const server = createServer((req, res) => {
42
+ const url = new URL(req.url, `http://localhost`);
43
+ if (url.pathname === '/callback') {
44
+ const key = url.searchParams.get('key');
45
+ const login = url.searchParams.get('login');
46
+ if (key && login) {
47
+ saveToken({ key, login });
48
+ res.writeHead(200, { 'Content-Type': 'text/html' });
49
+ res.end('<html><body><h1>Logged in to Gitstar!</h1><p>You can close this window.</p></body></html>');
50
+ server.close();
51
+ console.log(`Logged in as ${login}`);
52
+ resolve();
53
+ }
54
+ else {
55
+ res.writeHead(400, { 'Content-Type': 'text/html' });
56
+ res.end('<html><body><h1>Login failed</h1><p>Missing API key. Try again.</p></body></html>');
57
+ server.close();
58
+ reject(new Error('Login failed: no API key received'));
59
+ }
60
+ }
61
+ });
62
+ server.listen(9876, () => {
63
+ const addr = server.address();
64
+ const port = typeof addr === 'object' && addr ? addr.port : 9876;
65
+ const callbackUrl = encodeURIComponent(`http://localhost:${port}/callback`);
66
+ const authUrl = `${apiUrl}/auth/mcp?callback=${callbackUrl}`;
67
+ console.log(`Opening browser for login...`);
68
+ console.log(`If browser doesn't open, visit: ${authUrl}`);
69
+ import('open').then(({ default: open }) => open(authUrl));
70
+ });
71
+ server.on('error', () => {
72
+ server.listen(0, () => {
73
+ const addr = server.address();
74
+ const port = typeof addr === 'object' && addr ? addr.port : 0;
75
+ const callbackUrl = encodeURIComponent(`http://localhost:${port}/callback`);
76
+ const authUrl = `${apiUrl}/auth/mcp?callback=${callbackUrl}`;
77
+ console.log(`Opening browser for login...`);
78
+ console.log(`If browser doesn't open, visit: ${authUrl}`);
79
+ import('open').then(({ default: open }) => open(authUrl));
80
+ });
81
+ });
82
+ setTimeout(() => {
83
+ server.close();
84
+ reject(new Error('Login timed out after 5 minutes'));
85
+ }, 5 * 60 * 1000);
86
+ });
87
+ }
@@ -0,0 +1,2 @@
1
+ #!/usr/bin/env node
2
+ export {};
package/dist/index.js ADDED
@@ -0,0 +1,89 @@
1
+ #!/usr/bin/env node
2
+ import { McpServer } from '@modelcontextprotocol/sdk/server/mcp.js';
3
+ import { StdioServerTransport } from '@modelcontextprotocol/sdk/server/stdio.js';
4
+ import { Client } from '@modelcontextprotocol/sdk/client/index.js';
5
+ import { z } from 'zod';
6
+ import { createRemoteTransport } from './proxy.js';
7
+ import { getToken, getApiUrl, login } from './auth.js';
8
+ function jsonSchemaToZod(prop, required) {
9
+ let schema;
10
+ const enumValues = prop.enum;
11
+ if (enumValues && enumValues.length > 0) {
12
+ schema = z.enum(enumValues);
13
+ }
14
+ else {
15
+ switch (prop.type) {
16
+ case 'number':
17
+ case 'integer':
18
+ schema = z.number();
19
+ break;
20
+ case 'boolean':
21
+ schema = z.boolean();
22
+ break;
23
+ case 'array':
24
+ schema = z.array(z.unknown());
25
+ break;
26
+ case 'object':
27
+ schema = z.record(z.unknown());
28
+ break;
29
+ default:
30
+ schema = z.string();
31
+ }
32
+ }
33
+ if (prop.description) {
34
+ schema = schema.describe(prop.description);
35
+ }
36
+ if (!required) {
37
+ schema = schema.optional();
38
+ }
39
+ return schema;
40
+ }
41
+ async function main() {
42
+ const args = process.argv.slice(2);
43
+ if (args[0] === 'login') {
44
+ try {
45
+ await login();
46
+ process.exit(0);
47
+ }
48
+ catch (err) {
49
+ console.error('Login failed:', err.message);
50
+ process.exit(1);
51
+ }
52
+ }
53
+ const auth = getToken();
54
+ if (!auth) {
55
+ console.error('Not logged in. Run: npx @gitstar-ai/mcp login');
56
+ process.exit(1);
57
+ }
58
+ const apiUrl = getApiUrl();
59
+ // Create local MCP server that proxies to the remote HTTP server
60
+ const server = new McpServer({
61
+ name: 'gitstar',
62
+ version: '0.2.0',
63
+ });
64
+ // Connect to remote server as a client
65
+ const remoteTransport = createRemoteTransport(auth.key, apiUrl);
66
+ const client = new Client({ name: 'gitstar-proxy', version: '0.2.0' });
67
+ await client.connect(remoteTransport);
68
+ // Get available tools from remote and register them locally as proxies
69
+ const { tools } = await client.listTools();
70
+ for (const tool of tools) {
71
+ const properties = (tool.inputSchema?.properties ?? {});
72
+ const requiredFields = (tool.inputSchema?.required ?? []);
73
+ const shape = {};
74
+ for (const [key, prop] of Object.entries(properties)) {
75
+ shape[key] = jsonSchemaToZod(prop, requiredFields.includes(key));
76
+ }
77
+ server.tool(tool.name, tool.description || '', shape, async (params) => {
78
+ const result = await client.callTool({ name: tool.name, arguments: params });
79
+ return result;
80
+ });
81
+ }
82
+ // Connect local server to stdio
83
+ const transport = new StdioServerTransport();
84
+ await server.connect(transport);
85
+ }
86
+ main().catch((err) => {
87
+ console.error('Fatal:', err);
88
+ process.exit(1);
89
+ });
@@ -0,0 +1,2 @@
1
+ import { StreamableHTTPClientTransport } from '@modelcontextprotocol/sdk/client/streamableHttp.js';
2
+ export declare function createRemoteTransport(apiKey: string, apiUrl: string): StreamableHTTPClientTransport;
package/dist/proxy.js ADDED
@@ -0,0 +1,10 @@
1
+ import { StreamableHTTPClientTransport } from '@modelcontextprotocol/sdk/client/streamableHttp.js';
2
+ export function createRemoteTransport(apiKey, apiUrl) {
3
+ return new StreamableHTTPClientTransport(new URL(`${apiUrl}/mcp`), {
4
+ requestInit: {
5
+ headers: {
6
+ Authorization: `Bearer ${apiKey}`,
7
+ },
8
+ },
9
+ });
10
+ }
@@ -0,0 +1,7 @@
1
+ export interface AuthData {
2
+ key: string;
3
+ login: string;
4
+ }
5
+ export interface GitstarConfig {
6
+ api_url: string;
7
+ }
package/dist/types.js ADDED
@@ -0,0 +1 @@
1
+ export {};
package/package.json ADDED
@@ -0,0 +1,31 @@
1
+ {
2
+ "name": "@gitstar-ai/mcp",
3
+ "version": "0.2.0",
4
+ "type": "module",
5
+ "description": "Gitstar MCP server — interact with GitHub through Gitstar from Claude, Cursor, and other AI tools",
6
+ "bin": {
7
+ "gitstar-mcp": "./dist/index.js"
8
+ },
9
+ "main": "./dist/index.js",
10
+ "scripts": {
11
+ "build": "tsc",
12
+ "dev": "tsc --watch",
13
+ "start": "node dist/index.js",
14
+ "login": "node dist/index.js login"
15
+ },
16
+ "keywords": ["mcp", "github", "gitstar", "claude", "cursor", "ai"],
17
+ "license": "MIT",
18
+ "dependencies": {
19
+ "@modelcontextprotocol/sdk": "^1.25.2",
20
+ "open": "^10.1.0",
21
+ "zod": "^3.23.0"
22
+ },
23
+ "devDependencies": {
24
+ "typescript": "^5.5.0",
25
+ "@types/node": "^20.0.0"
26
+ },
27
+ "engines": {
28
+ "node": ">=18"
29
+ },
30
+ "files": ["dist"]
31
+ }