Files
stack/apps/api/src/mcp/tool-registry.service.ts
Jason Woltje b8805cee50 feat(#132): port MCP (Model Context Protocol) infrastructure
Implement MCP Phase 1 infrastructure for agent tool integration with
central hub, tool registry, and STDIO transport layers.

Components:
- McpHubService: Central registry for MCP server lifecycle
- StdioTransport: STDIO process communication with JSON-RPC 2.0
- ToolRegistryService: Tool catalog management
- McpController: REST API for MCP management

Endpoints:
- GET/POST /mcp/servers - List/register servers
- POST /mcp/servers/:id/start|stop - Lifecycle control
- DELETE /mcp/servers/:id - Unregister
- GET /mcp/tools - List tools
- POST /mcp/tools/:name/invoke - Invoke tool

Features:
- Full JSON-RPC 2.0 protocol support
- Process lifecycle management
- Buffered message parsing
- Type-safe with no explicit any types
- Proper cleanup on shutdown

Tests: 85 passing with 90.9% coverage

Fixes #132

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-01-31 13:07:58 -06:00

60 lines
1.3 KiB
TypeScript

import { Injectable } from "@nestjs/common";
import type { McpTool } from "./interfaces";
/**
* Service for managing MCP tool registry
* Maintains catalog of tools provided by MCP servers
*/
@Injectable()
export class ToolRegistryService {
private tools = new Map<string, McpTool>();
/**
* Register a tool from an MCP server
*/
registerTool(tool: McpTool): void {
this.tools.set(tool.name, tool);
}
/**
* Unregister a tool
*/
unregisterTool(toolName: string): void {
this.tools.delete(toolName);
}
/**
* Get tool by name
*/
getTool(name: string): McpTool | undefined {
return this.tools.get(name);
}
/**
* List all registered tools
*/
listTools(): McpTool[] {
return Array.from(this.tools.values());
}
/**
* List tools provided by a specific server
*/
listToolsByServer(serverId: string): McpTool[] {
return Array.from(this.tools.values()).filter((tool) => tool.serverId === serverId);
}
/**
* Clear all tools for a server
*/
clearServerTools(serverId: string): void {
const toolsToRemove = Array.from(this.tools.values())
.filter((tool) => tool.serverId === serverId)
.map((tool) => tool.name);
for (const toolName of toolsToRemove) {
this.tools.delete(toolName);
}
}
}