diff --git a/.dockerignore b/.dockerignore new file mode 100644 index 0000000..5609717 --- /dev/null +++ b/.dockerignore @@ -0,0 +1,8 @@ +node_modules +dist +coverage +test +*.test.ts +.git +.github +*.md diff --git a/Dockerfile b/Dockerfile new file mode 100644 index 0000000..3e6c249 --- /dev/null +++ b/Dockerfile @@ -0,0 +1,24 @@ +FROM node:22-slim AS builder + +WORKDIR /app + +COPY package*.json ./ +ENV HUSKY=0 +RUN npm ci + +COPY . . +RUN npm run build + +# ---- runtime ---- +FROM node:22-slim + +WORKDIR /app + +COPY --from=builder /app/dist ./dist +COPY --from=builder /app/package*.json ./ +ENV HUSKY=0 +RUN npm ci --omit=dev + +USER node + +CMD ["node", "dist/esm/index.js"] diff --git a/README.md b/README.md index f84c8ba..eaa7714 100644 --- a/README.md +++ b/README.md @@ -4,22 +4,33 @@ A [Model Context Protocol (MCP)](https://modelcontextprotocol.io/) server that g ## Quick Start -### Claude Code +### Hosted (no install required) + +Connect directly to the hosted endpoint — nothing to install or maintain: + +**Claude Code / Claude Desktop / Cursor / VS Code** ```json { "mcpServers": { "mapbox-docs": { - "command": "npx", - "args": ["-y", "@mapbox/mcp-docs-server"] + "url": "https://mcp-docs.mapbox.com/mcp" } } } ``` -### Claude Desktop +--- + +### npx (runs locally, no install) + +**Claude Code** — run `claude mcp add`: -Add to `~/Library/Application Support/Claude/claude_desktop_config.json` (macOS) or `%APPDATA%\Claude\claude_desktop_config.json` (Windows): +```bash +claude mcp add mapbox-docs -- npx -y @mapbox/mcp-docs-server +``` + +**Claude Desktop** — add to `~/Library/Application Support/Claude/claude_desktop_config.json` (macOS) or `%APPDATA%\Claude\claude_desktop_config.json` (Windows): ```json { @@ -32,9 +43,60 @@ Add to `~/Library/Application Support/Claude/claude_desktop_config.json` (macOS) } ``` -### Cursor / VS Code +**Cursor / VS Code** — add the same `mcpServers` block to your editor's MCP settings file. + +--- + +### Docker + +**Build the image:** + +```bash +docker build -t mapbox/mcp-docs-server . +``` + +**Or pull from the registry:** + +```bash +docker pull mapbox/mcp-docs-server +``` + +**Claude Desktop / Cursor / VS Code** — configure your MCP client to run the container: + +```json +{ + "mcpServers": { + "mapbox-docs": { + "command": "docker", + "args": ["run", "--rm", "-i", "mapbox/mcp-docs-server"] + } + } +} +``` + +--- + +### Local (from source) -Add the same `mcpServers` block to your editor's MCP settings file. +```bash +git clone https://github.com/mapbox/mcp-docs-server.git +cd mcp-docs-server +npm install +npm run build +``` + +**Claude Desktop / Cursor / VS Code:** + +```json +{ + "mcpServers": { + "mapbox-docs": { + "command": "node", + "args": ["/absolute/path/to/mcp-docs-server/dist/esm/index.js"] + } + } +} +``` ## Tools diff --git a/package.json b/package.json index 22db48b..7b78a25 100644 --- a/package.json +++ b/package.json @@ -18,7 +18,7 @@ "inspect:dev": "npx @modelcontextprotocol/inspector npx -y tsx src/index.ts", "lint": "eslint \"./src/**/*.{ts,tsx}\" \"./test/**/*.{ts,tsx}\" --no-error-on-unmatched-pattern", "lint:fix": "eslint \"./src/**/*.{ts,tsx}\" \"./test/**/*.{ts,tsx}\" --no-error-on-unmatched-pattern --fix", - "prepare": "husky && node .husky/setup-hooks.js", + "prepare": "node -e \"if(!process.env.CI&&process.env.HUSKY!=='0'){require('child_process').execSync('husky && node .husky/setup-hooks.js',{stdio:'inherit'})}\"", "spellcheck": "cspell \"*.md\" \"src/**/*.ts\" \"test/**/*.ts\"", "test": "vitest" }, diff --git a/scripts/build-helpers.cjs b/scripts/build-helpers.cjs index 6719c23..f9add9d 100644 --- a/scripts/build-helpers.cjs +++ b/scripts/build-helpers.cjs @@ -11,13 +11,24 @@ function mkdirp(dirPath) { } } +// Run a git command, returning a fallback string if git is unavailable +function tryGit(args, fallback = 'unknown') { + try { + return execSync(`git ${args}`, { stdio: ['pipe', 'pipe', 'pipe'] }) + .toString() + .trim(); + } catch { + return fallback; + } +} + // Generate version info function generateVersion() { mkdirp('dist'); - const sha = execSync('git rev-parse HEAD').toString().trim(); - const tag = execSync('git describe --tags --always').toString().trim(); - const branch = execSync('git rev-parse --abbrev-ref HEAD').toString().trim(); + const sha = tryGit('rev-parse HEAD'); + const tag = tryGit('describe --tags --always'); + const branch = tryGit('rev-parse --abbrev-ref HEAD'); const version = process.env.npm_package_version; const versionInfo = {