Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
84 changes: 79 additions & 5 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -108,20 +108,25 @@ npx @shelldandy/grafana-ui-mcp-server
grafana-ui-mcp [options]

Options:
--github-api-key, -g <token> GitHub Personal Access Token
--help, -h Show help message
--version, -v Show version information
--github-api-key, -g <token> GitHub Personal Access Token
--grafana-repo-path, -l <path> Path to local Grafana repository (takes precedence)
--help, -h Show help message
--version, -v Show version information

Environment Variables:
GITHUB_PERSONAL_ACCESS_TOKEN Alternative way to provide GitHub token
GITHUB_TOKEN Alternative way to provide GitHub token
GITHUB_PERSONAL_ACCESS_TOKEN Alternative way to provide GitHub token
GITHUB_TOKEN Alternative way to provide GitHub token
GRAFANA_REPO_PATH Path to local Grafana repository

Examples:
npx @shelldandy/grafana-ui-mcp-server --help
npx @shelldandy/grafana-ui-mcp-server --version
npx @shelldandy/grafana-ui-mcp-server -g ghp_1234567890abcdef
npx @shelldandy/grafana-ui-mcp-server --grafana-repo-path /path/to/grafana
npx @shelldandy/grafana-ui-mcp-server -l /path/to/grafana
GITHUB_PERSONAL_ACCESS_TOKEN=ghp_token npx @shelldandy/grafana-ui-mcp-server
GITHUB_TOKEN=ghp_token npx @shelldandy/grafana-ui-mcp-server
GRAFANA_REPO_PATH=/path/to/grafana npx @shelldandy/grafana-ui-mcp-server
```

## 🔑 GitHub API Token Setup
Expand Down Expand Up @@ -197,6 +202,75 @@ npx @shelldandy/grafana-ui-mcp-server --github-api-key ghp_your_token --help
curl -H "Authorization: token ghp_your_token" https://api.github.com/rate_limit
```

## 🏠 Local Development Support

**NEW**: Work with a local Grafana repository for faster development and access to uncommitted changes!

### 🎯 Why Use Local Repository?

- **⚡ Faster Access**: Direct filesystem reads, no network latency
- **🚫 No Rate Limits**: Unlimited component access
- **🔄 Real-time Updates**: See your local changes immediately
- **📡 Offline Support**: Works without internet connection
- **🧪 Development Workflow**: Test with modified/uncommitted components

### 🔧 Setup with Local Repository

1. **Clone the Grafana Repository**:
```bash
git clone https://github.com/grafana/grafana.git
cd grafana
```

2. **Use Local Path** (takes precedence over GitHub API):
```bash
# Command line option
npx @shelldandy/grafana-ui-mcp-server --grafana-repo-path /path/to/grafana
npx @shelldandy/grafana-ui-mcp-server -l /path/to/grafana

# Environment variable
export GRAFANA_REPO_PATH=/path/to/grafana
npx @shelldandy/grafana-ui-mcp-server
```

3. **Claude Desktop Configuration**:
```json
{
"mcpServers": {
"grafana-ui": {
"command": "npx",
"args": ["@shelldandy/grafana-ui-mcp-server"],
"env": {
"GRAFANA_REPO_PATH": "/path/to/your/grafana/repository"
}
}
}
}
```

### 🔄 Configuration Priority

The server checks sources in this order:

1. **Local Repository** (`--grafana-repo-path` or `GRAFANA_REPO_PATH`)
2. **GitHub API with Token** (`--github-api-key` or `GITHUB_*_TOKEN`)
3. **GitHub API without Token** (rate limited to 60 requests/hour)

### 🛡️ Graceful Fallback

- If local file doesn't exist → Falls back to GitHub API automatically
- If local repository is invalid → Falls back to GitHub API with warning
- Source is indicated in tool responses (`"source": "local"` vs `"source": "github"`)

### ✅ Verify Local Setup

```bash
# Test local repository access
npx @shelldandy/grafana-ui-mcp-server --grafana-repo-path /path/to/grafana --help

# Should show: "Local Grafana repository configured: /path/to/grafana"
```

## 🛠️ Tool Usage Examples

The MCP server provides the unified `grafana_ui` tool for AI assistants:
Expand Down
200 changes: 200 additions & 0 deletions specs/03-local-repo-support.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,200 @@
# Local Grafana Repository Support Specification

## Overview

Add a new CLI option `--grafana-repo-path` (and equivalent environment variable `GRAFANA_REPO_PATH`) to allow users to specify a local Grafana repository path. This option takes precedence over GitHub API access, enabling the MCP server to read components directly from a local filesystem.

## Implementation Plan

### 1. CLI Interface Updates (`src/index.ts`)

**Add new CLI option:**
- `--grafana-repo-path <path>` / `-l <path>` - Path to local Grafana repository
- Environment variable: `GRAFANA_REPO_PATH`
- Update help text to document the new option
- Precedence: Local repo → GitHub API key → Unauthenticated GitHub

**Configuration logic:**
```typescript
const { githubApiKey, grafanaRepoPath } = await parseArgs();

if (grafanaRepoPath) {
axios.setLocalGrafanaRepo(grafanaRepoPath);
console.error("Local Grafana repository configured");
} else if (githubApiKey) {
axios.setGitHubApiKey(githubApiKey);
console.error("GitHub API key configured");
}
```

### 2. Core Utilities Enhancement (`src/utils/axios.ts`)

**Add local filesystem support:**
- New function: `setLocalGrafanaRepo(repoPath: string)`
- New internal flag: `localRepoPath: string | null`
- Update all existing functions to check local repo first before GitHub API
- Add filesystem utilities using Node.js `fs` module

