Skip to content

Commit 16f2793

Browse files
committedDec 9, 2024
feat: make toolLoader load tools automatically
1 parent d637a65 commit 16f2793

File tree

5 files changed

+18
-73
lines changed

5 files changed

+18
-73
lines changed
 

Diff for: ‎package.json

+1-1
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
{
22
"name": "mcp-framework",
3-
"version": "0.1.2",
3+
"version": "0.1.3",
44
"description": "Framework for building Model Context Protocol (MCP) servers in Typescript",
55
"type": "module",
66
"author": "Alex Andru <alex@andru.codes>",

Diff for: ‎src/core/Logger.ts

+1-3
Original file line numberDiff line numberDiff line change
@@ -11,15 +11,13 @@ export class Logger {
1111
const timestamp = new Date().toISOString().replace(/[:.]/g, "-");
1212
const logDir = "logs";
1313

14-
// Ensure logs directory exists
1514
mkdir(logDir, { recursive: true }).catch((err) => {
1615
process.stderr.write(`Failed to create logs directory: ${err}\n`);
1716
});
1817

1918
this.logFilePath = join(logDir, `mcp-server-${timestamp}.log`);
2019
this.logStream = createWriteStream(this.logFilePath, { flags: "a" });
2120

22-
// Handle process termination
2321
process.on("exit", () => this.close());
2422
process.on("SIGINT", () => this.close());
2523
process.on("SIGTERM", () => this.close());
@@ -47,7 +45,7 @@ export class Logger {
4745
}
4846

4947
public log(message: string): void {
50-
this.info(message); // Alias for info
48+
this.info(message);
5149
}
5250

5351
public error(message: string): void {

Diff for: ‎src/core/MCPServer.ts

+2-9
Original file line numberDiff line numberDiff line change
@@ -4,14 +4,12 @@ import {
44
CallToolRequestSchema,
55
ListToolsRequestSchema,
66
} from "@modelcontextprotocol/sdk/types.js";
7-
import { ToolLoader, ToolLoaderOptions } from "./toolLoader.js";
7+
import { ToolLoader } from "./toolLoader.js";
88
import { BaseTool } from "../tools/BaseTool.js";
99

1010
export interface MCPServerConfig {
1111
name: string;
1212
version: string;
13-
toolsDir?: string;
14-
excludeTools?: string[];
1513
}
1614

1715
export class MCPServer {
@@ -34,11 +32,7 @@ export class MCPServer {
3432
}
3533
);
3634

37-
this.toolLoader = new ToolLoader({
38-
toolsDir: config.toolsDir,
39-
exclude: config.excludeTools,
40-
});
41-
35+
this.toolLoader = new ToolLoader();
4236
this.setupHandlers();
4337
}
4438

@@ -72,7 +66,6 @@ export class MCPServer {
7266
const transport = new StdioServerTransport();
7367
await this.server.connect(transport);
7468

75-
// Write errors to stderr instead of stdout
7669
process.stderr.write(`Server started with ${tools.length} tools\n`);
7770
} catch (error) {
7871
process.stderr.write(`Server initialization error: ${error}\n`);

Diff for: ‎src/core/toolLoader.ts

+13-59
Original file line numberDiff line numberDiff line change
@@ -1,67 +1,21 @@
11
import { BaseTool } from "../tools/BaseTool.js";
2-
import { dirname, join } from "path";
2+
import { join, dirname } from "path";
33
import { promises as fs } from "fs";
4-
import { statSync } from "fs";
5-
import { fileURLToPath } from "url";
6-
import { cwd } from "process";
74
import { logger } from "./Logger.js";
85

9-
export interface ToolLoaderOptions {
10-
toolsDir?: string;
11-
exclude?: string[];
12-
}
13-
146
export class ToolLoader {
15-
private toolsDir: string;
16-
private exclude: string[];
7+
private readonly TOOLS_DIR: string;
8+
private readonly EXCLUDED_FILES = ["BaseTool.js", "*.test.js", "*.spec.js"];
179

18-
constructor(options: ToolLoaderOptions = {}) {
19-
this.exclude = options.exclude || ["BaseTool.js", "*.test.js", "*.spec.js"];
20-
this.toolsDir = this.resolveToolsDir(options.toolsDir);
21-
logger.debug(`Initialized ToolLoader with directory: ${this.toolsDir}`);
22-
}
23-
24-
private resolveToolsDir(toolsDir?: string): string {
25-
if (toolsDir) {
26-
logger.debug(`Using provided tools directory: ${toolsDir}`);
27-
return toolsDir;
28-
}
29-
30-
const currentFilePath = fileURLToPath(import.meta.url);
31-
const currentDir = dirname(currentFilePath);
32-
const possiblePaths = [
33-
join(currentDir, "..", "tools"),
34-
join(currentDir, "..", "..", "tools"),
35-
join(cwd(), "dist", "tools"),
36-
join(cwd(), "build", "tools"),
37-
join(cwd(), "tools"),
38-
];
39-
40-
logger.debug(
41-
`Searching for tools in possible paths:\n${possiblePaths.join("\n")}`
42-
);
43-
44-
for (const path of possiblePaths) {
45-
try {
46-
if (statSync(path).isDirectory()) {
47-
logger.debug(`Found existing tools directory: ${path}`);
48-
return path;
49-
}
50-
} catch (e) {
51-
logger.debug(`Path ${path} not accessible`);
52-
}
53-
}
54-
55-
const fallbackPath = join(cwd(), "dist", "tools");
56-
logger.debug(
57-
`No valid tools directory found, falling back to: ${fallbackPath}`
58-
);
59-
return fallbackPath;
10+
constructor() {
11+
const mainModulePath = process.argv[1];
12+
this.TOOLS_DIR = join(dirname(mainModulePath), "tools");
13+
logger.debug(`Initialized ToolLoader with directory: ${this.TOOLS_DIR}`);
6014
}
6115

6216
private isToolFile(file: string): boolean {
6317
if (!file.endsWith(".js")) return false;
64-
const isExcluded = this.exclude.some((pattern) => {
18+
const isExcluded = this.EXCLUDED_FILES.some((pattern) => {
6519
if (pattern.includes("*")) {
6620
const regex = new RegExp(pattern.replace("*", ".*"));
6721
return regex.test(file);
@@ -94,22 +48,22 @@ export class ToolLoader {
9448

9549
async loadTools(): Promise<BaseTool[]> {
9650
try {
97-
logger.debug(`Attempting to load tools from: ${this.toolsDir}`);
51+
logger.debug(`Attempting to load tools from: ${this.TOOLS_DIR}`);
9852

9953
let stats;
10054
try {
101-
stats = await fs.stat(this.toolsDir);
55+
stats = await fs.stat(this.TOOLS_DIR);
10256
} catch (error) {
10357
logger.error(`Error accessing tools directory: ${error}`);
10458
return [];
10559
}
10660

10761
if (!stats.isDirectory()) {
108-
logger.error(`Path is not a directory: ${this.toolsDir}`);
62+
logger.error(`Path is not a directory: ${this.TOOLS_DIR}`);
10963
return [];
11064
}
11165

112-
const files = await fs.readdir(this.toolsDir);
66+
const files = await fs.readdir(this.TOOLS_DIR);
11367
logger.debug(`Found files in directory: ${files.join(", ")}`);
11468

11569
const tools: BaseTool[] = [];
@@ -120,7 +74,7 @@ export class ToolLoader {
12074
}
12175

12276
try {
123-
const fullPath = join(this.toolsDir, file);
77+
const fullPath = join(this.TOOLS_DIR, file);
12478
logger.debug(`Attempting to load tool from: ${fullPath}`);
12579

12680
const importPath = `file://${fullPath}`;

Diff for: ‎src/index.ts

+1-1
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,3 @@
11
export { MCPServer, type MCPServerConfig } from "./core/MCPServer.js";
22
export { BaseTool, BaseToolImplementation } from "./tools/BaseTool.js";
3-
export { ToolLoader, type ToolLoaderOptions } from "./core/toolLoader.js";
3+
export { ToolLoader } from "./core/toolLoader.js";

0 commit comments

Comments
 (0)
Please sign in to comment.