#
tokens: 7035/50000 10/10 files
lines: on (toggle) GitHub
raw markdown copy reset
# Directory Structure

```
├── .gitignore
├── biome.json
├── bun.lock
├── LICENSE
├── package.json
├── README.md
├── src
│   ├── index.ts
│   ├── logger.ts
│   ├── types.ts
│   └── utils.ts
├── tsconfig.json
└── tsdown.config.ts
```

# Files

--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------

```
 1 | # Dependencies
 2 | node_modules/
 3 | 
 4 | # Build output
 5 | dist/
 6 | build/
 7 | 
 8 | # Environment variables
 9 | .env
10 | .env.local
11 | .env.*.local
12 | 
13 | # IDE
14 | .vscode/
15 | .idea/
16 | *.swp
17 | *.swo
18 | 
19 | # Logs
20 | *.log
21 | npm-debug.log*
22 | pnpm-debug.log*
23 | 
24 | # Testing
25 | coverage/
26 | 
27 | # Database files
28 | *.db
29 | *.db-journal
30 | 
31 | # OS
32 | .DS_Store
33 | Thumbs.db
34 | 
```

--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------

```markdown
  1 | # mcp-turso
  2 | 
  3 | A Model Context Protocol (MCP) server that provides access to the Turso-hosted LibSQL databases. Currently, the server provides the following functionality:
  4 | 
  5 | -  Retrieving a list of tables in a database
  6 | -  Retrieving a database's schema
  7 | -  Retrieving the schema of a table
  8 | -  Performing SELECT queries
  9 | 
 10 | ## Configuration
 11 | 
 12 | ### With Claude Desktop
 13 | 
 14 | Add this to your `claude_desktop_config.json`:
 15 | 
 16 | ```json
 17 | {
 18 |    "mcpServers": [
 19 |       "turso": {
 20 |          "command": "npx",
 21 |          "args": ["-y", "mcp-turso"],
 22 |          "env": {
 23 |             "TURSO_DATABASE_URL": "your_url",
 24 |             "TURSO_AUTH_TOKEN": "your_token"
 25 |          }
 26 |       }
 27 |    ]
 28 | }
 29 | ```
 30 | 
 31 | You will need an existing database to continue. If you don't have one, [create one](https://docs.turso.tech/quickstart). To get the database URL via the Turso CLI, run:
 32 | 
 33 | ```bash
 34 | turso db show --url <database-name>
 35 | ```
 36 | 
 37 | Then get the database authentication token:
 38 | 
 39 | ```bash
 40 | turso db tokens create <database-name>
 41 | ```
 42 | 
 43 | Add those values to your configuration as shown above.
 44 | 
 45 | ### With Cursor
 46 | 
 47 | To configure the Turso MCP server with Cursor, add the following to your Cursor settings:
 48 | 
 49 | 1. Open Cursor and go to Settings (⚙️) > Settings (JSON)
 50 | 2. Add the following configuration to your settings JSON:
 51 | 
 52 | ```json
 53 | "mcpServers": {
 54 |   "turso": {
 55 |     "command": "npx",
 56 |     "args": ["-y", "mcp-turso"],
 57 |     "env": {
 58 |       "TURSO_DATABASE_URL": "your_url",
 59 |       "TURSO_AUTH_TOKEN": "your_token"
 60 |     }
 61 |   }
 62 | }
 63 | ```
 64 | 
 65 | Replace `your_url` and `your_token` with your Turso database URL and authentication token as described in the previous section.
 66 | 
 67 | ### Logging
 68 | 
 69 | The server includes a custom logger for debugging outside of Claude Desktop. By default, this logger writes to `<parent-dir>/logs/mcp-turso.log`, where `<parent-dir>` is the parent directory of directory containing the `mcp-turso` script. In other words, if the path to `mcp-turso` is `~/foo/bin/mcp-turso`, the logs will be at `~/foo/logs/mcp-turso.log`. If running with NPX as above, the default logs will be:
 70 | 
 71 | ```
 72 | ~/.npm/_npx/<npx-dir-name>/node_modules/mcp-turso/logs/mcp-turso.log
 73 | ```
 74 | 
 75 | If you would like to specify a custom path, you can include a `--logs` flag with an **absolute posix path** in the server's configuration:
 76 | 
 77 | ```json
 78 | {
 79 |    "mcpServers": [
 80 |       "turso": {
 81 |          "command": "npx",
 82 |          "args": ["-y", "mcp-turso", "--logs", "/Users/<username>/path/to/dir/mcp-logs.log"],
 83 |          "env": {
 84 |             "TURSO_DATABASE_URL": "your_url",
 85 |             "TURSO_AUTH_TOKEN": "your_token"
 86 |          }
 87 |       }
 88 |    ]
 89 | }
 90 | ```
 91 | 
 92 | The path to the log file (default or custom) is always logged to `stderr` when the server is created. For Claude desktop, this will show up in your server logs in `~/Library/Logs/Claude`.
 93 | 
 94 | _Note_: Right now, I haven't implemented specifying a custom logging file for Windows, but this is coming.
 95 | 
 96 | ## Server Capabilities
 97 | 
 98 | The server provides the following tools:
 99 | 
100 | -  `list_tables`
101 |    -  Get a list of all the tables in the database
102 |    -  No input
103 |    -  Returns: an array of table names
104 | -  `get_db_schema`
105 |    -  Get the schemas of all tables in the database
106 |    -  No input
107 |    -  Returns: an array of SQL creation statements
108 | -  `describe_table`
109 |    -  View schema information for a specific table
110 |    -  Input:
111 |       -  `table_name` (string): Name of table to describe
112 |    -  Returns: Array of column definitions with names and types
113 | -  `query_database`
114 |    -  Execute a SELECT query to read data from the database
115 |    -  Input:
116 |       -  `sql` (string): The SELECT SQL query to execute
117 |    -  Returns: Query results as an object of type `{ columns: string[]; rows: Record<string, unknown>[]; rowCount: number; }`
118 | 
119 | ## Todo
120 | 
121 | -  [ ] Add the ability to specify a custom log file on windows
122 | -  [ ] Add more query tools
123 | 
124 | ## License
125 | 
126 | MIT License - see the [LICENSE](LICENSE) file for details.
127 | 
```