**Function modifications:**
- `getComponentSource()` - Check local filesystem first
- `getComponentDemo()` - Read local `.story.tsx` files
- `getAvailableComponents()` - Use `fs.readdir()` on local components directory
- `getComponentMetadata()` - Parse local directory structure
- `getComponentDocumentation()` - Read local `.mdx` files
- `getComponentTests()` - Read local test files
- `searchComponents()` - Search local filesystem
- `getThemeFiles()` - Read local theme files
- `getComponentDependencies()` - Analyze local files
- `buildDirectoryTree()` - Build tree from local filesystem

**Path resolution:**
```typescript
const LOCAL_COMPONENTS_PATH = "packages/grafana-ui/src/components";
const resolveLocalPath = (subPath: string) =>
path.join(localRepoPath!, subPath);
```

### 3. Error Handling & Validation

**Validation checks:**
- Verify local path exists and is readable
- Check if path contains expected Grafana structure (`packages/grafana-ui/src/components/`)
- Graceful fallback to GitHub API if local files are missing
- Clear error messages for invalid local repository paths

**Graceful degradation:**
- If local file doesn't exist, try GitHub API as fallback
- Maintain same error message format for consistency
- Log source (local vs GitHub) for debugging

### 4. Performance Optimizations

**Local filesystem advantages:**
- No rate limiting concerns
- Faster file access (no network latency)
- Support for modified/uncommitted components
- Real-time development workflow support

**Caching strategy:**
- Minimal caching needed for local files
- Optional file modification time checking
- Preserve existing GitHub API caching when used as fallback

### 5. Documentation Updates

**Help text updates:**
- Document new `--grafana-repo-path` option
- Explain precedence order (local → GitHub API → unauthenticated)
- Add usage examples for local development workflow
- Update environment variable documentation

**README.md updates:**
- New "Local Development" section
- Examples of local repository setup
- Benefits of local vs GitHub API access
- Troubleshooting section for local path issues

## Benefits

1. **Development Workflow**: Developers can work with local, potentially modified components
2. **No Rate Limits**: Unlimited access to components without GitHub API constraints
3. **Faster Access**: Direct filesystem reads are faster than HTTP requests
4. **Offline Support**: Works without internet connection
5. **Real-time Updates**: Reflects local changes immediately
6. **Backward Compatibility**: Existing GitHub API workflow remains unchanged

## Files to Modify

1. `specs/03-local-repo-support.md` - **NEW** - This specification document
2. `src/index.ts` - Add CLI argument parsing for `--grafana-repo-path` option
3. `src/utils/axios.ts` - Add filesystem support and local repo precedence logic
4. `README.md` - Document new local repository feature

## Success Criteria

- [ ] CLI accepts `--grafana-repo-path` option and `GRAFANA_REPO_PATH` environment variable
- [ ] All 11 MCP tools work with local repository path
- [ ] Graceful fallback to GitHub API when local files missing
- [ ] Path validation with clear error messages
- [ ] Maintains backward compatibility with existing GitHub API workflow
- [ ] Documentation updated with local development examples
- [ ] No breaking changes to existing functionality

## Implementation Details

### CLI Argument Parsing

```typescript
// In parseArgs() function
const grafanaRepoPathIndex = args.findIndex(
(arg) => arg === "--grafana-repo-path" || arg === "-l",
);
let grafanaRepoPath = null;

if (grafanaRepoPathIndex !== -1 && args[grafanaRepoPathIndex + 1]) {
grafanaRepoPath = args[grafanaRepoPathIndex + 1];
} else if (process.env.GRAFANA_REPO_PATH) {
grafanaRepoPath = process.env.GRAFANA_REPO_PATH;
}

return { githubApiKey, grafanaRepoPath };
```

### Filesystem Functions

```typescript
// New filesystem utilities in axios.ts
import fs from 'fs';
import path from 'path';

let localRepoPath: string | null = null;

function setLocalGrafanaRepo(repoPath: string): void {
// Validate path exists and has expected structure
const componentsPath = path.join(repoPath, LOCAL_COMPONENTS_PATH);
if (!fs.existsSync(componentsPath)) {
throw new Error(`Invalid Grafana repository path: ${componentsPath} not found`);
}
localRepoPath = repoPath;
}

async function getComponentSourceLocal(componentName: string): Promise<string> {
if (!localRepoPath) return null;
const componentPath = path.join(localRepoPath, LOCAL_COMPONENTS_PATH, componentName, `${componentName}.tsx`);

try {
return fs.readFileSync(componentPath, 'utf8');
} catch (error) {
return null; // Fall back to GitHub API
}
}
```

### Help Text Updates

```text
Options:
--github-api-key, -g <token> GitHub Personal Access Token for API access
--grafana-repo-path, -l <path> Path to local Grafana repository (takes precedence over GitHub API)
--help, -h Show this help message
--version, -v Show version information

Environment Variables:
GITHUB_PERSONAL_ACCESS_TOKEN Alternative way to provide GitHub token
GITHUB_TOKEN Alternative way to provide GitHub token
GRAFANA_REPO_PATH Path to local Grafana repository

Examples:
npx @shelldandy/grafana-ui-mcp-server
npx @shelldandy/grafana-ui-mcp-server --github-api-key ghp_your_token_here
npx @shelldandy/grafana-ui-mcp-server --grafana-repo-path /path/to/grafana
npx @shelldandy/grafana-ui-mcp-server -l /path/to/grafana
```

## Testing Strategy

1. **Unit Testing**: Test filesystem functions with mock filesystem
2. **Integration Testing**: Test with actual local Grafana repository
3. **Fallback Testing**: Verify GitHub API fallback when local files missing
4. **Error Handling**: Test invalid paths and missing files
5. **Backward Compatibility**: Ensure existing GitHub workflow unaffected
Loading