@abhishekmcp/github 0.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +62 -0
- package/dist/auth.d.ts +21 -0
- package/dist/auth.js +158 -0
- package/dist/auth.js.map +1 -0
- package/dist/config.d.ts +23 -0
- package/dist/config.js +38 -0
- package/dist/config.js.map +1 -0
- package/dist/gh.d.ts +130 -0
- package/dist/gh.js +109 -0
- package/dist/gh.js.map +1 -0
- package/dist/index.d.ts +2 -0
- package/dist/index.js +191 -0
- package/dist/index.js.map +1 -0
- package/package.json +55 -0
package/README.md
ADDED
|
@@ -0,0 +1,62 @@
|
|
|
1
|
+
# @abhishekmcp/github
|
|
2
|
+
|
|
3
|
+
A GitHub [MCP](https://modelcontextprotocol.io) server: search, browse, and act on GitHub from any MCP
|
|
4
|
+
client. Authenticates via **OAuth device flow** (real OAuth, no hosted callback) or a **token**. Pure
|
|
5
|
+
JavaScript ([`@octokit/rest`](https://github.com/octokit/rest.js)), no native dependencies.
|
|
6
|
+
|
|
7
|
+
> GitHub ships an official, much larger MCP server. This is a focused, learning-oriented build that does
|
|
8
|
+
> auth/secrets handling cleanly.
|
|
9
|
+
|
|
10
|
+
## Tools
|
|
11
|
+
|
|
12
|
+
**Auth:** `github_login` (device flow), `github_logout`, `whoami`
|
|
13
|
+
**Search:** `search_repos`, `search_code`, `search_issues`
|
|
14
|
+
**Read:** `get_repo`, `list_issues`, `get_issue`, `list_pull_requests`, `get_pull_request`,
|
|
15
|
+
`get_file_contents`, `list_notifications`, `rate_limit`
|
|
16
|
+
**Write** (omitted when `GITHUB_READONLY=1`): `create_issue`, `add_issue_comment`
|
|
17
|
+
|
|
18
|
+
Responses are trimmed to the useful fields to stay token-efficient.
|
|
19
|
+
|
|
20
|
+
## Authentication
|
|
21
|
+
|
|
22
|
+
Resolved in this order (nothing is required at startup):
|
|
23
|
+
|
|
24
|
+
1. **Token** — `GITHUB_TOKEN` (or `GITHUB_PERSONAL_ACCESS_TOKEN`). A [Personal Access Token](https://github.com/settings/tokens); simplest path.
|
|
25
|
+
2. **Cached OAuth token** — from a previous `github_login`, stored at `~/.config/mcp-github/auth.json` (`0600`), auto-refreshed when possible.
|
|
26
|
+
3. Otherwise tools return a clear "run `github_login`" message.
|
|
27
|
+
|
|
28
|
+
### OAuth device flow (one-time setup)
|
|
29
|
+
Device flow needs a **public** OAuth-App client id (no secret):
|
|
30
|
+
1. Create a [GitHub OAuth App](https://github.com/settings/developers) and **enable Device Flow**.
|
|
31
|
+
2. `export GITHUB_CLIENT_ID=<client id>`.
|
|
32
|
+
3. Run `github_login` → open the printed URL, enter the code, then run `github_login` again to finish.
|
|
33
|
+
|
|
34
|
+
Tokens are cached locally with `0600` permissions and are never logged.
|
|
35
|
+
|
|
36
|
+
## Configuration
|
|
37
|
+
|
|
38
|
+
| Variable | Effect |
|
|
39
|
+
|----------|--------|
|
|
40
|
+
| `GITHUB_TOKEN` / `GITHUB_PERSONAL_ACCESS_TOKEN` | Use this PAT (skips OAuth). |
|
|
41
|
+
| `GITHUB_CLIENT_ID` | OAuth App client id for the device-flow login. |
|
|
42
|
+
| `GITHUB_READONLY` | `1`/`true` → only read + auth tools are registered. |
|
|
43
|
+
|
|
44
|
+
## Usage
|
|
45
|
+
|
|
46
|
+
```bash
|
|
47
|
+
# Claude Code (plugin): /plugin marketplace add Abhishekkumar2021/mcp-suite → /plugin install github
|
|
48
|
+
# Claude Code (manual):
|
|
49
|
+
claude mcp add github --env GITHUB_TOKEN=<pat> -- npx -y @abhishekmcp/github
|
|
50
|
+
```
|
|
51
|
+
|
|
52
|
+
```json
|
|
53
|
+
{
|
|
54
|
+
"mcpServers": {
|
|
55
|
+
"github": { "command": "npx", "args": ["-y", "@abhishekmcp/github"], "env": { "GITHUB_TOKEN": "<pat>" } }
|
|
56
|
+
}
|
|
57
|
+
}
|
|
58
|
+
```
|
|
59
|
+
|
|
60
|
+
## License
|
|
61
|
+
|
|
62
|
+
MIT
|
package/dist/auth.d.ts
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
export declare class NotAuthenticatedError extends Error {
|
|
2
|
+
constructor(msg?: string);
|
|
3
|
+
}
|
|
4
|
+
/**
|
|
5
|
+
* Resolve a usable token. Order: env PAT → cached (refresh if expired) →
|
|
6
|
+
* throw NotAuthenticatedError.
|
|
7
|
+
*/
|
|
8
|
+
export declare function getToken(): Promise<string>;
|
|
9
|
+
/** How the current token was obtained (for status messaging). */
|
|
10
|
+
export declare function authSource(): Promise<"env" | "cache" | "none">;
|
|
11
|
+
export interface LoginStatus {
|
|
12
|
+
state: "instructions" | "authorized" | "pending" | "error";
|
|
13
|
+
message: string;
|
|
14
|
+
}
|
|
15
|
+
/**
|
|
16
|
+
* Drive the device flow. First call requests a code and returns instructions;
|
|
17
|
+
* subsequent calls poll the same code (resilient to MCP tool-call timeouts).
|
|
18
|
+
*/
|
|
19
|
+
export declare function login(maxPollMs?: number): Promise<LoginStatus>;
|
|
20
|
+
/** Clear any cached token + pending device code. */
|
|
21
|
+
export declare function logout(): Promise<void>;
|
package/dist/auth.js
ADDED
|
@@ -0,0 +1,158 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Authentication: resolves a usable GitHub token from (1) an env PAT, (2) a
|
|
3
|
+
* cached OAuth token (refreshed if expired), or (3) the OAuth **device flow**.
|
|
4
|
+
* The device flow is hand-rolled against GitHub's 3 endpoints; tokens are cached
|
|
5
|
+
* at ~/.config/mcp-github/auth.json with 0600 perms and are never logged.
|
|
6
|
+
*/
|
|
7
|
+
import { promises as fs } from "node:fs";
|
|
8
|
+
import { ACCESS_TOKEN_URL, DEVICE_CODE_URL, SCOPES, getAuthFile, getClientId, getConfigDir, getEnvToken, } from "./config.js";
|
|
9
|
+
export class NotAuthenticatedError extends Error {
|
|
10
|
+
constructor(msg = "Not authenticated. Run github_login, or set GITHUB_TOKEN to a Personal Access Token.") {
|
|
11
|
+
super(msg);
|
|
12
|
+
this.name = "NotAuthenticatedError";
|
|
13
|
+
}
|
|
14
|
+
}
|
|
15
|
+
async function loadCache() {
|
|
16
|
+
try {
|
|
17
|
+
return JSON.parse(await fs.readFile(getAuthFile(), "utf8"));
|
|
18
|
+
}
|
|
19
|
+
catch {
|
|
20
|
+
return {};
|
|
21
|
+
}
|
|
22
|
+
}
|
|
23
|
+
async function saveCache(cache) {
|
|
24
|
+
await fs.mkdir(getConfigDir(), { recursive: true });
|
|
25
|
+
const file = getAuthFile();
|
|
26
|
+
const tmp = `${file}.${process.pid}.tmp`;
|
|
27
|
+
await fs.writeFile(tmp, JSON.stringify(cache, null, 2), { mode: 0o600 });
|
|
28
|
+
await fs.rename(tmp, file);
|
|
29
|
+
await fs.chmod(file, 0o600).catch(() => { });
|
|
30
|
+
}
|
|
31
|
+
/** POST application/x-www-form-urlencoded, parse JSON. */
|
|
32
|
+
async function postForm(url, params) {
|
|
33
|
+
const res = await fetch(url, {
|
|
34
|
+
method: "POST",
|
|
35
|
+
headers: { Accept: "application/json", "Content-Type": "application/x-www-form-urlencoded" },
|
|
36
|
+
body: new URLSearchParams(params).toString(),
|
|
37
|
+
});
|
|
38
|
+
return res.json();
|
|
39
|
+
}
|
|
40
|
+
/** Exchange a refresh token for a fresh access token (if the app issues them). */
|
|
41
|
+
async function refresh(stored) {
|
|
42
|
+
const clientId = getClientId();
|
|
43
|
+
if (!clientId || !stored.refresh_token)
|
|
44
|
+
return undefined;
|
|
45
|
+
const data = await postForm(ACCESS_TOKEN_URL, {
|
|
46
|
+
client_id: clientId,
|
|
47
|
+
grant_type: "refresh_token",
|
|
48
|
+
refresh_token: stored.refresh_token,
|
|
49
|
+
});
|
|
50
|
+
if (!data.access_token)
|
|
51
|
+
return undefined;
|
|
52
|
+
return tokenFromResponse(data);
|
|
53
|
+
}
|
|
54
|
+
function tokenFromResponse(data) {
|
|
55
|
+
return {
|
|
56
|
+
access_token: data.access_token,
|
|
57
|
+
refresh_token: data.refresh_token,
|
|
58
|
+
expires_at: data.expires_in ? Date.now() + Number(data.expires_in) * 1000 : undefined,
|
|
59
|
+
scope: data.scope,
|
|
60
|
+
};
|
|
61
|
+
}
|
|
62
|
+
/**
|
|
63
|
+
* Resolve a usable token. Order: env PAT → cached (refresh if expired) →
|
|
64
|
+
* throw NotAuthenticatedError.
|
|
65
|
+
*/
|
|
66
|
+
export async function getToken() {
|
|
67
|
+
const env = getEnvToken();
|
|
68
|
+
if (env)
|
|
69
|
+
return env;
|
|
70
|
+
const cache = await loadCache();
|
|
71
|
+
const stored = cache.token;
|
|
72
|
+
if (stored) {
|
|
73
|
+
const expired = stored.expires_at !== undefined && Date.now() >= stored.expires_at - 30_000;
|
|
74
|
+
if (!expired)
|
|
75
|
+
return stored.access_token;
|
|
76
|
+
const refreshed = await refresh(stored);
|
|
77
|
+
if (refreshed) {
|
|
78
|
+
await saveCache({ ...cache, token: refreshed });
|
|
79
|
+
return refreshed.access_token;
|
|
80
|
+
}
|
|
81
|
+
// expired and not refreshable → fall through to unauthenticated
|
|
82
|
+
}
|
|
83
|
+
throw new NotAuthenticatedError();
|
|
84
|
+
}
|
|
85
|
+
/** How the current token was obtained (for status messaging). */
|
|
86
|
+
export async function authSource() {
|
|
87
|
+
if (getEnvToken())
|
|
88
|
+
return "env";
|
|
89
|
+
return (await loadCache()).token ? "cache" : "none";
|
|
90
|
+
}
|
|
91
|
+
/**
|
|
92
|
+
* Drive the device flow. First call requests a code and returns instructions;
|
|
93
|
+
* subsequent calls poll the same code (resilient to MCP tool-call timeouts).
|
|
94
|
+
*/
|
|
95
|
+
export async function login(maxPollMs = 50_000) {
|
|
96
|
+
const clientId = getClientId();
|
|
97
|
+
if (!clientId) {
|
|
98
|
+
return {
|
|
99
|
+
state: "error",
|
|
100
|
+
message: "Device login needs a GitHub OAuth App. Set GITHUB_CLIENT_ID (register an OAuth App with device flow enabled), or use a Personal Access Token via GITHUB_TOKEN.",
|
|
101
|
+
};
|
|
102
|
+
}
|
|
103
|
+
const cache = await loadCache();
|
|
104
|
+
let pending = cache.pending;
|
|
105
|
+
// No live pending code → request one and return instructions.
|
|
106
|
+
if (!pending || Date.now() >= pending.expires_at) {
|
|
107
|
+
const data = await postForm(DEVICE_CODE_URL, { client_id: clientId, scope: SCOPES });
|
|
108
|
+
if (!data.device_code) {
|
|
109
|
+
return { state: "error", message: `Failed to start device flow: ${data.error_description || data.error || "unknown error"}` };
|
|
110
|
+
}
|
|
111
|
+
pending = {
|
|
112
|
+
device_code: data.device_code,
|
|
113
|
+
user_code: data.user_code,
|
|
114
|
+
verification_uri: data.verification_uri,
|
|
115
|
+
interval: Number(data.interval) || 5,
|
|
116
|
+
expires_at: Date.now() + Number(data.expires_in || 900) * 1000,
|
|
117
|
+
};
|
|
118
|
+
await saveCache({ ...cache, pending });
|
|
119
|
+
return {
|
|
120
|
+
state: "instructions",
|
|
121
|
+
message: `Open ${pending.verification_uri} and enter code ${pending.user_code}, then run github_login again to finish.`,
|
|
122
|
+
};
|
|
123
|
+
}
|
|
124
|
+
// Live pending code → poll for authorization (bounded).
|
|
125
|
+
const deadline = Date.now() + maxPollMs;
|
|
126
|
+
let interval = pending.interval;
|
|
127
|
+
while (Date.now() < deadline) {
|
|
128
|
+
const data = await postForm(ACCESS_TOKEN_URL, {
|
|
129
|
+
client_id: clientId,
|
|
130
|
+
device_code: pending.device_code,
|
|
131
|
+
grant_type: "urn:ietf:params:oauth:grant-type:device_code",
|
|
132
|
+
});
|
|
133
|
+
if (data.access_token) {
|
|
134
|
+
await saveCache({ token: tokenFromResponse(data) }); // clears pending
|
|
135
|
+
return { state: "authorized", message: "Authenticated with GitHub. ✅" };
|
|
136
|
+
}
|
|
137
|
+
if (data.error === "authorization_pending") {
|
|
138
|
+
// keep waiting
|
|
139
|
+
}
|
|
140
|
+
else if (data.error === "slow_down") {
|
|
141
|
+
interval = (Number(data.interval) || interval) + 5;
|
|
142
|
+
}
|
|
143
|
+
else {
|
|
144
|
+
await saveCache({ ...cache, pending: undefined });
|
|
145
|
+
return { state: "error", message: `Device login failed: ${data.error_description || data.error}` };
|
|
146
|
+
}
|
|
147
|
+
await new Promise((r) => setTimeout(r, interval * 1000));
|
|
148
|
+
}
|
|
149
|
+
return {
|
|
150
|
+
state: "pending",
|
|
151
|
+
message: `Still waiting for authorization. Open ${pending.verification_uri} (code ${pending.user_code}) and run github_login again.`,
|
|
152
|
+
};
|
|
153
|
+
}
|
|
154
|
+
/** Clear any cached token + pending device code. */
|
|
155
|
+
export async function logout() {
|
|
156
|
+
await fs.rm(getAuthFile(), { force: true });
|
|
157
|
+
}
|
|
158
|
+
//# sourceMappingURL=auth.js.map
|
package/dist/auth.js.map
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"auth.js","sourceRoot":"","sources":["../src/auth.ts"],"names":[],"mappings":"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"}
|
package/dist/config.d.ts
ADDED
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
/** Server version (kept in lockstep with package.json + index.ts). */
|
|
2
|
+
export declare const VERSION = "0.1.0";
|
|
3
|
+
/** OAuth scopes requested by the device flow (space-separated). */
|
|
4
|
+
export declare const SCOPES = "repo read:org notifications";
|
|
5
|
+
/** Default page size for list/search endpoints. */
|
|
6
|
+
export declare const DEFAULT_PER_PAGE = 30;
|
|
7
|
+
/** GitHub OAuth endpoints (device flow). */
|
|
8
|
+
export declare const DEVICE_CODE_URL = "https://github.com/login/device/code";
|
|
9
|
+
export declare const ACCESS_TOKEN_URL = "https://github.com/login/oauth/access_token";
|
|
10
|
+
/**
|
|
11
|
+
* Public OAuth-App client id for the device flow (no client secret needed).
|
|
12
|
+
* Register a GitHub OAuth App with device flow enabled and set GITHUB_CLIENT_ID.
|
|
13
|
+
* The PAT path works without this.
|
|
14
|
+
*/
|
|
15
|
+
export declare function getClientId(): string | undefined;
|
|
16
|
+
/** A Personal Access Token from the environment, if provided. */
|
|
17
|
+
export declare function getEnvToken(): string | undefined;
|
|
18
|
+
/** Config directory for the cached token (XDG-aware). */
|
|
19
|
+
export declare function getConfigDir(): string;
|
|
20
|
+
/** Path to the 0600 token cache. */
|
|
21
|
+
export declare function getAuthFile(): string;
|
|
22
|
+
/** When true, write tools are not registered. */
|
|
23
|
+
export declare function isReadOnly(): boolean;
|
package/dist/config.js
ADDED
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
import { homedir } from "node:os";
|
|
2
|
+
import path from "node:path";
|
|
3
|
+
/** Server version (kept in lockstep with package.json + index.ts). */
|
|
4
|
+
export const VERSION = "0.1.0";
|
|
5
|
+
/** OAuth scopes requested by the device flow (space-separated). */
|
|
6
|
+
export const SCOPES = "repo read:org notifications";
|
|
7
|
+
/** Default page size for list/search endpoints. */
|
|
8
|
+
export const DEFAULT_PER_PAGE = 30;
|
|
9
|
+
/** GitHub OAuth endpoints (device flow). */
|
|
10
|
+
export const DEVICE_CODE_URL = "https://github.com/login/device/code";
|
|
11
|
+
export const ACCESS_TOKEN_URL = "https://github.com/login/oauth/access_token";
|
|
12
|
+
/**
|
|
13
|
+
* Public OAuth-App client id for the device flow (no client secret needed).
|
|
14
|
+
* Register a GitHub OAuth App with device flow enabled and set GITHUB_CLIENT_ID.
|
|
15
|
+
* The PAT path works without this.
|
|
16
|
+
*/
|
|
17
|
+
export function getClientId() {
|
|
18
|
+
return process.env.GITHUB_CLIENT_ID?.trim() || undefined;
|
|
19
|
+
}
|
|
20
|
+
/** A Personal Access Token from the environment, if provided. */
|
|
21
|
+
export function getEnvToken() {
|
|
22
|
+
return (process.env.GITHUB_TOKEN || process.env.GITHUB_PERSONAL_ACCESS_TOKEN)?.trim() || undefined;
|
|
23
|
+
}
|
|
24
|
+
/** Config directory for the cached token (XDG-aware). */
|
|
25
|
+
export function getConfigDir() {
|
|
26
|
+
const base = process.env.XDG_CONFIG_HOME?.trim() || path.join(homedir(), ".config");
|
|
27
|
+
return path.join(base, "mcp-github");
|
|
28
|
+
}
|
|
29
|
+
/** Path to the 0600 token cache. */
|
|
30
|
+
export function getAuthFile() {
|
|
31
|
+
return path.join(getConfigDir(), "auth.json");
|
|
32
|
+
}
|
|
33
|
+
/** When true, write tools are not registered. */
|
|
34
|
+
export function isReadOnly() {
|
|
35
|
+
const v = (process.env.GITHUB_READONLY ?? "").toLowerCase();
|
|
36
|
+
return v === "1" || v === "true";
|
|
37
|
+
}
|
|
38
|
+
//# sourceMappingURL=config.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"config.js","sourceRoot":"","sources":["../src/config.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,OAAO,EAAE,MAAM,SAAS,CAAC;AAClC,OAAO,IAAI,MAAM,WAAW,CAAC;AAE7B,sEAAsE;AACtE,MAAM,CAAC,MAAM,OAAO,GAAG,OAAO,CAAC;AAE/B,mEAAmE;AACnE,MAAM,CAAC,MAAM,MAAM,GAAG,6BAA6B,CAAC;AAEpD,mDAAmD;AACnD,MAAM,CAAC,MAAM,gBAAgB,GAAG,EAAE,CAAC;AAEnC,4CAA4C;AAC5C,MAAM,CAAC,MAAM,eAAe,GAAG,sCAAsC,CAAC;AACtE,MAAM,CAAC,MAAM,gBAAgB,GAAG,6CAA6C,CAAC;AAE9E;;;;GAIG;AACH,MAAM,UAAU,WAAW;IACzB,OAAO,OAAO,CAAC,GAAG,CAAC,gBAAgB,EAAE,IAAI,EAAE,IAAI,SAAS,CAAC;AAC3D,CAAC;AAED,iEAAiE;AACjE,MAAM,UAAU,WAAW;IACzB,OAAO,CAAC,OAAO,CAAC,GAAG,CAAC,YAAY,IAAI,OAAO,CAAC,GAAG,CAAC,4BAA4B,CAAC,EAAE,IAAI,EAAE,IAAI,SAAS,CAAC;AACrG,CAAC;AAED,yDAAyD;AACzD,MAAM,UAAU,YAAY;IAC1B,MAAM,IAAI,GAAG,OAAO,CAAC,GAAG,CAAC,eAAe,EAAE,IAAI,EAAE,IAAI,IAAI,CAAC,IAAI,CAAC,OAAO,EAAE,EAAE,SAAS,CAAC,CAAC;IACpF,OAAO,IAAI,CAAC,IAAI,CAAC,IAAI,EAAE,YAAY,CAAC,CAAC;AACvC,CAAC;AAED,oCAAoC;AACpC,MAAM,UAAU,WAAW;IACzB,OAAO,IAAI,CAAC,IAAI,CAAC,YAAY,EAAE,EAAE,WAAW,CAAC,CAAC;AAChD,CAAC;AAED,iDAAiD;AACjD,MAAM,UAAU,UAAU;IACxB,MAAM,CAAC,GAAG,CAAC,OAAO,CAAC,GAAG,CAAC,eAAe,IAAI,EAAE,CAAC,CAAC,WAAW,EAAE,CAAC;IAC5D,OAAO,CAAC,KAAK,GAAG,IAAI,CAAC,KAAK,MAAM,CAAC;AACnC,CAAC"}
|
package/dist/gh.d.ts
ADDED
|
@@ -0,0 +1,130 @@
|
|
|
1
|
+
export declare function whoami(): Promise<{
|
|
2
|
+
login: string;
|
|
3
|
+
name: string | null;
|
|
4
|
+
url: string;
|
|
5
|
+
public_repos: number;
|
|
6
|
+
private_repos: number | undefined;
|
|
7
|
+
}>;
|
|
8
|
+
export declare function searchRepos(q: string, limit?: number): Promise<{
|
|
9
|
+
full_name: string;
|
|
10
|
+
stars: number;
|
|
11
|
+
language: string | null;
|
|
12
|
+
description: string | null;
|
|
13
|
+
url: string;
|
|
14
|
+
}[]>;
|
|
15
|
+
export declare function searchCode(q: string, limit?: number): Promise<{
|
|
16
|
+
repo: string;
|
|
17
|
+
path: string;
|
|
18
|
+
url: string;
|
|
19
|
+
}[]>;
|
|
20
|
+
export declare function searchIssues(q: string, limit?: number): Promise<{
|
|
21
|
+
repo: string;
|
|
22
|
+
number: number;
|
|
23
|
+
title: string;
|
|
24
|
+
state: string;
|
|
25
|
+
is_pr: boolean;
|
|
26
|
+
url: string;
|
|
27
|
+
}[]>;
|
|
28
|
+
export declare function getRepo(owner: string, repo: string): Promise<{
|
|
29
|
+
full_name: string;
|
|
30
|
+
description: string | null;
|
|
31
|
+
stars: number;
|
|
32
|
+
forks: number;
|
|
33
|
+
open_issues: number;
|
|
34
|
+
language: string | null;
|
|
35
|
+
default_branch: string;
|
|
36
|
+
license: string | null | undefined;
|
|
37
|
+
url: string;
|
|
38
|
+
}>;
|
|
39
|
+
export declare function listIssues(owner: string, repo: string, state: "open" | "closed" | "all", limit?: number): Promise<{
|
|
40
|
+
number: number;
|
|
41
|
+
title: string;
|
|
42
|
+
state: string;
|
|
43
|
+
comments: number;
|
|
44
|
+
url: string;
|
|
45
|
+
}[]>;
|
|
46
|
+
export declare function getIssue(owner: string, repo: string, issue_number: number): Promise<{
|
|
47
|
+
number: number;
|
|
48
|
+
title: string;
|
|
49
|
+
state: string;
|
|
50
|
+
author: string | undefined;
|
|
51
|
+
body: string | null | undefined;
|
|
52
|
+
url: string;
|
|
53
|
+
comments: {
|
|
54
|
+
author: string | undefined;
|
|
55
|
+
body: string | undefined;
|
|
56
|
+
}[];
|
|
57
|
+
}>;
|
|
58
|
+
export declare function listPullRequests(owner: string, repo: string, state: "open" | "closed" | "all", limit?: number): Promise<{
|
|
59
|
+
number: number;
|
|
60
|
+
title: string;
|
|
61
|
+
state: string;
|
|
62
|
+
author: string | undefined;
|
|
63
|
+
draft: boolean | undefined;
|
|
64
|
+
url: string;
|
|
65
|
+
}[]>;
|
|
66
|
+
export declare function getPullRequest(owner: string, repo: string, pull_number: number): Promise<{
|
|
67
|
+
number: number;
|
|
68
|
+
title: string;
|
|
69
|
+
state: "open" | "closed";
|
|
70
|
+
author: string;
|
|
71
|
+
body: string | null;
|
|
72
|
+
additions: number;
|
|
73
|
+
deletions: number;
|
|
74
|
+
changed_files: number;
|
|
75
|
+
merged: boolean;
|
|
76
|
+
url: string;
|
|
77
|
+
}>;
|
|
78
|
+
export declare function getFileContents(owner: string, repo: string, p: string, ref?: string): Promise<{
|
|
79
|
+
type: string;
|
|
80
|
+
entries: {
|
|
81
|
+
name: string;
|
|
82
|
+
type: "dir" | "file" | "submodule" | "symlink";
|
|
83
|
+
size: number;
|
|
84
|
+
}[];
|
|
85
|
+
path?: undefined;
|
|
86
|
+
size?: undefined;
|
|
87
|
+
note?: undefined;
|
|
88
|
+
content?: undefined;
|
|
89
|
+
} | {
|
|
90
|
+
type: string;
|
|
91
|
+
path: string;
|
|
92
|
+
size: number;
|
|
93
|
+
note: string;
|
|
94
|
+
entries?: undefined;
|
|
95
|
+
content?: undefined;
|
|
96
|
+
} | {
|
|
97
|
+
type: string;
|
|
98
|
+
path: string;
|
|
99
|
+
size: number;
|
|
100
|
+
content: string;
|
|
101
|
+
entries?: undefined;
|
|
102
|
+
note?: undefined;
|
|
103
|
+
} | {
|
|
104
|
+
type: "submodule" | "symlink";
|
|
105
|
+
entries?: undefined;
|
|
106
|
+
path?: undefined;
|
|
107
|
+
size?: undefined;
|
|
108
|
+
note?: undefined;
|
|
109
|
+
content?: undefined;
|
|
110
|
+
}>;
|
|
111
|
+
export declare function listNotifications(limit?: number): Promise<{
|
|
112
|
+
repo: string;
|
|
113
|
+
subject: string;
|
|
114
|
+
type: string;
|
|
115
|
+
reason: string;
|
|
116
|
+
unread: boolean;
|
|
117
|
+
}[]>;
|
|
118
|
+
export declare function rateLimit(): Promise<{
|
|
119
|
+
limit: number;
|
|
120
|
+
remaining: number;
|
|
121
|
+
reset: string;
|
|
122
|
+
}>;
|
|
123
|
+
export declare function createIssue(owner: string, repo: string, title: string, body?: string): Promise<{
|
|
124
|
+
number: number;
|
|
125
|
+
url: string;
|
|
126
|
+
}>;
|
|
127
|
+
export declare function addIssueComment(owner: string, repo: string, issue_number: number, body: string): Promise<{
|
|
128
|
+
id: number;
|
|
129
|
+
url: string;
|
|
130
|
+
}>;
|
package/dist/gh.js
ADDED
|
@@ -0,0 +1,109 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* GitHub API layer over @octokit/rest. Each call builds an Octokit with the
|
|
3
|
+
* currently-resolved token (so it picks up a fresh login). Wrappers return
|
|
4
|
+
* trimmed, token-efficient objects rather than raw API payloads.
|
|
5
|
+
*/
|
|
6
|
+
import { Octokit } from "@octokit/rest";
|
|
7
|
+
import { getToken } from "./auth.js";
|
|
8
|
+
import { DEFAULT_PER_PAGE, VERSION } from "./config.js";
|
|
9
|
+
async function octo() {
|
|
10
|
+
return new Octokit({ auth: await getToken(), userAgent: `mcp-github/${VERSION}` });
|
|
11
|
+
}
|
|
12
|
+
const cap = (n) => Math.min(Math.max(n ?? DEFAULT_PER_PAGE, 1), 100);
|
|
13
|
+
export async function whoami() {
|
|
14
|
+
const { data } = await (await octo()).rest.users.getAuthenticated();
|
|
15
|
+
return { login: data.login, name: data.name, url: data.html_url, public_repos: data.public_repos, private_repos: data.total_private_repos };
|
|
16
|
+
}
|
|
17
|
+
export async function searchRepos(q, limit) {
|
|
18
|
+
const { data } = await (await octo()).rest.search.repos({ q, per_page: cap(limit) });
|
|
19
|
+
return data.items.map((r) => ({ full_name: r.full_name, stars: r.stargazers_count, language: r.language, description: r.description, url: r.html_url }));
|
|
20
|
+
}
|
|
21
|
+
export async function searchCode(q, limit) {
|
|
22
|
+
const { data } = await (await octo()).rest.search.code({ q, per_page: cap(limit) });
|
|
23
|
+
return data.items.map((i) => ({ repo: i.repository.full_name, path: i.path, url: i.html_url }));
|
|
24
|
+
}
|
|
25
|
+
export async function searchIssues(q, limit) {
|
|
26
|
+
const { data } = await (await octo()).rest.search.issuesAndPullRequests({ q, per_page: cap(limit) });
|
|
27
|
+
return data.items.map((i) => ({ repo: i.repository_url.replace("https://api.github.com/repos/", ""), number: i.number, title: i.title, state: i.state, is_pr: !!i.pull_request, url: i.html_url }));
|
|
28
|
+
}
|
|
29
|
+
export async function getRepo(owner, repo) {
|
|
30
|
+
const { data } = await (await octo()).rest.repos.get({ owner, repo });
|
|
31
|
+
return {
|
|
32
|
+
full_name: data.full_name,
|
|
33
|
+
description: data.description,
|
|
34
|
+
stars: data.stargazers_count,
|
|
35
|
+
forks: data.forks_count,
|
|
36
|
+
open_issues: data.open_issues_count,
|
|
37
|
+
language: data.language,
|
|
38
|
+
default_branch: data.default_branch,
|
|
39
|
+
license: data.license?.spdx_id,
|
|
40
|
+
url: data.html_url,
|
|
41
|
+
};
|
|
42
|
+
}
|
|
43
|
+
export async function listIssues(owner, repo, state, limit) {
|
|
44
|
+
const { data } = await (await octo()).rest.issues.listForRepo({ owner, repo, state, per_page: cap(limit) });
|
|
45
|
+
return data.filter((i) => !i.pull_request).map((i) => ({ number: i.number, title: i.title, state: i.state, comments: i.comments, url: i.html_url }));
|
|
46
|
+
}
|
|
47
|
+
export async function getIssue(owner, repo, issue_number) {
|
|
48
|
+
const o = await octo();
|
|
49
|
+
const { data } = await o.rest.issues.get({ owner, repo, issue_number });
|
|
50
|
+
const { data: comments } = await o.rest.issues.listComments({ owner, repo, issue_number, per_page: 20 });
|
|
51
|
+
return {
|
|
52
|
+
number: data.number,
|
|
53
|
+
title: data.title,
|
|
54
|
+
state: data.state,
|
|
55
|
+
author: data.user?.login,
|
|
56
|
+
body: data.body,
|
|
57
|
+
url: data.html_url,
|
|
58
|
+
comments: comments.map((c) => ({ author: c.user?.login, body: c.body })),
|
|
59
|
+
};
|
|
60
|
+
}
|
|
61
|
+
export async function listPullRequests(owner, repo, state, limit) {
|
|
62
|
+
const { data } = await (await octo()).rest.pulls.list({ owner, repo, state, per_page: cap(limit) });
|
|
63
|
+
return data.map((p) => ({ number: p.number, title: p.title, state: p.state, author: p.user?.login, draft: p.draft, url: p.html_url }));
|
|
64
|
+
}
|
|
65
|
+
export async function getPullRequest(owner, repo, pull_number) {
|
|
66
|
+
const { data } = await (await octo()).rest.pulls.get({ owner, repo, pull_number });
|
|
67
|
+
return {
|
|
68
|
+
number: data.number,
|
|
69
|
+
title: data.title,
|
|
70
|
+
state: data.state,
|
|
71
|
+
author: data.user?.login,
|
|
72
|
+
body: data.body,
|
|
73
|
+
additions: data.additions,
|
|
74
|
+
deletions: data.deletions,
|
|
75
|
+
changed_files: data.changed_files,
|
|
76
|
+
merged: data.merged,
|
|
77
|
+
url: data.html_url,
|
|
78
|
+
};
|
|
79
|
+
}
|
|
80
|
+
export async function getFileContents(owner, repo, p, ref) {
|
|
81
|
+
const { data } = await (await octo()).rest.repos.getContent({ owner, repo, path: p, ref });
|
|
82
|
+
if (Array.isArray(data)) {
|
|
83
|
+
return { type: "dir", entries: data.map((e) => ({ name: e.name, type: e.type, size: e.size })) };
|
|
84
|
+
}
|
|
85
|
+
if (data.type === "file" && "content" in data) {
|
|
86
|
+
if (data.size > 1024 * 1024)
|
|
87
|
+
return { type: "file", path: data.path, size: data.size, note: "file too large to inline" };
|
|
88
|
+
return { type: "file", path: data.path, size: data.size, content: Buffer.from(data.content, "base64").toString("utf8") };
|
|
89
|
+
}
|
|
90
|
+
return { type: data.type };
|
|
91
|
+
}
|
|
92
|
+
export async function listNotifications(limit) {
|
|
93
|
+
const { data } = await (await octo()).rest.activity.listNotificationsForAuthenticatedUser({ per_page: cap(limit) });
|
|
94
|
+
return data.map((n) => ({ repo: n.repository.full_name, subject: n.subject.title, type: n.subject.type, reason: n.reason, unread: n.unread }));
|
|
95
|
+
}
|
|
96
|
+
export async function rateLimit() {
|
|
97
|
+
const { data } = await (await octo()).rest.rateLimit.get();
|
|
98
|
+
const core = data.resources.core;
|
|
99
|
+
return { limit: core.limit, remaining: core.remaining, reset: new Date(core.reset * 1000).toISOString() };
|
|
100
|
+
}
|
|
101
|
+
export async function createIssue(owner, repo, title, body) {
|
|
102
|
+
const { data } = await (await octo()).rest.issues.create({ owner, repo, title, body });
|
|
103
|
+
return { number: data.number, url: data.html_url };
|
|
104
|
+
}
|
|
105
|
+
export async function addIssueComment(owner, repo, issue_number, body) {
|
|
106
|
+
const { data } = await (await octo()).rest.issues.createComment({ owner, repo, issue_number, body });
|
|
107
|
+
return { id: data.id, url: data.html_url };
|
|
108
|
+
}
|
|
109
|
+
//# sourceMappingURL=gh.js.map
|
package/dist/gh.js.map
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"gh.js","sourceRoot":"","sources":["../src/gh.ts"],"names":[],"mappings":"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"}
|
package/dist/index.d.ts
ADDED
package/dist/index.js
ADDED
|
@@ -0,0 +1,191 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
/**
|
|
3
|
+
* @abhishekmcp/github — GitHub MCP server.
|
|
4
|
+
* Tool registration only; auth lives in auth.ts, API calls in gh.ts. Write tools
|
|
5
|
+
* are omitted when GITHUB_READONLY is set. No auth is required at startup —
|
|
6
|
+
* tools return clear guidance if the user isn't authenticated yet.
|
|
7
|
+
*/
|
|
8
|
+
import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
|
|
9
|
+
import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio.js";
|
|
10
|
+
import { z } from "zod";
|
|
11
|
+
import { VERSION, isReadOnly } from "./config.js";
|
|
12
|
+
import { NotAuthenticatedError, authSource, login, logout } from "./auth.js";
|
|
13
|
+
import * as gh from "./gh.js";
|
|
14
|
+
const server = new McpServer({ name: "mcp-github-server", version: VERSION });
|
|
15
|
+
const text = (value) => ({ content: [{ type: "text", text: value }] });
|
|
16
|
+
const json = (v) => text(JSON.stringify(v, null, 2));
|
|
17
|
+
function fail(err) {
|
|
18
|
+
if (err instanceof NotAuthenticatedError)
|
|
19
|
+
return text(err.message);
|
|
20
|
+
const e = err;
|
|
21
|
+
if (e?.status) {
|
|
22
|
+
let msg = `GitHub API error ${e.status}: ${e.message}`;
|
|
23
|
+
if (e.status === 401)
|
|
24
|
+
msg += " — token invalid/expired; run github_login or check GITHUB_TOKEN.";
|
|
25
|
+
const h = e.response?.headers;
|
|
26
|
+
if (e.status === 403 && h?.["x-ratelimit-remaining"] === "0") {
|
|
27
|
+
msg += ` — rate limit exceeded; resets at ${new Date(Number(h["x-ratelimit-reset"]) * 1000).toISOString()}.`;
|
|
28
|
+
}
|
|
29
|
+
return text(msg);
|
|
30
|
+
}
|
|
31
|
+
return text(`Error: ${err.message}`);
|
|
32
|
+
}
|
|
33
|
+
const owner = z.string().describe("Repository owner (user or org)");
|
|
34
|
+
const repo = z.string().describe("Repository name");
|
|
35
|
+
const stateEnum = z.enum(["open", "closed", "all"]).optional().describe("Filter by state (default open)");
|
|
36
|
+
// --- Auth tools (always) -------------------------------------------------
|
|
37
|
+
server.registerTool("github_login", {
|
|
38
|
+
title: "Log in to GitHub",
|
|
39
|
+
description: "Authenticate via GitHub OAuth device flow. First call returns a code + URL to open; run it again after authorizing to finish. (Or set GITHUB_TOKEN to skip.)",
|
|
40
|
+
inputSchema: {},
|
|
41
|
+
}, async () => {
|
|
42
|
+
try {
|
|
43
|
+
return text((await login()).message);
|
|
44
|
+
}
|
|
45
|
+
catch (err) {
|
|
46
|
+
return fail(err);
|
|
47
|
+
}
|
|
48
|
+
});
|
|
49
|
+
server.registerTool("github_logout", { title: "Log out", description: "Clear the cached GitHub token.", inputSchema: {} }, async () => {
|
|
50
|
+
await logout();
|
|
51
|
+
return text("Logged out (cached token cleared).");
|
|
52
|
+
});
|
|
53
|
+
server.registerTool("whoami", { title: "Who am I", description: "Show the authenticated GitHub user (and how the token was obtained).", inputSchema: {} }, async () => {
|
|
54
|
+
try {
|
|
55
|
+
const me = await gh.whoami();
|
|
56
|
+
return json({ ...me, auth_source: await authSource() });
|
|
57
|
+
}
|
|
58
|
+
catch (err) {
|
|
59
|
+
return fail(err);
|
|
60
|
+
}
|
|
61
|
+
});
|
|
62
|
+
// --- Search --------------------------------------------------------------
|
|
63
|
+
server.registerTool("search_repos", { title: "Search repositories", description: "Search GitHub repositories (GitHub search syntax).", inputSchema: { query: z.string(), limit: z.number().int().positive().max(100).optional() } }, async ({ query, limit }) => {
|
|
64
|
+
try {
|
|
65
|
+
return json(await gh.searchRepos(query, limit));
|
|
66
|
+
}
|
|
67
|
+
catch (err) {
|
|
68
|
+
return fail(err);
|
|
69
|
+
}
|
|
70
|
+
});
|
|
71
|
+
server.registerTool("search_code", { title: "Search code", description: "Search code across GitHub (e.g. 'addEventListener repo:owner/name').", inputSchema: { query: z.string(), limit: z.number().int().positive().max(100).optional() } }, async ({ query, limit }) => {
|
|
72
|
+
try {
|
|
73
|
+
return json(await gh.searchCode(query, limit));
|
|
74
|
+
}
|
|
75
|
+
catch (err) {
|
|
76
|
+
return fail(err);
|
|
77
|
+
}
|
|
78
|
+
});
|
|
79
|
+
server.registerTool("search_issues", { title: "Search issues/PRs", description: "Search issues and pull requests (GitHub search syntax).", inputSchema: { query: z.string(), limit: z.number().int().positive().max(100).optional() } }, async ({ query, limit }) => {
|
|
80
|
+
try {
|
|
81
|
+
return json(await gh.searchIssues(query, limit));
|
|
82
|
+
}
|
|
83
|
+
catch (err) {
|
|
84
|
+
return fail(err);
|
|
85
|
+
}
|
|
86
|
+
});
|
|
87
|
+
// --- Repos / issues / PRs (read) -----------------------------------------
|
|
88
|
+
server.registerTool("get_repo", { title: "Get repository", description: "Repository metadata (stars, language, default branch, license).", inputSchema: { owner, repo } }, async ({ owner, repo }) => {
|
|
89
|
+
try {
|
|
90
|
+
return json(await gh.getRepo(owner, repo));
|
|
91
|
+
}
|
|
92
|
+
catch (err) {
|
|
93
|
+
return fail(err);
|
|
94
|
+
}
|
|
95
|
+
});
|
|
96
|
+
server.registerTool("list_issues", { title: "List issues", description: "List a repo's issues (excludes PRs).", inputSchema: { owner, repo, state: stateEnum, limit: z.number().int().positive().max(100).optional() } }, async ({ owner, repo, state, limit }) => {
|
|
97
|
+
try {
|
|
98
|
+
return json(await gh.listIssues(owner, repo, state ?? "open", limit));
|
|
99
|
+
}
|
|
100
|
+
catch (err) {
|
|
101
|
+
return fail(err);
|
|
102
|
+
}
|
|
103
|
+
});
|
|
104
|
+
server.registerTool("get_issue", { title: "Get issue", description: "An issue's details plus its first comments.", inputSchema: { owner, repo, number: z.number().int().positive() } }, async ({ owner, repo, number }) => {
|
|
105
|
+
try {
|
|
106
|
+
return json(await gh.getIssue(owner, repo, number));
|
|
107
|
+
}
|
|
108
|
+
catch (err) {
|
|
109
|
+
return fail(err);
|
|
110
|
+
}
|
|
111
|
+
});
|
|
112
|
+
server.registerTool("list_pull_requests", { title: "List pull requests", description: "List a repo's pull requests.", inputSchema: { owner, repo, state: stateEnum, limit: z.number().int().positive().max(100).optional() } }, async ({ owner, repo, state, limit }) => {
|
|
113
|
+
try {
|
|
114
|
+
return json(await gh.listPullRequests(owner, repo, state ?? "open", limit));
|
|
115
|
+
}
|
|
116
|
+
catch (err) {
|
|
117
|
+
return fail(err);
|
|
118
|
+
}
|
|
119
|
+
});
|
|
120
|
+
server.registerTool("get_pull_request", { title: "Get pull request", description: "A PR's details (diff stats, merged state, body).", inputSchema: { owner, repo, number: z.number().int().positive() } }, async ({ owner, repo, number }) => {
|
|
121
|
+
try {
|
|
122
|
+
return json(await gh.getPullRequest(owner, repo, number));
|
|
123
|
+
}
|
|
124
|
+
catch (err) {
|
|
125
|
+
return fail(err);
|
|
126
|
+
}
|
|
127
|
+
});
|
|
128
|
+
server.registerTool("get_file_contents", { title: "Get file contents", description: "Read a file (decoded) or list a directory in a repo, at an optional ref.", inputSchema: { owner, repo, path: z.string(), ref: z.string().optional().describe("Branch, tag, or commit SHA") } }, async ({ owner, repo, path, ref }) => {
|
|
129
|
+
try {
|
|
130
|
+
return json(await gh.getFileContents(owner, repo, path, ref));
|
|
131
|
+
}
|
|
132
|
+
catch (err) {
|
|
133
|
+
return fail(err);
|
|
134
|
+
}
|
|
135
|
+
});
|
|
136
|
+
server.registerTool("list_notifications", { title: "List notifications", description: "Your unread GitHub notifications.", inputSchema: { limit: z.number().int().positive().max(100).optional() } }, async ({ limit }) => {
|
|
137
|
+
try {
|
|
138
|
+
return json(await gh.listNotifications(limit));
|
|
139
|
+
}
|
|
140
|
+
catch (err) {
|
|
141
|
+
return fail(err);
|
|
142
|
+
}
|
|
143
|
+
});
|
|
144
|
+
server.registerTool("rate_limit", { title: "Rate limit", description: "Your remaining GitHub API requests and reset time.", inputSchema: {} }, async () => {
|
|
145
|
+
try {
|
|
146
|
+
return json(await gh.rateLimit());
|
|
147
|
+
}
|
|
148
|
+
catch (err) {
|
|
149
|
+
return fail(err);
|
|
150
|
+
}
|
|
151
|
+
});
|
|
152
|
+
// --- Write tools (omitted when GITHUB_READONLY) --------------------------
|
|
153
|
+
if (!isReadOnly()) {
|
|
154
|
+
server.registerTool("create_issue", {
|
|
155
|
+
title: "Create issue",
|
|
156
|
+
description: "Open a new issue in a repository.",
|
|
157
|
+
inputSchema: { owner, repo, title: z.string(), body: z.string().optional() },
|
|
158
|
+
annotations: { destructiveHint: true },
|
|
159
|
+
}, async ({ owner, repo, title, body }) => {
|
|
160
|
+
try {
|
|
161
|
+
return json(await gh.createIssue(owner, repo, title, body));
|
|
162
|
+
}
|
|
163
|
+
catch (err) {
|
|
164
|
+
return fail(err);
|
|
165
|
+
}
|
|
166
|
+
});
|
|
167
|
+
server.registerTool("add_issue_comment", {
|
|
168
|
+
title: "Comment on issue",
|
|
169
|
+
description: "Add a comment to an issue or pull request.",
|
|
170
|
+
inputSchema: { owner, repo, number: z.number().int().positive(), body: z.string() },
|
|
171
|
+
annotations: { destructiveHint: true },
|
|
172
|
+
}, async ({ owner, repo, number, body }) => {
|
|
173
|
+
try {
|
|
174
|
+
return json(await gh.addIssueComment(owner, repo, number, body));
|
|
175
|
+
}
|
|
176
|
+
catch (err) {
|
|
177
|
+
return fail(err);
|
|
178
|
+
}
|
|
179
|
+
});
|
|
180
|
+
}
|
|
181
|
+
// --- Startup -------------------------------------------------------------
|
|
182
|
+
async function main() {
|
|
183
|
+
const transport = new StdioServerTransport();
|
|
184
|
+
await server.connect(transport);
|
|
185
|
+
console.error(`mcp-github-server v${VERSION} running${isReadOnly() ? " (read-only)" : ""}.`);
|
|
186
|
+
}
|
|
187
|
+
main().catch((err) => {
|
|
188
|
+
console.error("Fatal error starting mcp-github-server:", err);
|
|
189
|
+
process.exit(1);
|
|
190
|
+
});
|
|
191
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":";AACA;;;;;GAKG;AACH,OAAO,EAAE,SAAS,EAAE,MAAM,yCAAyC,CAAC;AACpE,OAAO,EAAE,oBAAoB,EAAE,MAAM,2CAA2C,CAAC;AACjF,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AACxB,OAAO,EAAE,OAAO,EAAE,UAAU,EAAE,MAAM,aAAa,CAAC;AAClD,OAAO,EAAE,qBAAqB,EAAE,UAAU,EAAE,KAAK,EAAE,MAAM,EAAE,MAAM,WAAW,CAAC;AAC7E,OAAO,KAAK,EAAE,MAAM,SAAS,CAAC;AAE9B,MAAM,MAAM,GAAG,IAAI,SAAS,CAAC,EAAE,IAAI,EAAE,mBAAmB,EAAE,OAAO,EAAE,OAAO,EAAE,CAAC,CAAC;AAE9E,MAAM,IAAI,GAAG,CAAC,KAAa,EAAE,EAAE,CAAC,CAAC,EAAE,OAAO,EAAE,CAAC,EAAE,IAAI,EAAE,MAAe,EAAE,IAAI,EAAE,KAAK,EAAE,CAAC,EAAE,CAAC,CAAC;AACxF,MAAM,IAAI,GAAG,CAAC,CAAU,EAAE,EAAE,CAAC,IAAI,CAAC,IAAI,CAAC,SAAS,CAAC,CAAC,EAAE,IAAI,EAAE,CAAC,CAAC,CAAC,CAAC;AAE9D,SAAS,IAAI,CAAC,GAAY;IACxB,IAAI,GAAG,YAAY,qBAAqB;QAAE,OAAO,IAAI,CAAC,GAAG,CAAC,OAAO,CAAC,CAAC;IACnE,MAAM,CAAC,GAAG,GAA6F,CAAC;IACxG,IAAI,CAAC,EAAE,MAAM,EAAE,CAAC;QACd,IAAI,GAAG,GAAG,oBAAoB,CAAC,CAAC,MAAM,KAAK,CAAC,CAAC,OAAO,EAAE,CAAC;QACvD,IAAI,CAAC,CAAC,MAAM,KAAK,GAAG;YAAE,GAAG,IAAI,mEAAmE,CAAC;QACjG,MAAM,CAAC,GAAG,CAAC,CAAC,QAAQ,EAAE,OAAO,CAAC;QAC9B,IAAI,CAAC,CAAC,MAAM,KAAK,GAAG,IAAI,CAAC,EAAE,CAAC,uBAAuB,CAAC,KAAK,GAAG,EAAE,CAAC;YAC7D,GAAG,IAAI,qCAAqC,IAAI,IAAI,CAAC,MAAM,CAAC,CAAC,CAAC,mBAAmB,CAAC,CAAC,GAAG,IAAI,CAAC,CAAC,WAAW,EAAE,GAAG,CAAC;QAC/G,CAAC;QACD,OAAO,IAAI,CAAC,GAAG,CAAC,CAAC;IACnB,CAAC;IACD,OAAO,IAAI,CAAC,UAAW,GAAa,CAAC,OAAO,EAAE,CAAC,CAAC;AAClD,CAAC;AAED,MAAM,KAAK,GAAG,CAAC,CAAC,MAAM,EAAE,CAAC,QAAQ,CAAC,gCAAgC,CAAC,CAAC;AACpE,MAAM,IAAI,GAAG,CAAC,CAAC,MAAM,EAAE,CAAC,QAAQ,CAAC,iBAAiB,CAAC,CAAC;AACpD,MAAM,SAAS,GAAG,CAAC,CAAC,IAAI,CAAC,CAAC,MAAM,EAAE,QAAQ,EAAE,KAAK,CAAC,CAAC,CAAC,QAAQ,EAAE,CAAC,QAAQ,CAAC,gCAAgC,CAAC,CAAC;AAE1G,4EAA4E;AAE5E,MAAM,CAAC,YAAY,CACjB,cAAc,EACd;IACE,KAAK,EAAE,kBAAkB;IACzB,WAAW,EACT,8JAA8J;IAChK,WAAW,EAAE,EAAE;CAChB,EACD,KAAK,IAAI,EAAE;IACT,IAAI,CAAC;QACH,OAAO,IAAI,CAAC,CAAC,MAAM,KAAK,EAAE,CAAC,CAAC,OAAO,CAAC,CAAC;IACvC,CAAC;IAAC,OAAO,GAAG,EAAE,CAAC;QACb,OAAO,IAAI,CAAC,GAAG,CAAC,CAAC;IACnB,CAAC;AACH,CAAC,CACF,CAAC;AAEF,MAAM,CAAC,YAAY,CACjB,eAAe,EACf,EAAE,KAAK,EAAE,SAAS,EAAE,WAAW,EAAE,gCAAgC,EAAE,WAAW,EAAE,EAAE,EAAE,EACpF,KAAK,IAAI,EAAE;IACT,MAAM,MAAM,EAAE,CAAC;IACf,OAAO,IAAI,CAAC,oCAAoC,CAAC,CAAC;AACpD,CAAC,CACF,CAAC;AAEF,MAAM,CAAC,YAAY,CACjB,QAAQ,EACR,EAAE,KAAK,EAAE,UAAU,EAAE,WAAW,EAAE,sEAAsE,EAAE,WAAW,EAAE,EAAE,EAAE,EAC3H,KAAK,IAAI,EAAE;IACT,IAAI,CAAC;QACH,MAAM,EAAE,GAAG,MAAM,EAAE,CAAC,MAAM,EAAE,CAAC;QAC7B,OAAO,IAAI,CAAC,EAAE,GAAG,EAAE,EAAE,WAAW,EAAE,MAAM,UAAU,EAAE,EAAE,CAAC,CAAC;IAC1D,CAAC;IAAC,OAAO,GAAG,EAAE,CAAC;QACb,OAAO,IAAI,CAAC,GAAG,CAAC,CAAC;IACnB,CAAC;AACH,CAAC,CACF,CAAC;AAEF,4EAA4E;AAE5E,MAAM,CAAC,YAAY,CACjB,cAAc,EACd,EAAE,KAAK,EAAE,qBAAqB,EAAE,WAAW,EAAE,oDAAoD,EAAE,WAAW,EAAE,EAAE,KAAK,EAAE,CAAC,CAAC,MAAM,EAAE,EAAE,KAAK,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,GAAG,EAAE,CAAC,QAAQ,EAAE,CAAC,GAAG,CAAC,GAAG,CAAC,CAAC,QAAQ,EAAE,EAAE,EAAE,EAC/L,KAAK,EAAE,EAAE,KAAK,EAAE,KAAK,EAAE,EAAE,EAAE;IACzB,IAAI,CAAC;QACH,OAAO,IAAI,CAAC,MAAM,EAAE,CAAC,WAAW,CAAC,KAAK,EAAE,KAAK,CAAC,CAAC,CAAC;IAClD,CAAC;IAAC,OAAO,GAAG,EAAE,CAAC;QACb,OAAO,IAAI,CAAC,GAAG,CAAC,CAAC;IACnB,CAAC;AACH,CAAC,CACF,CAAC;AAEF,MAAM,CAAC,YAAY,CACjB,aAAa,EACb,EAAE,KAAK,EAAE,aAAa,EAAE,WAAW,EAAE,sEAAsE,EAAE,WAAW,EAAE,EAAE,KAAK,EAAE,CAAC,CAAC,MAAM,EAAE,EAAE,KAAK,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,GAAG,EAAE,CAAC,QAAQ,EAAE,CAAC,GAAG,CAAC,GAAG,CAAC,CAAC,QAAQ,EAAE,EAAE,EAAE,EACzM,KAAK,EAAE,EAAE,KAAK,EAAE,KAAK,EAAE,EAAE,EAAE;IACzB,IAAI,CAAC;QACH,OAAO,IAAI,CAAC,MAAM,EAAE,CAAC,UAAU,CAAC,KAAK,EAAE,KAAK,CAAC,CAAC,CAAC;IACjD,CAAC;IAAC,OAAO,GAAG,EAAE,CAAC;QACb,OAAO,IAAI,CAAC,GAAG,CAAC,CAAC;IACnB,CAAC;AACH,CAAC,CACF,CAAC;AAEF,MAAM,CAAC,YAAY,CACjB,eAAe,EACf,EAAE,KAAK,EAAE,mBAAmB,EAAE,WAAW,EAAE,yDAAyD,EAAE,WAAW,EAAE,EAAE,KAAK,EAAE,CAAC,CAAC,MAAM,EAAE,EAAE,KAAK,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,GAAG,EAAE,CAAC,QAAQ,EAAE,CAAC,GAAG,CAAC,GAAG,CAAC,CAAC,QAAQ,EAAE,EAAE,EAAE,EAClM,KAAK,EAAE,EAAE,KAAK,EAAE,KAAK,EAAE,EAAE,EAAE;IACzB,IAAI,CAAC;QACH,OAAO,IAAI,CAAC,MAAM,EAAE,CAAC,YAAY,CAAC,KAAK,EAAE,KAAK,CAAC,CAAC,CAAC;IACnD,CAAC;IAAC,OAAO,GAAG,EAAE,CAAC;QACb,OAAO,IAAI,CAAC,GAAG,CAAC,CAAC;IACnB,CAAC;AACH,CAAC,CACF,CAAC;AAEF,4EAA4E;AAE5E,MAAM,CAAC,YAAY,CACjB,UAAU,EACV,EAAE,KAAK,EAAE,gBAAgB,EAAE,WAAW,EAAE,iEAAiE,EAAE,WAAW,EAAE,EAAE,KAAK,EAAE,IAAI,EAAE,EAAE,EACzI,KAAK,EAAE,EAAE,KAAK,EAAE,IAAI,EAAE,EAAE,EAAE;IACxB,IAAI,CAAC;QACH,OAAO,IAAI,CAAC,MAAM,EAAE,CAAC,OAAO,CAAC,KAAK,EAAE,IAAI,CAAC,CAAC,CAAC;IAC7C,CAAC;IAAC,OAAO,GAAG,EAAE,CAAC;QACb,OAAO,IAAI,CAAC,GAAG,CAAC,CAAC;IACnB,CAAC;AACH,CAAC,CACF,CAAC;AAEF,MAAM,CAAC,YAAY,CACjB,aAAa,EACb,EAAE,KAAK,EAAE,aAAa,EAAE,WAAW,EAAE,sCAAsC,EAAE,WAAW,EAAE,EAAE,KAAK,EAAE,IAAI,EAAE,KAAK,EAAE,SAAS,EAAE,KAAK,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,GAAG,EAAE,CAAC,QAAQ,EAAE,CAAC,GAAG,CAAC,GAAG,CAAC,CAAC,QAAQ,EAAE,EAAE,EAAE,EACrL,KAAK,EAAE,EAAE,KAAK,EAAE,IAAI,EAAE,KAAK,EAAE,KAAK,EAAE,EAAE,EAAE;IACtC,IAAI,CAAC;QACH,OAAO,IAAI,CAAC,MAAM,EAAE,CAAC,UAAU,CAAC,KAAK,EAAE,IAAI,EAAE,KAAK,IAAI,MAAM,EAAE,KAAK,CAAC,CAAC,CAAC;IACxE,CAAC;IAAC,OAAO,GAAG,EAAE,CAAC;QACb,OAAO,IAAI,CAAC,GAAG,CAAC,CAAC;IACnB,CAAC;AACH,CAAC,CACF,CAAC;AAEF,MAAM,CAAC,YAAY,CACjB,WAAW,EACX,EAAE,KAAK,EAAE,WAAW,EAAE,WAAW,EAAE,6CAA6C,EAAE,WAAW,EAAE,EAAE,KAAK,EAAE,IAAI,EAAE,MAAM,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,GAAG,EAAE,CAAC,QAAQ,EAAE,EAAE,EAAE,EACrJ,KAAK,EAAE,EAAE,KAAK,EAAE,IAAI,EAAE,MAAM,EAAE,EAAE,EAAE;IAChC,IAAI,CAAC;QACH,OAAO,IAAI,CAAC,MAAM,EAAE,CAAC,QAAQ,CAAC,KAAK,EAAE,IAAI,EAAE,MAAM,CAAC,CAAC,CAAC;IACtD,CAAC;IAAC,OAAO,GAAG,EAAE,CAAC;QACb,OAAO,IAAI,CAAC,GAAG,CAAC,CAAC;IACnB,CAAC;AACH,CAAC,CACF,CAAC;AAEF,MAAM,CAAC,YAAY,CACjB,oBAAoB,EACpB,EAAE,KAAK,EAAE,oBAAoB,EAAE,WAAW,EAAE,8BAA8B,EAAE,WAAW,EAAE,EAAE,KAAK,EAAE,IAAI,EAAE,KAAK,EAAE,SAAS,EAAE,KAAK,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,GAAG,EAAE,CAAC,QAAQ,EAAE,CAAC,GAAG,CAAC,GAAG,CAAC,CAAC,QAAQ,EAAE,EAAE,EAAE,EACpL,KAAK,EAAE,EAAE,KAAK,EAAE,IAAI,EAAE,KAAK,EAAE,KAAK,EAAE,EAAE,EAAE;IACtC,IAAI,CAAC;QACH,OAAO,IAAI,CAAC,MAAM,EAAE,CAAC,gBAAgB,CAAC,KAAK,EAAE,IAAI,EAAE,KAAK,IAAI,MAAM,EAAE,KAAK,CAAC,CAAC,CAAC;IAC9E,CAAC;IAAC,OAAO,GAAG,EAAE,CAAC;QACb,OAAO,IAAI,CAAC,GAAG,CAAC,CAAC;IACnB,CAAC;AACH,CAAC,CACF,CAAC;AAEF,MAAM,CAAC,YAAY,CACjB,kBAAkB,EAClB,EAAE,KAAK,EAAE,kBAAkB,EAAE,WAAW,EAAE,kDAAkD,EAAE,WAAW,EAAE,EAAE,KAAK,EAAE,IAAI,EAAE,MAAM,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,GAAG,EAAE,CAAC,QAAQ,EAAE,EAAE,EAAE,EACjK,KAAK,EAAE,EAAE,KAAK,EAAE,IAAI,EAAE,MAAM,EAAE,EAAE,EAAE;IAChC,IAAI,CAAC;QACH,OAAO,IAAI,CAAC,MAAM,EAAE,CAAC,cAAc,CAAC,KAAK,EAAE,IAAI,EAAE,MAAM,CAAC,CAAC,CAAC;IAC5D,CAAC;IAAC,OAAO,GAAG,EAAE,CAAC;QACb,OAAO,IAAI,CAAC,GAAG,CAAC,CAAC;IACnB,CAAC;AACH,CAAC,CACF,CAAC;AAEF,MAAM,CAAC,YAAY,CACjB,mBAAmB,EACnB,EAAE,KAAK,EAAE,mBAAmB,EAAE,WAAW,EAAE,0EAA0E,EAAE,WAAW,EAAE,EAAE,KAAK,EAAE,IAAI,EAAE,IAAI,EAAE,CAAC,CAAC,MAAM,EAAE,EAAE,GAAG,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,QAAQ,EAAE,CAAC,QAAQ,CAAC,4BAA4B,CAAC,EAAE,EAAE,EAC1O,KAAK,EAAE,EAAE,KAAK,EAAE,IAAI,EAAE,IAAI,EAAE,GAAG,EAAE,EAAE,EAAE;IACnC,IAAI,CAAC;QACH,OAAO,IAAI,CAAC,MAAM,EAAE,CAAC,eAAe,CAAC,KAAK,EAAE,IAAI,EAAE,IAAI,EAAE,GAAG,CAAC,CAAC,CAAC;IAChE,CAAC;IAAC,OAAO,GAAG,EAAE,CAAC;QACb,OAAO,IAAI,CAAC,GAAG,CAAC,CAAC;IACnB,CAAC;AACH,CAAC,CACF,CAAC;AAEF,MAAM,CAAC,YAAY,CACjB,oBAAoB,EACpB,EAAE,KAAK,EAAE,oBAAoB,EAAE,WAAW,EAAE,mCAAmC,EAAE,WAAW,EAAE,EAAE,KAAK,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,GAAG,EAAE,CAAC,QAAQ,EAAE,CAAC,GAAG,CAAC,GAAG,CAAC,CAAC,QAAQ,EAAE,EAAE,EAAE,EAC1J,KAAK,EAAE,EAAE,KAAK,EAAE,EAAE,EAAE;IAClB,IAAI,CAAC;QACH,OAAO,IAAI,CAAC,MAAM,EAAE,CAAC,iBAAiB,CAAC,KAAK,CAAC,CAAC,CAAC;IACjD,CAAC;IAAC,OAAO,GAAG,EAAE,CAAC;QACb,OAAO,IAAI,CAAC,GAAG,CAAC,CAAC;IACnB,CAAC;AACH,CAAC,CACF,CAAC;AAEF,MAAM,CAAC,YAAY,CACjB,YAAY,EACZ,EAAE,KAAK,EAAE,YAAY,EAAE,WAAW,EAAE,oDAAoD,EAAE,WAAW,EAAE,EAAE,EAAE,EAC3G,KAAK,IAAI,EAAE;IACT,IAAI,CAAC;QACH,OAAO,IAAI,CAAC,MAAM,EAAE,CAAC,SAAS,EAAE,CAAC,CAAC;IACpC,CAAC;IAAC,OAAO,GAAG,EAAE,CAAC;QACb,OAAO,IAAI,CAAC,GAAG,CAAC,CAAC;IACnB,CAAC;AACH,CAAC,CACF,CAAC;AAEF,4EAA4E;AAE5E,IAAI,CAAC,UAAU,EAAE,EAAE,CAAC;IAClB,MAAM,CAAC,YAAY,CACjB,cAAc,EACd;QACE,KAAK,EAAE,cAAc;QACrB,WAAW,EAAE,mCAAmC;QAChD,WAAW,EAAE,EAAE,KAAK,EAAE,IAAI,EAAE,KAAK,EAAE,CAAC,CAAC,MAAM,EAAE,EAAE,IAAI,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,QAAQ,EAAE,EAAE;QAC5E,WAAW,EAAE,EAAE,eAAe,EAAE,IAAI,EAAE;KACvC,EACD,KAAK,EAAE,EAAE,KAAK,EAAE,IAAI,EAAE,KAAK,EAAE,IAAI,EAAE,EAAE,EAAE;QACrC,IAAI,CAAC;YACH,OAAO,IAAI,CAAC,MAAM,EAAE,CAAC,WAAW,CAAC,KAAK,EAAE,IAAI,EAAE,KAAK,EAAE,IAAI,CAAC,CAAC,CAAC;QAC9D,CAAC;QAAC,OAAO,GAAG,EAAE,CAAC;YACb,OAAO,IAAI,CAAC,GAAG,CAAC,CAAC;QACnB,CAAC;IACH,CAAC,CACF,CAAC;IAEF,MAAM,CAAC,YAAY,CACjB,mBAAmB,EACnB;QACE,KAAK,EAAE,kBAAkB;QACzB,WAAW,EAAE,4CAA4C;QACzD,WAAW,EAAE,EAAE,KAAK,EAAE,IAAI,EAAE,MAAM,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,GAAG,EAAE,CAAC,QAAQ,EAAE,EAAE,IAAI,EAAE,CAAC,CAAC,MAAM,EAAE,EAAE;QACnF,WAAW,EAAE,EAAE,eAAe,EAAE,IAAI,EAAE;KACvC,EACD,KAAK,EAAE,EAAE,KAAK,EAAE,IAAI,EAAE,MAAM,EAAE,IAAI,EAAE,EAAE,EAAE;QACtC,IAAI,CAAC;YACH,OAAO,IAAI,CAAC,MAAM,EAAE,CAAC,eAAe,CAAC,KAAK,EAAE,IAAI,EAAE,MAAM,EAAE,IAAI,CAAC,CAAC,CAAC;QACnE,CAAC;QAAC,OAAO,GAAG,EAAE,CAAC;YACb,OAAO,IAAI,CAAC,GAAG,CAAC,CAAC;QACnB,CAAC;IACH,CAAC,CACF,CAAC;AACJ,CAAC;AAED,4EAA4E;AAE5E,KAAK,UAAU,IAAI;IACjB,MAAM,SAAS,GAAG,IAAI,oBAAoB,EAAE,CAAC;IAC7C,MAAM,MAAM,CAAC,OAAO,CAAC,SAAS,CAAC,CAAC;IAChC,OAAO,CAAC,KAAK,CAAC,sBAAsB,OAAO,WAAW,UAAU,EAAE,CAAC,CAAC,CAAC,cAAc,CAAC,CAAC,CAAC,EAAE,GAAG,CAAC,CAAC;AAC/F,CAAC;AAED,IAAI,EAAE,CAAC,KAAK,CAAC,CAAC,GAAG,EAAE,EAAE;IACnB,OAAO,CAAC,KAAK,CAAC,yCAAyC,EAAE,GAAG,CAAC,CAAC;IAC9D,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;AAClB,CAAC,CAAC,CAAC"}
|
package/package.json
ADDED
|
@@ -0,0 +1,55 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@abhishekmcp/github",
|
|
3
|
+
"version": "0.1.0",
|
|
4
|
+
"description": "MCP server for GitHub — search repos/code/issues, read repos/issues/PRs/files, and create issues, authenticated via OAuth device flow or a token, from any MCP client.",
|
|
5
|
+
"mcpName": "io.github.Abhishekkumar2021/github",
|
|
6
|
+
"type": "module",
|
|
7
|
+
"bin": {
|
|
8
|
+
"mcp-github": "dist/index.js"
|
|
9
|
+
},
|
|
10
|
+
"files": [
|
|
11
|
+
"dist"
|
|
12
|
+
],
|
|
13
|
+
"publishConfig": {
|
|
14
|
+
"access": "public",
|
|
15
|
+
"provenance": true
|
|
16
|
+
},
|
|
17
|
+
"scripts": {
|
|
18
|
+
"build": "tsc",
|
|
19
|
+
"watch": "tsc --watch",
|
|
20
|
+
"start": "node dist/index.js",
|
|
21
|
+
"dev": "tsc && node dist/index.js",
|
|
22
|
+
"test": "npm run build && node --test test/*.test.mjs",
|
|
23
|
+
"prepublishOnly": "npm run build"
|
|
24
|
+
},
|
|
25
|
+
"keywords": [
|
|
26
|
+
"mcp",
|
|
27
|
+
"modelcontextprotocol",
|
|
28
|
+
"github",
|
|
29
|
+
"octokit",
|
|
30
|
+
"claude"
|
|
31
|
+
],
|
|
32
|
+
"author": "Abhishek (https://github.com/Abhishekkumar2021)",
|
|
33
|
+
"license": "MIT",
|
|
34
|
+
"homepage": "https://github.com/Abhishekkumar2021/mcp-suite/tree/main/servers/github#readme",
|
|
35
|
+
"repository": {
|
|
36
|
+
"type": "git",
|
|
37
|
+
"url": "git+https://github.com/Abhishekkumar2021/mcp-suite.git",
|
|
38
|
+
"directory": "servers/github"
|
|
39
|
+
},
|
|
40
|
+
"bugs": {
|
|
41
|
+
"url": "https://github.com/Abhishekkumar2021/mcp-suite/issues"
|
|
42
|
+
},
|
|
43
|
+
"engines": {
|
|
44
|
+
"node": ">=18"
|
|
45
|
+
},
|
|
46
|
+
"dependencies": {
|
|
47
|
+
"@modelcontextprotocol/sdk": "^1.29.0",
|
|
48
|
+
"@octokit/rest": "^21.0.0",
|
|
49
|
+
"zod": "^3.23.8"
|
|
50
|
+
},
|
|
51
|
+
"devDependencies": {
|
|
52
|
+
"@types/node": "^22.0.0",
|
|
53
|
+
"typescript": "^5.6.0"
|
|
54
|
+
}
|
|
55
|
+
}
|