mcpison 1.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (3) hide show
  1. package/README.md +74 -0
  2. package/bin/mcpison.js +139 -0
  3. package/package.json +31 -0
package/README.md ADDED
@@ -0,0 +1,74 @@
1
+ # mcpison - MCP to ISON Transport Proxy
2
+
3
+ `mcpison` 是一个透明的 MCP (Model Context Protocol) 传输层拦截代理。它可以将现有的 MCP Server (如返回包含庞大 JSON 数据的 `tools/call` 强结构) 的标准输出,实时转换为极端轻量级的 **ISON 格式**,大幅节约向大语言模型传输的 Token,且**无需修改任何原本的 MCP Server 代码**。
4
+
5
+ ## 核心特性
6
+
7
+ - **零侵入性**:直接包装现有的启动命令,无需向你的代码中引入任何依赖。
8
+ - **动态转换**:自动监听 MCP 特有的标准输入/输出流,解析 `tools/call` 并在响应时替换 JSON `text` 内容。
9
+ - **Token 节约**:借助 [ISON-format](https://github.com/ISON-format/ison),可以有效减少 JSON 在结构封套上浪费的无用 Token。
10
+
11
+ ## 安装
12
+
13
+ 可以通过全局安装此代理(或如果你已经将其构建):
14
+
15
+ ```bash
16
+ npm install -g mcpison
17
+ ```
18
+
19
+ *(或者在项目本地通过 `npm link` 建立全局命令以供测试)*
20
+
21
+ ## 使用方式
22
+
23
+ 只需在你当前使用的 MCP Client 配置文件(例如 Claude Desktop 的 `claude_desktop_config.json` 或 Cursor 的相关配置)中,在现有的 server 命令前垫加一层 `mcpison`:
24
+
25
+ ### 原始配置
26
+
27
+ ```json
28
+ "mcpServers": {
29
+ "my-sql-server": {
30
+ "command": "node",
31
+ "args": ["/path/to/sql-server.js"]
32
+ }
33
+ }
34
+ ```
35
+
36
+ ### 修改后配置 (加入了 `mcpison`)
37
+
38
+ ```json
39
+ "mcpServers": {
40
+ "my-sql-server": {
41
+ "command": "mcpison",
42
+ "args": ["node", "/path/to/sql-server.js"]
43
+ }
44
+ }
45
+ ```
46
+
47
+ > **注意:** `mcpison` 之后的内容就是你原本需要执行的子进程以及它需要的参数。
48
+
49
+ ## 调试模式 (Debug)
50
+
51
+ 如果你想要查看你具体节省了多少字节,可以加上 `--debug` 标志。
52
+
53
+ ```json
54
+ "mcpServers": {
55
+ "my-sql-server": {
56
+ "command": "mcpison",
57
+ "args": ["--debug", "node", "/path/to/sql-server.js"]
58
+ }
59
+ }
60
+ ```
61
+
62
+ MCP Client 的日志中(通常通过 `stderr` 重定向)可以实时打印如下信息:
63
+
64
+ ```
65
+ [mcpison DEBUG] Request ID 1001 Optimized: 395 bytes -> 240 bytes (Saved ~155 bytes)
66
+ ```
67
+
68
+
69
+ ## 测试
70
+
71
+ ```bash
72
+ node test/run-test.js
73
+ ```
74
+ 该测试会启动一个 Mock MCP Server,并向其发送 `tools/call` 以证明响应内容被正确转为了 ISON 格式。
package/bin/mcpison.js ADDED
@@ -0,0 +1,139 @@
1
+ #!/usr/bin/env node
2
+
3
+ const { spawn } = require('child_process');
4
+ const readline = require('readline');
5
+ const { jsonToISON } = require('ison-parser');
6
+
7
+ // 提取专属参数并保留传递给子进程的参数
8
+ const args = process.argv.slice(2);
9
+ let isDebug = false;
10
+
11
+ const spawnArgs = [];
12
+ for (let i = 0; i < args.length; i++) {
13
+ if (args[i] === '--debug') {
14
+ isDebug = true;
15
+ } else {
16
+ spawnArgs.push(args[i]);
17
+ }
18
+ }
19
+
20
+ if (spawnArgs.length === 0) {
21
+ console.error("Usage: mcpison [--debug] <command> [args...]");
22
+ process.exit(1);
23
+ }
24
+
25
+ const command = spawnArgs[0];
26
+ const commandArgs = spawnArgs.slice(1);
27
+
28
+ // 启动底层 MCP Server 子进程
29
+ const child = spawn(command, commandArgs, {
30
+ stdio: ['pipe', 'pipe', 'inherit'] // 将 stderr 直接透传给父进程
31
+ });
32
+
33
+ child.on('error', (err) => {
34
+ console.error(`Failed to start child process: ${err.message}`);
35
+ process.exit(1);
36
+ });
37
+
38
+ child.on('exit', (code, signal) => {
39
+ process.exit(code || Number(Boolean(signal)));
40
+ });
41
+
42
+ // 使用 readline 逐行处理 stdin (Client -> Proxy -> Server)
43
+ const rlStdin = readline.createInterface({
44
+ input: process.stdin,
45
+ output: null,
46
+ terminal: false
47
+ });
48
+
49
+ // 记录所有 Client 发送过来的 "tools/call" 请求的 ID
50
+ const pendingCallToolIds = new Set();
51
+
52
+ rlStdin.on('line', (line) => {
53
+ if (!line.trim()) return;
54
+
55
+ try {
56
+ const req = JSON.parse(line);
57
+ // 拦截识别 tools/call
58
+ if (req.method === 'tools/call' && req.id !== undefined) {
59
+ pendingCallToolIds.add(req.id);
60
+ }
61
+ } catch (err) {
62
+ // 不是合法 JSON,忽略
63
+ }
64
+
65
+ // 将请求原样转发给子进程
66
+ child.stdin.write(line + '\n');
67
+ });
68
+
69
+ rlStdin.on('close', () => {
70
+ child.stdin.end();
71
+ });
72
+
73
+ // 使用 readline 逐行处理 stdout (Server -> Proxy -> Client)
74
+ const rlStdout = readline.createInterface({
75
+ input: child.stdout,
76
+ output: null,
77
+ terminal: false
78
+ });
79
+
80
+ rlStdout.on('line', (line) => {
81
+ if (!line.trim()) {
82
+ process.stdout.write(line + '\n');
83
+ return;
84
+ }
85
+
86
+ try {
87
+ const res = JSON.parse(line);
88
+
89
+ // 检查是否是我们追踪的 call_tool 响应
90
+ if (res.id !== undefined && res.result && res.result.content && Array.isArray(res.result.content)) {
91
+ if (pendingCallToolIds.has(res.id)) {
92
+ // 这是 call_tool 响应,拦截并转换其中的 JSON text
93
+ let tokenSaved = 0;
94
+ let origLength = 0;
95
+ let newLength = 0;
96
+
97
+ for (let i = 0; i < res.result.content.length; i++) {
98
+ const item = res.result.content[i];
99
+ if (item.type === 'text' && typeof item.text === 'string') {
100
+ try {
101
+ // 尝试将里面的文本解析为 JSON 以便验证它确实是 JSON 数据
102
+ JSON.parse(item.text); // 进行验证
103
+ const isonStr = jsonToISON(item.text);
104
+
105
+ if (isDebug) {
106
+ origLength += item.text.length;
107
+ newLength += isonStr.length;
108
+ tokenSaved += (item.text.length - isonStr.length);
109
+ }
110
+
111
+ // 替换文本为 ISON
112
+ item.text = isonStr;
113
+ } catch (innerErr) {
114
+ // 内部文本不是标准 JSON,或者是简单的 String,不作转换
115
+ }
116
+ }
117
+ }
118
+
119
+ // 移除已经响应的请求 ID
120
+ pendingCallToolIds.delete(res.id);
121
+
122
+ if (isDebug && tokenSaved > 0) {
123
+ console.error(`[mcpison DEBUG] Request ID ${res.id} Optimized: ${origLength} bytes -> ${newLength} bytes (Saved ~${tokenSaved} bytes)`);
124
+ }
125
+
126
+ // 修改完后,将整个 JSON-RPC 对象重新序列化输出到 Client
127
+ process.stdout.write(JSON.stringify(res) + '\n');
128
+ return;
129
+ }
130
+ }
131
+
132
+ // 其他情况或者未命中的响应,原样输出
133
+ process.stdout.write(line + '\n');
134
+
135
+ } catch (err) {
136
+ // 解析失败(比如它输出了些非 JSON 调试信息),安全地将其原样透传
137
+ process.stdout.write(line + '\n');
138
+ }
139
+ });
package/package.json ADDED
@@ -0,0 +1,31 @@
1
+ {
2
+ "name": "mcpison",
3
+ "version": "1.0.0",
4
+ "description": "A minimal, token-efficient MCP transport interceptor converting JSON to ISON.",
5
+ "main": "bin/mcpison.js",
6
+ "bin": {
7
+ "mcpison": "bin/mcpison.js"
8
+ },
9
+ "files": [
10
+ "bin/mcpison.js"
11
+ ],
12
+ "scripts": {
13
+ "test": "node test/run-test.js"
14
+ },
15
+ "keywords": [
16
+ "mcp",
17
+ "ison",
18
+ "proxy",
19
+ "interceptor",
20
+ "token",
21
+ "jsonrpc"
22
+ ],
23
+ "author": "TRX",
24
+ "license": "MIT",
25
+ "dependencies": {
26
+ "ison-parser": "^1.0.0"
27
+ },
28
+ "engines": {
29
+ "node": ">=18.0.0"
30
+ }
31
+ }