@spec2tools/stdio-mcp 0.1.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/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ The MIT License (MIT)
2
+
3
+ Copyright (c) 2026
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
package/README.md ADDED
@@ -0,0 +1,194 @@
1
+ # @spec2tools/stdio-mcp
2
+
3
+ MCP (Model Context Protocol) server that exposes OpenAPI endpoints as tools via stdio transport. This allows AI agents like Claude to call any API described by an OpenAPI specification.
4
+
5
+ ## Installation
6
+
7
+ ```bash
8
+ npm install @spec2tools/stdio-mcp
9
+ # or
10
+ pnpm add @spec2tools/stdio-mcp
11
+ ```
12
+
13
+ ## Quick Start
14
+
15
+ ### With Claude Desktop
16
+
17
+ Add to your `claude_desktop_config.json`:
18
+
19
+ ```json
20
+ {
21
+ "mcpServers": {
22
+ "my-api": {
23
+ "command": "npx",
24
+ "args": ["@spec2tools/stdio-mcp", "./path/to/openapi.yaml"]
25
+ }
26
+ }
27
+ }
28
+ ```
29
+
30
+ For authenticated APIs:
31
+
32
+ ```json
33
+ {
34
+ "mcpServers": {
35
+ "my-api": {
36
+ "command": "npx",
37
+ "args": ["@spec2tools/stdio-mcp", "./openapi.yaml", "--api-key", "your-api-key"]
38
+ }
39
+ }
40
+ }
41
+ ```
42
+
43
+ Or using environment variables:
44
+
45
+ ```json
46
+ {
47
+ "mcpServers": {
48
+ "my-api": {
49
+ "command": "npx",
50
+ "args": ["@spec2tools/stdio-mcp", "./openapi.yaml"],
51
+ "env": {
52
+ "API_KEY": "your-api-key"
53
+ }
54
+ }
55
+ }
56
+ }
57
+ ```
58
+
59
+ ### CLI Usage
60
+
61
+ ```bash
62
+ # Start server with local spec
63
+ spec2tools-mcp ./openapi.yaml
64
+
65
+ # Start server with remote spec
66
+ spec2tools-mcp https://api.example.com/openapi.json
67
+
68
+ # Start with authentication
69
+ spec2tools-mcp ./api.yaml --api-key your-api-key
70
+
71
+ # Or use environment variable
72
+ API_KEY=your-api-key spec2tools-mcp ./api.yaml
73
+ ```
74
+
75
+ ### Programmatic Usage
76
+
77
+ ```typescript
78
+ import { startMcpServer } from '@spec2tools/stdio-mcp';
79
+
80
+ await startMcpServer({
81
+ spec: './openapi.yaml',
82
+ name: 'my-api-server',
83
+ version: '1.0.0',
84
+ apiKey: 'your-api-key', // optional
85
+ });
86
+ ```
87
+
88
+ ## CLI Options
89
+
90
+ | Option | Description |
91
+ |--------|-------------|
92
+ | `<spec-path>` | Path or URL to OpenAPI specification (JSON or YAML) |
93
+ | `--name <name>` | Server name for MCP (default: `openapi-mcp-server`) |
94
+ | `--version <ver>` | Server version for MCP (default: `1.0.0`) |
95
+ | `--api-key <key>` | API key or bearer token for authentication |
96
+ | `-h, --help` | Show help message |
97
+
98
+ ## Environment Variables
99
+
100
+ | Variable | Description |
101
+ |----------|-------------|
102
+ | `API_KEY` | API key or bearer token for authentication |
103
+
104
+ ## How It Works
105
+
106
+ 1. **Loads OpenAPI Spec**: Reads your OpenAPI 3.x specification from a local file or URL (supports both JSON and YAML)
107
+
108
+ 2. **Parses Operations**: Converts each API operation into an MCP tool with:
109
+ - Tool name from `operationId` (or generated from method + path)
110
+ - Description from `summary` or `description`
111
+ - Input schema from parameters and request body
112
+
113
+ 3. **Starts MCP Server**: Creates a stdio-based MCP server that AI agents can connect to
114
+
115
+ 4. **Handles Tool Calls**: When an agent calls a tool, the server:
116
+ - Validates the parameters
117
+ - Builds the HTTP request (URL, headers, body)
118
+ - Adds authentication if configured
119
+ - Executes the request and returns the response
120
+
121
+ ## Supported OpenAPI Features
122
+
123
+ - **HTTP Methods**: GET, POST, PUT, PATCH, DELETE
124
+ - **Parameters**: Path and query parameters (string, number, boolean, arrays)
125
+ - **Request Bodies**: JSON with primitives and flat objects
126
+ - **Authentication**: Bearer tokens, API keys (header or query)
127
+
128
+ ### Limitations
129
+
130
+ - Nested objects beyond 1 level deep are not supported
131
+ - Arrays of objects are not supported
132
+ - Schema composition (`anyOf`, `oneOf`, `allOf`) is not supported
133
+ - File uploads are not supported
134
+ - `$ref` schema references are not supported
135
+
136
+ ## Example
137
+
138
+ Given this OpenAPI spec:
139
+
140
+ ```yaml
141
+ openapi: 3.0.0
142
+ info:
143
+ title: User API
144
+ version: 1.0.0
145
+ servers:
146
+ - url: https://api.example.com
147
+ paths:
148
+ /users:
149
+ get:
150
+ operationId: listUsers
151
+ summary: List all users
152
+ parameters:
153
+ - name: limit
154
+ in: query
155
+ schema:
156
+ type: integer
157
+ responses:
158
+ '200':
159
+ description: Success
160
+ /users/{id}:
161
+ get:
162
+ operationId: getUser
163
+ summary: Get user by ID
164
+ parameters:
165
+ - name: id
166
+ in: path
167
+ required: true
168
+ schema:
169
+ type: integer
170
+ responses:
171
+ '200':
172
+ description: Success
173
+ ```
174
+
175
+ The MCP server will expose two tools:
176
+
177
+ - `listUsers(limit?: number)` - List all users
178
+ - `getUser(id: number)` - Get user by ID
179
+
180
+ An AI agent can then call these tools naturally:
181
+
182
+ > "Get me the user with ID 42"
183
+
184
+ The agent will call `getUser({ id: 42 })` and receive the API response.
185
+
186
+ ## Related Packages
187
+
188
+ - [`@spec2tools/core`](../core) - Core utilities for OpenAPI parsing
189
+ - [`@spec2tools/cli`](../cli) - Interactive CLI with chat interface
190
+ - [`@spec2tools/sdk`](../sdk) - AI SDK tool generation
191
+
192
+ ## License
193
+
194
+ MIT
@@ -0,0 +1,3 @@
1
+ #!/usr/bin/env node
2
+ export { startMcpServer, McpServerOptions } from './server.js';
3
+ //# sourceMappingURL=index.d.ts.map
package/dist/index.js ADDED
@@ -0,0 +1,97 @@
1
+ #!/usr/bin/env node
2
+ import { startMcpServer } from './server.js';
3
+ // Re-export for programmatic use
4
+ export { startMcpServer } from './server.js';
5
+ /**
6
+ * CLI entry point
7
+ * Usage: spec2tools-mcp <spec-path> [--name <server-name>] [--version <server-version>]
8
+ *
9
+ * Authentication can be provided via:
10
+ * - Environment variable: API_KEY
11
+ * - Command line: --api-key <key>
12
+ */
13
+ async function main() {
14
+ const args = process.argv.slice(2);
15
+ if (args.length === 0 || args.includes('--help') || args.includes('-h')) {
16
+ printUsage();
17
+ process.exit(args.includes('--help') || args.includes('-h') ? 0 : 1);
18
+ }
19
+ const options = parseArgs(args);
20
+ if (!options.spec) {
21
+ console.error('Error: OpenAPI spec path is required');
22
+ printUsage();
23
+ process.exit(1);
24
+ }
25
+ try {
26
+ await startMcpServer(options);
27
+ }
28
+ catch (error) {
29
+ console.error('Error starting MCP server:', error instanceof Error ? error.message : error);
30
+ process.exit(1);
31
+ }
32
+ }
33
+ function parseArgs(args) {
34
+ const options = { spec: '' };
35
+ for (let i = 0; i < args.length; i++) {
36
+ const arg = args[i];
37
+ if (arg === '--name' && args[i + 1]) {
38
+ options.name = args[++i];
39
+ }
40
+ else if (arg === '--version' && args[i + 1]) {
41
+ options.version = args[++i];
42
+ }
43
+ else if (arg === '--api-key' && args[i + 1]) {
44
+ options.apiKey = args[++i];
45
+ }
46
+ else if (!arg.startsWith('-')) {
47
+ options.spec = arg;
48
+ }
49
+ }
50
+ return options;
51
+ }
52
+ function printUsage() {
53
+ console.log(`
54
+ @spec2tools/stdio-mcp - MCP server exposing OpenAPI endpoints as tools
55
+
56
+ Usage:
57
+ spec2tools-mcp <spec-path> [options]
58
+
59
+ Arguments:
60
+ spec-path Path or URL to OpenAPI specification (JSON or YAML)
61
+
62
+ Options:
63
+ --name <name> Server name for MCP (default: openapi-mcp-server)
64
+ --version <ver> Server version for MCP (default: 1.0.0)
65
+ --api-key <key> API key or token for authentication
66
+ -h, --help Show this help message
67
+
68
+ Environment Variables:
69
+ API_KEY API key or token for authentication
70
+
71
+ Examples:
72
+ # Start server with local spec
73
+ spec2tools-mcp ./openapi.yaml
74
+
75
+ # Start server with remote spec
76
+ spec2tools-mcp https://api.example.com/openapi.json
77
+
78
+ # Start with authentication
79
+ API_KEY=xxx spec2tools-mcp ./api.yaml
80
+
81
+ # Configure in Claude Desktop (claude_desktop_config.json):
82
+ {
83
+ "mcpServers": {
84
+ "my-api": {
85
+ "command": "npx",
86
+ "args": ["@spec2tools/stdio-mcp", "./openapi.yaml"]
87
+ }
88
+ }
89
+ }
90
+ `);
91
+ }
92
+ // Run CLI if this is the entry point
93
+ main().catch((error) => {
94
+ console.error('Fatal error:', error);
95
+ process.exit(1);
96
+ });
97
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1,25 @@
1
+ export interface McpServerOptions {
2
+ /** Path or URL to OpenAPI specification */
3
+ spec: string;
4
+ /** Server name for MCP */
5
+ name?: string;
6
+ /** Server version for MCP */
7
+ version?: string;
8
+ /** API key or token for authentication */
9
+ apiKey?: string;
10
+ }
11
+ /**
12
+ * Create and start an MCP server that exposes OpenAPI operations as tools.
13
+ *
14
+ * @example
15
+ * ```ts
16
+ * import { startMcpServer } from '@spec2tools/stdio-mcp';
17
+ *
18
+ * await startMcpServer({
19
+ * spec: './openapi.yaml',
20
+ * name: 'my-api-server',
21
+ * });
22
+ * ```
23
+ */
24
+ export declare function startMcpServer(options: McpServerOptions): Promise<void>;
25
+ //# sourceMappingURL=server.d.ts.map
package/dist/server.js ADDED
@@ -0,0 +1,93 @@
1
+ import { Server } from '@modelcontextprotocol/sdk/server/index.js';
2
+ import { StdioServerTransport } from '@modelcontextprotocol/sdk/server/stdio.js';
3
+ import { ListToolsRequestSchema, CallToolRequestSchema, } from '@modelcontextprotocol/sdk/types.js';
4
+ import { zodToJsonSchema } from 'zod-to-json-schema';
5
+ import { loadOpenAPISpec, extractBaseUrl, extractAuthConfig, parseOperations, AuthManager, createExecutableTools, } from '@spec2tools/core';
6
+ /**
7
+ * Create and start an MCP server that exposes OpenAPI operations as tools.
8
+ *
9
+ * @example
10
+ * ```ts
11
+ * import { startMcpServer } from '@spec2tools/stdio-mcp';
12
+ *
13
+ * await startMcpServer({
14
+ * spec: './openapi.yaml',
15
+ * name: 'my-api-server',
16
+ * });
17
+ * ```
18
+ */
19
+ export async function startMcpServer(options) {
20
+ const { spec: specPath, name = 'openapi-mcp-server', version = '0.1.0' } = options;
21
+ // Load and parse OpenAPI spec
22
+ const spec = await loadOpenAPISpec(specPath);
23
+ const baseUrl = extractBaseUrl(spec);
24
+ const authConfig = extractAuthConfig(spec);
25
+ // Set up auth manager
26
+ const authManager = new AuthManager(authConfig);
27
+ configureAuth(authManager, authConfig, options);
28
+ // Parse operations into tool definitions and create executable tools
29
+ const toolDefs = parseOperations(spec);
30
+ const tools = createExecutableTools(toolDefs, baseUrl, authManager);
31
+ // Create MCP server
32
+ const server = new Server({ name, version }, { capabilities: { tools: { listChanged: false } } });
33
+ // Register tool listing handler
34
+ server.setRequestHandler(ListToolsRequestSchema, async () => {
35
+ return {
36
+ tools: tools.map((tool) => ({
37
+ name: tool.name,
38
+ description: tool.description,
39
+ inputSchema: zodToJsonSchema(tool.parameters, { target: 'jsonSchema7' }),
40
+ })),
41
+ };
42
+ });
43
+ // Register tool execution handler
44
+ server.setRequestHandler(CallToolRequestSchema, async (request) => {
45
+ const { name: toolName, arguments: args } = request.params;
46
+ const tool = tools.find((t) => t.name === toolName);
47
+ if (!tool) {
48
+ return {
49
+ content: [{ type: 'text', text: `Error: Unknown tool "${toolName}"` }],
50
+ isError: true,
51
+ };
52
+ }
53
+ try {
54
+ const result = await tool.execute(args ?? {});
55
+ const resultText = typeof result === 'string' ? result : JSON.stringify(result, null, 2);
56
+ return {
57
+ content: [{ type: 'text', text: resultText }],
58
+ };
59
+ }
60
+ catch (error) {
61
+ let errorMessage;
62
+ if (error instanceof Error) {
63
+ errorMessage = error.message;
64
+ // Include stack trace for debugging if available
65
+ if (error.stack) {
66
+ errorMessage += `\n\nStack trace:\n${error.stack}`;
67
+ }
68
+ }
69
+ else {
70
+ errorMessage = String(error);
71
+ }
72
+ return {
73
+ content: [{ type: 'text', text: `Error: ${errorMessage}` }],
74
+ isError: true,
75
+ };
76
+ }
77
+ });
78
+ // Start stdio transport
79
+ const transport = new StdioServerTransport();
80
+ await server.connect(transport);
81
+ }
82
+ /**
83
+ * Configure authentication from options or environment variables
84
+ */
85
+ function configureAuth(authManager, authConfig, options) {
86
+ // Check for explicit option first, then fall back to environment variable
87
+ const apiKey = options.apiKey || process.env.API_KEY;
88
+ // Set the API key if provided, regardless of auth type
89
+ if (apiKey) {
90
+ authManager.setAccessToken(apiKey);
91
+ }
92
+ }
93
+ //# sourceMappingURL=server.js.map
package/package.json ADDED
@@ -0,0 +1,55 @@
1
+ {
2
+ "name": "@spec2tools/stdio-mcp",
3
+ "version": "0.1.0",
4
+ "description": "MCP server that exposes OpenAPI endpoints as tools via stdio transport",
5
+ "type": "module",
6
+ "main": "dist/index.js",
7
+ "types": "dist/index.d.ts",
8
+ "bin": {
9
+ "spec2tools-mcp": "./dist/index.js"
10
+ },
11
+ "exports": {
12
+ ".": {
13
+ "import": "./dist/index.js",
14
+ "types": "./dist/index.d.ts"
15
+ }
16
+ },
17
+ "files": [
18
+ "dist/**/*.js",
19
+ "dist/**/*.d.ts"
20
+ ],
21
+ "keywords": [
22
+ "openapi",
23
+ "mcp",
24
+ "model-context-protocol",
25
+ "ai",
26
+ "agent",
27
+ "tools",
28
+ "stdio"
29
+ ],
30
+ "license": "MIT",
31
+ "repository": {
32
+ "type": "git",
33
+ "url": "git+https://github.com/CahidArda/spec2tools.git",
34
+ "directory": "packages/stdio-mcp"
35
+ },
36
+ "dependencies": {
37
+ "@modelcontextprotocol/sdk": "^1.0.0",
38
+ "zod": "^3.24.0",
39
+ "zod-to-json-schema": "^3.24.0",
40
+ "@spec2tools/core": "0.1.1"
41
+ },
42
+ "devDependencies": {
43
+ "@types/node": "^22.0.0",
44
+ "typescript": "^5.6.0"
45
+ },
46
+ "engines": {
47
+ "node": ">=18.0.0"
48
+ },
49
+ "scripts": {
50
+ "build": "tsc",
51
+ "postbuild": "chmod +x dist/index.js",
52
+ "dev": "tsc --watch",
53
+ "typecheck": "tsc --noEmit"
54
+ }
55
+ }