Introduce a Helm-chart-like template system for MCP servers. Templates are YAML files in templates/ that get seeded into the DB on startup. Users can browse them with `mcpctl get templates`, inspect with `mcpctl describe template`, and instantiate with `mcpctl create server --from-template=`. Also adds Portainer deployment scripts, mcplocal systemd service, Streamable HTTP MCP endpoint, and RPM packaging for mcpctl-local. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
54 lines
1.6 KiB
TypeScript
54 lines
1.6 KiB
TypeScript
import type { McpTemplate } from '@prisma/client';
|
|
import type { ITemplateRepository } from '../repositories/template.repository.js';
|
|
import { CreateTemplateSchema, UpdateTemplateSchema } from '../validation/template.schema.js';
|
|
import { NotFoundError, ConflictError } from './mcp-server.service.js';
|
|
|
|
export class TemplateService {
|
|
constructor(private readonly repo: ITemplateRepository) {}
|
|
|
|
async list(namePattern?: string): Promise<McpTemplate[]> {
|
|
if (namePattern) {
|
|
return this.repo.search(namePattern);
|
|
}
|
|
return this.repo.findAll();
|
|
}
|
|
|
|
async getById(id: string): Promise<McpTemplate> {
|
|
const template = await this.repo.findById(id);
|
|
if (template === null) {
|
|
throw new NotFoundError(`Template not found: ${id}`);
|
|
}
|
|
return template;
|
|
}
|
|
|
|
async getByName(name: string): Promise<McpTemplate> {
|
|
const template = await this.repo.findByName(name);
|
|
if (template === null) {
|
|
throw new NotFoundError(`Template not found: ${name}`);
|
|
}
|
|
return template;
|
|
}
|
|
|
|
async create(input: unknown): Promise<McpTemplate> {
|
|
const data = CreateTemplateSchema.parse(input);
|
|
|
|
const existing = await this.repo.findByName(data.name);
|
|
if (existing !== null) {
|
|
throw new ConflictError(`Template already exists: ${data.name}`);
|
|
}
|
|
|
|
return this.repo.create(data);
|
|
}
|
|
|
|
async update(id: string, input: unknown): Promise<McpTemplate> {
|
|
const data = UpdateTemplateSchema.parse(input);
|
|
await this.getById(id);
|
|
return this.repo.update(id, data);
|
|
}
|
|
|
|
async delete(id: string): Promise<void> {
|
|
await this.getById(id);
|
|
await this.repo.delete(id);
|
|
}
|
|
}
|