Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
26 commits
Select commit Hold shift + click to select a range
154a5a0
chore: developed basic MCP server for some APIs
prathameshy7 May 30, 2025
e6521be
chore: added more tools and refactored the code
prathameshy7 Jun 3, 2025
aa2aaf6
chore: added build to gitignore
prathameshy7 Jun 3, 2025
7f6993a
chore: removed mpc build from the remote push
prathameshy7 Jun 3, 2025
d4cc8ef
chore: removed mpc build from the remote push
prathameshy7 Jun 3, 2025
94b3044
chore: fetching checkmate base url and user token from env file
prathameshy7 Jun 3, 2025
419c206
Merge branch 'master' into chore/mcp-server
mayankkush1 Nov 19, 2025
98d4141
added new mcp server capabilities of CRUD
mayankkush1 Nov 20, 2025
a34d5ca
added mcp server for checkmate
mayankkush1 Nov 20, 2025
ed63aa9
changes
mayankkush1 Nov 24, 2025
2956d1d
restored env example
mayankkush1 Nov 24, 2025
7faaf30
Merge branch 'master' into chore/mcp-server
mayankkush1 Nov 24, 2025
d0b268a
added yarn
mayankkush1 Nov 24, 2025
fb0dd3e
Merge branch 'chore/mcp-server' of github.com:ds-horizon/checkmate in…
mayankkush1 Nov 24, 2025
8874612
Fixed types, testing pending
mayankkush1 Nov 24, 2025
fe49a38
updated
mayankkush1 Nov 24, 2025
04c27ae
fixed prettier issues:
mayankkush1 Nov 24, 2025
d9bbeb9
yarn changes
mayankkush1 Nov 24, 2025
9ab82a4
Fixed broken test cases
mayankkush1 Nov 24, 2025
59a2957
Removed useless files
mayankkush1 Nov 24, 2025
05c77fa
fixed docker file for mcp server
mayankkush1 Nov 24, 2025
0e70481
updated install script
mayankkush1 Nov 27, 2025
94cd927
fixed install script to manage mcp
mayankkush1 Nov 27, 2025
9f260a6
Merge branch 'master' into chore/mcp-server
mayankkush1 Nov 27, 2025
dc687dd
fixed yarn lock file
mayankkush1 Nov 27, 2025
b9b32e0
Merge branch 'chore/mcp-server' of github.com:ds-horizon/checkmate in…
mayankkush1 Nov 27, 2025
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
57 changes: 55 additions & 2 deletions .github/workflows/checks.yml
Original file line number Diff line number Diff line change
Expand Up @@ -19,12 +19,13 @@ jobs:
with:
node-version-file: '.nvmrc'

- name: Set up Yarn v4 (Berry)
- name: Set up Yarn
run: |
corepack enable
corepack prepare yarn@1.22.19 --activate

- name: Install dependencies
run: yarn install --immutable
run: yarn install --frozen-lockfile

- name: Run unit tests
run: yarn unit:test:coverage
Expand Down Expand Up @@ -90,3 +91,55 @@ jobs:
body: coverageMessage
});
}

mcp-server-test:
name: MCP Server Tests
runs-on: ubuntu-latest
defaults:
run:
working-directory: mcp-server

steps:
- name: Checkout code
uses: actions/checkout@v3
with:
ref: ${{ github.event.pull_request.head.sha }}
fetch-depth: 1

- name: Set up Node.js
uses: actions/setup-node@v3
with:
node-version-file: '.nvmrc'

- name: Set up Yarn
run: |
corepack enable
corepack prepare yarn@1.22.19 --activate

- name: Install dependencies
working-directory: mcp-server
run: yarn install --frozen-lockfile

- name: Run type check
working-directory: mcp-server
run: yarn typecheck

- name: Run linter
working-directory: mcp-server
run: yarn lint

- name: Check formatting
working-directory: mcp-server
run: yarn format:check

- name: Run tests
working-directory: mcp-server
run: yarn test
env:
NODE_ENV: test

- name: Run tests with coverage
working-directory: mcp-server
run: yarn test:coverage
env:
NODE_ENV: test
5 changes: 3 additions & 2 deletions .github/workflows/create-tag.yml
Original file line number Diff line number Diff line change
Expand Up @@ -23,12 +23,13 @@ jobs:
git config --global user.name "GitHub Actions Bot"
git config --global user.email "actions@github.com"

- name: Set up Yarn v4 (Berry)
- name: Set up Yarn
run: |
corepack enable
corepack prepare yarn@1.22.19 --activate

- name: Install dependencies
run: yarn install --immutable
run: yarn install --frozen-lockfile

- name: Extract version from config.json
id: extract_version
Expand Down
4 changes: 2 additions & 2 deletions .github/workflows/documentation-deployment.yml
Original file line number Diff line number Diff line change
Expand Up @@ -27,11 +27,11 @@ jobs:
- name: Enable Corepack and Set up Yarn
run: |
corepack enable
corepack prepare yarn@4.10.3 --activate
corepack prepare yarn@1.22.19 --activate

