Skip to main content
Glama
README.md
# Keephub MCP Server

A standalone Model Context Protocol (MCP) server that enables Large Language Models to interact with the Keephub REST API. Built on `@modelcontextprotocol/sdk` with Streamable HTTP transport, it provides domain-specific tools and guided workflows for the Keephub ecosystem.

## Table Of Contents

- [Features](#features)
- [Quick Start](#quick-start)
- [MCP Tool Catalog](#mcp-tool-catalog)
- [Architecture](#architecture)
- [Configuration & Authentication](#configuration--authentication)
- [Development](#development)
- [Build & Production](#build--production)

## Features

- **Secure Authentication**: Utilizes `AsyncLocalStorage` to inject security context from HTTP request headers (`Authorization`, `X-Base-Url`). Tokens and credentials are never exposed as tool parameters to the LLM.
- **Native HTTP Transport**: Direct interaction with the Keephub REST API via `KeephubClient` utilizing native `fetch()`. No third-party API middleman is required.
- **Structured Error Handling**: Implements standardized API and MCP error structures to ensure clear, actionable feedback to the LLM.
- **Health Check Endpoint**: Exposes `GET /health` so hosting platforms (for example Railway) can verify service liveness.
- **Domain-Specific Tools**: Functionality is modularized into dedicated namespaces:
  - **Content**: Create, update, delete, approve, reject, and query content (news, events, forms, pages).
  - **Tasks**: Create and manage actionable tasks, task templates, approvals, progress, and statuses.
  - **Users**: Search and retrieve full user profiles by ID, login name, group, or organizational unit.
  - **Orgchart**: Traverse and navigate Keephub organizational structures (parents, children, ancestors).
  - **Form Submissions**: View form results, get submitter details, and update orgunit visibilities.
- **Pre-configured Prompts (Skills)**: Provides built-in MCP prompts designed to guide the LLM through complex workflows (for example creating tasks, updating content, and navigating orgcharts).

## Quick Start

1. Install dependencies:

```bash
npm install
```

2. Configure authentication via either request headers or environment variables:

- Headers: `Authorization`, `X-Base-Url`
- Env fallback: `KEEPHUB_TOKEN`, `KEEPHUB_BASE_URL` (optional `PORT`)

3. Start development server:

```bash
npm run dev
```

4. Verify health endpoint:

```bash
curl http://localhost:3000/health
```

## MCP Tool Catalog

The server currently exposes **55 MCP tools**, grouped by namespace.

### Discovery (1)

- `search_keephub_capabilities`: Router/index tool that helps the LLM choose the right tools and workflow prompts.

### Context (6)

- `context_discoverCreateContext`: Resolve current user identity and available orgunits/groups/content pools for create operations.
- `context_getMyProfile`: Fetch the authenticated user's full profile.
- `context_getMyScopeIds`: Fetch compact scope IDs (user, orgunits, groups, content pools).
- `context_getContentPools`: List available content pools.
- `context_getGroups`: List available groups.
- `context_getOrgchartRoots`: List root orgchart nodes.

### Content (12)

- `content_create`: Create content (news, event, form, manual, faq, training).
- `content_updateById`: Update content by ID.
- `content_delete`: Delete content by ID.
- `content_getById`: Get content by ID.
- `content_findByContentPool`: Find content by content pool.
- `content_findByGroup`: Find content by group.
- `content_findByOrgunit`: Find content by orgunit.
- `content_findMyCandidates`: Find compact candidate content items in current user scope.
- `content_getEditableSummary`: Get compact editable summary of content.
- `content_getApprovalState`: Get compact approval-state summary of content.
- `content_approveContent`: Approve pending content.
- `content_rejectContent`: Reject pending content.

### Tasks (19)

- `task_createTask`: Create a task template.
- `task_updateTask`: Update task template in place (non-destructive merge flow).
- `task_deleteTask`: Delete task template.
- `task_getTask`: Get task template by ID.
- `task_getTaskInstance`: Get task instance by ID.
- `task_getEditableSummary`: Get compact editable summary for task template.
- `task_findMyCandidates`: Find compact candidate task templates for current user scope.
- `task_getTaskByOrgunit`: Find task templates by orgunit.
- `task_getTaskProgress`: Get completion progress for task template.
- `task_getTaskStatusCounts`: Get status counts for task template.
- `task_getTemplateByTask`: Get originating task template for a task instance.
- `task_getMyAssignedTasks`: List task instances assigned to current user.
- `task_getMyTasksAwaitingApproval`: List current user's own tasks awaiting approval.
- `task_getMyPendingApprovals`: List task instances awaiting current user's approval.
- `task_getApprovalState`: Get compact approval-state summary for task instance.
- `task_normalizeUrls`: Normalize Keephub task template/task instance URLs.
- `task_approveTask`: Approve pending task instance.
- `task_approveAllPendingByTemplate`: Bulk-approve pending task instances for a template.
- `task_rejectTask`: Reject pending task instance.

### Users (5)

- `user_getById`: Get user by ID.
- `user_findByName`: Find users by display name.
- `user_findByLoginName`: Find user by login name.
- `user_findByGroup`: Find users by group.
- `user_findByOrgunit`: Find users by orgunit.

### Orgchart (4)

- `orgchart_getById`: Get orgunit by ID.
- `orgchart_getParent`: Get parent orgunit.
- `orgchart_getChildren`: Get child orgunits.
- `orgchart_getAncestors`: Get ancestor orgunits.

### Form Submissions (8)

- `formSubmission_findByForm`: Find form submissions by form content ID.
- `formSubmission_getFormSubmission`: Get form submission by ID.
- `formSubmission_getEditContext`: Get compact edit context for a submission.
- `formSubmission_getSubmissionOrgunits`: Get submission visibility orgunits.
- `formSubmission_updateSubmissionOrgunits`: Update submission visibility orgunits.
- `formSubmission_getSubmitterDetails`: Get submitter details for submission.
- `formSubmission_calculateResponseDuration`: Calculate submission response duration.
- `formSubmission_findOneBySubmitterName`: Find one recent submission by submitter name.

### Tool Reference (Purpose + Key Inputs)

#### Discovery

| Tool | Purpose | Key Inputs |
| --- | --- | --- |
| `search_keephub_capabilities` | Suggest the best tool/prompt workflow for a user request. | `query` |

#### Context

| Tool | Purpose | Key Inputs |
| --- | --- | --- |
| `context_discoverCreateContext` | Resolve user identity and creation scopes. | none |
| `context_getMyProfile` | Get authenticated user profile. | none |
| `context_getMyScopeIds` | Get compact scope IDs. | none |
| `context_getContentPools` | List available content pools. | `limit`, `skip`, `allPages`, `maxPages` |
| `context_getGroups` | List visible groups. | `limit`, `skip`, `allPages`, `maxPages` |
| `context_getOrgchartRoots` | List top-level orgchart nodes. | `limit` |

#### Content

| Tool | Purpose | Key Inputs |
| --- | --- | --- |
| `content_create` | Create new content. | `contentType`, `payload` |
| `content_updateById` | Update content by ID. | `contentId`, `payload` |
| `content_delete` | Delete content by ID. | `contentId`, `contentType?` |
| `content_getById` | Get full content by ID. | `contentId` |
| `content_findByContentPool` | Find content by content pool. | `poolId`, `options?` |
| `content_findByGroup` | Find content by group. | `groupId`, `options?` |
| `content_findByOrgunit` | Find content by orgunit. | `orgunitId`, `options?` |
| `content_findMyCandidates` | Find compact candidates in user scope. | `query?`, `contentType?`, `approvalStatus?`, `limit?`, `maxPages?` |
| `content_getEditableSummary` | Get compact editable summary. | `contentId` |
| `content_getApprovalState` | Get compact approval-state summary. | `contentId` |
| `content_approveContent` | Approve pending content. | `contentId`, `contentType` |
| `content_rejectContent` | Reject pending content. | `contentId`, `contentType`, `reason?` |

#### Tasks

| Tool | Purpose | Key Inputs |
| --- | --- | --- |
| `task_createTask` | Create task template. | `payload` |
| `task_updateTask` | Update task template in place. | `taskId`, `changes` |
| `task_deleteTask` | Delete task template. | `taskId` |
| `task_getTask` | Get task template by ID. | `taskId` |
| `task_getTaskInstance` | Get task instance by ID. | `taskInstanceId` |
| `task_getEditableSummary` | Get compact task template summary. | `taskId` |
| `task_findMyCandidates` | Find compact candidate task templates. | `query?`, `type?`, `pendingApprovalOnly?`, `limit?`, `maxPages?` |
| `task_getTaskByOrgunit` | Find task templates by orgunit. | `orgunitId`, `options?` |
| `task_getTaskProgress` | Get task template progress. | `taskId` |
| `task_getTaskStatusCounts` | Get task status counts. | `taskId` |
| `task_getTemplateByTask` | Get template for task instance. | `taskInstanceId` |
| `task_getMyAssignedTasks` | List task instances assigned to me. | `query?`, `status?`, `limit?`, `skip?`, `allPages?`, `maxPages?`, `sortBy?`, `sortOrder?` |
| `task_getMyTasksAwaitingApproval` | List my submitted tasks awaiting approval. | `query?`, `limit?`, `skip?`, `allPages?`, `maxPages?`, `sortBy?`, `sortOrder?` |
| `task_getMyPendingApprovals` | List tasks awaiting my approval. | `templateLimit?`, `maxPages?` |
| `task_getApprovalState` | Get task instance approval-state summary. | `taskInstanceId` |
| `task_normalizeUrls` | Normalize app URLs for task/template IDs. | `taskTemplateId?`, `taskInstanceId?` |
| `task_approveTask` | Approve pending task instance. | `taskId`, `approvalComment?` |
| `task_approveAllPendingByTemplate` | Bulk approve pending instances for a template. | `taskTemplateId`, `approvalComment?` |
| `task_rejectTask` | Reject pending task instance. | `taskId`, `rejectionReason` |

#### Users

| Tool | Purpose | Key Inputs |
| --- | --- | --- |
| `user_getById` | Get user by ID. | `userId` |
| `user_findByName` | Find users by display name. | `name`, `exact?`, `limit?`, `orgunitId?`, `maxPages?` |
| `user_findByLoginName` | Find user by login name. | `loginName` |
| `user_findByGroup` | Find users by group. | `groupId` |
| `user_findByOrgunit` | Find users by orgunit. | `orgunitId` |

#### Orgchart

| Tool | Purpose | Key Inputs |
| --- | --- | --- |
| `orgchart_getById` | Get orgunit by ID. | `id` |
| `orgchart_getParent` | Get orgunit parent. | `id` |
| `orgchart_getChildren` | Get child orgunits. | `id` |
| `orgchart_getAncestors` | Get ancestor orgunits. | `id` |

#### Form Submissions

| Tool | Purpose | Key Inputs |
| --- | --- | --- |
| `formSubmission_findByForm` | Find submissions by form content ID. | `contentRef`, `options?` |
| `formSubmission_getFormSubmission` | Get submission by ID. | `formSubmissionId` |
| `formSubmission_getEditContext` | Get compact submission edit context. | `formSubmissionId` |
| `formSubmission_getSubmissionOrgunits` | Get submission orgunit visibility. | `formSubmissionId` |
| `formSubmission_updateSubmissionOrgunits` | Update submission orgunit visibility. | `formSubmissionId`, `newOrgunitId` |
| `formSubmission_getSubmitterDetails` | Get submitter details. | `formSubmissionId` |
| `formSubmission_calculateResponseDuration` | Calculate response duration. | `formSubmissionId` |
| `formSubmission_findOneBySubmitterName` | Find one recent submission by submitter name. | `submitterName`, `options?` |

### Prompt-Guided Workflows

In addition to tools, the server also registers MCP prompts (skills) for complex, multi-step flows such as content creation/updating, task template creation, orgchart navigation, rejection handling, and form submission orgunit updates.

## Architecture

- **`src/mcp/setup.ts`**: Main MCP server configuration; registers all tools and prompts.
- **`src/mcp/tools/*.ts`**: Domain-specific MCP tool handlers.
- **`src/mcp/prompts/*.ts`**: Guided multi-step workflows (skills).
- **`src/mcp/auth.ts`**: `AsyncLocalStorage`-based auth context propagation.
- **`src/lib/keephubClient.ts`**: Fetch-based Keephub REST API client.

## Configuration & Authentication

The MCP server uses `AsyncLocalStorage` to securely handle credentials. Credentials can be provided either through HTTP request headers (best for per-request multi-tenant usage) or through environment variables (best for local or single-tenant deployment).

### 1. HTTP Headers

- `Authorization`: Keephub bearer token (for example `Bearer YOUR_TOKEN`)
- `X-Base-Url`: Base API URL for the Keephub instance

### 2. Environment Variables (Fallback)

If headers are not provided, the server falls back to these environment variables:

- `KEEPHUB_TOKEN`: Bearer token
- `KEEPHUB_BASE_URL`: Base API URL (for example `https://api.keephub.io`)
- `PORT`: Optional listen port (default `3000`)

You can place these values in a `.env` file for local development.

## Development

Install dependencies:

```bash
npm install
```

Run the development server:

```bash
npm run dev
```

Health check (local):

```bash
curl http://localhost:3000/health
```

## Build & Production

Compile the project for production:

```bash
npm run build
```

Start the production server:

```bash
npm run start
```