--------------------------------------------------------------------------------
/tsdown.config.ts:
--------------------------------------------------------------------------------

```typescript
1 | import { defineConfig } from "tsdown";
2 | 
3 | export default defineConfig({
4 | 	entry: ["./src/index.ts"],
5 | 	target: "es2022",
6 | 	clean: true,
7 | 	dts: true,
8 | });
9 | 
```

--------------------------------------------------------------------------------
/tsconfig.json:
--------------------------------------------------------------------------------

```json
 1 | {
 2 |    "extends": "@total-typescript/tsconfig/tsc/no-dom/library",
 3 |    "compilerOptions": {
 4 |       "forceConsistentCasingInFileNames": true,
 5 |       "rootDir": "src",
 6 |       "outDir": "dist",
 7 |       "sourceMap": false,
 8 |       "declaration": false,
 9 |       "moduleResolution": "bundler",
10 |       "module": "ESNext",
11 |       "resolveJsonModule": true
12 |    },
13 |    "exclude": ["node_modules", "dist"],
14 |    "include": ["src/**/*"]
15 | }
16 | 
```

--------------------------------------------------------------------------------
/biome.json:
--------------------------------------------------------------------------------

```json
 1 | {
 2 | 	"$schema": "https://biomejs.dev/schemas/1.9.4/schema.json",
 3 | 	"vcs": {
 4 | 		"enabled": false,
 5 | 		"clientKind": "git",
 6 | 		"useIgnoreFile": false
 7 | 	},
 8 | 	"files": {
 9 | 		"ignoreUnknown": false,
10 | 		"ignore": []
11 | 	},
12 | 	"formatter": {
13 | 		"enabled": true,
14 | 		"indentStyle": "tab"
15 | 	},
16 | 	"organizeImports": {
17 | 		"enabled": true
18 | 	},
19 | 	"linter": {
20 | 		"enabled": true,
21 | 		"rules": {
22 | 			"recommended": true
23 | 		}
24 | 	},
25 | 	"javascript": {
26 | 		"formatter": {
27 | 			"quoteStyle": "double"
28 | 		}
29 | 	}
30 | }
31 | 
```

