Skip to content
Open
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
12 changes: 12 additions & 0 deletions .claude/settings.local.json
Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Added this to help future Claude Code sessions

Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
{
"permissions": {
"allow": [
"Bash(npm run build:*)",
"WebFetch(domain:github.com)",
"Bash(npm run lint)",
"Bash(TRANSPORT_TYPE=stdio node dist/index.js --help)",
"Bash(tasklist:*)"
],
"deny": []
}
}
128 changes: 128 additions & 0 deletions CLAUDE.md
Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Initial Claude Code file

Original file line number Diff line number Diff line change
@@ -0,0 +1,128 @@
# CLAUDE.md

This file provides guidance to Claude Code (claude.ai/code) when working with code in this repository.

## Project Overview

This is a **Model Context Protocol (MCP) server** for CData Connect Cloud API integration. It enables AI agents to interact with cloud-connected data sources through SQL queries, metadata introspection, and stored procedure execution.

## Development Commands

### Build and Development
- `npm run build` - Compile TypeScript to dist/
- `npm run dev` - Start development server with ts-node (default: HTTP transport)
- `npm run dev:http` - Start development server with HTTP transport
- `npm run dev:stdio` - Start development server with STDIO transport
- `npm run watch` - Watch TypeScript files and recompile on changes
- `npm run clean` - Remove dist/ directory

### Production
- `npm start` - Start compiled server (default: HTTP transport)
- `npm run start:http` - Start with HTTP transport
- `npm run start:stdio` - Start with STDIO transport
- `npm run build-start` - Build then start production server

### Code Quality
- `npm run lint` - Run ESLint with auto-fix
- `npm run format` - Format code with Prettier
- `npm run lint:format` - Run both lint and format

### Testing and Debugging
- `npm run inspector` - Launch MCP Inspector web UI
- `npm run inspector:stdio` - Launch inspector with STDIO transport
- `npm run inspector:http` - Launch inspector with HTTP transport (requires separate server start)
- `npm run inspector:cli` - CLI mode inspector with STDIO transport
- `npm run test:inspector` - Quick automated inspector test
- `npm run validate:inspector` - Validate inspector configuration

## Architecture

### Core Components

**Entry Point**: `src/index.ts`
- Global request ID tracking
- Environment configuration loading
- Transport initialization

**MCP Server**: `src/server/mcpServer.ts`
- Basic MCP server instance using @modelcontextprotocol/sdk
- Server name: "CData Connect Cloud"

**Transport Layer**: `src/transports/`
- `index.ts` - Transport selection logic (HTTP vs STDIO)
- `httpTransport.ts` - HTTP server with Express.js endpoints
- `stdioTransport.ts` - Standard I/O transport for CLI usage

**Tool Registry**: `src/server/toolRegistry.ts`
- Registers all MCP tools with the server
- Handles tool parameter validation using Zod schemas
- Error handling and response formatting

### Tool Categories

**Data Operations** (`src/tools/query/`):
- `queryData` - Execute SQL queries with optional parameters
- `execData` - Execute stored procedures

**Metadata Operations** (`src/tools/metadata/`):
- `getCatalogs` - List available connections/catalogs
- `getSchemas` - List schemas within catalogs
- `getTables` - List tables within schemas
- `getColumns` - Get column metadata for tables
- `getPrimaryKeys` - Retrieve primary key information
- `getIndexes` - Get index information
- `getImportedKeys` / `getExportedKeys` - Foreign key relationships
- `getProcedures` - List stored procedures
- `getProcedureParameters` - Get procedure parameter information

### HTTP Transport Endpoints

When using HTTP transport (default), the server provides:
- `/mcp` - Primary MCP endpoint with session management
- `/direct` - Direct JSON-RPC endpoint without sessions
- `/.well-known/mc/manifest.json` - MCP discovery manifest

### Configuration

