Skip to content

Commit 9f99f71

Browse files
committed
Cache Viewer Permission on Server Startup #7626
1 parent 097294e commit 9f99f71

2 files changed

Lines changed: 46 additions & 17 deletions

File tree

ai/mcp/server/github-workflow/mcp-stdio.mjs

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@ import {
1212

1313
import { listTools, callTool } from './services/toolService.mjs';
1414
import HealthService from './services/HealthService.mjs';
15+
import RepositoryService from './services/RepositoryService.mjs';
1516

1617
const server = new Server({
1718
name: 'neo-github-workflow',
@@ -130,6 +131,8 @@ async function main() {
130131
health.githubCli.details.forEach(detail => logger.warn(` ${detail}`));
131132
} else {
132133
logger.info('✅ [Startup] GitHub CLI health check passed');
134+
// Proactively fetch and cache viewer permission
135+
await RepositoryService.fetchAndCacheViewerPermission();
133136
}
134137

135138
const transport = new StdioServerTransport();

ai/mcp/server/github-workflow/services/RepositoryService.mjs

Lines changed: 43 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,8 @@
1-
import Base from '../../../../../src/core/Base.mjs';
2-
import GraphqlService from './GraphqlService.mjs';
3-
import aiConfig from '../config.mjs';
4-
import logger from '../logger.mjs';
5-
import { GET_VIEWER_PERMISSION } from './queries/repositoryQueries.mjs';
1+
import aiConfig from '../config.mjs';
2+
import Base from '../../../../../src/core/Base.mjs';
3+
import GraphqlService from './GraphqlService.mjs';
4+
import logger from '../logger.mjs';
5+
import {GET_VIEWER_PERMISSION} from './queries/repositoryQueries.mjs';
66

77
/**
88
* Service for interacting with the GitHub repository itself.
@@ -12,33 +12,59 @@ import { GET_VIEWER_PERMISSION } from './queries/repositoryQueries.mjs';
1212
*/
1313
class RepositoryService extends Base {
1414
static config = {
15+
/**
16+
* @member {String} className='Neo.ai.mcp.server.github-workflow.RepositoryService'
17+
* @protected
18+
*/
1519
className: 'Neo.ai.mcp.server.github-workflow.RepositoryService',
20+
/**
21+
* @member {Boolean} singleton=true
22+
* @protected
23+
*/
1624
singleton: true
1725
}
1826

1927
/**
20-
* Fetches the current user's permission level for the repository.
21-
* @returns {Promise<object>} A promise that resolves to an object containing the permission level or a structured error.
28+
* The permission level string for the current user (e.g., 'ADMIN', 'WRITE').
29+
* This value is fetched and cached on server startup.
30+
* @member {String|null} viewerPermission=null
2231
*/
23-
async getViewerPermission() {
32+
viewerPermission = null;
33+
34+
/**
35+
* Fetches the current user's permission level from the API and caches it.
36+
* This method is intended for internal use at startup but can be called on demand.
37+
* @returns {Promise<string|null>} The permission string or null on failure.
38+
*/
39+
async fetchAndCacheViewerPermission() {
2440
const variables = {
2541
owner: aiConfig.owner,
26-
repo: aiConfig.repo
42+
repo : aiConfig.repo
2743
};
2844

2945
try {
3046
const data = await GraphqlService.query(GET_VIEWER_PERMISSION, variables);
31-
const permission = data.repository.viewerPermission;
32-
logger.info(`Viewer permission for ${aiConfig.owner}/${aiConfig.repo}: ${permission}`);
33-
return { permission };
47+
this.viewerPermission = data.repository.viewerPermission;
48+
logger.info(`Fetched and cached viewer permission: ${this.viewerPermission}`);
49+
return this.viewerPermission;
3450
} catch (error) {
3551
logger.error('Error fetching viewer permission via GraphQL:', error);
36-
return {
37-
error: 'GraphQL API request failed',
38-
message: error.message,
39-
code: 'GRAPHQL_API_ERROR'
40-
};
52+
return null;
53+
}
54+
}
55+
56+
/**
57+
* Returns the cached permission level of the current user, wrapped in an object.
58+
* @returns {Promise<object>} A promise that resolves to an object of the shape `{permission: '...'}`.
59+
*/
60+
async getViewerPermission() {
61+
if (!this.viewerPermission) {
62+
// This can happen if the initial fetch on startup failed.
63+
// We will try to fetch it again on demand.
64+
logger.warn('Viewer permission not cached, attempting to fetch now...');
65+
await this.fetchAndCacheViewerPermission();
4166
}
67+
return { permission: this.viewerPermission };
4268
}
4369
}
4470

0 commit comments

Comments
 (0)