@nvhien20vn/git-mcp-server
Version:
88 lines (87 loc) ⢠5.09 kB
JavaScript
/**
* Handles the setup and connection for the Stdio MCP transport.
* Implements the MCP Specification 2025-03-26 for stdio transport.
* This transport communicates directly over standard input (stdin) and
* standard output (stdout), typically used when the MCP server is launched
* as a child process by a host application.
*
* Specification Reference:
* https://github.com/modelcontextprotocol/modelcontextprotocol/blob/main/docs/specification/2025-03-26/basic/transports.mdx#stdio
*
* --- Authentication Note ---
* As per the MCP Authorization Specification (2025-03-26, Section 1.2),
* STDIO transports SHOULD NOT implement HTTP-based authentication flows.
* Authorization is typically handled implicitly by the host application
* controlling the server process. This implementation follows that guideline.
*
* @see {@link https://github.com/modelcontextprotocol/modelcontextprotocol/blob/main/docs/specification/2025-03-26/basic/authorization.mdx | MCP Authorization Specification}
*/
import { StdioServerTransport } from '@modelcontextprotocol/sdk/server/stdio.js';
// Import core utilities: ErrorHandler for centralized error management and logger for logging.
import { ErrorHandler, logger } from '../../utils/index.js';
// --- Stdio Session State ---
// Since stdio typically involves a single, persistent connection managed by a parent,
// we manage a single working directory state for the entire process.
let currentWorkingDirectory = undefined; // Initialize as undefined
/**
* Gets the current working directory set for the stdio session.
* @returns {string | undefined} The current working directory path or undefined if not set.
*/
export function getStdioWorkingDirectory() {
return currentWorkingDirectory;
}
/**
* Sets the working directory for the stdio session.
* @param {string} dir - The new working directory path.
*/
export function setStdioWorkingDirectory(dir) {
currentWorkingDirectory = dir;
logger.info(`Stdio working directory set to: ${dir}`, { operation: 'setStdioWorkingDirectory' });
}
/**
* Connects a given McpServer instance to the Stdio transport. (Asynchronous)
* Initializes the SDK's StdioServerTransport, which handles reading newline-delimited
* JSON-RPC messages from process.stdin and writing corresponding messages to process.stdout,
* adhering to the MCP stdio transport specification.
*
* MCP Spec Points Covered by SDK's StdioServerTransport:
* - Reads JSON-RPC messages (requests, notifications, responses, batches) from stdin.
* - Writes JSON-RPC messages to stdout.
* - Handles newline delimiters and ensures no embedded newlines in output messages.
* - Ensures only valid MCP messages are written to stdout.
*
* Note: Logging via the `logger` utility MAY result in output to stderr, which is
* permitted by the spec for logging purposes.
*
* @param {McpServer} server - The McpServer instance containing the core logic (tools, resources).
* @param {Record<string, any>} context - Logging context for correlation.
* @returns {Promise<void>} A promise that resolves when the connection is successfully established.
* @throws {Error} Throws an error if the connection fails during setup (e.g., issues connecting server to transport).
*/
export async function connectStdioTransport(server, context) {
// Add a specific operation name to the context for better log filtering.
const operationContext = { ...context, operation: 'connectStdioTransport', transportType: 'Stdio' };
logger.debug('Attempting to connect stdio transport...', operationContext);
try {
logger.debug('Creating StdioServerTransport instance...', operationContext);
// Instantiate the transport provided by the SDK for standard I/O communication.
// This class encapsulates the logic for reading from stdin and writing to stdout
// according to the MCP stdio spec.
const transport = new StdioServerTransport();
logger.debug('Connecting McpServer instance to StdioServerTransport...', operationContext);
// Establish the link between the server's core logic and the transport layer.
// This internally starts the necessary listeners on process.stdin.
await server.connect(transport);
// Log successful connection. The server is now ready to process messages via stdio.
logger.info('MCP Server connected and listening via stdio transport.', operationContext);
// Use logger.notice for startup message to ensure MCP compliance and proper handling by clients.
logger.notice(`\nš MCP Server running in STDIO mode.\n (MCP Spec: 2025-03-26 Stdio Transport)\n`, operationContext);
}
catch (err) {
// Catch and handle any critical errors during the transport connection setup.
// Mark as critical because the server cannot function without a connected transport.
ErrorHandler.handleError(err, { ...operationContext, critical: true });
// Rethrow the error to signal the failure to the calling code (e.g., the main server startup).
throw err;
}
}