- name: Install Dependencies
working-directory: ./website
run: yarn install --immutable
run: yarn install --frozen-lockfile

- name: Build Docusaurus Website
working-directory: ./website
Expand Down
99 changes: 99 additions & 0 deletions .github/workflows/mcp-server.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,99 @@
name: MCP Server CI

on:
push:
branches: [ master, main ]
paths:
- 'mcp-server/**'
pull_request:
branches: [ master, main ]
paths:
- 'mcp-server/**'

defaults:
run:
working-directory: mcp-server

jobs:
test:
name: Test
runs-on: ubuntu-latest

strategy:
matrix:
node-version: [20.x] # Only test on Node 20

steps:
- uses: actions/checkout@v4

- name: Setup Node.js ${{ matrix.node-version }}
uses: actions/setup-node@v4
with:
node-version: ${{ matrix.node-version }}
cache: 'yarn'
cache-dependency-path: mcp-server/yarn.lock

- name: Set up Yarn
run: |
corepack enable
corepack prepare yarn@1.22.19 --activate

- name: Install dependencies
run: yarn install --frozen-lockfile

- name: Run type check
run: yarn typecheck

- name: Run linter
run: yarn lint

- name: Check formatting
run: yarn format:check

- name: Run tests
run: yarn test

- name: Run tests with coverage
run: yarn test:coverage

- name: Upload coverage to Codecov
uses: codecov/codecov-action@v4
with:
files: ./mcp-server/coverage/lcov.info
flags: mcp-server
name: mcp-server-coverage

build:
name: Build
runs-on: ubuntu-latest
needs: test

steps:
- uses: actions/checkout@v4

- name: Setup Node.js
uses: actions/setup-node@v4
with:
node-version: '20.x'
cache: 'yarn'
cache-dependency-path: mcp-server/yarn.lock

- name: Set up Yarn
run: |
corepack enable
corepack prepare yarn@1.22.19 --activate

- name: Install dependencies
run: yarn install --frozen-lockfile

- name: Build
run: yarn build

- name: Test built artifact
run: |
if [ ! -f build/index.js ]; then
echo "Build artifact not found!"
exit 1
fi
echo "Build successful!"

58 changes: 58 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -108,6 +108,64 @@ cd checkmate

