index.tsā¢4.63 kB
import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio.js";
import { z } from "zod";
import { searchFiles } from "./lib/search.js";
import { readConfigFile, writeConfigFile } from "./lib/files.js";
const mcp = new McpServer({ name: "Config-MCP-Server", version: "0.1.0" });
// searchDocs
mcp.tool(
"searchDocs",
"Search developer documentation files (Markdown, MDX, text) in the workspace",
{
query: z.string().describe("Search term or phrase to find in documentation"),
include: z
.array(z.string())
.optional()
.describe("Custom glob patterns to include (default: markdown and docs files)"),
},
async ({ query, include }: { query: string; include?: string[] }) => {
try {
const patterns = include ?? ["**/*.md", "**/*.mdx", "**/*.txt", "docs/**/*", "**/README.*"];
const results = await searchFiles(query, patterns, { maxResults: 50 });
return { content: results };
} catch (error) {
return { content: [{ type: "text", text: `Error searching docs: ${error}` }], isError: true };
}
}
);
// searchSettings
mcp.tool(
"searchSettings",
"Search configuration and settings files (JSON/JSONC) for keys or values",
{
query: z.string().describe("Search term to find in settings files"),
include: z.array(z.string()).optional().describe("Custom glob patterns for settings files"),
},
async ({ query, include }: { query: string; include?: string[] }) => {
try {
const patterns = include ?? [
"**/.vscode/settings.json",
"**/settings.json",
"**/*.json",
"**/*.jsonc",
];
const results = await searchFiles(query, patterns, { maxResults: 50 });
return { content: results };
} catch (error) {
return {
content: [{ type: "text", text: `Error searching settings: ${error}` }],
isError: true,
};
}
}
);
// getConfig
mcp.tool(
"getConfig",
"Read a configuration file (JSON/JSONC/YAML/TOML) and optionally extract a specific key",
{
file: z.string().describe("Path to the configuration file"),
key: z.string().optional().describe("Optional dot-separated key path (e.g., 'database.host')"),
},
async ({ file, key }: { file: string; key?: string }) => {
try {
const data = await readConfigFile(file);
const value = key
? key.split(".").reduce((o: any, k: string) => (o ? o[k] : undefined), data)
: data;
return { content: [{ type: "text", text: JSON.stringify(value, null, 2) }] };
} catch (error) {
return { content: [{ type: "text", text: `Error reading config: ${error}` }], isError: true };
}
}
);
// setConfig
mcp.tool(
"setConfig",
"Update a configuration file by setting a value at a specific key path",
{
file: z.string().describe("Path to the configuration file"),
key: z.string().describe("Dot-separated key path to update (e.g., 'database.host')"),
value: z.string().describe("JSON-encoded value to set"),
},
async ({ file, key, value }: { file: string; key: string; value: string }) => {
try {
const json = JSON.parse(value);
const data = await readConfigFile(file);
const path = key.split(".");
let curr: any = data;
for (let i = 0; i < path.length - 1; i++) {
const p = path[i];
if (typeof curr[p] !== "object" || curr[p] === null) curr[p] = {};
curr = curr[p];
}
curr[path[path.length - 1]] = json;
await writeConfigFile(file, data);
return { content: [{ type: "text", text: `Successfully updated ${key} in ${file}` }] };
} catch (error) {
return {
content: [{ type: "text", text: `Error updating config: ${error}` }],
isError: true,
};
}
}
);
// listConfigs
mcp.tool(
"listConfigs",
"List configuration files in the workspace matching specified patterns",
{
include: z
.array(z.string())
.default(["**/*.{json,jsonc,yaml,yml,toml}"])
.describe("Glob patterns for config files"),
},
async ({ include }: { include: string[] }) => {
try {
const items = await searchFiles("", include, { listOnly: true, maxResults: 200 });
return { content: items };
} catch (error) {
return {
content: [{ type: "text", text: `Error listing configs: ${error}` }],
isError: true,
};
}
}
);
async function main() {
const transport = new StdioServerTransport();
await mcp.connect(transport);
}
main().catch((err) => {
console.error(err);
process.exit(1);
});