mcp-react-toolkit 1.2.0 → 1.3.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +48 -2
- package/bin/cli.mjs +59 -0
- package/node_modules/@mcp-showcase/shared/build/McpServerBase.d.ts +18 -0
- package/node_modules/@mcp-showcase/shared/build/McpServerBase.d.ts.map +1 -0
- package/node_modules/@mcp-showcase/shared/build/McpServerBase.js +74 -0
- package/node_modules/@mcp-showcase/shared/build/McpServerBase.js.map +1 -0
- package/node_modules/@mcp-showcase/shared/build/ToolRegistry.d.ts +9 -0
- package/node_modules/@mcp-showcase/shared/build/ToolRegistry.d.ts.map +1 -0
- package/node_modules/@mcp-showcase/shared/build/ToolRegistry.js +22 -0
- package/node_modules/@mcp-showcase/shared/build/ToolRegistry.js.map +1 -0
- package/node_modules/@mcp-showcase/shared/build/fs.d.ts +8 -0
- package/node_modules/@mcp-showcase/shared/build/fs.d.ts.map +1 -0
- package/node_modules/@mcp-showcase/shared/build/fs.js +45 -0
- package/node_modules/@mcp-showcase/shared/build/fs.js.map +1 -0
- package/node_modules/@mcp-showcase/shared/build/index.d.ts +5 -0
- package/node_modules/@mcp-showcase/shared/build/index.d.ts.map +1 -0
- package/node_modules/@mcp-showcase/shared/build/index.js +5 -0
- package/node_modules/@mcp-showcase/shared/build/index.js.map +1 -0
- package/node_modules/@mcp-showcase/shared/build/types.d.ts +36 -0
- package/node_modules/@mcp-showcase/shared/build/types.d.ts.map +1 -0
- package/node_modules/@mcp-showcase/shared/build/types.js +5 -0
- package/node_modules/@mcp-showcase/shared/build/types.js.map +1 -0
- package/node_modules/@mcp-showcase/shared/package.json +24 -0
- package/node_modules/@mcp-showcase/shared/src/McpServerBase.ts +100 -0
- package/node_modules/@mcp-showcase/shared/src/ToolRegistry.ts +38 -0
- package/node_modules/@mcp-showcase/shared/src/fs.ts +49 -0
- package/node_modules/@mcp-showcase/shared/src/index.ts +12 -0
- package/node_modules/@mcp-showcase/shared/src/types.ts +44 -0
- package/node_modules/@mcp-showcase/shared/tsconfig.json +8 -0
- package/package.json +27 -1
- package/tools/shared/package.json +2 -1
- package/CONTRIBUTING.md +0 -157
- package/demo/legacy-app/src/App.jsx +0 -12
- package/demo/legacy-app/src/components/Dashboard.jsx +0 -51
- package/demo/legacy-app/src/components/UserCard.jsx +0 -32
- package/demo/legacy-app/src/hooks/useUsers.js +0 -38
- package/demo/legacy-app/src/utils/api.js +0 -30
- package/glama.json +0 -4
- package/server.json +0 -20
- package/tools/accessibility-checker/build/rules.test.d.ts +0 -2
- package/tools/accessibility-checker/build/rules.test.d.ts.map +0 -1
- package/tools/accessibility-checker/build/rules.test.js.map +0 -1
- package/tools/code-modernizer/build/utils/file-ops.test.d.ts +0 -2
- package/tools/code-modernizer/build/utils/file-ops.test.d.ts.map +0 -1
- package/tools/code-modernizer/build/utils/file-ops.test.js.map +0 -1
- package/tools/component-factory/build/utils.test.d.ts +0 -2
- package/tools/component-factory/build/utils.test.d.ts.map +0 -1
- package/tools/component-factory/build/utils.test.js.map +0 -1
- package/tools/component-fixer/build/index.test.d.ts +0 -2
- package/tools/component-fixer/build/index.test.d.ts.map +0 -1
- package/tools/component-fixer/build/index.test.js.map +0 -1
- package/tools/component-reviewer/build/index.test.d.ts +0 -2
- package/tools/component-reviewer/build/index.test.d.ts.map +0 -1
- package/tools/component-reviewer/build/index.test.js.map +0 -1
- package/tools/dep-auditor/build/index.test.d.ts +0 -2
- package/tools/dep-auditor/build/index.test.d.ts.map +0 -1
- package/tools/dep-auditor/build/index.test.js.map +0 -1
- package/tools/generate-tests/build/analyzer.test.d.ts +0 -2
- package/tools/generate-tests/build/analyzer.test.d.ts.map +0 -1
- package/tools/generate-tests/build/analyzer.test.js.map +0 -1
- package/tools/json-viewer/build/utils.test.d.ts +0 -2
- package/tools/json-viewer/build/utils.test.d.ts.map +0 -1
- package/tools/json-viewer/build/utils.test.js.map +0 -1
- package/tools/legacy-analyzer/build/index.test.d.ts +0 -2
- package/tools/legacy-analyzer/build/index.test.d.ts.map +0 -1
- package/tools/legacy-analyzer/build/index.test.js.map +0 -1
- package/tools/lighthouse-runner/build/index.test.d.ts +0 -2
- package/tools/lighthouse-runner/build/index.test.d.ts.map +0 -1
- package/tools/lighthouse-runner/build/index.test.js.map +0 -1
- package/tools/monorepo-manager/build/utils.test.d.ts +0 -2
- package/tools/monorepo-manager/build/utils.test.d.ts.map +0 -1
- package/tools/monorepo-manager/build/utils.test.js.map +0 -1
- package/tools/performance-audit/build/index.test.d.ts +0 -2
- package/tools/performance-audit/build/index.test.d.ts.map +0 -1
- package/tools/performance-audit/build/index.test.js.map +0 -1
- package/tools/quality-pipeline/build/utils.test.d.ts +0 -2
- package/tools/quality-pipeline/build/utils.test.d.ts.map +0 -1
- package/tools/quality-pipeline/build/utils.test.js.map +0 -1
- package/tools/render-analyzer/build/index.test.d.ts +0 -2
- package/tools/render-analyzer/build/index.test.d.ts.map +0 -1
- package/tools/render-analyzer/build/index.test.js.map +0 -1
- package/tools/storybook-generator/build/index.test.d.ts +0 -2
- package/tools/storybook-generator/build/index.test.d.ts.map +0 -1
- package/tools/storybook-generator/build/index.test.js.map +0 -1
- package/tools/test-gap-analyzer/build/index.test.d.ts +0 -2
- package/tools/test-gap-analyzer/build/index.test.d.ts.map +0 -1
- package/tools/test-gap-analyzer/build/index.test.js.map +0 -1
- package/tools/typescript-enforcer/build/scanner.test.d.ts +0 -2
- package/tools/typescript-enforcer/build/scanner.test.d.ts.map +0 -1
- package/tools/typescript-enforcer/build/scanner.test.js.map +0 -1
package/README.md
CHANGED
|
@@ -2,6 +2,7 @@
|
|
|
2
2
|
|
|
3
3
|
MCP servers for React + TypeScript development automation. Works with Claude Desktop, Cline, Cursor — and as plain CLI scripts — one protocol, zero duplication.
|
|
4
4
|
|
|
5
|
+
[](https://www.npmjs.com/package/mcp-react-toolkit)
|
|
5
6
|
[](https://github.com/Nishant-Chaudhary5338/mcp-toolkit/actions/workflows/ci.yml)
|
|
6
7
|
[](LICENSE)
|
|
7
8
|
[](https://github.com/modelcontextprotocol/typescript-sdk)
|
|
@@ -9,6 +10,37 @@ MCP servers for React + TypeScript development automation. Works with Claude Des
|
|
|
9
10
|
|
|
10
11
|
---
|
|
11
12
|
|
|
13
|
+
## Install
|
|
14
|
+
|
|
15
|
+
Published on npm as [`mcp-react-toolkit`](https://www.npmjs.com/package/mcp-react-toolkit). No clone or build required — run any of the 17 servers straight from npm:
|
|
16
|
+
|
|
17
|
+
```bash
|
|
18
|
+
npx mcp-react-toolkit --list # list all 17 tools
|
|
19
|
+
npx mcp-react-toolkit legacy-analyzer # run one as an MCP server (stdio)
|
|
20
|
+
```
|
|
21
|
+
|
|
22
|
+
### Add to Claude Desktop / Cursor / Cline
|
|
23
|
+
|
|
24
|
+
```jsonc
|
|
25
|
+
// claude_desktop_config.json
|
|
26
|
+
{
|
|
27
|
+
"mcpServers": {
|
|
28
|
+
"legacy-analyzer": {
|
|
29
|
+
"command": "npx",
|
|
30
|
+
"args": ["-y", "mcp-react-toolkit", "legacy-analyzer"]
|
|
31
|
+
},
|
|
32
|
+
"component-factory": {
|
|
33
|
+
"command": "npx",
|
|
34
|
+
"args": ["-y", "mcp-react-toolkit", "component-factory"]
|
|
35
|
+
}
|
|
36
|
+
}
|
|
37
|
+
}
|
|
38
|
+
```
|
|
39
|
+
|
|
40
|
+
Swap in any tool name from `npx mcp-react-toolkit --list`. Restart your client and the tools appear.
|
|
41
|
+
|
|
42
|
+
---
|
|
43
|
+
|
|
12
44
|
## What's here
|
|
13
45
|
|
|
14
46
|
```
|
|
@@ -19,6 +51,18 @@ client/ React 19 showcase SPA — tool catalog, workflow demos, animated flo
|
|
|
19
51
|
|
|
20
52
|
---
|
|
21
53
|
|
|
54
|
+
## Companion package
|
|
55
|
+
|
|
56
|
+
[`@mcp-toolkit/code-indexer`](https://www.npmjs.com/package/@mcp-toolkit/code-indexer) — a standalone code-intelligence engine that indexes any TS/React repo into a queryable **code graph** (files · components · functions, and the `imports`/`renders`/`calls`/`references` edges between them) and answers structural questions — *who renders this, who calls this, find references, blast radius, cycles* — over a CLI, an HTTP/WS server with a live 3D viewer, and an MCP server. Separate package, same family:
|
|
57
|
+
|
|
58
|
+
```bash
|
|
59
|
+
npx @mcp-toolkit/code-indexer mcp # stdio MCP server (8 tools)
|
|
60
|
+
npx @mcp-toolkit/code-indexer index . # one-shot index → .code-graph/graph.json
|
|
61
|
+
npx @mcp-toolkit/code-indexer query who-renders --id "cmp:src/Button.tsx#Button"
|
|
62
|
+
```
|
|
63
|
+
|
|
64
|
+
---
|
|
65
|
+
|
|
22
66
|
## Tools
|
|
23
67
|
|
|
24
68
|
All 17 tools are production-ready: built, tested, and CI-verified on Node 20 + 22.
|
|
@@ -131,7 +175,9 @@ new MyTool().run();
|
|
|
131
175
|
|
|
132
176
|
---
|
|
133
177
|
|
|
134
|
-
## Run
|
|
178
|
+
## Run from source (contributors)
|
|
179
|
+
|
|
180
|
+
Prefer npm for everyday use (see [Install](#install)). Clone only to hack on the tools or run the showcase UI:
|
|
135
181
|
|
|
136
182
|
```sh
|
|
137
183
|
git clone https://github.com/Nishant-Chaudhary5338/mcp-toolkit.git
|
|
@@ -142,7 +188,7 @@ npm test # 450 tests across all 17 tools
|
|
|
142
188
|
npm run dev # server on :3002, client on :5173
|
|
143
189
|
```
|
|
144
190
|
|
|
145
|
-
###
|
|
191
|
+
### Point Claude Desktop at a local build
|
|
146
192
|
|
|
147
193
|
```jsonc
|
|
148
194
|
// ~/Library/Application Support/Claude/claude_desktop_config.json
|
package/bin/cli.mjs
ADDED
|
@@ -0,0 +1,59 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
import { fileURLToPath } from "node:url";
|
|
3
|
+
import path from "node:path";
|
|
4
|
+
import { existsSync } from "node:fs";
|
|
5
|
+
|
|
6
|
+
const ROOT = path.resolve(path.dirname(fileURLToPath(import.meta.url)), "..");
|
|
7
|
+
|
|
8
|
+
const TOOLS = [
|
|
9
|
+
"component-factory",
|
|
10
|
+
"component-reviewer",
|
|
11
|
+
"component-fixer",
|
|
12
|
+
"storybook-generator",
|
|
13
|
+
"code-modernizer",
|
|
14
|
+
"typescript-enforcer",
|
|
15
|
+
"accessibility-checker",
|
|
16
|
+
"generate-tests",
|
|
17
|
+
"quality-pipeline",
|
|
18
|
+
"render-analyzer",
|
|
19
|
+
"performance-audit",
|
|
20
|
+
"test-gap-analyzer",
|
|
21
|
+
"legacy-analyzer",
|
|
22
|
+
"dep-auditor",
|
|
23
|
+
"monorepo-manager",
|
|
24
|
+
"lighthouse-runner",
|
|
25
|
+
"json-viewer",
|
|
26
|
+
];
|
|
27
|
+
|
|
28
|
+
const requested = process.argv[2];
|
|
29
|
+
|
|
30
|
+
if (!requested || requested === "--list" || requested === "-l" || requested === "list") {
|
|
31
|
+
const lines = TOOLS.map((t) => ` • ${t}`).join("\n");
|
|
32
|
+
process.stdout.write(
|
|
33
|
+
`mcp-react-toolkit — 17 MCP servers for React + TypeScript\n\n` +
|
|
34
|
+
`Usage:\n npx mcp-react-toolkit <tool>\n\nAvailable tools:\n${lines}\n\n` +
|
|
35
|
+
`Add one to Claude Desktop / Cursor:\n` +
|
|
36
|
+
` "legacy-analyzer": { "command": "npx", "args": ["-y", "mcp-react-toolkit", "legacy-analyzer"] }\n`,
|
|
37
|
+
);
|
|
38
|
+
process.exit(requested ? 0 : 1);
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
if (!TOOLS.includes(requested)) {
|
|
42
|
+
process.stderr.write(
|
|
43
|
+
`Unknown tool: "${requested}".\nRun \`npx mcp-react-toolkit --list\` to see all 17 tools.\n`,
|
|
44
|
+
);
|
|
45
|
+
process.exit(1);
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
const entry = path.join(ROOT, "tools", requested, "build", "index.js");
|
|
49
|
+
if (!existsSync(entry)) {
|
|
50
|
+
process.stderr.write(`Tool "${requested}" is missing its build at ${entry}.\n`);
|
|
51
|
+
process.exit(1);
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
// Importing the tool's entry boots its MCP server on stdio.
|
|
55
|
+
await import(pathToFileUrl(entry));
|
|
56
|
+
|
|
57
|
+
function pathToFileUrl(p) {
|
|
58
|
+
return new URL(`file://${p}`).href;
|
|
59
|
+
}
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
import { Server } from '@modelcontextprotocol/sdk/server/index.js';
|
|
2
|
+
import { ToolRegistry } from './ToolRegistry.js';
|
|
3
|
+
import type { ServerConfig, ToolDefinition, ToolHandler, ToolResult } from './types.js';
|
|
4
|
+
export declare abstract class McpServerBase {
|
|
5
|
+
protected server: Server;
|
|
6
|
+
protected registry: ToolRegistry;
|
|
7
|
+
protected config: ServerConfig;
|
|
8
|
+
constructor(config: ServerConfig);
|
|
9
|
+
protected abstract registerTools(): void;
|
|
10
|
+
protected addTool(name: string, description: string, inputSchema: ToolDefinition['inputSchema'], handler: ToolHandler): void;
|
|
11
|
+
private setupHandlers;
|
|
12
|
+
private setupErrorHandlers;
|
|
13
|
+
protected success<T extends Record<string, unknown>>(data: T): ToolResult;
|
|
14
|
+
protected error(error: unknown): ToolResult;
|
|
15
|
+
run(): Promise<void>;
|
|
16
|
+
shutdown(): Promise<void>;
|
|
17
|
+
}
|
|
18
|
+
//# sourceMappingURL=McpServerBase.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"McpServerBase.d.ts","sourceRoot":"","sources":["../src/McpServerBase.ts"],"names":[],"mappings":"AAIA,OAAO,EAAE,MAAM,EAAE,MAAM,2CAA2C,CAAC;AAQnE,OAAO,EAAE,YAAY,EAAE,MAAM,mBAAmB,CAAC;AACjD,OAAO,KAAK,EAAE,YAAY,EAAE,cAAc,EAAE,WAAW,EAAE,UAAU,EAAE,MAAM,YAAY,CAAC;AAExF,8BAAsB,aAAa;IACjC,SAAS,CAAC,MAAM,EAAE,MAAM,CAAC;IACzB,SAAS,CAAC,QAAQ,EAAE,YAAY,CAAC;IACjC,SAAS,CAAC,MAAM,EAAE,YAAY,CAAC;gBAEnB,MAAM,EAAE,YAAY;IAchC,SAAS,CAAC,QAAQ,CAAC,aAAa,IAAI,IAAI;IAExC,SAAS,CAAC,OAAO,CACf,IAAI,EAAE,MAAM,EACZ,WAAW,EAAE,MAAM,EACnB,WAAW,EAAE,cAAc,CAAC,aAAa,CAAC,EAC1C,OAAO,EAAE,WAAW,GACnB,IAAI;IAIP,OAAO,CAAC,aAAa;IAqBrB,OAAO,CAAC,kBAAkB;IAS1B,SAAS,CAAC,OAAO,CAAC,CAAC,SAAS,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,EAAE,IAAI,EAAE,CAAC,GAAG,UAAU;IAMzE,SAAS,CAAC,KAAK,CAAC,KAAK,EAAE,OAAO,GAAG,UAAU;IAQrC,GAAG,IAAI,OAAO,CAAC,IAAI,CAAC;IAMpB,QAAQ,IAAI,OAAO,CAAC,IAAI,CAAC;CAIhC"}
|
|
@@ -0,0 +1,74 @@
|
|
|
1
|
+
// ============================================================================
|
|
2
|
+
// MCP SERVER BASE - Abstract base class for all MCP servers
|
|
3
|
+
// ============================================================================
|
|
4
|
+
import { Server } from '@modelcontextprotocol/sdk/server/index.js';
|
|
5
|
+
import { StdioServerTransport } from '@modelcontextprotocol/sdk/server/stdio.js';
|
|
6
|
+
import { CallToolRequestSchema, ErrorCode, ListToolsRequestSchema, McpError, } from '@modelcontextprotocol/sdk/types.js';
|
|
7
|
+
import { ToolRegistry } from './ToolRegistry.js';
|
|
8
|
+
export class McpServerBase {
|
|
9
|
+
server;
|
|
10
|
+
registry;
|
|
11
|
+
config;
|
|
12
|
+
constructor(config) {
|
|
13
|
+
this.config = config;
|
|
14
|
+
this.registry = new ToolRegistry();
|
|
15
|
+
this.server = new Server({ name: config.name, version: config.version }, { capabilities: { tools: {} } });
|
|
16
|
+
this.setupHandlers();
|
|
17
|
+
this.setupErrorHandlers();
|
|
18
|
+
this.registerTools();
|
|
19
|
+
}
|
|
20
|
+
addTool(name, description, inputSchema, handler) {
|
|
21
|
+
this.registry.register(name, description, inputSchema, handler);
|
|
22
|
+
}
|
|
23
|
+
setupHandlers() {
|
|
24
|
+
this.server.setRequestHandler(ListToolsRequestSchema, async () => ({
|
|
25
|
+
tools: this.registry.getAllDefinitions(),
|
|
26
|
+
}));
|
|
27
|
+
this.server.setRequestHandler(CallToolRequestSchema, async (request) => {
|
|
28
|
+
const { name, arguments: args } = request.params;
|
|
29
|
+
const handler = this.registry.getHandler(name);
|
|
30
|
+
if (!handler) {
|
|
31
|
+
throw new McpError(ErrorCode.MethodNotFound, `Unknown tool: ${name}`);
|
|
32
|
+
}
|
|
33
|
+
try {
|
|
34
|
+
return await handler(args);
|
|
35
|
+
}
|
|
36
|
+
catch (error) {
|
|
37
|
+
if (error instanceof McpError)
|
|
38
|
+
throw error;
|
|
39
|
+
const message = error instanceof Error ? error.message : String(error);
|
|
40
|
+
throw new McpError(ErrorCode.InternalError, `Tool execution failed: ${message}`);
|
|
41
|
+
}
|
|
42
|
+
});
|
|
43
|
+
}
|
|
44
|
+
setupErrorHandlers() {
|
|
45
|
+
this.server.onerror = (error) => {
|
|
46
|
+
console.error(`[${this.config.name}] MCP Error:`, error);
|
|
47
|
+
};
|
|
48
|
+
process.on('SIGINT', async () => {
|
|
49
|
+
await this.shutdown();
|
|
50
|
+
});
|
|
51
|
+
}
|
|
52
|
+
success(data) {
|
|
53
|
+
return {
|
|
54
|
+
content: [{ type: 'text', text: JSON.stringify({ success: true, ...data }, null, 2) }],
|
|
55
|
+
};
|
|
56
|
+
}
|
|
57
|
+
error(error) {
|
|
58
|
+
const msg = error instanceof Error ? error.message : String(error);
|
|
59
|
+
return {
|
|
60
|
+
content: [{ type: 'text', text: JSON.stringify({ success: false, error: msg }, null, 2) }],
|
|
61
|
+
isError: true,
|
|
62
|
+
};
|
|
63
|
+
}
|
|
64
|
+
async run() {
|
|
65
|
+
const transport = new StdioServerTransport();
|
|
66
|
+
await this.server.connect(transport);
|
|
67
|
+
console.error(`${this.config.name} MCP server v${this.config.version} running on stdio`);
|
|
68
|
+
}
|
|
69
|
+
async shutdown() {
|
|
70
|
+
await this.server.close();
|
|
71
|
+
process.exit(0);
|
|
72
|
+
}
|
|
73
|
+
}
|
|
74
|
+
//# sourceMappingURL=McpServerBase.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"McpServerBase.js","sourceRoot":"","sources":["../src/McpServerBase.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
import type { ToolDefinition, ToolHandler } from './types.js';
|
|
2
|
+
export declare class ToolRegistry {
|
|
3
|
+
private tools;
|
|
4
|
+
register(name: string, description: string, inputSchema: ToolDefinition['inputSchema'], handler: ToolHandler): void;
|
|
5
|
+
getHandler(name: string): ToolHandler | undefined;
|
|
6
|
+
getAllDefinitions(): ToolDefinition[];
|
|
7
|
+
has(name: string): boolean;
|
|
8
|
+
}
|
|
9
|
+
//# sourceMappingURL=ToolRegistry.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"ToolRegistry.d.ts","sourceRoot":"","sources":["../src/ToolRegistry.ts"],"names":[],"mappings":"AAIA,OAAO,KAAK,EAAE,cAAc,EAAE,WAAW,EAAE,MAAM,YAAY,CAAC;AAO9D,qBAAa,YAAY;IACvB,OAAO,CAAC,KAAK,CAA0C;IAEvD,QAAQ,CACN,IAAI,EAAE,MAAM,EACZ,WAAW,EAAE,MAAM,EACnB,WAAW,EAAE,cAAc,CAAC,aAAa,CAAC,EAC1C,OAAO,EAAE,WAAW,GACnB,IAAI;IAOP,UAAU,CAAC,IAAI,EAAE,MAAM,GAAG,WAAW,GAAG,SAAS;IAIjD,iBAAiB,IAAI,cAAc,EAAE;IAIrC,GAAG,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO;CAG3B"}
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
// ============================================================================
|
|
2
|
+
// TOOL REGISTRY - Tool registration and lookup helper
|
|
3
|
+
// ============================================================================
|
|
4
|
+
export class ToolRegistry {
|
|
5
|
+
tools = new Map();
|
|
6
|
+
register(name, description, inputSchema, handler) {
|
|
7
|
+
if (this.tools.has(name)) {
|
|
8
|
+
throw new Error(`Tool already registered: ${name}`);
|
|
9
|
+
}
|
|
10
|
+
this.tools.set(name, { definition: { name, description, inputSchema }, handler });
|
|
11
|
+
}
|
|
12
|
+
getHandler(name) {
|
|
13
|
+
return this.tools.get(name)?.handler;
|
|
14
|
+
}
|
|
15
|
+
getAllDefinitions() {
|
|
16
|
+
return Array.from(this.tools.values()).map(t => t.definition);
|
|
17
|
+
}
|
|
18
|
+
has(name) {
|
|
19
|
+
return this.tools.has(name);
|
|
20
|
+
}
|
|
21
|
+
}
|
|
22
|
+
//# sourceMappingURL=ToolRegistry.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"ToolRegistry.js","sourceRoot":"","sources":["../src/ToolRegistry.ts"],"names":[],"mappings":"AAAA,+EAA+E;AAC/E,sDAAsD;AACtD,+EAA+E;AAS/E,MAAM,OAAO,YAAY;IACf,KAAK,GAAgC,IAAI,GAAG,EAAE,CAAC;IAEvD,QAAQ,CACN,IAAY,EACZ,WAAmB,EACnB,WAA0C,EAC1C,OAAoB;QAEpB,IAAI,IAAI,CAAC,KAAK,CAAC,GAAG,CAAC,IAAI,CAAC,EAAE,CAAC;YACzB,MAAM,IAAI,KAAK,CAAC,4BAA4B,IAAI,EAAE,CAAC,CAAC;QACtD,CAAC;QACD,IAAI,CAAC,KAAK,CAAC,GAAG,CAAC,IAAI,EAAE,EAAE,UAAU,EAAE,EAAE,IAAI,EAAE,WAAW,EAAE,WAAW,EAAE,EAAE,OAAO,EAAE,CAAC,CAAC;IACpF,CAAC;IAED,UAAU,CAAC,IAAY;QACrB,OAAO,IAAI,CAAC,KAAK,CAAC,GAAG,CAAC,IAAI,CAAC,EAAE,OAAO,CAAC;IACvC,CAAC;IAED,iBAAiB;QACf,OAAO,KAAK,CAAC,IAAI,CAAC,IAAI,CAAC,KAAK,CAAC,MAAM,EAAE,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,UAAU,CAAC,CAAC;IAChE,CAAC;IAED,GAAG,CAAC,IAAY;QACd,OAAO,IAAI,CAAC,KAAK,CAAC,GAAG,CAAC,IAAI,CAAC,CAAC;IAC9B,CAAC;CACF"}
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
export declare const MAX_FILE_BYTES: number;
|
|
2
|
+
export declare const DEFAULT_SKIP_DIRS: Set<string>;
|
|
3
|
+
export declare function safeReadJson<T>(filePath: string): T | null;
|
|
4
|
+
export declare function safeReadFile(filePath: string): string | null;
|
|
5
|
+
export declare function isNextJsProject(dir: string): boolean;
|
|
6
|
+
export declare const NEXTJS_ROUTE_FILES: Set<string>;
|
|
7
|
+
export declare function isServerComponent(filePath: string, content: string): boolean;
|
|
8
|
+
//# sourceMappingURL=fs.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"fs.d.ts","sourceRoot":"","sources":["../src/fs.ts"],"names":[],"mappings":"AAGA,eAAO,MAAM,cAAc,QAAmB,CAAC;AAE/C,eAAO,MAAM,iBAAiB,aAG5B,CAAC;AAEH,wBAAgB,YAAY,CAAC,CAAC,EAAE,QAAQ,EAAE,MAAM,GAAG,CAAC,GAAG,IAAI,CAO1D;AAED,wBAAgB,YAAY,CAAC,QAAQ,EAAE,MAAM,GAAG,MAAM,GAAG,IAAI,CAQ5D;AAED,wBAAgB,eAAe,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAMpD;AAED,eAAO,MAAM,kBAAkB,aAK7B,CAAC;AAEH,wBAAgB,iBAAiB,CAAC,QAAQ,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,GAAG,OAAO,CAI5E"}
|
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
import * as fs from 'fs';
|
|
2
|
+
import * as path from 'path';
|
|
3
|
+
export const MAX_FILE_BYTES = 10 * 1024 * 1024; // 10 MB
|
|
4
|
+
export const DEFAULT_SKIP_DIRS = new Set([
|
|
5
|
+
'node_modules', 'build', 'dist', '.next', '.turbo', '__tests__',
|
|
6
|
+
'.git', 'coverage', '.cache', 'out', '.vercel', '.svelte-kit',
|
|
7
|
+
]);
|
|
8
|
+
export function safeReadJson(filePath) {
|
|
9
|
+
try {
|
|
10
|
+
const raw = fs.readFileSync(filePath, 'utf-8');
|
|
11
|
+
return JSON.parse(raw);
|
|
12
|
+
}
|
|
13
|
+
catch {
|
|
14
|
+
return null;
|
|
15
|
+
}
|
|
16
|
+
}
|
|
17
|
+
export function safeReadFile(filePath) {
|
|
18
|
+
try {
|
|
19
|
+
const stat = fs.statSync(filePath);
|
|
20
|
+
if (stat.size > MAX_FILE_BYTES)
|
|
21
|
+
return null;
|
|
22
|
+
return fs.readFileSync(filePath, 'utf-8');
|
|
23
|
+
}
|
|
24
|
+
catch {
|
|
25
|
+
return null;
|
|
26
|
+
}
|
|
27
|
+
}
|
|
28
|
+
export function isNextJsProject(dir) {
|
|
29
|
+
return (fs.existsSync(path.join(dir, 'next.config.js')) ||
|
|
30
|
+
fs.existsSync(path.join(dir, 'next.config.ts')) ||
|
|
31
|
+
fs.existsSync(path.join(dir, 'next.config.mjs')));
|
|
32
|
+
}
|
|
33
|
+
export const NEXTJS_ROUTE_FILES = new Set([
|
|
34
|
+
'page.tsx', 'page.ts', 'layout.tsx', 'layout.ts',
|
|
35
|
+
'loading.tsx', 'loading.ts', 'error.tsx', 'error.ts',
|
|
36
|
+
'not-found.tsx', 'not-found.ts', 'template.tsx', 'template.ts',
|
|
37
|
+
'route.ts', 'route.tsx',
|
|
38
|
+
]);
|
|
39
|
+
export function isServerComponent(filePath, content) {
|
|
40
|
+
const name = path.basename(filePath);
|
|
41
|
+
if (!NEXTJS_ROUTE_FILES.has(name))
|
|
42
|
+
return false;
|
|
43
|
+
return !content.includes("'use client'") && !content.includes('"use client"');
|
|
44
|
+
}
|
|
45
|
+
//# sourceMappingURL=fs.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"fs.js","sourceRoot":"","sources":["../src/fs.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,MAAM,IAAI,CAAC;AACzB,OAAO,KAAK,IAAI,MAAM,MAAM,CAAC;AAE7B,MAAM,CAAC,MAAM,cAAc,GAAG,EAAE,GAAG,IAAI,GAAG,IAAI,CAAC,CAAC,QAAQ;AAExD,MAAM,CAAC,MAAM,iBAAiB,GAAG,IAAI,GAAG,CAAC;IACvC,cAAc,EAAE,OAAO,EAAE,MAAM,EAAE,OAAO,EAAE,QAAQ,EAAE,WAAW;IAC/D,MAAM,EAAE,UAAU,EAAE,QAAQ,EAAE,KAAK,EAAE,SAAS,EAAE,aAAa;CAC9D,CAAC,CAAC;AAEH,MAAM,UAAU,YAAY,CAAI,QAAgB;IAC9C,IAAI,CAAC;QACH,MAAM,GAAG,GAAG,EAAE,CAAC,YAAY,CAAC,QAAQ,EAAE,OAAO,CAAC,CAAC;QAC/C,OAAO,IAAI,CAAC,KAAK,CAAC,GAAG,CAAM,CAAC;IAC9B,CAAC;IAAC,MAAM,CAAC;QACP,OAAO,IAAI,CAAC;IACd,CAAC;AACH,CAAC;AAED,MAAM,UAAU,YAAY,CAAC,QAAgB;IAC3C,IAAI,CAAC;QACH,MAAM,IAAI,GAAG,EAAE,CAAC,QAAQ,CAAC,QAAQ,CAAC,CAAC;QACnC,IAAI,IAAI,CAAC,IAAI,GAAG,cAAc;YAAE,OAAO,IAAI,CAAC;QAC5C,OAAO,EAAE,CAAC,YAAY,CAAC,QAAQ,EAAE,OAAO,CAAC,CAAC;IAC5C,CAAC;IAAC,MAAM,CAAC;QACP,OAAO,IAAI,CAAC;IACd,CAAC;AACH,CAAC;AAED,MAAM,UAAU,eAAe,CAAC,GAAW;IACzC,OAAO,CACL,EAAE,CAAC,UAAU,CAAC,IAAI,CAAC,IAAI,CAAC,GAAG,EAAE,gBAAgB,CAAC,CAAC;QAC/C,EAAE,CAAC,UAAU,CAAC,IAAI,CAAC,IAAI,CAAC,GAAG,EAAE,gBAAgB,CAAC,CAAC;QAC/C,EAAE,CAAC,UAAU,CAAC,IAAI,CAAC,IAAI,CAAC,GAAG,EAAE,iBAAiB,CAAC,CAAC,CACjD,CAAC;AACJ,CAAC;AAED,MAAM,CAAC,MAAM,kBAAkB,GAAG,IAAI,GAAG,CAAC;IACxC,UAAU,EAAE,SAAS,EAAE,YAAY,EAAE,WAAW;IAChD,aAAa,EAAE,YAAY,EAAE,WAAW,EAAE,UAAU;IACpD,eAAe,EAAE,cAAc,EAAE,cAAc,EAAE,aAAa;IAC9D,UAAU,EAAE,WAAW;CACxB,CAAC,CAAC;AAEH,MAAM,UAAU,iBAAiB,CAAC,QAAgB,EAAE,OAAe;IACjE,MAAM,IAAI,GAAG,IAAI,CAAC,QAAQ,CAAC,QAAQ,CAAC,CAAC;IACrC,IAAI,CAAC,kBAAkB,CAAC,GAAG,CAAC,IAAI,CAAC;QAAE,OAAO,KAAK,CAAC;IAChD,OAAO,CAAC,OAAO,CAAC,QAAQ,CAAC,cAAc,CAAC,IAAI,CAAC,OAAO,CAAC,QAAQ,CAAC,cAAc,CAAC,CAAC;AAChF,CAAC"}
|
|
@@ -0,0 +1,5 @@
|
|
|
1
|
+
export * from './types.js';
|
|
2
|
+
export { McpServerBase } from './McpServerBase.js';
|
|
3
|
+
export { ToolRegistry } from './ToolRegistry.js';
|
|
4
|
+
export { safeReadJson, safeReadFile, isNextJsProject, isServerComponent, NEXTJS_ROUTE_FILES, DEFAULT_SKIP_DIRS, MAX_FILE_BYTES, } from './fs.js';
|
|
5
|
+
//# sourceMappingURL=index.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,cAAc,YAAY,CAAC;AAC3B,OAAO,EAAE,aAAa,EAAE,MAAM,oBAAoB,CAAC;AACnD,OAAO,EAAE,YAAY,EAAE,MAAM,mBAAmB,CAAC;AACjD,OAAO,EACL,YAAY,EACZ,YAAY,EACZ,eAAe,EACf,iBAAiB,EACjB,kBAAkB,EAClB,iBAAiB,EACjB,cAAc,GACf,MAAM,SAAS,CAAC"}
|
|
@@ -0,0 +1,5 @@
|
|
|
1
|
+
export * from './types.js';
|
|
2
|
+
export { McpServerBase } from './McpServerBase.js';
|
|
3
|
+
export { ToolRegistry } from './ToolRegistry.js';
|
|
4
|
+
export { safeReadJson, safeReadFile, isNextJsProject, isServerComponent, NEXTJS_ROUTE_FILES, DEFAULT_SKIP_DIRS, MAX_FILE_BYTES, } from './fs.js';
|
|
5
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,cAAc,YAAY,CAAC;AAC3B,OAAO,EAAE,aAAa,EAAE,MAAM,oBAAoB,CAAC;AACnD,OAAO,EAAE,YAAY,EAAE,MAAM,mBAAmB,CAAC;AACjD,OAAO,EACL,YAAY,EACZ,YAAY,EACZ,eAAe,EACf,iBAAiB,EACjB,kBAAkB,EAClB,iBAAiB,EACjB,cAAc,GACf,MAAM,SAAS,CAAC"}
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
export interface ToolDefinition {
|
|
2
|
+
name: string;
|
|
3
|
+
description: string;
|
|
4
|
+
inputSchema: {
|
|
5
|
+
type: 'object';
|
|
6
|
+
properties: Record<string, SchemaProperty>;
|
|
7
|
+
required?: string[];
|
|
8
|
+
};
|
|
9
|
+
}
|
|
10
|
+
export interface SchemaProperty {
|
|
11
|
+
type: string;
|
|
12
|
+
description?: string;
|
|
13
|
+
default?: unknown;
|
|
14
|
+
enum?: string[];
|
|
15
|
+
items?: SchemaProperty;
|
|
16
|
+
properties?: Record<string, SchemaProperty>;
|
|
17
|
+
}
|
|
18
|
+
export interface ToolResult {
|
|
19
|
+
content: ToolContent[];
|
|
20
|
+
isError?: boolean;
|
|
21
|
+
_meta?: Record<string, unknown>;
|
|
22
|
+
[key: string]: unknown;
|
|
23
|
+
}
|
|
24
|
+
export interface ToolContent {
|
|
25
|
+
type: 'text' | 'image' | 'resource';
|
|
26
|
+
text?: string;
|
|
27
|
+
data?: string;
|
|
28
|
+
mimeType?: string;
|
|
29
|
+
}
|
|
30
|
+
export interface ServerConfig {
|
|
31
|
+
name: string;
|
|
32
|
+
version: string;
|
|
33
|
+
capabilities?: Record<string, unknown>;
|
|
34
|
+
}
|
|
35
|
+
export type ToolHandler = (args: unknown) => Promise<ToolResult>;
|
|
36
|
+
//# sourceMappingURL=types.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":"AAIA,MAAM,WAAW,cAAc;IAC7B,IAAI,EAAE,MAAM,CAAC;IACb,WAAW,EAAE,MAAM,CAAC;IACpB,WAAW,EAAE;QACX,IAAI,EAAE,QAAQ,CAAC;QACf,UAAU,EAAE,MAAM,CAAC,MAAM,EAAE,cAAc,CAAC,CAAC;QAC3C,QAAQ,CAAC,EAAE,MAAM,EAAE,CAAC;KACrB,CAAC;CACH;AAED,MAAM,WAAW,cAAc;IAC7B,IAAI,EAAE,MAAM,CAAC;IACb,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,OAAO,CAAC,EAAE,OAAO,CAAC;IAClB,IAAI,CAAC,EAAE,MAAM,EAAE,CAAC;IAChB,KAAK,CAAC,EAAE,cAAc,CAAC;IACvB,UAAU,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,cAAc,CAAC,CAAC;CAC7C;AAED,MAAM,WAAW,UAAU;IACzB,OAAO,EAAE,WAAW,EAAE,CAAC;IACvB,OAAO,CAAC,EAAE,OAAO,CAAC;IAClB,KAAK,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;IAChC,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC;CACxB;AAED,MAAM,WAAW,WAAW;IAC1B,IAAI,EAAE,MAAM,GAAG,OAAO,GAAG,UAAU,CAAC;IACpC,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,QAAQ,CAAC,EAAE,MAAM,CAAC;CACnB;AAED,MAAM,WAAW,YAAY;IAC3B,IAAI,EAAE,MAAM,CAAC;IACb,OAAO,EAAE,MAAM,CAAC;IAChB,YAAY,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;CACxC;AAED,MAAM,MAAM,WAAW,GAAG,CAAC,IAAI,EAAE,OAAO,KAAK,OAAO,CAAC,UAAU,CAAC,CAAC"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"types.js","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":"AAAA,+EAA+E;AAC/E,6CAA6C;AAC7C,+EAA+E"}
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@mcp-showcase/shared",
|
|
3
|
+
"version": "1.0.0",
|
|
4
|
+
"type": "module",
|
|
5
|
+
"exports": {
|
|
6
|
+
".": {
|
|
7
|
+
"import": "./build/index.js",
|
|
8
|
+
"types": "./build/index.d.ts"
|
|
9
|
+
}
|
|
10
|
+
},
|
|
11
|
+
"main": "./build/index.js",
|
|
12
|
+
"scripts": {
|
|
13
|
+
"build": "tsc",
|
|
14
|
+
"dev": "tsc --watch"
|
|
15
|
+
},
|
|
16
|
+
"peerDependencies": {
|
|
17
|
+
"@modelcontextprotocol/sdk": "^1.12.0"
|
|
18
|
+
},
|
|
19
|
+
"devDependencies": {
|
|
20
|
+
"@modelcontextprotocol/sdk": "^1.12.0",
|
|
21
|
+
"@types/node": "^20.0.0",
|
|
22
|
+
"typescript": "^5.0.0"
|
|
23
|
+
}
|
|
24
|
+
}
|
|
@@ -0,0 +1,100 @@
|
|
|
1
|
+
// ============================================================================
|
|
2
|
+
// MCP SERVER BASE - Abstract base class for all MCP servers
|
|
3
|
+
// ============================================================================
|
|
4
|
+
|
|
5
|
+
import { Server } from '@modelcontextprotocol/sdk/server/index.js';
|
|
6
|
+
import { StdioServerTransport } from '@modelcontextprotocol/sdk/server/stdio.js';
|
|
7
|
+
import {
|
|
8
|
+
CallToolRequestSchema,
|
|
9
|
+
ErrorCode,
|
|
10
|
+
ListToolsRequestSchema,
|
|
11
|
+
McpError,
|
|
12
|
+
} from '@modelcontextprotocol/sdk/types.js';
|
|
13
|
+
import { ToolRegistry } from './ToolRegistry.js';
|
|
14
|
+
import type { ServerConfig, ToolDefinition, ToolHandler, ToolResult } from './types.js';
|
|
15
|
+
|
|
16
|
+
export abstract class McpServerBase {
|
|
17
|
+
protected server: Server;
|
|
18
|
+
protected registry: ToolRegistry;
|
|
19
|
+
protected config: ServerConfig;
|
|
20
|
+
|
|
21
|
+
constructor(config: ServerConfig) {
|
|
22
|
+
this.config = config;
|
|
23
|
+
this.registry = new ToolRegistry();
|
|
24
|
+
|
|
25
|
+
this.server = new Server(
|
|
26
|
+
{ name: config.name, version: config.version },
|
|
27
|
+
{ capabilities: { tools: {} } }
|
|
28
|
+
);
|
|
29
|
+
|
|
30
|
+
this.setupHandlers();
|
|
31
|
+
this.setupErrorHandlers();
|
|
32
|
+
this.registerTools();
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
protected abstract registerTools(): void;
|
|
36
|
+
|
|
37
|
+
protected addTool(
|
|
38
|
+
name: string,
|
|
39
|
+
description: string,
|
|
40
|
+
inputSchema: ToolDefinition['inputSchema'],
|
|
41
|
+
handler: ToolHandler
|
|
42
|
+
): void {
|
|
43
|
+
this.registry.register(name, description, inputSchema, handler);
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
private setupHandlers(): void {
|
|
47
|
+
this.server.setRequestHandler(ListToolsRequestSchema, async () => ({
|
|
48
|
+
tools: this.registry.getAllDefinitions(),
|
|
49
|
+
}));
|
|
50
|
+
|
|
51
|
+
this.server.setRequestHandler(CallToolRequestSchema, async (request) => {
|
|
52
|
+
const { name, arguments: args } = request.params;
|
|
53
|
+
const handler = this.registry.getHandler(name);
|
|
54
|
+
if (!handler) {
|
|
55
|
+
throw new McpError(ErrorCode.MethodNotFound, `Unknown tool: ${name}`);
|
|
56
|
+
}
|
|
57
|
+
try {
|
|
58
|
+
return await handler(args);
|
|
59
|
+
} catch (error) {
|
|
60
|
+
if (error instanceof McpError) throw error;
|
|
61
|
+
const message = error instanceof Error ? error.message : String(error);
|
|
62
|
+
throw new McpError(ErrorCode.InternalError, `Tool execution failed: ${message}`);
|
|
63
|
+
}
|
|
64
|
+
});
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
private setupErrorHandlers(): void {
|
|
68
|
+
this.server.onerror = (error) => {
|
|
69
|
+
console.error(`[${this.config.name}] MCP Error:`, error);
|
|
70
|
+
};
|
|
71
|
+
process.on('SIGINT', async () => {
|
|
72
|
+
await this.shutdown();
|
|
73
|
+
});
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
protected success<T extends Record<string, unknown>>(data: T): ToolResult {
|
|
77
|
+
return {
|
|
78
|
+
content: [{ type: 'text', text: JSON.stringify({ success: true, ...data }, null, 2) }],
|
|
79
|
+
};
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
protected error(error: unknown): ToolResult {
|
|
83
|
+
const msg = error instanceof Error ? error.message : String(error);
|
|
84
|
+
return {
|
|
85
|
+
content: [{ type: 'text', text: JSON.stringify({ success: false, error: msg }, null, 2) }],
|
|
86
|
+
isError: true,
|
|
87
|
+
};
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
async run(): Promise<void> {
|
|
91
|
+
const transport = new StdioServerTransport();
|
|
92
|
+
await this.server.connect(transport);
|
|
93
|
+
console.error(`${this.config.name} MCP server v${this.config.version} running on stdio`);
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
async shutdown(): Promise<void> {
|
|
97
|
+
await this.server.close();
|
|
98
|
+
process.exit(0);
|
|
99
|
+
}
|
|
100
|
+
}
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
// ============================================================================
|
|
2
|
+
// TOOL REGISTRY - Tool registration and lookup helper
|
|
3
|
+
// ============================================================================
|
|
4
|
+
|
|
5
|
+
import type { ToolDefinition, ToolHandler } from './types.js';
|
|
6
|
+
|
|
7
|
+
interface RegisteredTool {
|
|
8
|
+
definition: ToolDefinition;
|
|
9
|
+
handler: ToolHandler;
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
export class ToolRegistry {
|
|
13
|
+
private tools: Map<string, RegisteredTool> = new Map();
|
|
14
|
+
|
|
15
|
+
register(
|
|
16
|
+
name: string,
|
|
17
|
+
description: string,
|
|
18
|
+
inputSchema: ToolDefinition['inputSchema'],
|
|
19
|
+
handler: ToolHandler
|
|
20
|
+
): void {
|
|
21
|
+
if (this.tools.has(name)) {
|
|
22
|
+
throw new Error(`Tool already registered: ${name}`);
|
|
23
|
+
}
|
|
24
|
+
this.tools.set(name, { definition: { name, description, inputSchema }, handler });
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
getHandler(name: string): ToolHandler | undefined {
|
|
28
|
+
return this.tools.get(name)?.handler;
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
getAllDefinitions(): ToolDefinition[] {
|
|
32
|
+
return Array.from(this.tools.values()).map(t => t.definition);
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
has(name: string): boolean {
|
|
36
|
+
return this.tools.has(name);
|
|
37
|
+
}
|
|
38
|
+
}
|
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
import * as fs from 'fs';
|
|
2
|
+
import * as path from 'path';
|
|
3
|
+
|
|
4
|
+
export const MAX_FILE_BYTES = 10 * 1024 * 1024; // 10 MB
|
|
5
|
+
|
|
6
|
+
export const DEFAULT_SKIP_DIRS = new Set([
|
|
7
|
+
'node_modules', 'build', 'dist', '.next', '.turbo', '__tests__',
|
|
8
|
+
'.git', 'coverage', '.cache', 'out', '.vercel', '.svelte-kit',
|
|
9
|
+
]);
|
|
10
|
+
|
|
11
|
+
export function safeReadJson<T>(filePath: string): T | null {
|
|
12
|
+
try {
|
|
13
|
+
const raw = fs.readFileSync(filePath, 'utf-8');
|
|
14
|
+
return JSON.parse(raw) as T;
|
|
15
|
+
} catch {
|
|
16
|
+
return null;
|
|
17
|
+
}
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
export function safeReadFile(filePath: string): string | null {
|
|
21
|
+
try {
|
|
22
|
+
const stat = fs.statSync(filePath);
|
|
23
|
+
if (stat.size > MAX_FILE_BYTES) return null;
|
|
24
|
+
return fs.readFileSync(filePath, 'utf-8');
|
|
25
|
+
} catch {
|
|
26
|
+
return null;
|
|
27
|
+
}
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
export function isNextJsProject(dir: string): boolean {
|
|
31
|
+
return (
|
|
32
|
+
fs.existsSync(path.join(dir, 'next.config.js')) ||
|
|
33
|
+
fs.existsSync(path.join(dir, 'next.config.ts')) ||
|
|
34
|
+
fs.existsSync(path.join(dir, 'next.config.mjs'))
|
|
35
|
+
);
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
export const NEXTJS_ROUTE_FILES = new Set([
|
|
39
|
+
'page.tsx', 'page.ts', 'layout.tsx', 'layout.ts',
|
|
40
|
+
'loading.tsx', 'loading.ts', 'error.tsx', 'error.ts',
|
|
41
|
+
'not-found.tsx', 'not-found.ts', 'template.tsx', 'template.ts',
|
|
42
|
+
'route.ts', 'route.tsx',
|
|
43
|
+
]);
|
|
44
|
+
|
|
45
|
+
export function isServerComponent(filePath: string, content: string): boolean {
|
|
46
|
+
const name = path.basename(filePath);
|
|
47
|
+
if (!NEXTJS_ROUTE_FILES.has(name)) return false;
|
|
48
|
+
return !content.includes("'use client'") && !content.includes('"use client"');
|
|
49
|
+
}
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
export * from './types.js';
|
|
2
|
+
export { McpServerBase } from './McpServerBase.js';
|
|
3
|
+
export { ToolRegistry } from './ToolRegistry.js';
|
|
4
|
+
export {
|
|
5
|
+
safeReadJson,
|
|
6
|
+
safeReadFile,
|
|
7
|
+
isNextJsProject,
|
|
8
|
+
isServerComponent,
|
|
9
|
+
NEXTJS_ROUTE_FILES,
|
|
10
|
+
DEFAULT_SKIP_DIRS,
|
|
11
|
+
MAX_FILE_BYTES,
|
|
12
|
+
} from './fs.js';
|