**Environment Variables**:
- `CDATA_USERNAME` - CData Connect Cloud username (required)
- `CDATA_PAT` - Personal Access Token (required)
- `CDATA_API_URL` - API URL (default: https://cloud.cdata.com/api)
- `TRANSPORT_TYPE` - "http" or "stdio" (default: "http")
- `PORT` - HTTP server port (default: 3000)
- `HOST` - HTTP server host (default: localhost)
- `LOG_ENABLED` - Enable logging (default: false)
- `LOG_LEVEL` - Log level (default: info)

**Inspector Configuration**: `mcp-inspector.json`
- Pre-configured for both STDIO and HTTP transports
- Used by MCP Inspector for testing and debugging

## Development Workflow

1. **Environment Setup**: Create `.env` file with required CData credentials
2. **Development**: Use `npm run dev` for live development with HTTP transport
3. **Testing**: Use `npm run inspector` to test tools with MCP Inspector
4. **Code Quality**: Run `npm run lint:format` before commits
5. **Build**: Use `npm run build` to compile for production

## Key Dependencies

- `@modelcontextprotocol/sdk` - Core MCP functionality
- `axios` - HTTP client for CData API requests
- `express` - HTTP server framework
- `winston` - Logging framework
- `zod` - Schema validation for tool parameters
- `dotenv` - Environment variable management

## Transport Modes

**HTTP Transport** (Default):
- Better for integration with web-based AI clients
- Provides REST-like endpoints and MCP protocol endpoints
- Session management and connection pooling

**STDIO Transport**:
- Direct stdin/stdout communication
- Better for CLI tools and direct process communication
- Used by Claude Desktop and similar clients
4 changes: 2 additions & 2 deletions package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

1 change: 1 addition & 0 deletions src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ import { setupTransport } from './transports';

// Declare a global variable to track the current request ID
declare global {
// eslint-disable-next-line no-var
var currentRequestId: string | number | null;
}
global.currentRequestId = null;
Expand Down
1 change: 1 addition & 0 deletions src/server/mcpServer.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ const server = new McpServer({
version: '1.0.5',
capabilities: {
tools: {},
prompts: {},
},
});

Expand Down
64 changes: 63 additions & 1 deletion src/server/toolRegistry.ts
Original file line number Diff line number Diff line change
Expand Up @@ -13,12 +13,15 @@ import {
getSchemas,
getTables,
} from '../tools/metadata';
import { getPrompts, generatePromptMessages } from '../tools/prompts/prompts';

/**
* Register all tools with the MCP server
* Register all tools and prompts with the MCP server
* @param server The MCP server instance
*/
export function registerTools(server: McpServer) {
// Register prompts
registerPrompts(server);
// Query Data tool
server.tool(
'queryData',
Expand Down Expand Up @@ -405,3 +408,62 @@ export function registerTools(server: McpServer) {
},
);
}

/**
* Register prompts with the MCP server
* @param server The MCP server instance
*/
function registerPrompts(server: McpServer) {
const prompts = getPrompts();

// Register each prompt individually
prompts.forEach(prompt => {
// Convert prompt arguments to Zod schema
const argsSchema: Record<string, z.ZodType> = {};

if (prompt.arguments) {
prompt.arguments.forEach(arg => {
// Convert to Zod string schema, make optional if not required
argsSchema[arg.name] = arg.required
? z.string().describe(arg.description || '')
: z
.string()
.optional()
.describe(arg.description || '');
});
}

// Register the prompt using the correct API
if (Object.keys(argsSchema).length > 0) {
// Prompt with arguments
server.prompt(prompt.name, prompt.description || '', argsSchema, args => {
const messages = generatePromptMessages(prompt.name, args || {});
return {
description: prompt.description || '',
messages: messages.map(msg => ({
role: msg.role as 'user' | 'assistant',
content: {
type: 'text' as const,
text: msg.content.text,
},
})),
};
});
} else {
// Prompt without arguments
server.prompt(prompt.name, prompt.description || '', () => {
const messages = generatePromptMessages(prompt.name, {});
return {
description: prompt.description || '',
messages: messages.map(msg => ({
role: msg.role as 'user' | 'assistant',
content: {
type: 'text' as const,
text: msg.content.text,
},
})),
};
});
}
});
}
Loading