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
44 changes: 44 additions & 0 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
name: CI

on:
pull_request:
branches: [ main ]
push:
branches: [ main ]

jobs:
server-tests:
runs-on: ubuntu-latest
steps:
- name: Checkout
uses: actions/checkout@v4

- name: Setup pnpm
uses: pnpm/action-setup@v4
with:
version: 10.5.0
run_install: false

- name: Get pnpm store directory
id: pnpm-store
shell: bash
run: echo "STORE_PATH=$(pnpm store path --silent)" >> $GITHUB_OUTPUT

- name: Setup pnpm cache
uses: actions/cache@v4
with:
path: ${{ steps.pnpm-store.outputs.STORE_PATH }}
key: ${{ runner.os }}-pnpm-store-${{ hashFiles('**/pnpm-lock.yaml') }}
restore-keys: |
${{ runner.os }}-pnpm-store-

- name: Setup Node.js
uses: actions/setup-node@v4
with:
node-version: '20'

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

- name: Run server tests
run: pnpm --filter server test
8 changes: 4 additions & 4 deletions apps/server/__tests__/call_agent_multiple_instances.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -26,9 +26,9 @@ describe('CallAgentTool configurable name', () => {
expect(dynDocs.name).toBe('call_agent_docs');
expect(dynOps.name).toBe('call_agent_ops');

const out1 = await dynDocs.invoke({ input: 'x' }, { configurable: { thread_id: 'p' } } as any);
const out2 = await dynOps.invoke({ input: 'y' }, { configurable: { thread_id: 'p' } } as any);
expect(out1).toContain('ok-p');
expect(out2).toContain('ok-p');
const out1 = await dynDocs.invoke({ input: 'x', childThreadId: 'docs' }, { configurable: { thread_id: 'p' } } as any);
const out2 = await dynOps.invoke({ input: 'y', childThreadId: 'ops' }, { configurable: { thread_id: 'p' } } as any);
expect(out1).toContain('ok-p__docs');
expect(out2).toContain('ok-p__ops');
});
});
20 changes: 14 additions & 6 deletions apps/server/__tests__/graph.mcp.integration.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,6 @@ import { ConfigService } from '../src/services/config.service';
import { SlackService } from '../src/services/slack.service';
import { CheckpointerService } from '../src/services/checkpointer.service';
import { LiveGraphRuntime, GraphDefinition } from '../src/graph';
import { MongoService } from '../src/services/mongo.service';

// This test only validates that the graph can wire the mcpServer node without throwing.
// It does not attempt to start a real filesystem MCP server (would require network/npm). Instead, we configure
Expand All @@ -22,7 +21,7 @@ function dockerAvailable() {
describe('Graph MCP integration', () => {
it('constructs graph with mcpServer template without error (deferred start)', async () => {
if (!dockerAvailable()) {
return; // skip silently
return; // skip silently when Docker likely unavailable
}

// Stub MCP server start & listTools to avoid requiring a real MCP server process for this wiring test.
Expand All @@ -36,7 +35,19 @@ describe('Graph MCP integration', () => {
return [];
};
const logger = new LoggerService();
const configService = ConfigService.fromEnv();

// Build a test ConfigService instance directly; no reliance on process.env
const configService = new ConfigService({
githubAppId: 'test',
githubAppPrivateKey: 'test',
githubInstallationId: 'test',
openaiApiKey: 'test',
githubToken: 'test',
slackBotToken: 'xoxb-test',
slackAppToken: 'xapp-test',
mongodbUrl: 'mongodb://localhost:27017/?replicaSet=rs0',
} as any);

const slackService = new SlackService(configService, logger);
const containerService = new ContainerService(logger);
const checkpointerService = new CheckpointerService(logger);
Expand All @@ -45,9 +56,6 @@ describe('Graph MCP integration', () => {
get: async () => undefined,
put: async () => undefined,
});
// minimal mongo stub (not connecting real db for test) - methods used in graph may be limited
const mongo = new MongoService(configService, logger);
// skip connect for integration-lite scenario

const templateRegistry = buildTemplateRegistry({
logger,
Expand Down