Skip to main content
Glama
JWears

Local Docs MCP Server

by JWears
README.md
# Local Docs MCP Server

A TypeScript-based Model Context Protocol (MCP) server that exposes multiple local documentation folders (namespaces) to AI assistants via tools and resources.

## Features

- **šŸ”Œ HTTP Transport**: Uses Streamable HTTP on `POST /mcp` (no stdio)
- **šŸ“ Multi-Namespace Support**: Organize docs across multiple roots with namespace isolation
- **šŸ”— Resource Access**: Dynamic resource template `docs://{namespace}/{path}` for file access
- **šŸ› ļø Three Tools**:
  - `list_files` - List files matching glob patterns across namespaces
  - `read_file` - Read specific file contents from a namespace
  - `search` - Search for text across multiple files and namespaces
- **šŸ”’ Security**: Path traversal prevention, symlink escape detection, binary file filtering, configurable file size limits
- **šŸ“ MIME Types**: Automatic MIME type detection for all files
- **āš™ļø Flexible Configuration**: Configure via environment variables or `docs.config.json`

## Installation

Dependencies are already installed. If you need to reinstall:

```bash
npm install
```

## Configuration

### Method 1: Configuration File (`docs.config.json`)

Create a `docs.config.json` file in the project root:

```json
{
  "roots": [
    {
      "ns": "docs",
      "path": "./docs"
    },
    {
      "ns": "api",
      "path": "./api-docs"
    },
    {
      "ns": "guides",
      "path": "C:/absolute/path/to/guides"
    }
  ],
  "maxFileKB": 256,
  "allowSymlinks": false,
  "ignore": [
    "**/node_modules/**",
    "**/.git/**",
    "**/dist/**",
    "**/build/**"
  ]
}
```

### Method 2: Environment Variables

Set the `DOCS_DIRS` environment variable with comma-separated namespace:path pairs:

```bash
# Windows PowerShell
$env:DOCS_DIRS="docs:./docs,api:./api-docs,guides:C:/path/to/guides"
npm run dev
```

**Note:** Environment variables take precedence and will override/merge with `docs.config.json`.

### Configuration Options

- `roots`: Array of namespace definitions
  - `ns`: Namespace identifier (alphanumeric, hyphens, underscores)
  - `path`: Absolute or relative path to the root directory
- `maxFileKB`: Maximum file size in kilobytes (default: 256)
- `allowSymlinks`: Allow symlinks that point outside the namespace (default: false)
- `ignore`: Glob patterns to ignore (default: node_modules, .git, etc.)
- `PORT`: Server port via environment variable (default: 3000)

## Running the Server

### Development Mode (with auto-reload)

```bash
npm run dev
```

### Production Mode

```bash
npm start
```

The server will print the MCP URL on startup:

```
šŸš€ Local Docs MCP Server running
šŸ“ Registered namespaces:
   - docs: C:\Users\...\mcp-day\docs
   - api: C:\Users\...\mcp-day\api-docs
šŸ”— MCP URL: http://localhost:3000/mcp
šŸ’š Health check: http://localhost:3000/health
```

## Testing with MCP Inspector

1. **Install MCP Inspector** (if not already installed):
   ```bash
   npx @modelcontextprotocol/inspector
   ```

2. **Start the server** in one terminal:
   ```bash
   npm run dev
   ```

3. **Open MCP Inspector** in another terminal:
   ```bash
   npx @modelcontextprotocol/inspector
   ```

4. **Connect to the server**:
   - In the Inspector UI, enter the MCP URL: `http://localhost:3000/mcp`
   - Transport type: `HTTP`

5. **Test the tools**:

   **List Files (all namespaces):**
   ```json
   {
     "pattern": "**/*.md",
     "max": 50
   }
   ```

   **List Files (specific namespace):**
   ```json
   {
     "pattern": "**/*.md",
     "ns": "docs",
     "max": 50
   }
   ```

   **List Files (multiple namespaces):**
   ```json
   {
     "pattern": "**/*.md",
     "ns": ["docs", "api"],
     "max": 50
   }
   ```

   **Read File:**
   ```json
   {
     "ns": "docs",
     "path": "welcome.md"
   }
   ```

   **Search (all namespaces):**
   ```json
   {
     "query": "MCP",
     "glob": "**/*.md",
     "max": 100
   }
   ```

   **Search (specific namespace):**
   ```json
   {
     "query": "MCP",
     "glob": "**/*.md",
     "ns": "docs",
     "max": 100
   }
   ```

6. **Test Resources**:
   - Resources now use namespace URIs: `docs://{namespace}/{path}`
   - Example: `docs://docs/welcome.md`, `docs://api/endpoints.md`
   - Click on any resource link in the Inspector
   - The file content should appear with proper MIME type

## Project Structure

```
mcp-day/
ā”œā”€ā”€ server.ts              # Main MCP server implementation
ā”œā”€ā”€ src/
│   └── roots.ts          # RootRegistry implementation
ā”œā”€ā”€ package.json          # Project configuration
ā”œā”€ā”€ tsconfig.json         # TypeScript configuration
ā”œā”€ā”€ docs.config.json      # Namespace configuration
ā”œā”€ā”€ README.md            # This file
└── docs/                # Default documentation namespace
    ā”œā”€ā”€ welcome.md       # Sample markdown file
    ā”œā”€ā”€ api.md           # API reference
    └── config.json      # Sample JSON file
```