--------------------------------------------------------------------------------
/src/types.ts:
--------------------------------------------------------------------------------

```typescript
 1 | import { z } from "zod";
 2 | 
 3 | export const TableColumnSchema = z.object({
 4 | 	name: z.string(),
 5 | 	type: z.string(),
 6 | 	notnull: z.number(),
 7 | 	dflt_value: z.union([z.string(), z.null()]),
 8 | 	pk: z.number(),
 9 | });
10 | 
11 | export type TableColumn = z.infer<typeof TableColumnSchema>;
12 | 
13 | export const envSchema = z.object({
14 | 	TURSO_DATABASE_URL: z.string().min(1, "Database URL is required"),
15 | 	TURSO_AUTH_TOKEN: z.string().min(1, "Auth token is required"),
16 | });
17 | 
18 | export type Config = z.infer<typeof envSchema>;
19 | 
20 | export type TextContent = {
21 | 	type: "text";
22 | 	text: string;
23 | };
24 | 
25 | export type ImageContent = {
26 | 	type: "image";
27 | 	data: string;
28 | 	mimeType: string;
29 | };
30 | 
31 | export type Content = TextContent | ImageContent;
32 | 
33 | export type ContentResult = {
34 | 	content: Content[];
35 | 	isError?: boolean;
36 | };
37 | 
```

--------------------------------------------------------------------------------
/package.json:
--------------------------------------------------------------------------------

```json
 1 | {
 2 | 	"name": "mcp-turso",
 3 | 	"version": "0.2.1",
 4 | 	"description": "MCP server for interacting with Turso-hosted LibSQL databases",
 5 | 	"license": "MIT",
 6 | 	"author": "Nico Baier",
 7 | 	"type": "module",
 8 | 	"bin": {
 9 | 		"mcp-turso": "dist/index.js"
10 | 	},
11 | 	"files": [
12 | 		"dist",
13 | 		"README.md",
14 | 		"LICENSE"
15 | 	],
16 | 	"repository": {
17 | 		"type": "git",
18 | 		"url": "git+https://github.com/nbbaier/mcp-turso.git"
19 | 	},
20 | 	"homepage": "https://github.com/nbbaier/mcp-turso#readme",
21 | 	"bugs": "https://github.com/nbbaier/mcp-turso/issues",
22 | 	"scripts": {
23 | 		"build": "tsdown && chmod +x dist/index.js"
24 | 	},
25 | 	"keywords": [
26 | 		"mcp",
27 | 		"libsql",
28 | 		"sqlite",
29 | 		"turso",
30 | 		"database",
31 | 		"model-context-protocol",
32 | 		"mcp-server",
33 | 		"ai",
34 | 		"sql"
35 | 	],
36 | 	"dependencies": {
37 | 		"@libsql/client": "^0.15.15",
38 | 		"@modelcontextprotocol/sdk": "^1.17.5",
39 | 		"fastmcp": "^3.16.0",
40 | 		"zod": "^4.1.5"
41 | 	},
42 | 	"devDependencies": {
43 | 		"@total-typescript/tsconfig": "^1.0.4",
44 | 		"@types/bun": "^1.2.21",
45 | 		"tsdown": "^0.15.0",
46 | 		"typescript": "^5.9.2"
47 | 	}
48 | }
```

--------------------------------------------------------------------------------
/src/logger.ts:
--------------------------------------------------------------------------------

