//
// File: server.ts
// Brief: Main MCP server implementation for Google CodeWiki integration
//
// Copyright (c) 2025 Chris Bunting <cbuntingde@gmail.com>
//
// This source code is licensed under the MIT license found in the
// LICENSE file in the root directory of this source tree.
//
import { Server } from '@modelcontextprotocol/sdk/server/index.js';
import { StdioServerTransport } from '@modelcontextprotocol/sdk/server/stdio.js';
import {
CallToolRequestSchema,
ListToolsRequestSchema,
} from '@modelcontextprotocol/sdk/types.js';
import { CodeWikiClient } from './codewiki-client.js';
import { CacheManager } from './cache-manager.js';
const server = new Server(
{
name: 'codewiki-mcp-server',
version: '1.0.0',
},
{
capabilities: {
tools: {},
resources: {},
},
}
);
// Initialize cache manager and CodeWiki client
const cacheManager = new CacheManager();
const codeWikiClient = new CodeWikiClient(cacheManager);
// List available tools
server.setRequestHandler(ListToolsRequestSchema, async () => {
return {
tools: [
{
name: 'search_repository',
description: 'Search for a GitHub repository on Google CodeWiki',
inputSchema: {
type: 'object',
properties: {
query: {
type: 'string',
description: 'Search query for repository name or owner/repo format',
},
},
required: ['query'],
},
},
{
name: 'get_repository_docs',
description: 'Get documentation for a specific GitHub repository',
inputSchema: {
type: 'object',
properties: {
owner: {
type: 'string',
description: 'Repository owner/organization',
},
repo: {
type: 'string',
description: 'Repository name',
},
force_refresh: {
type: 'boolean',
description: 'Force refresh cached documentation',
default: false,
},
},
required: ['owner', 'repo'],
},
},
{
name: 'search_documentation',
description: 'Search within cached documentation for a repository',
inputSchema: {
type: 'object',
properties: {
owner: {
type: 'string',
description: 'Repository owner/organization',
},
repo: {
type: 'string',
description: 'Repository name',
},
query: {
type: 'string',
description: 'Search query within the documentation',
},
},
required: ['owner', 'repo', 'query'],
},
},
{
name: 'list_cached_repositories',
description: 'List all repositories currently cached',
inputSchema: {
type: 'object',
properties: {},
},
},
{
name: 'clear_cache',
description: 'Clear the documentation cache',
inputSchema: {
type: 'object',
properties: {
owner: {
type: 'string',
description: 'Specific repository to clear (optional)',
},
repo: {
type: 'string',
description: 'Repository name when clearing specific repo',
},
},
},
},
],
};
});
// Handle tool calls
server.setRequestHandler(CallToolRequestSchema, async (request) => {
const { name, arguments: args } = request.params;
try {
switch (name) {
case 'search_repository': {
const query = (args as any)?.query;
if (!query) {
throw new Error('Query is required');
}
const results = await codeWikiClient.searchRepository(query);
return {
content: [
{
type: 'text',
text: JSON.stringify(results, null, 2),
},
],
};
}
case 'get_repository_docs': {
const { owner, repo, force_refresh = false } = args as any;
if (!owner || !repo) {
throw new Error('Owner and repo are required');
}
const docs = await codeWikiClient.getRepositoryDocs(owner, repo, force_refresh);
return {
content: [
{
type: 'text',
text: JSON.stringify(docs, null, 2),
},
],
};
}
case 'search_documentation': {
const { owner, repo, query } = args as any;
if (!owner || !repo || !query) {
throw new Error('Owner, repo, and query are required');
}
const results = await codeWikiClient.searchDocumentation(owner, repo, query);
return {
content: [
{
type: 'text',
text: JSON.stringify(results, null, 2),
},
],
};
}
case 'list_cached_repositories': {
const repos = await cacheManager.listRepositories();
return {
content: [
{
type: 'text',
text: JSON.stringify(repos, null, 2),
},
],
};
}
case 'clear_cache': {
const { owner, repo } = args as any;
if (owner && repo) {
await cacheManager.clearRepository(owner, repo);
return {
content: [
{
type: 'text',
text: `Cleared cache for ${owner}/${repo}`,
},
],
};
} else {
await cacheManager.clearAll();
return {
content: [
{
type: 'text',
text: 'Cleared all cached documentation',
},
],
};
}
}
default:
throw new Error(`Unknown tool: ${name}`);
}
} catch (error) {
return {
content: [
{
type: 'text',
text: `Error: ${error instanceof Error ? error.message : 'Unknown error'}`,
},
],
isError: true,
};
}
});
// Start the server
async function main() {
const transport = new StdioServerTransport();
await server.connect(transport);
console.error('CodeWiki MCP Server started');
}
main().catch((error) => {
console.error('Failed to start server:', error);
process.exit(1);
});