@agentailor/create-mcp-server 0.4.1 → 0.5.1
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 +65 -0
- package/dist/cli.d.ts +15 -0
- package/dist/cli.js +60 -0
- package/dist/cli.test.d.ts +1 -0
- package/dist/cli.test.js +145 -0
- package/dist/index.js +24 -183
- package/dist/interactive.d.ts +1 -0
- package/dist/interactive.js +103 -0
- package/dist/project-generator.d.ts +15 -0
- package/dist/project-generator.js +85 -0
- package/dist/templates/fastmcp/readme.js +37 -3
- package/dist/templates/sdk/stateful/readme.js +37 -3
- package/dist/templates/sdk/stateless/readme.js +37 -3
- package/package.json +2 -1
package/README.md
CHANGED
|
@@ -1,13 +1,59 @@
|
|
|
1
1
|
# @agentailor/create-mcp-server
|
|
2
2
|
|
|
3
|
+
[](https://www.npmjs.com/package/@agentailor/create-mcp-server)
|
|
4
|
+
[](https://github.com/agentailor/create-mcp-server/actions/workflows/test.yml)
|
|
5
|
+
[](https://www.npmjs.com/package/@agentailor/create-mcp-server)
|
|
6
|
+
[](https://opensource.org/licenses/MIT)
|
|
7
|
+
[](https://nodejs.org/)
|
|
8
|
+
[](https://github.com/agentailor/create-mcp-server/pulls)
|
|
9
|
+
|
|
3
10
|
Scaffold production-ready MCP servers in seconds.
|
|
4
11
|
|
|
5
12
|
## Quick Start
|
|
6
13
|
|
|
14
|
+
**Interactive mode** (guided prompts):
|
|
15
|
+
|
|
7
16
|
```bash
|
|
8
17
|
npx @agentailor/create-mcp-server
|
|
9
18
|
```
|
|
10
19
|
|
|
20
|
+
**CLI mode** (all options via arguments):
|
|
21
|
+
|
|
22
|
+
```bash
|
|
23
|
+
npx @agentailor/create-mcp-server --name=my-server
|
|
24
|
+
```
|
|
25
|
+
|
|
26
|
+
## CLI Options
|
|
27
|
+
|
|
28
|
+
| Option | Short | Default | Description |
|
|
29
|
+
|--------|-------|---------|-------------|
|
|
30
|
+
| `--name` | `-n` | — | Project name (required in CLI mode) |
|
|
31
|
+
| `--package-manager` | `-p` | `npm` | Package manager: npm, pnpm, yarn |
|
|
32
|
+
| `--framework` | `-f` | `sdk` | Framework: sdk, fastmcp |
|
|
33
|
+
| `--template` | `-t` | `stateless` | Server mode: stateless, stateful |
|
|
34
|
+
| `--oauth` | — | `false` | Enable OAuth (sdk+stateful only) |
|
|
35
|
+
| `--no-git` | — | `false` | Skip git initialization |
|
|
36
|
+
| `--help` | `-h` | — | Show help |
|
|
37
|
+
| `--version` | `-V` | — | Show version |
|
|
38
|
+
|
|
39
|
+
**Examples:**
|
|
40
|
+
|
|
41
|
+
```bash
|
|
42
|
+
# Minimal - uses all defaults
|
|
43
|
+
npx @agentailor/create-mcp-server --name=my-server
|
|
44
|
+
|
|
45
|
+
# Full options
|
|
46
|
+
npx @agentailor/create-mcp-server \
|
|
47
|
+
--name=my-auth-server \
|
|
48
|
+
--package-manager=pnpm \
|
|
49
|
+
--framework=sdk \
|
|
50
|
+
--template=stateful \
|
|
51
|
+
--oauth
|
|
52
|
+
|
|
53
|
+
# Short flags
|
|
54
|
+
npx @agentailor/create-mcp-server -n my-server -p yarn -f fastmcp
|
|
55
|
+
```
|
|
56
|
+
|
|
11
57
|
## Features
|
|
12
58
|
|
|
13
59
|
- **Two frameworks** — Official MCP SDK or FastMCP
|
|
@@ -80,6 +126,25 @@ my-mcp-server/
|
|
|
80
126
|
- `npm run dev` — build and start the server
|
|
81
127
|
- `npm run inspect` — open MCP Inspector (update URL in `package.json` if needed)
|
|
82
128
|
|
|
129
|
+
## Learning Resources
|
|
130
|
+
|
|
131
|
+
| Guide | Description |
|
|
132
|
+
|-------|-------------|
|
|
133
|
+
| [Create Your First MCP Server in 5 Minutes](https://blog.agentailor.com/posts/create-your-first-mcp-server-in-5-minutes?utm_source=github&utm_medium=readme&utm_campaign=create-mcp-server) | Build your first production-ready MCP server. A complete beginner guide to scaffolding a Fetch MCP server with TypeScript. |
|
|
134
|
+
| [Securing MCP Servers with Keycloak](https://blog.agentailor.com/posts/oauth-for-mcp-servers-practical-guide-keycloak?utm_source=github&utm_medium=readme&utm_campaign=create-mcp-server) | Learn how to secure your MCP servers with OAuth authentication using Keycloak. |
|
|
135
|
+
| [Getting Started with FastMCP](https://blog.agentailor.com/posts/getting-started-with-fastmcp?utm_source=github&utm_medium=readme&utm_campaign=create-mcp-server) | Build MCP servers faster with FastMCP — the TypeScript framework inspired by Python's most popular MCP library. |
|
|
136
|
+
| [OAuth for MCP Clients (Next.js + LangGraph.js)](https://blog.agentailor.com/posts/mcp-client-oauth-nextjs-langgraph?utm_source=github&utm_medium=readme&utm_campaign=create-mcp-server) | Implement OAuth authentication in your MCP client using Next.js and the MCP SDK. |
|
|
137
|
+
|
|
138
|
+
## Need help building MCP servers or agent infrastructure?
|
|
139
|
+
|
|
140
|
+
I help teams design and ship production-ready AI agent systems (MCP, LangGraph, RAG, memory, performance).
|
|
141
|
+
|
|
142
|
+
If you’re building something serious on top of this:
|
|
143
|
+
|
|
144
|
+
→ [DM me on LinkedIn](https://www.linkedin.com/in/ali-ibrahim-junior/)
|
|
145
|
+
|
|
146
|
+
Happy to jump on a short call.
|
|
147
|
+
|
|
83
148
|
## What is MCP?
|
|
84
149
|
|
|
85
150
|
The [Model Context Protocol](https://modelcontextprotocol.io/) (MCP) is an open protocol that enables AI assistants to interact with external tools, data sources, and services.
|
package/dist/cli.d.ts
ADDED
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
import type { PackageManager, Framework } from './templates/common/types.js';
|
|
2
|
+
export type TemplateType = 'stateless' | 'stateful';
|
|
3
|
+
export interface CLIOptions {
|
|
4
|
+
name: string;
|
|
5
|
+
packageManager: PackageManager;
|
|
6
|
+
framework: Framework;
|
|
7
|
+
template: TemplateType;
|
|
8
|
+
oauth: boolean;
|
|
9
|
+
git: boolean;
|
|
10
|
+
}
|
|
11
|
+
export interface ParseResult {
|
|
12
|
+
mode: 'interactive' | 'cli';
|
|
13
|
+
options?: CLIOptions;
|
|
14
|
+
}
|
|
15
|
+
export declare function parseArguments(): ParseResult;
|
package/dist/cli.js
ADDED
|
@@ -0,0 +1,60 @@
|
|
|
1
|
+
import { Command, Option, InvalidArgumentError } from 'commander';
|
|
2
|
+
const NAME_REGEX = /^[a-z0-9-_]+$/i;
|
|
3
|
+
const VERSION = '0.4.1';
|
|
4
|
+
function validateName(value) {
|
|
5
|
+
if (!NAME_REGEX.test(value)) {
|
|
6
|
+
throw new InvalidArgumentError('Project name can only contain letters, numbers, hyphens, and underscores');
|
|
7
|
+
}
|
|
8
|
+
return value;
|
|
9
|
+
}
|
|
10
|
+
export function parseArguments() {
|
|
11
|
+
const program = new Command();
|
|
12
|
+
program
|
|
13
|
+
.name('create-mcp-server')
|
|
14
|
+
.description('Create a new MCP (Model Context Protocol) server project')
|
|
15
|
+
.version(VERSION)
|
|
16
|
+
.option('-n, --name <name>', 'Project name', validateName)
|
|
17
|
+
.addOption(new Option('-p, --package-manager <manager>', 'Package manager')
|
|
18
|
+
.choices(['npm', 'pnpm', 'yarn'])
|
|
19
|
+
.default('npm'))
|
|
20
|
+
.addOption(new Option('-f, --framework <framework>', 'Framework to use')
|
|
21
|
+
.choices(['sdk', 'fastmcp'])
|
|
22
|
+
.default('sdk'))
|
|
23
|
+
.addOption(new Option('-t, --template <type>', 'Template type')
|
|
24
|
+
.choices(['stateless', 'stateful'])
|
|
25
|
+
.default('stateless'))
|
|
26
|
+
.option('--oauth', 'Enable OAuth authentication (sdk+stateful only)', false)
|
|
27
|
+
.option('--no-git', 'Skip git repository initialization');
|
|
28
|
+
program.parse();
|
|
29
|
+
const opts = program.opts();
|
|
30
|
+
// Detect mode based on whether any option was explicitly provided
|
|
31
|
+
// Check for CLI args (excluding node, script path, --help, --version)
|
|
32
|
+
const cliArgs = process.argv.slice(2);
|
|
33
|
+
const hasExplicitArgs = cliArgs.some((arg) => arg.startsWith('-') && !['--help', '-h', '--version', '-V'].includes(arg));
|
|
34
|
+
if (!hasExplicitArgs) {
|
|
35
|
+
return { mode: 'interactive' };
|
|
36
|
+
}
|
|
37
|
+
// CLI mode - validate required args
|
|
38
|
+
if (!opts.name) {
|
|
39
|
+
console.error('\nError: --name is required when using CLI arguments\n');
|
|
40
|
+
console.error('Usage: create-mcp-server --name=my-server [options]\n');
|
|
41
|
+
console.error('Run with --help for all options.\n');
|
|
42
|
+
process.exit(1);
|
|
43
|
+
}
|
|
44
|
+
// Validate OAuth constraint
|
|
45
|
+
if (opts.oauth && (opts.framework !== 'sdk' || opts.template !== 'stateful')) {
|
|
46
|
+
console.error('\nError: --oauth is only valid with --framework=sdk and --template=stateful\n');
|
|
47
|
+
process.exit(1);
|
|
48
|
+
}
|
|
49
|
+
return {
|
|
50
|
+
mode: 'cli',
|
|
51
|
+
options: {
|
|
52
|
+
name: opts.name,
|
|
53
|
+
packageManager: opts.packageManager,
|
|
54
|
+
framework: opts.framework,
|
|
55
|
+
template: opts.template,
|
|
56
|
+
oauth: opts.oauth,
|
|
57
|
+
git: opts.git, // Commander handles --no-git -> git: false
|
|
58
|
+
},
|
|
59
|
+
};
|
|
60
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
package/dist/cli.test.js
ADDED
|
@@ -0,0 +1,145 @@
|
|
|
1
|
+
import { describe, it, expect, vi, beforeEach, afterEach } from 'vitest';
|
|
2
|
+
// We need to test the CLI argument parsing logic
|
|
3
|
+
// Commander modifies process.argv, so we need to mock it carefully
|
|
4
|
+
describe('CLI argument parsing', () => {
|
|
5
|
+
const originalArgv = process.argv;
|
|
6
|
+
const originalExit = process.exit;
|
|
7
|
+
beforeEach(() => {
|
|
8
|
+
// Reset modules to clear commander's state
|
|
9
|
+
vi.resetModules();
|
|
10
|
+
});
|
|
11
|
+
afterEach(() => {
|
|
12
|
+
process.argv = originalArgv;
|
|
13
|
+
process.exit = originalExit;
|
|
14
|
+
});
|
|
15
|
+
it('returns interactive mode when no arguments provided', async () => {
|
|
16
|
+
process.argv = ['node', 'create-mcp-server'];
|
|
17
|
+
const { parseArguments } = await import('./cli.js');
|
|
18
|
+
const result = parseArguments();
|
|
19
|
+
expect(result.mode).toBe('interactive');
|
|
20
|
+
expect(result.options).toBeUndefined();
|
|
21
|
+
});
|
|
22
|
+
it('returns cli mode with valid arguments', async () => {
|
|
23
|
+
process.argv = ['node', 'create-mcp-server', '--name=my-server'];
|
|
24
|
+
const { parseArguments } = await import('./cli.js');
|
|
25
|
+
const result = parseArguments();
|
|
26
|
+
expect(result.mode).toBe('cli');
|
|
27
|
+
expect(result.options?.name).toBe('my-server');
|
|
28
|
+
});
|
|
29
|
+
it('uses defaults for optional arguments', async () => {
|
|
30
|
+
process.argv = ['node', 'create-mcp-server', '--name=my-server'];
|
|
31
|
+
const { parseArguments } = await import('./cli.js');
|
|
32
|
+
const result = parseArguments();
|
|
33
|
+
expect(result.options?.packageManager).toBe('npm');
|
|
34
|
+
expect(result.options?.framework).toBe('sdk');
|
|
35
|
+
expect(result.options?.template).toBe('stateless');
|
|
36
|
+
expect(result.options?.oauth).toBe(false);
|
|
37
|
+
expect(result.options?.git).toBe(true);
|
|
38
|
+
});
|
|
39
|
+
it('parses all arguments correctly', async () => {
|
|
40
|
+
process.argv = [
|
|
41
|
+
'node',
|
|
42
|
+
'create-mcp-server',
|
|
43
|
+
'--name=test-project',
|
|
44
|
+
'--package-manager=pnpm',
|
|
45
|
+
'--framework=fastmcp',
|
|
46
|
+
'--template=stateful',
|
|
47
|
+
'--no-git',
|
|
48
|
+
];
|
|
49
|
+
const { parseArguments } = await import('./cli.js');
|
|
50
|
+
const result = parseArguments();
|
|
51
|
+
expect(result.options).toEqual({
|
|
52
|
+
name: 'test-project',
|
|
53
|
+
packageManager: 'pnpm',
|
|
54
|
+
framework: 'fastmcp',
|
|
55
|
+
template: 'stateful',
|
|
56
|
+
oauth: false,
|
|
57
|
+
git: false,
|
|
58
|
+
});
|
|
59
|
+
});
|
|
60
|
+
it('parses short flags correctly', async () => {
|
|
61
|
+
process.argv = [
|
|
62
|
+
'node',
|
|
63
|
+
'create-mcp-server',
|
|
64
|
+
'-n',
|
|
65
|
+
'my-project',
|
|
66
|
+
'-p',
|
|
67
|
+
'yarn',
|
|
68
|
+
'-f',
|
|
69
|
+
'sdk',
|
|
70
|
+
'-t',
|
|
71
|
+
'stateful',
|
|
72
|
+
];
|
|
73
|
+
const { parseArguments } = await import('./cli.js');
|
|
74
|
+
const result = parseArguments();
|
|
75
|
+
expect(result.options?.name).toBe('my-project');
|
|
76
|
+
expect(result.options?.packageManager).toBe('yarn');
|
|
77
|
+
expect(result.options?.framework).toBe('sdk');
|
|
78
|
+
expect(result.options?.template).toBe('stateful');
|
|
79
|
+
});
|
|
80
|
+
it('parses oauth flag correctly for sdk+stateful', async () => {
|
|
81
|
+
process.argv = [
|
|
82
|
+
'node',
|
|
83
|
+
'create-mcp-server',
|
|
84
|
+
'--name=my-auth-server',
|
|
85
|
+
'--framework=sdk',
|
|
86
|
+
'--template=stateful',
|
|
87
|
+
'--oauth',
|
|
88
|
+
];
|
|
89
|
+
const { parseArguments } = await import('./cli.js');
|
|
90
|
+
const result = parseArguments();
|
|
91
|
+
expect(result.options?.oauth).toBe(true);
|
|
92
|
+
expect(result.options?.framework).toBe('sdk');
|
|
93
|
+
expect(result.options?.template).toBe('stateful');
|
|
94
|
+
});
|
|
95
|
+
it('exits with error when --name is missing in CLI mode', async () => {
|
|
96
|
+
process.argv = ['node', 'create-mcp-server', '--package-manager=npm'];
|
|
97
|
+
let exitCode;
|
|
98
|
+
process.exit = vi.fn((code) => {
|
|
99
|
+
exitCode = code;
|
|
100
|
+
throw new Error('process.exit called');
|
|
101
|
+
});
|
|
102
|
+
const consoleError = vi.spyOn(console, 'error').mockImplementation(() => { });
|
|
103
|
+
const { parseArguments } = await import('./cli.js');
|
|
104
|
+
expect(() => parseArguments()).toThrow('process.exit called');
|
|
105
|
+
expect(exitCode).toBe(1);
|
|
106
|
+
expect(consoleError).toHaveBeenCalledWith(expect.stringContaining('--name is required when using CLI arguments'));
|
|
107
|
+
consoleError.mockRestore();
|
|
108
|
+
});
|
|
109
|
+
it('exits with error when --oauth used without sdk+stateful', async () => {
|
|
110
|
+
process.argv = ['node', 'create-mcp-server', '--name=test', '--oauth', '--framework=fastmcp'];
|
|
111
|
+
let exitCode;
|
|
112
|
+
process.exit = vi.fn((code) => {
|
|
113
|
+
exitCode = code;
|
|
114
|
+
throw new Error('process.exit called');
|
|
115
|
+
});
|
|
116
|
+
const consoleError = vi.spyOn(console, 'error').mockImplementation(() => { });
|
|
117
|
+
const { parseArguments } = await import('./cli.js');
|
|
118
|
+
expect(() => parseArguments()).toThrow('process.exit called');
|
|
119
|
+
expect(exitCode).toBe(1);
|
|
120
|
+
expect(consoleError).toHaveBeenCalledWith(expect.stringContaining('--oauth is only valid with --framework=sdk and --template=stateful'));
|
|
121
|
+
consoleError.mockRestore();
|
|
122
|
+
});
|
|
123
|
+
it('exits with error for invalid project name', async () => {
|
|
124
|
+
process.argv = ['node', 'create-mcp-server', '--name=invalid name!'];
|
|
125
|
+
let exitCode;
|
|
126
|
+
process.exit = vi.fn((code) => {
|
|
127
|
+
exitCode = code;
|
|
128
|
+
throw new Error('process.exit called');
|
|
129
|
+
});
|
|
130
|
+
const consoleError = vi.spyOn(console, 'error').mockImplementation(() => { });
|
|
131
|
+
const { parseArguments } = await import('./cli.js');
|
|
132
|
+
expect(() => parseArguments()).toThrow('process.exit called');
|
|
133
|
+
expect(exitCode).toBe(1);
|
|
134
|
+
consoleError.mockRestore();
|
|
135
|
+
});
|
|
136
|
+
it('treats --help flag as interactive mode (does not require --name)', async () => {
|
|
137
|
+
// When --help is the only flag, commander handles it and exits
|
|
138
|
+
// We just verify that --help alone doesn't trigger CLI mode validation
|
|
139
|
+
process.argv = ['node', 'create-mcp-server'];
|
|
140
|
+
const { parseArguments } = await import('./cli.js');
|
|
141
|
+
const result = parseArguments();
|
|
142
|
+
// No args = interactive mode
|
|
143
|
+
expect(result.mode).toBe('interactive');
|
|
144
|
+
});
|
|
145
|
+
});
|
package/dist/index.js
CHANGED
|
@@ -1,189 +1,30 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
|
-
import
|
|
3
|
-
import {
|
|
4
|
-
import {
|
|
5
|
-
import { execSync } from 'node:child_process';
|
|
6
|
-
import { getPackageJsonTemplate } from './templates/common/package.json.js';
|
|
7
|
-
import { getTsconfigTemplate } from './templates/common/tsconfig.json.js';
|
|
8
|
-
import { getGitignoreTemplate } from './templates/common/gitignore.js';
|
|
9
|
-
import { getEnvExampleTemplate } from './templates/common/env.example.js';
|
|
10
|
-
import { getServerTemplate as getSdkStatelessServerTemplate, getIndexTemplate as getSdkStatelessIndexTemplate, getReadmeTemplate as getSdkStatelessReadmeTemplate, } from './templates/sdk/stateless/index.js';
|
|
11
|
-
import { getServerTemplate as getSdkStatefulServerTemplate, getIndexTemplate as getSdkStatefulIndexTemplate, getReadmeTemplate as getSdkStatefulReadmeTemplate, getAuthTemplate as getSdkAuthTemplate, } from './templates/sdk/stateful/index.js';
|
|
12
|
-
import { getServerTemplate as getFastMCPServerTemplate, getIndexTemplate as getFastMCPIndexTemplate, getReadmeTemplate as getFastMCPReadmeTemplate, } from './templates/fastmcp/index.js';
|
|
13
|
-
import { getDockerfileTemplate, getDockerignoreTemplate } from './templates/deployment/index.js';
|
|
14
|
-
const sdkTemplateFunctions = {
|
|
15
|
-
stateless: {
|
|
16
|
-
getServerTemplate: getSdkStatelessServerTemplate,
|
|
17
|
-
getIndexTemplate: getSdkStatelessIndexTemplate,
|
|
18
|
-
getReadmeTemplate: getSdkStatelessReadmeTemplate,
|
|
19
|
-
},
|
|
20
|
-
stateful: {
|
|
21
|
-
getServerTemplate: getSdkStatefulServerTemplate,
|
|
22
|
-
getIndexTemplate: getSdkStatefulIndexTemplate,
|
|
23
|
-
getReadmeTemplate: getSdkStatefulReadmeTemplate,
|
|
24
|
-
getAuthTemplate: getSdkAuthTemplate,
|
|
25
|
-
},
|
|
26
|
-
};
|
|
27
|
-
const fastmcpTemplateFunctions = {
|
|
28
|
-
getServerTemplate: getFastMCPServerTemplate,
|
|
29
|
-
getIndexTemplate: getFastMCPIndexTemplate,
|
|
30
|
-
getReadmeTemplate: getFastMCPReadmeTemplate,
|
|
31
|
-
};
|
|
32
|
-
const packageManagerCommands = {
|
|
33
|
-
npm: { install: 'npm install', dev: 'npm run dev' },
|
|
34
|
-
pnpm: { install: 'pnpm install', dev: 'pnpm dev' },
|
|
35
|
-
yarn: { install: 'yarn', dev: 'yarn dev' },
|
|
36
|
-
};
|
|
2
|
+
import { parseArguments } from './cli.js';
|
|
3
|
+
import { runInteractiveMode } from './interactive.js';
|
|
4
|
+
import { generateProject } from './project-generator.js';
|
|
37
5
|
async function main() {
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
process.exit(0);
|
|
42
|
-
};
|
|
43
|
-
const projectNameResponse = await prompts({
|
|
44
|
-
type: 'text',
|
|
45
|
-
name: 'projectName',
|
|
46
|
-
message: 'Project name:',
|
|
47
|
-
initial: 'my-mcp-server',
|
|
48
|
-
validate: (value) => {
|
|
49
|
-
if (!value)
|
|
50
|
-
return 'Project name is required';
|
|
51
|
-
if (!/^[a-z0-9-_]+$/i.test(value)) {
|
|
52
|
-
return 'Project name can only contain letters, numbers, hyphens, and underscores';
|
|
53
|
-
}
|
|
54
|
-
return true;
|
|
55
|
-
},
|
|
56
|
-
}, { onCancel });
|
|
57
|
-
const { projectName } = projectNameResponse;
|
|
58
|
-
if (!projectName) {
|
|
59
|
-
console.log('\n❌ Project name is required\n');
|
|
60
|
-
process.exit(1);
|
|
6
|
+
const { mode, options } = parseArguments();
|
|
7
|
+
if (mode === 'interactive') {
|
|
8
|
+
await runInteractiveMode();
|
|
61
9
|
}
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
}, { onCancel });
|
|
73
|
-
const packageManager = packageManagerResponse.packageManager || 'npm';
|
|
74
|
-
// Framework selection
|
|
75
|
-
const frameworkResponse = await prompts({
|
|
76
|
-
type: 'select',
|
|
77
|
-
name: 'framework',
|
|
78
|
-
message: 'Framework:',
|
|
79
|
-
choices: [
|
|
80
|
-
{
|
|
81
|
-
title: 'Official MCP SDK',
|
|
82
|
-
value: 'sdk',
|
|
83
|
-
description: 'Full control with Express.js',
|
|
84
|
-
},
|
|
85
|
-
{
|
|
86
|
-
title: 'FastMCP',
|
|
87
|
-
value: 'fastmcp',
|
|
88
|
-
description: 'Simpler API, less boilerplate',
|
|
89
|
-
},
|
|
90
|
-
],
|
|
91
|
-
initial: 0,
|
|
92
|
-
}, { onCancel });
|
|
93
|
-
const framework = frameworkResponse.framework || 'sdk';
|
|
94
|
-
// Server mode selection
|
|
95
|
-
const templateTypeResponse = await prompts({
|
|
96
|
-
type: 'select',
|
|
97
|
-
name: 'templateType',
|
|
98
|
-
message: 'Server mode:',
|
|
99
|
-
choices: [
|
|
100
|
-
{ title: 'Stateless', value: 'stateless', description: 'Simple HTTP server' },
|
|
101
|
-
{
|
|
102
|
-
title: 'Stateful',
|
|
103
|
-
value: 'stateful',
|
|
104
|
-
description: 'Session-based server with SSE support',
|
|
105
|
-
},
|
|
106
|
-
],
|
|
107
|
-
initial: 0,
|
|
108
|
-
}, { onCancel });
|
|
109
|
-
const templateType = templateTypeResponse.templateType || 'stateless';
|
|
110
|
-
// OAuth prompt - only for SDK stateful template
|
|
111
|
-
let withOAuth = false;
|
|
112
|
-
if (framework === 'sdk' && templateType === 'stateful') {
|
|
113
|
-
const oauthResponse = await prompts({
|
|
114
|
-
type: 'confirm',
|
|
115
|
-
name: 'withOAuth',
|
|
116
|
-
message: 'Enable OAuth authentication?',
|
|
117
|
-
initial: false,
|
|
118
|
-
}, { onCancel });
|
|
119
|
-
withOAuth = oauthResponse.withOAuth ?? false;
|
|
10
|
+
else {
|
|
11
|
+
// CLI mode - options is guaranteed to be defined
|
|
12
|
+
await generateProject({
|
|
13
|
+
projectName: options.name,
|
|
14
|
+
packageManager: options.packageManager,
|
|
15
|
+
framework: options.framework,
|
|
16
|
+
templateType: options.template,
|
|
17
|
+
withOAuth: options.oauth,
|
|
18
|
+
withGitInit: options.git,
|
|
19
|
+
});
|
|
120
20
|
}
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
message: 'Initialize git repository?',
|
|
126
|
-
initial: true,
|
|
127
|
-
}, { onCancel });
|
|
128
|
-
const withGitInit = gitInitResponse.withGitInit ?? false;
|
|
129
|
-
const templateOptions = {
|
|
130
|
-
withOAuth,
|
|
131
|
-
packageManager,
|
|
132
|
-
framework,
|
|
133
|
-
stateless: templateType === 'stateless',
|
|
134
|
-
};
|
|
135
|
-
const projectPath = join(process.cwd(), projectName);
|
|
136
|
-
const srcPath = join(projectPath, 'src');
|
|
137
|
-
try {
|
|
138
|
-
// Create directories
|
|
139
|
-
await mkdir(srcPath, { recursive: true });
|
|
140
|
-
// Build list of files to write
|
|
141
|
-
const filesToWrite = [];
|
|
142
|
-
if (framework === 'fastmcp') {
|
|
143
|
-
// FastMCP templates
|
|
144
|
-
filesToWrite.push(writeFile(join(srcPath, 'server.ts'), fastmcpTemplateFunctions.getServerTemplate(projectName)), writeFile(join(srcPath, 'index.ts'), fastmcpTemplateFunctions.getIndexTemplate(templateOptions)), writeFile(join(projectPath, 'README.md'), fastmcpTemplateFunctions.getReadmeTemplate(projectName, templateOptions)));
|
|
145
|
-
}
|
|
146
|
-
else {
|
|
147
|
-
// SDK templates
|
|
148
|
-
const templates = sdkTemplateFunctions[templateType];
|
|
149
|
-
filesToWrite.push(writeFile(join(srcPath, 'server.ts'), templates.getServerTemplate(projectName)), writeFile(join(srcPath, 'index.ts'), templates.getIndexTemplate(templateOptions)), writeFile(join(projectPath, 'README.md'), templates.getReadmeTemplate(projectName, templateOptions)));
|
|
150
|
-
// Conditionally add auth.ts for OAuth-enabled stateful template
|
|
151
|
-
if (withOAuth && templates.getAuthTemplate) {
|
|
152
|
-
filesToWrite.push(writeFile(join(srcPath, 'auth.ts'), templates.getAuthTemplate()));
|
|
153
|
-
}
|
|
154
|
-
}
|
|
155
|
-
// Common files for all templates
|
|
156
|
-
filesToWrite.push(writeFile(join(projectPath, 'package.json'), getPackageJsonTemplate(projectName, templateOptions)), writeFile(join(projectPath, 'tsconfig.json'), getTsconfigTemplate()), writeFile(join(projectPath, '.gitignore'), getGitignoreTemplate()), writeFile(join(projectPath, '.env.example'), getEnvExampleTemplate(templateOptions)));
|
|
157
|
-
// Deployment files for all templates
|
|
158
|
-
filesToWrite.push(writeFile(join(projectPath, 'Dockerfile'), getDockerfileTemplate(templateOptions)), writeFile(join(projectPath, '.dockerignore'), getDockerignoreTemplate()));
|
|
159
|
-
// Write all template files
|
|
160
|
-
await Promise.all(filesToWrite);
|
|
161
|
-
// Initialize git repository if requested
|
|
162
|
-
if (withGitInit) {
|
|
163
|
-
try {
|
|
164
|
-
execSync('git init', { cwd: projectPath, stdio: 'ignore' });
|
|
165
|
-
}
|
|
166
|
-
catch {
|
|
167
|
-
console.log('\n⚠️ Could not initialize git repository (is git installed?)');
|
|
168
|
-
}
|
|
169
|
-
}
|
|
170
|
-
const commands = packageManagerCommands[packageManager];
|
|
171
|
-
const frameworkName = framework === 'fastmcp' ? 'FastMCP' : 'MCP SDK';
|
|
172
|
-
console.log(`\n✅ Created ${projectName} with ${frameworkName} at ${projectPath}`);
|
|
173
|
-
console.log(`\nNext steps:`);
|
|
174
|
-
console.log(` cd ${projectName}`);
|
|
175
|
-
console.log(` ${commands.install}`);
|
|
176
|
-
console.log(` ${commands.dev}`);
|
|
177
|
-
console.log(`\n`);
|
|
21
|
+
}
|
|
22
|
+
main().catch((error) => {
|
|
23
|
+
if (error instanceof Error) {
|
|
24
|
+
console.error(`\nError: ${error.message}\n`);
|
|
178
25
|
}
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
console.error(`\n❌ Error: ${error.message}\n`);
|
|
182
|
-
}
|
|
183
|
-
else {
|
|
184
|
-
console.error('\n❌ An unexpected error occurred\n');
|
|
185
|
-
}
|
|
186
|
-
process.exit(1);
|
|
26
|
+
else {
|
|
27
|
+
console.error('\nAn unexpected error occurred\n');
|
|
187
28
|
}
|
|
188
|
-
|
|
189
|
-
|
|
29
|
+
process.exit(1);
|
|
30
|
+
});
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export declare function runInteractiveMode(): Promise<void>;
|
|
@@ -0,0 +1,103 @@
|
|
|
1
|
+
import prompts from 'prompts';
|
|
2
|
+
import { generateProject } from './project-generator.js';
|
|
3
|
+
export async function runInteractiveMode() {
|
|
4
|
+
console.log('\nCreate MCP Server\n');
|
|
5
|
+
const onCancel = () => {
|
|
6
|
+
console.log('\nOperation cancelled\n');
|
|
7
|
+
process.exit(0);
|
|
8
|
+
};
|
|
9
|
+
const projectNameResponse = await prompts({
|
|
10
|
+
type: 'text',
|
|
11
|
+
name: 'projectName',
|
|
12
|
+
message: 'Project name:',
|
|
13
|
+
initial: 'my-mcp-server',
|
|
14
|
+
validate: (value) => {
|
|
15
|
+
if (!value)
|
|
16
|
+
return 'Project name is required';
|
|
17
|
+
if (!/^[a-z0-9-_]+$/i.test(value)) {
|
|
18
|
+
return 'Project name can only contain letters, numbers, hyphens, and underscores';
|
|
19
|
+
}
|
|
20
|
+
return true;
|
|
21
|
+
},
|
|
22
|
+
}, { onCancel });
|
|
23
|
+
const { projectName } = projectNameResponse;
|
|
24
|
+
if (!projectName) {
|
|
25
|
+
console.log('\nProject name is required\n');
|
|
26
|
+
process.exit(1);
|
|
27
|
+
}
|
|
28
|
+
const packageManagerResponse = await prompts({
|
|
29
|
+
type: 'select',
|
|
30
|
+
name: 'packageManager',
|
|
31
|
+
message: 'Package manager:',
|
|
32
|
+
choices: [
|
|
33
|
+
{ title: 'npm', value: 'npm' },
|
|
34
|
+
{ title: 'pnpm', value: 'pnpm' },
|
|
35
|
+
{ title: 'yarn', value: 'yarn' },
|
|
36
|
+
],
|
|
37
|
+
initial: 0,
|
|
38
|
+
}, { onCancel });
|
|
39
|
+
const packageManager = packageManagerResponse.packageManager || 'npm';
|
|
40
|
+
// Framework selection
|
|
41
|
+
const frameworkResponse = await prompts({
|
|
42
|
+
type: 'select',
|
|
43
|
+
name: 'framework',
|
|
44
|
+
message: 'Framework:',
|
|
45
|
+
choices: [
|
|
46
|
+
{
|
|
47
|
+
title: 'Official MCP SDK',
|
|
48
|
+
value: 'sdk',
|
|
49
|
+
description: 'Full control with Express.js',
|
|
50
|
+
},
|
|
51
|
+
{
|
|
52
|
+
title: 'FastMCP',
|
|
53
|
+
value: 'fastmcp',
|
|
54
|
+
description: 'Simpler API, less boilerplate',
|
|
55
|
+
},
|
|
56
|
+
],
|
|
57
|
+
initial: 0,
|
|
58
|
+
}, { onCancel });
|
|
59
|
+
const framework = frameworkResponse.framework || 'sdk';
|
|
60
|
+
// Server mode selection
|
|
61
|
+
const templateTypeResponse = await prompts({
|
|
62
|
+
type: 'select',
|
|
63
|
+
name: 'templateType',
|
|
64
|
+
message: 'Server mode:',
|
|
65
|
+
choices: [
|
|
66
|
+
{ title: 'Stateless', value: 'stateless', description: 'Simple HTTP server' },
|
|
67
|
+
{
|
|
68
|
+
title: 'Stateful',
|
|
69
|
+
value: 'stateful',
|
|
70
|
+
description: 'Session-based server with SSE support',
|
|
71
|
+
},
|
|
72
|
+
],
|
|
73
|
+
initial: 0,
|
|
74
|
+
}, { onCancel });
|
|
75
|
+
const templateType = templateTypeResponse.templateType || 'stateless';
|
|
76
|
+
// OAuth prompt - only for SDK stateful template
|
|
77
|
+
let withOAuth = false;
|
|
78
|
+
if (framework === 'sdk' && templateType === 'stateful') {
|
|
79
|
+
const oauthResponse = await prompts({
|
|
80
|
+
type: 'confirm',
|
|
81
|
+
name: 'withOAuth',
|
|
82
|
+
message: 'Enable OAuth authentication?',
|
|
83
|
+
initial: false,
|
|
84
|
+
}, { onCancel });
|
|
85
|
+
withOAuth = oauthResponse.withOAuth ?? false;
|
|
86
|
+
}
|
|
87
|
+
// Git init prompt
|
|
88
|
+
const gitInitResponse = await prompts({
|
|
89
|
+
type: 'confirm',
|
|
90
|
+
name: 'withGitInit',
|
|
91
|
+
message: 'Initialize git repository?',
|
|
92
|
+
initial: true,
|
|
93
|
+
}, { onCancel });
|
|
94
|
+
const withGitInit = gitInitResponse.withGitInit ?? false;
|
|
95
|
+
await generateProject({
|
|
96
|
+
projectName,
|
|
97
|
+
packageManager,
|
|
98
|
+
framework,
|
|
99
|
+
templateType,
|
|
100
|
+
withOAuth,
|
|
101
|
+
withGitInit,
|
|
102
|
+
});
|
|
103
|
+
}
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
import type { Framework, PackageManager } from './templates/common/types.js';
|
|
2
|
+
import type { TemplateType } from './cli.js';
|
|
3
|
+
export declare const packageManagerCommands: Record<PackageManager, {
|
|
4
|
+
install: string;
|
|
5
|
+
dev: string;
|
|
6
|
+
}>;
|
|
7
|
+
export interface ProjectConfig {
|
|
8
|
+
projectName: string;
|
|
9
|
+
packageManager: PackageManager;
|
|
10
|
+
framework: Framework;
|
|
11
|
+
templateType: TemplateType;
|
|
12
|
+
withOAuth: boolean;
|
|
13
|
+
withGitInit: boolean;
|
|
14
|
+
}
|
|
15
|
+
export declare function generateProject(config: ProjectConfig): Promise<void>;
|
|
@@ -0,0 +1,85 @@
|
|
|
1
|
+
import { mkdir, writeFile } from 'node:fs/promises';
|
|
2
|
+
import { join } from 'node:path';
|
|
3
|
+
import { execSync } from 'node:child_process';
|
|
4
|
+
import { getPackageJsonTemplate } from './templates/common/package.json.js';
|
|
5
|
+
import { getTsconfigTemplate } from './templates/common/tsconfig.json.js';
|
|
6
|
+
import { getGitignoreTemplate } from './templates/common/gitignore.js';
|
|
7
|
+
import { getEnvExampleTemplate } from './templates/common/env.example.js';
|
|
8
|
+
import { getServerTemplate as getSdkStatelessServerTemplate, getIndexTemplate as getSdkStatelessIndexTemplate, getReadmeTemplate as getSdkStatelessReadmeTemplate, } from './templates/sdk/stateless/index.js';
|
|
9
|
+
import { getServerTemplate as getSdkStatefulServerTemplate, getIndexTemplate as getSdkStatefulIndexTemplate, getReadmeTemplate as getSdkStatefulReadmeTemplate, getAuthTemplate as getSdkAuthTemplate, } from './templates/sdk/stateful/index.js';
|
|
10
|
+
import { getServerTemplate as getFastMCPServerTemplate, getIndexTemplate as getFastMCPIndexTemplate, getReadmeTemplate as getFastMCPReadmeTemplate, } from './templates/fastmcp/index.js';
|
|
11
|
+
import { getDockerfileTemplate, getDockerignoreTemplate } from './templates/deployment/index.js';
|
|
12
|
+
const sdkTemplateFunctions = {
|
|
13
|
+
stateless: {
|
|
14
|
+
getServerTemplate: getSdkStatelessServerTemplate,
|
|
15
|
+
getIndexTemplate: getSdkStatelessIndexTemplate,
|
|
16
|
+
getReadmeTemplate: getSdkStatelessReadmeTemplate,
|
|
17
|
+
},
|
|
18
|
+
stateful: {
|
|
19
|
+
getServerTemplate: getSdkStatefulServerTemplate,
|
|
20
|
+
getIndexTemplate: getSdkStatefulIndexTemplate,
|
|
21
|
+
getReadmeTemplate: getSdkStatefulReadmeTemplate,
|
|
22
|
+
getAuthTemplate: getSdkAuthTemplate,
|
|
23
|
+
},
|
|
24
|
+
};
|
|
25
|
+
const fastmcpTemplateFunctions = {
|
|
26
|
+
getServerTemplate: getFastMCPServerTemplate,
|
|
27
|
+
getIndexTemplate: getFastMCPIndexTemplate,
|
|
28
|
+
getReadmeTemplate: getFastMCPReadmeTemplate,
|
|
29
|
+
};
|
|
30
|
+
export const packageManagerCommands = {
|
|
31
|
+
npm: { install: 'npm install', dev: 'npm run dev' },
|
|
32
|
+
pnpm: { install: 'pnpm install', dev: 'pnpm dev' },
|
|
33
|
+
yarn: { install: 'yarn', dev: 'yarn dev' },
|
|
34
|
+
};
|
|
35
|
+
export async function generateProject(config) {
|
|
36
|
+
const { projectName, packageManager, framework, templateType, withOAuth, withGitInit } = config;
|
|
37
|
+
const templateOptions = {
|
|
38
|
+
withOAuth,
|
|
39
|
+
packageManager,
|
|
40
|
+
framework,
|
|
41
|
+
stateless: templateType === 'stateless',
|
|
42
|
+
};
|
|
43
|
+
const projectPath = join(process.cwd(), projectName);
|
|
44
|
+
const srcPath = join(projectPath, 'src');
|
|
45
|
+
// Create directories
|
|
46
|
+
await mkdir(srcPath, { recursive: true });
|
|
47
|
+
// Build list of files to write
|
|
48
|
+
const filesToWrite = [];
|
|
49
|
+
if (framework === 'fastmcp') {
|
|
50
|
+
// FastMCP templates
|
|
51
|
+
filesToWrite.push(writeFile(join(srcPath, 'server.ts'), fastmcpTemplateFunctions.getServerTemplate(projectName)), writeFile(join(srcPath, 'index.ts'), fastmcpTemplateFunctions.getIndexTemplate(templateOptions)), writeFile(join(projectPath, 'README.md'), fastmcpTemplateFunctions.getReadmeTemplate(projectName, templateOptions)));
|
|
52
|
+
}
|
|
53
|
+
else {
|
|
54
|
+
// SDK templates
|
|
55
|
+
const templates = sdkTemplateFunctions[templateType];
|
|
56
|
+
filesToWrite.push(writeFile(join(srcPath, 'server.ts'), templates.getServerTemplate(projectName)), writeFile(join(srcPath, 'index.ts'), templates.getIndexTemplate(templateOptions)), writeFile(join(projectPath, 'README.md'), templates.getReadmeTemplate(projectName, templateOptions)));
|
|
57
|
+
// Conditionally add auth.ts for OAuth-enabled stateful template
|
|
58
|
+
if (withOAuth && templates.getAuthTemplate) {
|
|
59
|
+
filesToWrite.push(writeFile(join(srcPath, 'auth.ts'), templates.getAuthTemplate()));
|
|
60
|
+
}
|
|
61
|
+
}
|
|
62
|
+
// Common files for all templates
|
|
63
|
+
filesToWrite.push(writeFile(join(projectPath, 'package.json'), getPackageJsonTemplate(projectName, templateOptions)), writeFile(join(projectPath, 'tsconfig.json'), getTsconfigTemplate()), writeFile(join(projectPath, '.gitignore'), getGitignoreTemplate()), writeFile(join(projectPath, '.env.example'), getEnvExampleTemplate(templateOptions)));
|
|
64
|
+
// Deployment files for all templates
|
|
65
|
+
filesToWrite.push(writeFile(join(projectPath, 'Dockerfile'), getDockerfileTemplate(templateOptions)), writeFile(join(projectPath, '.dockerignore'), getDockerignoreTemplate()));
|
|
66
|
+
// Write all template files
|
|
67
|
+
await Promise.all(filesToWrite);
|
|
68
|
+
// Initialize git repository if requested
|
|
69
|
+
if (withGitInit) {
|
|
70
|
+
try {
|
|
71
|
+
execSync('git init', { cwd: projectPath, stdio: 'ignore' });
|
|
72
|
+
}
|
|
73
|
+
catch {
|
|
74
|
+
console.log('\n Could not initialize git repository (is git installed?)');
|
|
75
|
+
}
|
|
76
|
+
}
|
|
77
|
+
const commands = packageManagerCommands[packageManager];
|
|
78
|
+
const frameworkName = framework === 'fastmcp' ? 'FastMCP' : 'MCP SDK';
|
|
79
|
+
console.log(`\nCreated ${projectName} with ${frameworkName} at ${projectPath}`);
|
|
80
|
+
console.log(`\nNext steps:`);
|
|
81
|
+
console.log(` cd ${projectName}`);
|
|
82
|
+
console.log(` ${commands.install}`);
|
|
83
|
+
console.log(` ${commands.dev}`);
|
|
84
|
+
console.log(`\n`);
|
|
85
|
+
}
|
|
@@ -2,9 +2,27 @@ export function getReadmeTemplate(projectName, options) {
|
|
|
2
2
|
const packageManager = options?.packageManager ?? 'npm';
|
|
3
3
|
const stateless = options?.stateless ?? false;
|
|
4
4
|
const commands = {
|
|
5
|
-
npm: {
|
|
6
|
-
|
|
7
|
-
|
|
5
|
+
npm: {
|
|
6
|
+
install: 'npm install',
|
|
7
|
+
dev: 'npm run dev',
|
|
8
|
+
build: 'npm run build',
|
|
9
|
+
start: 'npm start',
|
|
10
|
+
inspect: 'npm run inspect',
|
|
11
|
+
},
|
|
12
|
+
pnpm: {
|
|
13
|
+
install: 'pnpm install',
|
|
14
|
+
dev: 'pnpm dev',
|
|
15
|
+
build: 'pnpm build',
|
|
16
|
+
start: 'pnpm start',
|
|
17
|
+
inspect: 'pnpm inspect',
|
|
18
|
+
},
|
|
19
|
+
yarn: {
|
|
20
|
+
install: 'yarn',
|
|
21
|
+
dev: 'yarn dev',
|
|
22
|
+
build: 'yarn build',
|
|
23
|
+
start: 'yarn start',
|
|
24
|
+
inspect: 'yarn inspect',
|
|
25
|
+
},
|
|
8
26
|
};
|
|
9
27
|
const cmd = commands[packageManager];
|
|
10
28
|
const modeDescription = stateless
|
|
@@ -34,6 +52,22 @@ ${cmd.start}
|
|
|
34
52
|
|
|
35
53
|
The server will start on port 3000 by default. You can change this by setting the \`PORT\` environment variable.
|
|
36
54
|
|
|
55
|
+
## Testing with MCP Inspector
|
|
56
|
+
|
|
57
|
+
This project includes [MCP Inspector](https://github.com/modelcontextprotocol/inspector) as a dev dependency for testing and debugging.
|
|
58
|
+
|
|
59
|
+
First, start the server in one terminal:
|
|
60
|
+
|
|
61
|
+
\`\`\`bash
|
|
62
|
+
${cmd.dev}
|
|
63
|
+
\`\`\`
|
|
64
|
+
|
|
65
|
+
Then, in another terminal, launch the inspector:
|
|
66
|
+
|
|
67
|
+
\`\`\`bash
|
|
68
|
+
${cmd.inspect}
|
|
69
|
+
\`\`\`
|
|
70
|
+
|
|
37
71
|
## API Endpoints
|
|
38
72
|
|
|
39
73
|
- **POST /mcp** - Main MCP endpoint for JSON-RPC messages
|
|
@@ -2,9 +2,27 @@ export function getReadmeTemplate(projectName, options) {
|
|
|
2
2
|
const withOAuth = options?.withOAuth ?? false;
|
|
3
3
|
const packageManager = options?.packageManager ?? 'npm';
|
|
4
4
|
const commands = {
|
|
5
|
-
npm: {
|
|
6
|
-
|
|
7
|
-
|
|
5
|
+
npm: {
|
|
6
|
+
install: 'npm install',
|
|
7
|
+
dev: 'npm run dev',
|
|
8
|
+
build: 'npm run build',
|
|
9
|
+
start: 'npm start',
|
|
10
|
+
inspect: 'npm run inspect',
|
|
11
|
+
},
|
|
12
|
+
pnpm: {
|
|
13
|
+
install: 'pnpm install',
|
|
14
|
+
dev: 'pnpm dev',
|
|
15
|
+
build: 'pnpm build',
|
|
16
|
+
start: 'pnpm start',
|
|
17
|
+
inspect: 'pnpm inspect',
|
|
18
|
+
},
|
|
19
|
+
yarn: {
|
|
20
|
+
install: 'yarn',
|
|
21
|
+
dev: 'yarn dev',
|
|
22
|
+
build: 'yarn build',
|
|
23
|
+
start: 'yarn start',
|
|
24
|
+
inspect: 'yarn inspect',
|
|
25
|
+
},
|
|
8
26
|
}[packageManager];
|
|
9
27
|
const description = withOAuth
|
|
10
28
|
? 'A stateful streamable HTTP MCP (Model Context Protocol) server with session management and OAuth authentication.'
|
|
@@ -116,6 +134,22 @@ ${commands.start}
|
|
|
116
134
|
\`\`\`
|
|
117
135
|
|
|
118
136
|
The server will start on port 3000 by default. You can change this by setting the \`PORT\` environment variable.
|
|
137
|
+
|
|
138
|
+
## Testing with MCP Inspector
|
|
139
|
+
|
|
140
|
+
This project includes [MCP Inspector](https://github.com/modelcontextprotocol/inspector) as a dev dependency for testing and debugging.
|
|
141
|
+
|
|
142
|
+
First, start the server in one terminal:
|
|
143
|
+
|
|
144
|
+
\`\`\`bash
|
|
145
|
+
${commands.dev}
|
|
146
|
+
\`\`\`
|
|
147
|
+
|
|
148
|
+
Then, in another terminal, launch the inspector:
|
|
149
|
+
|
|
150
|
+
\`\`\`bash
|
|
151
|
+
${commands.inspect}
|
|
152
|
+
\`\`\`
|
|
119
153
|
${oauthSection}
|
|
120
154
|
## API Endpoints
|
|
121
155
|
|
|
@@ -1,9 +1,27 @@
|
|
|
1
1
|
export function getReadmeTemplate(projectName, options) {
|
|
2
2
|
const packageManager = options?.packageManager ?? 'npm';
|
|
3
3
|
const commands = {
|
|
4
|
-
npm: {
|
|
5
|
-
|
|
6
|
-
|
|
4
|
+
npm: {
|
|
5
|
+
install: 'npm install',
|
|
6
|
+
dev: 'npm run dev',
|
|
7
|
+
build: 'npm run build',
|
|
8
|
+
start: 'npm start',
|
|
9
|
+
inspect: 'npm run inspect',
|
|
10
|
+
},
|
|
11
|
+
pnpm: {
|
|
12
|
+
install: 'pnpm install',
|
|
13
|
+
dev: 'pnpm dev',
|
|
14
|
+
build: 'pnpm build',
|
|
15
|
+
start: 'pnpm start',
|
|
16
|
+
inspect: 'pnpm inspect',
|
|
17
|
+
},
|
|
18
|
+
yarn: {
|
|
19
|
+
install: 'yarn',
|
|
20
|
+
dev: 'yarn dev',
|
|
21
|
+
build: 'yarn build',
|
|
22
|
+
start: 'yarn start',
|
|
23
|
+
inspect: 'yarn inspect',
|
|
24
|
+
},
|
|
7
25
|
}[packageManager];
|
|
8
26
|
return `# ${projectName}
|
|
9
27
|
|
|
@@ -29,6 +47,22 @@ ${commands.start}
|
|
|
29
47
|
|
|
30
48
|
The server will start on port 3000 by default. You can change this by setting the \`PORT\` environment variable.
|
|
31
49
|
|
|
50
|
+
## Testing with MCP Inspector
|
|
51
|
+
|
|
52
|
+
This project includes [MCP Inspector](https://github.com/modelcontextprotocol/inspector) as a dev dependency for testing and debugging.
|
|
53
|
+
|
|
54
|
+
First, start the server in one terminal:
|
|
55
|
+
|
|
56
|
+
\`\`\`bash
|
|
57
|
+
${commands.dev}
|
|
58
|
+
\`\`\`
|
|
59
|
+
|
|
60
|
+
Then, in another terminal, launch the inspector:
|
|
61
|
+
|
|
62
|
+
\`\`\`bash
|
|
63
|
+
${commands.inspect}
|
|
64
|
+
\`\`\`
|
|
65
|
+
|
|
32
66
|
## API Endpoints
|
|
33
67
|
|
|
34
68
|
- **POST /mcp** - Main MCP endpoint for JSON-RPC messages
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@agentailor/create-mcp-server",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.5.1",
|
|
4
4
|
"description": "Create a new MCP (Model Context Protocol) server project",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"bin": {
|
|
@@ -37,6 +37,7 @@
|
|
|
37
37
|
"node": ">=20"
|
|
38
38
|
},
|
|
39
39
|
"dependencies": {
|
|
40
|
+
"commander": "^14.0.3",
|
|
40
41
|
"prompts": "^2.4.2"
|
|
41
42
|
},
|
|
42
43
|
"devDependencies": {
|