## Tools Reference

### list_files

Lists files in the docs directory matching a glob pattern. Can filter by namespace(s).

**Input:**
- `pattern` (optional): Glob pattern (default: `**/*.{md,mdx,txt,json}`)
- `ns` (optional): Namespace(s) to search - string or array. If omitted, searches all namespaces
- `max` (optional): Maximum results (default: 200)

**Output:**
- `count`: Number of files returned
- `namespaces`: Array of searched namespaces
- `files`: Array with `ns`, `path`, `uri`, `size`, `mtime`, `mimeType`
- Resource links for each file as `docs://{ns}/{path}`

### read_file

Reads a file from a specific namespace in the docs directory.

**Input:**
- `ns` (required): Namespace to read from
- `path` (required): Relative path to the file within the namespace

**Output:**
- `ns`: Namespace
- `path`: File path
- `bytes`: File size
- `lines`: Line count
- Resource link to the file content as `docs://{ns}/{path}`

### search

Searches for text in files. Can filter by namespace(s).

**Input:**
- `query` (required): Search text
- `glob` (optional): File pattern to search
- `ns` (optional): Namespace(s) to search - string or array. If omitted, searches all namespaces
- `max` (optional): Maximum matches (default: 100)
- `contextLines` (optional): Context lines (default: 1)

**Output:**
- `query`: Search term
- `namespaces`: Array of searched namespaces
- `matchCount`: Number of matches
- `matches`: Array with `ns`, `path`, `lineNumber`, `line`, `start`, `end`, `uri`
- Resource links to matched files as `docs://{ns}/{path}`

## Resources

The server exposes dynamic resource templates for each namespace:

- **URI Pattern**: `docs://{namespace}/{path}`
- **Examples**: 
  - `docs://docs/welcome.md`
  - `docs://api/endpoints.md`
  - `docs://guides/tutorial.md`
- **Returns**: File content with correct MIME type

Resources are automatically linked in tool responses and can be opened directly in the MCP Inspector.

## Security Features

1. **Path Traversal Protection**: All paths are validated to ensure they're within the namespace root
2. **Symlink Escape Detection**: By default, symlinks pointing outside the namespace are blocked (configurable)
3. **Binary File Rejection**: Binary files are automatically skipped
4. **Configurable File Size Limits**: Files larger than the configured limit are rejected (default: 256KB)
5. **Namespace Validation**: Namespace identifiers are validated (alphanumeric, hyphens, underscores only)
6. **Ignore Patterns**: Automatically skip node_modules, .git, and other configured patterns
7. **Sanitized Errors**: Error messages don't expose internal paths

## Customization

### Using Multiple Namespaces

**Example 1: Via environment variable**
```bash
# Windows PowerShell
$env:DOCS_DIRS="docs:./docs,api:./api-docs,guides:C:/guides"
npm run dev
```

**Example 2: Via docs.config.json**
```json
{
  "roots": [
    { "ns": "docs", "path": "./docs" },
    { "ns": "api", "path": "./api-docs" },
    { "ns": "guides", "path": "C:/absolute/path/to/guides" }
  ]
}
```

To add new namespaces, edit the `docs.config.json` file and restart the server.

### Configuring File Size Limits

Edit `docs.config.json`:
```json
{
  "maxFileKB": 512,
  "roots": [...]
}
```

### Allowing Symlinks

Edit `docs.config.json`:
```json
{
  "allowSymlinks": true,
  "roots": [...]
}
```

**Warning:** Only enable if you trust the symlink targets. This allows symlinks to point outside namespace roots.

### Custom Ignore Patterns

Edit `docs.config.json`:
```json
{
  "ignore": [
    "**/node_modules/**",
    "**/.git/**",
    "**/dist/**",
    "**/build/**",
    "**/*.log",
    "**/tmp/**"
  ],
  "roots": [...]
}
```

## Troubleshooting

**Server won't start:**
- Check if port 3000 is already in use
- Try a different port: `$env:PORT="3001"; npm start`
- Check TypeScript compilation errors

**Files not appearing:**
- Verify namespace configuration in `docs.config.json` or `DOCS_DIRS`
- Check that namespace paths exist and are accessible
- Ensure files match the glob pattern
- Check file permissions
- Review ignore patterns

**Namespace not found errors:**
- Run `roots.list` tool to see registered namespaces
- Check namespace spelling (case-sensitive)
- Verify `docs.config.json` is valid JSON
- Check console logs for initialization warnings

**Inspector can't connect:**
- Verify the server is running
- Check the MCP URL is correct: `http://localhost:3000/mcp`
- Ensure no firewall is blocking the connection
- Check health endpoint: `http://localhost:3000/health`

**Path traversal or symlink errors:**
- Ensure paths are relative to the namespace root
- Check `allowSymlinks` setting if using symlinks
- Verify symlinks don't escape the namespace directory

**File too large errors:**
- Increase `maxFileKB` in `docs.config.json`
- Or filter out large files using ignore patterns

## License

ISC

Maintenance

ActivityInactive
ResponsivenessNo issues