Skip to content

Commit df74fa9

Browse files
authored
Merge pull request #34 from rollbar/brianr/fix-31-v2
Fix module loading; add e2e test
2 parents 8c971c1 + a6433e7 commit df74fa9

File tree

6 files changed

+555
-40
lines changed

6 files changed

+555
-40
lines changed

.github/workflows/ci.yml

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,6 @@
11
name: CI
22

33
on:
4-
push:
5-
branches: [ "**" ]
64
pull_request:
75

86
concurrency:
@@ -46,3 +44,5 @@ jobs:
4644

4745
- name: Run end-to-end tests
4846
run: npm run test:e2e
47+
env:
48+
ROLLBAR_E2E_READ_TOKEN: ${{ secrets.ROLLBAR_E2E_READ_TOKEN }}

package.json

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
{
22
"name": "@rollbar/mcp-server",
3-
"version": "0.2.0",
3+
"version": "0.2.1",
44
"description": "Model Context Protocol server for Rollbar",
55
"repository": {
66
"type": "git",
@@ -20,7 +20,7 @@
2020
"test": "vitest run",
2121
"test:watch": "vitest",
2222
"test:coverage": "vitest run --coverage",
23-
"test:e2e": "bash tests/e2e/test-npx-install.sh",
23+
"test:e2e": "bash tests/e2e/test-npx-install.sh && bash tests/e2e/test-get-item-details.sh",
2424
"prepublishOnly": "npm run build && npm test"
2525
},
2626
"files": [
@@ -38,7 +38,7 @@
3838
"author": "Rollbar, Inc.",
3939
"license": "MIT",
4040
"engines": {
41-
"node": ">=18"
41+
"node": ">=20"
4242
},
4343
"dependencies": {
4444
"@modelcontextprotocol/sdk": "^1.10.1",

src/utils/truncation.ts

Lines changed: 69 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,10 @@
11
import { createRequire } from "module";
22
import { dirname, join } from "path";
33

4-
// Import rollbar's truncation module using CommonJS require
4+
//
5+
// -- Import rollbar's truncation module using CommonJS require --
6+
//
7+
// TODO - remove this workaround once https://github.com/rollbar/rollbar.js/issues/1283 is fixed.
58
const require = createRequire(import.meta.url);
69

710
// Define types for the rollbar truncation module
@@ -13,21 +16,72 @@ interface RollbarTruncation {
1316
) => { value: string };
1417
}
1518

16-
// Load rollbar/src/truncation using require.
17-
// TODO - remove this workaround once https://github.com/rollbar/rollbar.js/issues/1283 is fixed.
18-
let truncation: RollbarTruncation;
19-
try {
20-
// First try the direct import (works when running from source)
21-
truncation = require("rollbar/src/truncation") as RollbarTruncation;
22-
} catch {
23-
// If that fails, resolve through the main module path
24-
// The main module is at rollbar/src/server/rollbar.js
25-
// So we need to go up to rollbar/src/ and then find truncation.js
26-
const rollbarPath = require.resolve("rollbar");
27-
const rollbarSrcDir = dirname(dirname(rollbarPath)); // Go up from src/server to src
28-
const truncationPath = join(rollbarSrcDir, "truncation.js");
29-
truncation = require(truncationPath) as RollbarTruncation;
19+
// Type for the loaded module which might be in various formats
20+
interface LoadedModule {
21+
truncate?: unknown;
22+
default?: unknown;
23+
__esModule?: boolean;
24+
[key: string]: unknown;
25+
}
26+
27+
// Since rollbar 3.0.0-alpha.2 doesn't export the truncation subpath,
28+
// we need to resolve through the main module path
29+
// The main module is at rollbar/src/server/rollbar.js
30+
// So we need to go up to rollbar/src/ and then find truncation.js
31+
const rollbarPath = require.resolve("rollbar");
32+
const rollbarSrcDir = dirname(dirname(rollbarPath)); // Go up from src/server to src
33+
const truncationPath = join(rollbarSrcDir, "truncation.js");
34+
35+
// Use dynamic import to handle the module properly
36+
// This is wrapped in an IIFE to handle the async nature
37+
/* c8 ignore start */
38+
let truncation: RollbarTruncation = {
39+
truncate: () => {
40+
throw new Error("Truncation not yet initialized");
41+
},
42+
};
43+
/* c8 ignore stop */
44+
45+
// Load the module synchronously using require
46+
const truncationModule = require(truncationPath) as LoadedModule;
47+
48+
// Handle different module formats
49+
// When TypeScript compiles and the output is loaded, we might get:
50+
// 1. Direct CommonJS exports: { truncate: fn, ... }
51+
// 2. Wrapped ES module: { __esModule: true, default: { truncate: fn, ... } }
52+
// 3. Other wrapper: { default: { truncate: fn, ... } }
53+
/* c8 ignore start */
54+
if (typeof truncationModule.truncate === "function") {
55+
// Direct CommonJS export
56+
truncation = truncationModule as RollbarTruncation;
57+
} else if (
58+
truncationModule.default &&
59+
typeof (truncationModule.default as LoadedModule).truncate === "function"
60+
) {
61+
// Wrapped with default export
62+
truncation = truncationModule.default as RollbarTruncation;
63+
} else if (truncationModule.__esModule && truncationModule.default) {
64+
// ES module interop
65+
truncation = truncationModule.default as RollbarTruncation;
66+
} else {
67+
// Last resort - try to find truncate function anywhere in the module
68+
for (const key of Object.keys(truncationModule)) {
69+
const value = truncationModule[key];
70+
if (
71+
value &&
72+
typeof value === "object" &&
73+
typeof (value as LoadedModule).truncate === "function"
74+
) {
75+
truncation = value as RollbarTruncation;
76+
break;
77+
}
78+
}
3079
}
80+
/* c8 ignore stop */
81+
82+
//
83+
// -- End workaround --
84+
//
3185

3286
// Token estimation constants
3387
const CHARS_PER_TOKEN = 4; // Rough estimate: 1 token ≈ 4 characters

tests/e2e/test-get-item-details.sh

Lines changed: 84 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,84 @@
1+
#!/bin/bash
2+
3+
# E2E test to verify get-item-details works via npx
4+
# Tests that the tool can be invoked without errors
5+
6+
set -e # Exit on error
7+
8+
echo "Starting E2E test for get-item-details via npx..."
9+
10+
# Colors for output
11+
RED='\033[0;31m'
12+
GREEN='\033[0;32m'
13+
YELLOW='\033[1;33m'
14+
NC='\033[0m' # No Color
15+
16+
# Get the project root directory
17+
PROJECT_ROOT="$(cd "$(dirname "$0")/../.." && pwd)"
18+
cd "$PROJECT_ROOT"
19+
20+
# Check if jq is available
21+
if ! command -v jq &> /dev/null; then
22+
echo -e "${RED}✗ jq is required for this test but not installed${NC}"
23+
exit 1
24+
fi
25+
26+
# Check if ROLLBAR_E2E_READ_TOKEN is set
27+
if [ -z "$ROLLBAR_E2E_READ_TOKEN" ]; then
28+
echo -e "${RED}✗ ROLLBAR_E2E_READ_TOKEN environment variable is required${NC}"
29+
exit 1
30+
fi
31+
32+
# Clean up function
33+
cleanup() {
34+
echo -e "${YELLOW}Cleaning up...${NC}"
35+
if [ -d "$TEMP_DIR" ]; then
36+
rm -rf "$TEMP_DIR"
37+
fi
38+
if [ -f "$TARBALL" ]; then
39+
rm -f "$TARBALL"
40+
fi
41+
if [ -f "test-output.json" ]; then
42+
rm -f test-output.json
43+
fi
44+
}
45+
46+
# Set up trap to clean up on exit
47+
trap cleanup EXIT
48+
49+
echo "Step 1: Building the package..."
50+
npm run build
51+
52+
echo "Step 2: Creating npm package tarball..."
53+
TARBALL=$(npm pack 2>&1 | tail -n 1)
54+
echo "Created tarball: $TARBALL"
55+
56+
echo "Step 3: Creating temporary test directory..."
57+
TEMP_DIR=$(mktemp -d)
58+
echo "Temp directory: $TEMP_DIR"
59+
60+
echo "Step 4: Testing get-item-details via npx..."
61+
cd "$TEMP_DIR"
62+
63+
# Copy the tarball to temp dir for npx to use
64+
cp "$PROJECT_ROOT/$TARBALL" .
65+
66+
echo "Running: npx -y @modelcontextprotocol/inspector --cli -e ROLLBAR_ACCESS_TOKEN=\$ROLLBAR_E2E_READ_TOKEN npx -y ./$TARBALL --method tools/call --tool-name get-item-details --tool-arg counter=8 --tool-arg max_tokens=100"
67+
68+
# Run the command and capture output
69+
npx -y @modelcontextprotocol/inspector --cli -e ROLLBAR_ACCESS_TOKEN=$ROLLBAR_E2E_READ_TOKEN npx -y ./$TARBALL --method tools/call --tool-name get-item-details --tool-arg counter=8 --tool-arg max_tokens=100 > test-output.json 2>&1
70+
71+
# Check the output using jq
72+
HAS_CONTENT=$(jq -r 'has("content")' test-output.json 2>/dev/null || echo "false")
73+
IS_ERROR=$(jq -r '.isError // false' test-output.json 2>/dev/null || echo "true")
74+
75+
if [ "$HAS_CONTENT" = "true" ] && [ "$IS_ERROR" = "false" ]; then
76+
echo -e "${GREEN}✓ E2E test passed!${NC}"
77+
echo "get-item-details works correctly via npx"
78+
exit 0
79+
else
80+
echo -e "${RED}✗ E2E test failed: Tool invocation returned an error${NC}"
81+
echo "Response:"
82+
cat test-output.json
83+
exit 1
84+
fi

0 commit comments

Comments
 (0)