```typescript
 1 | import { appendFileSync, existsSync, mkdirSync } from "node:fs";
 2 | import { dirname, join } from "node:path";
 3 | import { fileURLToPath } from "node:url";
 4 | import { name } from "../package.json" with { type: "json" };
 5 | 
 6 | const __filename = fileURLToPath(import.meta.url);
 7 | const __dirname = dirname(__filename);
 8 | const parentDir = join(__dirname, "..");
 9 | const logsDir = join(parentDir, "logs");
10 | 
11 | export const DEFAULT_LOG_FILE = join(logsDir, `${name}.log`);
12 | 
13 | /**
14 |  * Formats a log message with timestamp, level, and optional data.
15 |  *
16 |  * @param level - The log level (INFO, ERROR, DEBUG, etc)
17 |  * @param message - The log message text
18 |  * @param data - Optional data to include in the log entry
19 |  * @returns A formatted log string
20 |  */
21 | function formatLogMessage(
22 | 	level: string,
23 | 	message: string,
24 | 	data?: unknown,
25 | ): string {
26 | 	const timestamp = new Date().toISOString();
27 | 	const dataStr = data ? `\n${JSON.stringify(data, null, 2)}` : "";
28 | 	return `[${timestamp}] [${level}] ${message}${dataStr}\n`;
29 | }
30 | 
31 | /**
32 |  * Creates a logger instance that writes to the specified log file.
33 |  *
34 |  * @param logFile - Path to the log file (defaults to DEFAULT_LOG_FILE)
35 |  * @returns A logger object with info, error, and debug methods
36 |  */
37 | /**
38 |  * Creates a logger instance that writes log messages to a file.
39 |  *
40 |  * @param logFile - The path to the log file. Defaults to DEFAULT_LOG_FILE.
41 |  * @returns A `logger` object with methods for logging at different levels.
42 |  * @returns {Object} `logger` - The logger object.
43 |  * @returns {string} `logger.logFile` - The path to the log file.
44 |  * @returns {function} `logger.log` - Logs a message with a custom level.
45 |  * @returns {function} `logger.info` - Logs an info level message.
46 |  * @returns {function} `logger.error` - Logs an error level message.
47 |  * @returns {function} `logger.debug` - Logs a debug level message.
48 |  */
49 | export function createLogger(logFile: string = DEFAULT_LOG_FILE) {
50 | 	const logDir = dirname(logFile);
51 | 	if (!existsSync(logDir)) mkdirSync(logDir, { recursive: true });
52 | 	if (!existsSync(logFile)) appendFileSync(logFile, "");
53 | 
54 | 	return {
55 | 		logFile,
56 | 		log(level: string, message: string, data?: unknown): void {
57 | 			const logMessage = formatLogMessage(level, message, data);
58 | 			appendFileSync(logFile, logMessage);
59 | 		},
60 | 		info(message: string, data?: unknown): void {
61 | 			const logMessage = formatLogMessage("INFO", message, data);
62 | 			appendFileSync(logFile, logMessage);
63 | 		},
64 | 		error(message: string, error?: unknown): void {
65 | 			const logMessage = formatLogMessage("ERROR", message, error);
66 | 			appendFileSync(logFile, logMessage);
67 | 		},
68 | 		debug(message: string, data?: unknown): void {
69 | 			const logMessage = formatLogMessage("DEBUG", message, data);
70 | 			appendFileSync(logFile, logMessage);
71 | 		},
72 | 	};
73 | }
74 | 
75 | export default createLogger;
76 | 
```

--------------------------------------------------------------------------------
/src/index.ts:
--------------------------------------------------------------------------------

