@rashidazarang/aptly-mcp
Version:
Model Context Protocol server for Aptly package repository management - enables AI assistants to manage Debian repositories
196 lines • 8.84 kB
JavaScript
import { Server } from '@modelcontextprotocol/sdk/server/index.js';
import { StdioServerTransport } from '@modelcontextprotocol/sdk/server/stdio.js';
import { CallToolRequestSchema, ErrorCode, ListResourcesRequestSchema, ListToolsRequestSchema, McpError, ReadResourceRequestSchema, } from '@modelcontextprotocol/sdk/types.js';
import { AptlyClient } from './utils/aptly-client.js';
import { createRepositoryTools, handleRepositoryTool } from './tools/repository-tools.js';
import { createPackageTools, handlePackageTool } from './tools/package-tools.js';
import { createSnapshotTools, handleSnapshotTool } from './tools/snapshot-tools.js';
import { createPublishTools, handlePublishTool } from './tools/publish-tools.js';
import { createMirrorTools, handleMirrorTool } from './tools/mirror-tools.js';
export class AptlyMcpServer {
server;
client;
constructor() {
// Initialize Aptly client from environment
const aptlyURL = process.env.APTLY_API_URL || 'http://localhost:8080';
const authToken = process.env.APTLY_AUTH_TOKEN;
this.client = new AptlyClient({
baseURL: aptlyURL,
authToken
});
// Initialize MCP server
this.server = new Server({
name: 'aptly-mcp',
version: '1.1.0',
}, {
capabilities: {
resources: {},
tools: {},
},
});
this.setupHandlers();
}
setupHandlers() {
// List available tools
this.server.setRequestHandler(ListToolsRequestSchema, async () => {
const repoTools = createRepositoryTools(this.client);
const packageTools = createPackageTools(this.client);
const snapshotTools = createSnapshotTools(this.client);
const publishTools = createPublishTools(this.client);
const mirrorTools = createMirrorTools(this.client);
const allTools = [
...repoTools,
...packageTools,
...snapshotTools,
...publishTools,
...mirrorTools,
{
name: 'aptly_health_check',
description: 'Check if Aptly server is running and accessible',
inputSchema: {
type: 'object',
properties: {},
required: []
}
}
];
return { tools: allTools };
});
// Handle tool calls
this.server.setRequestHandler(CallToolRequestSchema, async (request) => {
const { name, arguments: args } = request.params;
try {
// Health check tool
if (name === 'aptly_health_check') {
const isHealthy = await this.client.ping();
return {
content: [{
type: 'text',
text: isHealthy
? '✅ Aptly server is running and accessible'
: '❌ Aptly server is not accessible'
}]
};
}
// Repository tools
if (['aptly_create_repo', 'aptly_list_repos', 'aptly_get_repo', 'aptly_delete_repo'].includes(name)) {
return await handleRepositoryTool(this.client, name, args);
}
// Package tools
if (['aptly_list_packages', 'aptly_search_packages', 'aptly_add_packages', 'aptly_list_uploaded_files', 'aptly_delete_uploaded_files'].includes(name)) {
return await handlePackageTool(this.client, name, args);
}
// Snapshot tools
if (['aptly_list_snapshots', 'aptly_create_snapshot'].includes(name)) {
return await handleSnapshotTool(this.client, name, args);
}
// Publish tools
if (['aptly_list_published', 'aptly_publish_repo', 'aptly_publish_snapshot'].includes(name)) {
return await handlePublishTool(this.client, name, args);
}
// Mirror tools
if (['aptly_list_mirrors', 'aptly_create_mirror', 'aptly_update_mirror', 'aptly_get_mirror'].includes(name)) {
return await handleMirrorTool(this.client, name, args);
}
throw new McpError(ErrorCode.MethodNotFound, `Unknown tool: ${name}`);
}
catch (error) {
const errorMessage = error instanceof Error ? error.message : String(error);
throw new McpError(ErrorCode.InternalError, `Tool execution failed: ${errorMessage}`);
}
});
// List available resources
this.server.setRequestHandler(ListResourcesRequestSchema, async () => {
return {
resources: [
{
uri: 'aptly://repositories',
mimeType: 'application/json',
name: 'Repositories',
description: 'List of all local repositories'
},
{
uri: 'aptly://mirrors',
mimeType: 'application/json',
name: 'Mirrors',
description: 'List of all configured mirrors'
},
{
uri: 'aptly://snapshots',
mimeType: 'application/json',
name: 'Snapshots',
description: 'List of all snapshots'
},
{
uri: 'aptly://published',
mimeType: 'application/json',
name: 'Published Repositories',
description: 'List of all published repositories'
}
]
};
});
// Handle resource reads
this.server.setRequestHandler(ReadResourceRequestSchema, async (request) => {
const { uri } = request.params;
try {
switch (uri) {
case 'aptly://repositories': {
const repos = await this.client.listRepositories();
return {
contents: [{
uri,
mimeType: 'application/json',
text: JSON.stringify(repos, null, 2)
}]
};
}
case 'aptly://mirrors': {
const mirrors = await this.client.listMirrors();
return {
contents: [{
uri,
mimeType: 'application/json',
text: JSON.stringify(mirrors, null, 2)
}]
};
}
case 'aptly://snapshots': {
const snapshots = await this.client.listSnapshots();
return {
contents: [{
uri,
mimeType: 'application/json',
text: JSON.stringify(snapshots, null, 2)
}]
};
}
case 'aptly://published': {
const published = await this.client.listPublishedRepositories();
return {
contents: [{
uri,
mimeType: 'application/json',
text: JSON.stringify(published, null, 2)
}]
};
}
default:
throw new McpError(ErrorCode.InvalidRequest, `Unknown resource: ${uri}`);
}
}
catch (error) {
const errorMessage = error instanceof Error ? error.message : String(error);
throw new McpError(ErrorCode.InternalError, `Failed to read resource: ${errorMessage}`);
}
});
}
async run() {
const transport = new StdioServerTransport();
await this.server.connect(transport);
}
getServer() {
return this.server;
}
}
//# sourceMappingURL=server.js.map