[Postman](https://documenter.getpostman.com/view/23217307/2sAYXFgwRt) collection of APIs is currently available, comprehensive documentation is in progress.

### 🤖 MCP Server

Checkmate includes an [MCP (Model Context Protocol)](https://modelcontextprotocol.io/) server that allows AI assistants like Claude to interact with your Checkmate instance programmatically.

**Features:**
- ✅ Full API access through AI assistants
- ✅ Manage tests, projects, and runs via natural language
- ✅ Update test statuses and track progress
- ✅ Query test history and analytics
- ✅ TypeScript-based with full type safety
- ✅ Docker support for production deployment

**Local Development Setup:**

For local development, start both the app and MCP server together:

```bash
# Start Checkmate app and MCP server together
yarn dev:with-mcp
```

Or run separately:

```bash
# Terminal 1: Start Checkmate app
yarn dev

# Terminal 2: Start MCP server
yarn mcp:dev
```

**Prerequisites:**
1. Get your API token from Checkmate UI (User Settings → API Tokens → Generate Token)
2. Update `mcp-server/.env` with your token:
```env
CHECKMATE_API_BASE=http://localhost:3000
CHECKMATE_API_TOKEN=your-api-token-here
```

**Docker Deployment:**

```bash
# Start all services including MCP server
docker-compose up -d

# Check MCP server status
docker-compose ps checkmate-mcp

# View MCP server logs
docker-compose logs -f checkmate-mcp
```

**Documentation:**
- [MCP Server README](./mcp-server/README.md) - Complete setup and usage
- [Local Setup Guide](./mcp-server/LOCAL_SETUP.md) - Running MCP server locally
- [MCP Tools Guide](./website/docs/guides/api/mcp-tools.mdx) - Tool usage examples
- [Docker Deployment](./website/docs/project/mcp-docker.mdx) - Production deployment with Docker

### ⚙️ TechStack Used:

- <span style="display: flex; align-items: center;">
Expand Down
5 changes: 5 additions & 0 deletions app/routes/api/v1/__tests__/editProject.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,12 +9,14 @@ import {
responseHandler,
} from '~/routes/utilities/responseHandler'
import {getRequestParams} from '../../../utilities/utils'
import {checkProjectOwnership} from '~/routes/utilities/projectOwnership'
import {action} from '../editProject'

jest.mock('../../../utilities/utils')
jest.mock('@controllers/projects.controller')
jest.mock('~/routes/utilities/responseHandler')
jest.mock('~/routes/utilities/checkForUserAndAccess')
jest.mock('~/routes/utilities/projectOwnership')

describe('editProject action', () => {
const mockRequest = {
Expand Down Expand Up @@ -45,6 +47,7 @@ describe('editProject action', () => {
it('should update a project and return a successful response', async () => {
;(getUserAndCheckAccess as jest.Mock).mockResolvedValue(mockUser)
;(getRequestParams as jest.Mock).mockResolvedValue(mockData)
;(checkProjectOwnership as jest.Mock).mockResolvedValue({hasAccess: true})
;(ProjectsController.editProject as jest.Mock).mockResolvedValue(
mockUpdatedProjectResponse,
)
Expand Down Expand Up @@ -118,6 +121,7 @@ describe('editProject action', () => {

;(getUserAndCheckAccess as jest.Mock).mockResolvedValue(mockUser)
;(getRequestParams as jest.Mock).mockResolvedValue(mockData)
;(checkProjectOwnership as jest.Mock).mockResolvedValue({hasAccess: true})
;(ProjectsController.editProject as jest.Mock).mockRejectedValue(sqlError)
;(errorResponseHandler as jest.Mock).mockImplementation(
(response) => response,
Expand Down Expand Up @@ -146,6 +150,7 @@ describe('editProject action', () => {

;(getUserAndCheckAccess as jest.Mock).mockResolvedValue(mockUser)
;(getRequestParams as jest.Mock).mockResolvedValue(mockData)
;(checkProjectOwnership as jest.Mock).mockResolvedValue({hasAccess: true})
;(ProjectsController.editProject as jest.Mock).mockRejectedValue(
unexpectedError,
)
Expand Down
6 changes: 6 additions & 0 deletions app/routes/api/v1/__tests__/updateProjectStatus.test.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import {action} from '~/routes/api/v1/updateProjectStatus'
import ProjectsController from '@controllers/projects.controller'
import {getUserAndCheckAccess} from '~/routes/utilities/checkForUserAndAccess'
import {checkProjectOwnership} from '~/routes/utilities/projectOwnership'
import {responseHandler} from '~/routes/utilities/responseHandler'
import {
getRequestParams,
Expand All @@ -15,6 +16,7 @@ jest.mock('@controllers/projects.controller')
jest.mock('~/routes/utilities/responseHandler')
jest.mock('~/routes/utilities/checkForUserAndAccess')
jest.mock('~/routes/utilities/utils')
jest.mock('~/routes/utilities/projectOwnership')

describe('Update Project Status - Action Function', () => {
beforeEach(() => {
Expand All @@ -36,6 +38,7 @@ describe('Update Project Status - Action Function', () => {

;(getUserAndCheckAccess as jest.Mock).mockResolvedValue(mockUser)
;(getRequestParams as jest.Mock).mockResolvedValue(requestData)
;(checkProjectOwnership as jest.Mock).mockResolvedValue({hasAccess: true})
;(ProjectsController.updateProjectStatus as jest.Mock).mockResolvedValue(
mockResponse,
)
Expand Down Expand Up @@ -106,6 +109,7 @@ describe('Update Project Status - Action Function', () => {

;(getUserAndCheckAccess as jest.Mock).mockResolvedValue({userId: 456})
;(getRequestParams as jest.Mock).mockResolvedValue(requestData)
;(checkProjectOwnership as jest.Mock).mockResolvedValue({hasAccess: true})
;(ProjectsController.updateProjectStatus as jest.Mock).mockRejectedValue(
mockSqlError,
)
Expand Down Expand Up @@ -144,6 +148,7 @@ describe('Update Project Status - Action Function', () => {

;(getUserAndCheckAccess as jest.Mock).mockResolvedValue(mockUser)
;(getRequestParams as jest.Mock).mockResolvedValue(requestData)
;(checkProjectOwnership as jest.Mock).mockResolvedValue({hasAccess: true})
;(ProjectsController.updateProjectStatus as jest.Mock).mockResolvedValue(
mockResponse,
)
Expand Down Expand Up @@ -177,6 +182,7 @@ describe('Update Project Status - Action Function', () => {

;(getUserAndCheckAccess as jest.Mock).mockResolvedValue(undefined)
;(getRequestParams as jest.Mock).mockResolvedValue(requestData)
;(checkProjectOwnership as jest.Mock).mockResolvedValue({hasAccess: true})
;(ProjectsController.updateProjectStatus as jest.Mock).mockResolvedValue(
mockResponse,
)
Expand Down
15 changes: 15 additions & 0 deletions app/routes/api/v1/editProject.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ import {z} from 'zod'
import ProjectsController from '~/dataController/projects.controller'
import {API} from '~/routes/utilities/api'
import {getUserAndCheckAccess} from '~/routes/utilities/checkForUserAndAccess'
import {checkProjectOwnership} from '~/routes/utilities/projectOwnership'
import {
errorResponseHandler,
responseHandler,
Expand All @@ -29,6 +30,20 @@ export const action = async ({request}: ActionFunctionArgs) => {
EditProjectRequestSchema,
)

// Check project ownership
const ownershipCheck = await checkProjectOwnership({
projectId: data.projectId,
userId: user?.userId ?? 0,
userRole: user?.role ?? '',
})

if (!ownershipCheck.hasAccess) {
return responseHandler({
error: ownershipCheck.message || 'Access denied',
status: 403,
})
}

await ProjectsController.editProject({
...data,
userId: user?.userId ?? 0,
Expand Down
Loading