#!/usr/bin/env node
import { Server } from "@modelcontextprotocol/sdk/server/index.js";
import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio.js";
import {
CallToolRequestSchema,
ListToolsRequestSchema,
Tool,
} from "@modelcontextprotocol/sdk/types.js";
import { z } from "zod";
import { Config, ConfigSchema } from "./types.js";
import { RestClient } from "./rest-client.js";
import { ConfigLoader } from "./config-loader.js";
class McpRestServer {
private server: Server;
private restClient?: RestClient;
private autoConfigured: boolean = false;
constructor() {
this.server = new Server({
name: "mcp-rest-server",
version: "1.0.0",
});
this.setupHandlers();
}
private async tryAutoConfiguration(): Promise<void> {
try {
const config = ConfigLoader.loadConfig();
this.restClient = new RestClient(config);
await this.restClient.initialize();
this.autoConfigured = true;
console.log(`✅ Auto-configured REST client for ${config.baseUrl}`);
} catch (error) {
// Auto-configuration failed, will require manual configuration
console.log(
"ℹ️ Auto-configuration not available. Use configure_rest_client tool to set up manually."
);
console.log(
"💡 For auto-configuration, provide configuration via CLI args, environment variables, or config file."
);
}
}
private setupHandlers(): void {
this.server.setRequestHandler(ListToolsRequestSchema, async () => {
return {
tools: [
{
name: "configure_rest_client",
description:
"Configure the REST client with base URL, authentication, and optional Swagger documentation URL",
inputSchema: {
type: "object",
properties: {
baseUrl: {
type: "string",
description: "Base URL for the REST API",
},
swaggerUrl: {
type: "string",
description:
"URL to Swagger/OpenAPI documentation (optional)",
},
auth: {
type: "object",
oneOf: [
{
type: "object",
properties: {
type: { type: "string", enum: ["token"] },
token: {
type: "string",
description: "Authentication token",
},
},
required: ["type", "token"],
},
{
type: "object",
properties: {
type: { type: "string", enum: ["login"] },
username: {
type: "string",
description: "Username for login",
},
password: {
type: "string",
description: "Password for login",
},
loginEndpoint: {
type: "string",
description: "Login endpoint path",
},
tokenField: {
type: "string",
description:
"Field name for access token in response (default: access_token)",
},
},
required: [
"type",
"username",
"password",
"loginEndpoint",
],
},
],
},
timeout: {
type: "number",
description:
"Request timeout in milliseconds (default: 30000)",
},
retries: {
type: "number",
description:
"Number of retries for failed requests (default: 3)",
},
},
required: ["baseUrl", "auth"],
},
},
{
name: "http_request",
description: "Make an HTTP request to the configured API",
inputSchema: {
type: "object",
properties: {
method: {
type: "string",
enum: ["GET", "POST", "PUT", "DELETE", "PATCH"],
description: "HTTP method",
},
path: {
type: "string",
description: "API endpoint path",
},
params: {
type: "object",
description:
"Query parameters (for GET) or request body parameters",
},
body: {
type: "object",
description: "Request body (for POST, PUT, PATCH)",
},
headers: {
type: "object",
description: "Additional headers",
},
},
required: ["method", "path"],
},
},
{
name: "get_swagger_documentation",
description:
"Get the complete Swagger/OpenAPI documentation for available endpoints",
inputSchema: {
type: "object",
properties: {},
},
},
{
name: "search_endpoints",
description: "Search for endpoints in the Swagger documentation",
inputSchema: {
type: "object",
properties: {
query: {
type: "string",
description: "Search query to find matching endpoints",
},
},
required: ["query"],
},
},
{
name: "get_endpoint_info",
description: "Get detailed information about a specific endpoint",
inputSchema: {
type: "object",
properties: {
path: {
type: "string",
description: "Endpoint path",
},
method: {
type: "string",
description: "HTTP method",
},
},
required: ["path", "method"],
},
},
{
name: "check_authentication",
description: "Check if the client is currently authenticated",
inputSchema: {
type: "object",
properties: {},
},
},
{
name: "logout",
description: "Logout and clear authentication state",
inputSchema: {
type: "object",
properties: {},
},
},
] as Tool[],
};
});
this.server.setRequestHandler(CallToolRequestSchema, async (request) => {
const { name, arguments: args } = request.params;
try {
switch (name) {
case "configure_rest_client":
return await this.configureRestClient(args);
case "http_request":
return await this.makeHttpRequest(args);
case "get_swagger_documentation":
return await this.getSwaggerDocumentation();
case "search_endpoints":
return await this.searchEndpoints(args);
case "get_endpoint_info":
return await this.getEndpointInfo(args);
case "check_authentication":
return await this.checkAuthentication();
case "logout":
return await this.logout();
default:
throw new Error(`Unknown tool: ${name}`);
}
} catch (error) {
return {
content: [
{
type: "text",
text: `Error: ${
error instanceof Error ? error.message : "Unknown error"
}`,
},
],
isError: true,
};
}
});
}
private async configureRestClient(args: any) {
try {
const config = ConfigSchema.parse(args);
this.restClient = new RestClient(config);
await this.restClient.initialize();
return {
content: [
{
type: "text",
text: `REST client configured successfully for ${config.baseUrl}${
config.swaggerUrl
? ` with Swagger documentation from ${config.swaggerUrl}`
: ""
}`,
},
],
};
} catch (error) {
throw new Error(
`Configuration failed: ${
error instanceof Error ? error.message : "Unknown error"
}`
);
}
}
private async makeHttpRequest(args: any) {
if (!this.restClient) {
throw new Error(
"REST client not configured. Use configure_rest_client tool or provide configuration via CLI/environment variables."
);
}
const { method, path, params, body, headers } = args;
const response = await this.restClient.makeRequest({
method,
path,
params,
body,
headers,
});
return {
content: [
{
type: "text",
text: JSON.stringify(
{
status: response.status,
statusText: response.statusText,
data: response.data,
headers: response.headers,
},
null,
2
),
},
],
};
}
private async getSwaggerDocumentation() {
if (!this.restClient) {
throw new Error(
"REST client not configured. Use configure_rest_client tool or provide configuration via CLI/environment variables."
);
}
const documentation = this.restClient.getSwaggerDocumentation();
return {
content: [
{
type: "text",
text: documentation,
},
],
};
}
private async searchEndpoints(args: any) {
if (!this.restClient) {
throw new Error(
"REST client not configured. Use configure_rest_client tool or provide configuration via CLI/environment variables."
);
}
const { query } = args;
const results = this.restClient.searchEndpoints(query);
return {
content: [
{
type: "text",
text: results,
},
],
};
}
private async getEndpointInfo(args: any) {
if (!this.restClient) {
throw new Error(
"REST client not configured. Use configure_rest_client tool or provide configuration via CLI/environment variables."
);
}
const { path, method } = args;
const info = this.restClient.getEndpointInfo(path, method);
return {
content: [
{
type: "text",
text: info,
},
],
};
}
private async checkAuthentication() {
if (!this.restClient) {
throw new Error(
"REST client not configured. Use configure_rest_client tool or provide configuration via CLI/environment variables."
);
}
const isAuthenticated = this.restClient.isAuthenticated();
return {
content: [
{
type: "text",
text: `Authentication status: ${
isAuthenticated ? "Authenticated" : "Not authenticated"
}`,
},
],
};
}
private async logout() {
if (!this.restClient) {
throw new Error(
"REST client not configured. Use configure_rest_client tool or provide configuration via CLI/environment variables."
);
}
await this.restClient.logout();
return {
content: [
{
type: "text",
text: "Successfully logged out",
},
],
};
}
async run(): Promise<void> {
await this.tryAutoConfiguration();
const transport = new StdioServerTransport();
await this.server.connect(transport);
}
}
async function main() {
// Check for help flag
if (process.argv.includes("--help") || process.argv.includes("-h")) {
ConfigLoader.printUsage();
process.exit(0);
}
const server = new McpRestServer();
await server.run();
}
main().catch((error) => {
console.error("Server error:", error);
process.exit(1);
});