```typescript
  1 | import { FastMCP } from "fastmcp";
  2 | import { z } from "zod";
  3 | import createLogger from "./logger.js";
  4 | import {
  5 | 	getLogFile,
  6 | 	listTables,
  7 | 	content,
  8 | 	dbSchema,
  9 | 	describeTable,
 10 | 	query,
 11 | 	getVersion,
 12 | } from "./utils.js";
 13 | import { createClient, type Client } from "@libsql/client";
 14 | import { version } from "../package.json" with { type: "json" };
 15 | 
 16 | const server = new FastMCP({
 17 | 	name: "Turso MCP Server",
 18 | 	version: getVersion(version),
 19 | });
 20 | 
 21 | const dbUrl = process.env.TURSO_DATABASE_URL;
 22 | const authToken = process.env.TURSO_AUTH_TOKEN;
 23 | const logFile = getLogFile();
 24 | 
 25 | const logger = createLogger(logFile);
 26 | 
 27 | if (!dbUrl) {
 28 | 	logger.error("TURSO_DATABASE_URL environment variable is required");
 29 | 	process.exit(1);
 30 | }
 31 | 
 32 | if (!authToken) {
 33 | 	logger.error("TURSO_AUTH_TOKEN environment variable is required");
 34 | 	process.exit(1);
 35 | }
 36 | 
 37 | let db: Client;
 38 | 
 39 | try {
 40 | 	db = createClient({ url: dbUrl, authToken });
 41 | 	logger.info("Successfully connected to Turso database");
 42 | } catch (error) {
 43 | 	logger.error("Failed to connect to Turso database", error);
 44 | 	process.exit(1);
 45 | }
 46 | 
 47 | server.addTool({
 48 | 	name: "list_tables",
 49 | 	description: "List all tables in the database",
 50 | 	parameters: z.object({}),
 51 | 	execute: async () => {
 52 | 		try {
 53 | 			logger.info("Executing list_tables");
 54 | 			const tables = await listTables(db);
 55 | 			return content(JSON.stringify({ tables }, null, 2));
 56 | 		} catch (error) {
 57 | 			logger.error("Failed to list tables", error);
 58 | 			return content(
 59 | 				`Error listing tables: ${error instanceof Error ? error.message : String(error)}`,
 60 | 				true,
 61 | 			);
 62 | 		}
 63 | 	},
 64 | });
 65 | 
 66 | server.addTool({
 67 | 	name: "get_db_schema",
 68 | 	description: "Get the schema for all tables in the database",
 69 | 	parameters: z.object({}),
 70 | 	execute: async () => {
 71 | 		try {
 72 | 			const schema = await dbSchema(db);
 73 | 			return content(JSON.stringify({ schema }, null, 2));
 74 | 		} catch (error) {
 75 | 			return content(
 76 | 				`Error getting schema: ${error instanceof Error ? error.message : String(error)}`,
 77 | 				true,
 78 | 			);
 79 | 		}
 80 | 	},
 81 | });
 82 | 
 83 | server.addTool({
 84 | 	name: "describe_table",
 85 | 	description: "View schema information for a specific table",
 86 | 	parameters: z.object({
 87 | 		table_name: z
 88 | 			.string()
 89 | 			.describe("Name of the table to describe")
 90 | 			.min(1, "Table name is required"),
 91 | 	}),
 92 | 	execute: async ({ table_name }) => {
 93 | 		try {
 94 | 			logger.info(`Executing describe_table for table: ${table_name}`);
 95 | 			const schema = await describeTable(table_name, db);
 96 | 			return content(JSON.stringify({ schema }, null, 2));
 97 | 		} catch (error) {
 98 | 			logger.error(`Failed to describe table ${table_name}`, error);
 99 | 			return content(
100 | 				`Error describing table: ${error instanceof Error ? error.message : String(error)}`,
101 | 				true,
102 | 			);
103 | 		}
104 | 	},
105 | });
106 | 
107 | server.addTool({
108 | 	name: "query_database",
109 | 	description: "Execute a SELECT query to read data from the database",
110 | 	parameters: z.object({
111 | 		sql: z
112 | 			.string()
113 | 			.describe("SQL query to execute")
114 | 			.min(1, "SQL query is required"),
115 | 	}),
116 | 	execute: async ({ sql }) => {
117 | 		try {
118 | 			logger.info(`Executing query: ${sql}`);
119 | 			const result = await query(sql, db);
120 | 			return content(JSON.stringify(result, null, 2));
121 | 		} catch (error) {
122 | 			logger.error("Failed to execute query", error);
123 | 			return content(
124 | 				`Error executing query: ${error instanceof Error ? error.message : String(error)}`,
125 | 				true,
126 | 			);
127 | 		}
128 | 	},
129 | });
130 | 
131 | process.on("uncaughtException", (error) => {
132 | 	logger.error("Uncaught exception", error);
133 | });
134 | 
135 | process.on("unhandledRejection", (reason) => {
136 | 	logger.error("Unhandled rejection", reason);
137 | });
138 | 
139 | console.error(`[INFO] Additional logs available at: ${logger.logFile}`);
140 | 
141 | server.start({
142 | 	transportType: "stdio",
143 | });
144 | 
145 | process.on("exit", (code) => {
146 | 	logger.info("Turso MCP server closed", code);
147 | });
148 | 
```

