Skip to content
Open
Show file tree
Hide file tree
Changes from 2 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
3 changes: 3 additions & 0 deletions apps/jscpd-server/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -71,5 +71,8 @@
"typescript": "^5.9.3",
"vitest": "^4.1.9"
},
"optionalDependencies": {
"@blackwell-systems/gcf": "2.2.1"
},
"preferGlobal": true
}
4 changes: 4 additions & 0 deletions apps/jscpd-server/src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,10 @@ function initServerCli(packageJson: any, argv: string[]): Command {
.option(
"-H, --host [string]",
"host to bind the server to (Default is 0.0.0.0)",
)
.option(
"--gcf",
"Enable GCF output format for MCP tool responses (56% fewer tokens)",
);

addCommonOptions(cli);
Expand Down
9 changes: 5 additions & 4 deletions apps/jscpd-server/src/server/mcp-server.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
import { z } from "zod";
import { JscpdServerService } from "./service";
import { API_INFO } from "./constants";
import { serialize } from "./serialize";
Comment thread
coderabbitai[bot] marked this conversation as resolved.

export const createMcpServer = (service: JscpdServerService) => {
const server = new McpServer(
Expand Down Expand Up @@ -46,7 +47,7 @@ export const createMcpServer = (service: JscpdServerService) => {
content: [
{
type: "text",
text: JSON.stringify(result, null, 2),
text: serialize(result),
},
],
};
Expand Down Expand Up @@ -79,7 +80,7 @@ export const createMcpServer = (service: JscpdServerService) => {
content: [
{
type: "text",
text: JSON.stringify(stats, null, 2),
text: serialize(stats),
},
],
};
Expand Down Expand Up @@ -113,7 +114,7 @@ export const createMcpServer = (service: JscpdServerService) => {
content: [
{
type: "text",
text: JSON.stringify(statistics),
text: serialize(statistics),
},
],
};
Expand Down Expand Up @@ -145,7 +146,7 @@ export const createMcpServer = (service: JscpdServerService) => {
contents: [
{
uri: uri.href,
text: JSON.stringify(stats, null, 2),
text: serialize(stats),
},
],
};
Expand Down
51 changes: 51 additions & 0 deletions apps/jscpd-server/src/server/serialize.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
/**
* Optional GCF (Graph Compact Format) serialization for MCP tool responses.
*
* When enabled, structured data is encoded using GCF's tabular encoding
* instead of JSON, saving ~56% of tokens on duplication results.
*
* Enable via CLI flag: jscpd-server --gcf
* Or environment variable: JSCPD_OUTPUT_FORMAT=gcf
*
* Requires the optional @blackwell-systems/gcf package.
*/

let encodeGeneric: ((data: unknown) => string) | null = null;

try {
const gcf = await import("@blackwell-systems/gcf");
encodeGeneric = gcf.encodeGeneric;
} catch {
// GCF is an optional dependency
}

let gcfEnabled: boolean | null = null;

/**
* Check whether GCF output is enabled and available.
* Returns true only when the `--gcf` flag or `JSCPD_OUTPUT_FORMAT=gcf`
* env var is set AND the `@blackwell-systems/gcf` package is installed.
*/
export function isGcfEnabled(): boolean {
if (gcfEnabled === null) {
gcfEnabled =
process.env.JSCPD_OUTPUT_FORMAT === "gcf" ||
process.argv.includes("--gcf");
}
return gcfEnabled && encodeGeneric !== null;
}

/**
* Serialize data as JSON or GCF depending on configuration.
* Drop-in replacement for JSON.stringify(data, null, 2).
*/
export function serialize(data: unknown, indent = 2): string {
if (isGcfEnabled() && encodeGeneric) {
try {
return encodeGeneric(data);
} catch {
// Fall back to JSON on any encoding error
}
}
return JSON.stringify(data, null, indent);
}