--------------------------------------------------------------------------------
/src/utils.ts:
--------------------------------------------------------------------------------

```typescript
  1 | import type { Client } from "@libsql/client";
  2 | import { parseArgs } from "node:util";
  3 | import { z } from "zod";
  4 | import { DEFAULT_LOG_FILE } from "./logger.js";
  5 | import {
  6 | 	type Config,
  7 | 	type TableColumn,
  8 | 	type TextContent,
  9 | 	envSchema,
 10 | } from "./types.js";
 11 | 
 12 | /**
 13 |  * Retrieves a list of all tables in the Turso database.
 14 |  *
 15 |  * @param client - The Turso database client instance
 16 |  * @returns A promise that resolves to an array of table names
 17 |  */
 18 | export async function listTables(client: Client): Promise<string[]> {
 19 | 	const result = await client.execute({
 20 | 		sql: "SELECT name FROM sqlite_master WHERE type='table' AND name NOT LIKE 'sqlite_%'",
 21 | 		args: [],
 22 | 	});
 23 | 
 24 | 	return result.rows.map((row) => row.name as string);
 25 | }
 26 | 
 27 | /**
 28 |  * Retrieves the SQL schema definitions for all tables in the database.
 29 |  *
 30 |  * @param client - The Turso database client instance
 31 |  * @returns A promise that resolves to an array of SQL schema statements
 32 |  */
 33 | export async function dbSchema(client: Client): Promise<string[]> {
 34 | 	const result = await client.execute({
 35 | 		sql: "SELECT sql FROM sqlite_master WHERE type='table' AND name NOT LIKE 'sqlite_%'",
 36 | 		args: [],
 37 | 	});
 38 | 
 39 | 	return result.rows.map((row) => row.sql as string);
 40 | }
 41 | 
 42 | /**
 43 |  * Retrieves detailed schema information for a specific table.
 44 |  *
 45 |  * @param tableName - The name of the table to describe
 46 |  * @param client - The Turso database client instance
 47 |  * @returns A promise that resolves to an array of column definitions
 48 |  * @throws Error if the table name is invalid or the table doesn't exist
 49 |  */
 50 | export async function describeTable(
 51 | 	tableName: string,
 52 | 	client: Client,
 53 | ): Promise<TableColumn[]> {
 54 | 	if (!/^[a-zA-Z0-9_]+$/.test(tableName)) {
 55 | 		throw new Error(
 56 | 			"Invalid table name. Only alphanumeric characters and underscores are allowed.",
 57 | 		);
 58 | 	}
 59 | 
 60 | 	const result = await client.execute({
 61 | 		sql: `PRAGMA table_info(${tableName})`,
 62 | 		args: [],
 63 | 	});
 64 | 
 65 | 	if (result.rows.length === 0) {
 66 | 		throw new Error(`Table '${tableName}' not found`);
 67 | 	}
 68 | 
 69 | 	return result.rows.map((row) => ({
 70 | 		name: row.name as string,
 71 | 		type: row.type as string,
 72 | 		notnull: row.notnull as number,
 73 | 		dflt_value: row.dflt_value as string | null,
 74 | 		pk: row.pk as number,
 75 | 	}));
 76 | }
 77 | 
 78 | /**
 79 |  * Executes a SELECT SQL query against the database.
 80 |  *
 81 |  * @param sql - The SQL query to execute (must be a SELECT query)
 82 |  * @param client - The Turso database client instance
 83 |  * @returns A promise that resolves to an object containing columns, rows, and row count
 84 |  * @throws Error if the query is not a SELECT query
 85 |  */
 86 | export async function query<T = Record<string, unknown>>(
 87 | 	sql: string,
 88 | 	client: Client,
 89 | ): Promise<{
 90 | 	columns: string[];
 91 | 	rows: T[];
 92 | 	rowCount: number;
 93 | }> {
 94 | 	const trimmedQuery = sql.trim().toUpperCase();
 95 | 	if (!trimmedQuery.startsWith("SELECT")) {
 96 | 		throw new Error("Only SELECT queries are allowed for safety reasons");
 97 | 	}
 98 | 
 99 | 	const result = await client.execute({
100 | 		sql,
101 | 		args: [],
102 | 	});
103 | 
104 | 	return {
105 | 		columns: result.columns,
106 | 		rows: result.rows as T[],
107 | 		rowCount: result.rows.length,
108 | 	};
109 | }
110 | 
111 | /**
112 |  * Loads and validates environment configuration for the Turso database.
113 |  *
114 |  * @returns A validated configuration object
115 |  * @throws Error if the configuration is invalid
116 |  */
117 | export function loadConfig(): Config {
118 | 	const config = envSchema.safeParse(process.env);
119 | 
120 | 	if (!config.success) {
121 | 		throw new Error(`Configuration error: ${config.error.message}`);
122 | 	}
123 | 
124 | 	return config.data;
125 | }
126 | 
127 | /**
128 |  * Creates a formatted content response object for MCP tools.
129 |  *
130 |  * @param text - The text content to include in the response
131 |  * @param error - Whether this content represents an error (default: false)
132 |  * @returns A formatted content result object
133 |  */
134 | export function content(
135 | 	text: string,
136 | 	error = false,
137 | ): { content: TextContent[]; isError: boolean } {
138 | 	return {
139 | 		content: [{ type: "text", text }],
140 | 		isError: error,
141 | 	};
142 | }
143 | 
144 | /**
145 |  * Determines the log file path based on command line arguments or defaults.
146 |  *
147 |  * @returns The path to the log file
148 |  */
149 | export function getLogFile(): string {
150 | 	const { values } = parseArgs({
151 | 		args: process.argv,
152 | 		options: {
153 | 			logs: {
154 | 				type: "string",
155 | 			},
156 | 		},
157 | 		strict: true,
158 | 		allowPositionals: true,
159 | 	});
160 | 
161 | 	const parsedLogs = z
162 | 		.string()
163 | 		.refine((targetPath) => {
164 | 			const posixPath = targetPath.split("\\").join("/");
165 | 			return targetPath === posixPath && posixPath.includes("/");
166 | 		})
167 | 		.safeParse(values.logs);
168 | 
169 | 	return values.logs && parsedLogs.success ? parsedLogs.data : DEFAULT_LOG_FILE;
170 | }
171 | 
172 | /**
173 |  * Retrieves the version string from a package.json file.
174 |  *
175 |  * @param pkg - The package.json file content
176 |  * @returns The version string
177 |  */
178 | export function getVersion(version: string): `${number}.${number}.${number}` {
179 | 	return version.match(/^\d+\.\d+\.\d+$/)
180 | 		? (version as `${number}.${number}.${number}`)
181 | 		: "0.0.0";
182 | }
183 | 
```