@kontexted/mcp-cli 0.1.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.
- package/.github/CODEOWNERS +1 -0
- package/LICENSE +21 -0
- package/bun.lock +194 -0
- package/package.json +21 -0
- package/src/index.js +506 -0
|
@@ -0,0 +1 @@
|
|
|
1
|
+
* @danielbilek
|
package/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 Rabbyte
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
package/bun.lock
ADDED
|
@@ -0,0 +1,194 @@
|
|
|
1
|
+
{
|
|
2
|
+
"lockfileVersion": 1,
|
|
3
|
+
"configVersion": 1,
|
|
4
|
+
"workspaces": {
|
|
5
|
+
"": {
|
|
6
|
+
"name": "@kontexted/mcp-cli",
|
|
7
|
+
"dependencies": {
|
|
8
|
+
"@modelcontextprotocol/sdk": "^1.25.3",
|
|
9
|
+
"zod": "^4.3.5",
|
|
10
|
+
},
|
|
11
|
+
},
|
|
12
|
+
},
|
|
13
|
+
"packages": {
|
|
14
|
+
"@hono/node-server": ["@hono/node-server@1.19.9", "", { "peerDependencies": { "hono": "^4" } }, "sha512-vHL6w3ecZsky+8P5MD+eFfaGTyCeOHUIFYMGpQGbrBTSmNNoxv0if69rEZ5giu36weC5saFuznL411gRX7bJDw=="],
|
|
15
|
+
|
|
16
|
+
"@modelcontextprotocol/sdk": ["@modelcontextprotocol/sdk@1.25.3", "", { "dependencies": { "@hono/node-server": "^1.19.9", "ajv": "^8.17.1", "ajv-formats": "^3.0.1", "content-type": "^1.0.5", "cors": "^2.8.5", "cross-spawn": "^7.0.5", "eventsource": "^3.0.2", "eventsource-parser": "^3.0.0", "express": "^5.0.1", "express-rate-limit": "^7.5.0", "jose": "^6.1.1", "json-schema-typed": "^8.0.2", "pkce-challenge": "^5.0.0", "raw-body": "^3.0.0", "zod": "^3.25 || ^4.0", "zod-to-json-schema": "^3.25.0" }, "peerDependencies": { "@cfworker/json-schema": "^4.1.1" }, "optionalPeers": ["@cfworker/json-schema"] }, "sha512-vsAMBMERybvYgKbg/l4L1rhS7VXV1c0CtyJg72vwxONVX0l4ZfKVAnZEWTQixJGTzKnELjQ59e4NbdFDALRiAQ=="],
|
|
17
|
+
|
|
18
|
+
"accepts": ["accepts@2.0.0", "", { "dependencies": { "mime-types": "^3.0.0", "negotiator": "^1.0.0" } }, "sha512-5cvg6CtKwfgdmVqY1WIiXKc3Q1bkRqGLi+2W/6ao+6Y7gu/RCwRuAhGEzh5B4KlszSuTLgZYuqFqo5bImjNKng=="],
|
|
19
|
+
|
|
20
|
+
"ajv": ["ajv@8.17.1", "", { "dependencies": { "fast-deep-equal": "^3.1.3", "fast-uri": "^3.0.1", "json-schema-traverse": "^1.0.0", "require-from-string": "^2.0.2" } }, "sha512-B/gBuNg5SiMTrPkC+A2+cW0RszwxYmn6VYxB/inlBStS5nx6xHIt/ehKRhIMhqusl7a8LjQoZnjCs5vhwxOQ1g=="],
|
|
21
|
+
|
|
22
|
+
"ajv-formats": ["ajv-formats@3.0.1", "", { "dependencies": { "ajv": "^8.0.0" } }, "sha512-8iUql50EUR+uUcdRQ3HDqa6EVyo3docL8g5WJ3FNcWmu62IbkGUue/pEyLBW8VGKKucTPgqeks4fIU1DA4yowQ=="],
|
|
23
|
+
|
|
24
|
+
"body-parser": ["body-parser@2.2.2", "", { "dependencies": { "bytes": "^3.1.2", "content-type": "^1.0.5", "debug": "^4.4.3", "http-errors": "^2.0.0", "iconv-lite": "^0.7.0", "on-finished": "^2.4.1", "qs": "^6.14.1", "raw-body": "^3.0.1", "type-is": "^2.0.1" } }, "sha512-oP5VkATKlNwcgvxi0vM0p/D3n2C3EReYVX+DNYs5TjZFn/oQt2j+4sVJtSMr18pdRr8wjTcBl6LoV+FUwzPmNA=="],
|
|
25
|
+
|
|
26
|
+
"bytes": ["bytes@3.1.2", "", {}, "sha512-/Nf7TyzTx6S3yRJObOAV7956r8cr2+Oj8AC5dt8wSP3BQAoeX58NoHyCU8P8zGkNXStjTSi6fzO6F0pBdcYbEg=="],
|
|
27
|
+
|
|
28
|
+
"call-bind-apply-helpers": ["call-bind-apply-helpers@1.0.2", "", { "dependencies": { "es-errors": "^1.3.0", "function-bind": "^1.1.2" } }, "sha512-Sp1ablJ0ivDkSzjcaJdxEunN5/XvksFJ2sMBFfq6x0ryhQV/2b/KwFe21cMpmHtPOSij8K99/wSfoEuTObmuMQ=="],
|
|
29
|
+
|
|
30
|
+
"call-bound": ["call-bound@1.0.4", "", { "dependencies": { "call-bind-apply-helpers": "^1.0.2", "get-intrinsic": "^1.3.0" } }, "sha512-+ys997U96po4Kx/ABpBCqhA9EuxJaQWDQg7295H4hBphv3IZg0boBKuwYpt4YXp6MZ5AmZQnU/tyMTlRpaSejg=="],
|
|
31
|
+
|
|
32
|
+
"content-disposition": ["content-disposition@1.0.1", "", {}, "sha512-oIXISMynqSqm241k6kcQ5UwttDILMK4BiurCfGEREw6+X9jkkpEe5T9FZaApyLGGOnFuyMWZpdolTXMtvEJ08Q=="],
|
|
33
|
+
|
|
34
|
+
"content-type": ["content-type@1.0.5", "", {}, "sha512-nTjqfcBFEipKdXCv4YDQWCfmcLZKm81ldF0pAopTvyrFGVbcR6P/VAAd5G7N+0tTr8QqiU0tFadD6FK4NtJwOA=="],
|
|
35
|
+
|
|
36
|
+
"cookie": ["cookie@0.7.2", "", {}, "sha512-yki5XnKuf750l50uGTllt6kKILY4nQ1eNIQatoXEByZ5dWgnKqbnqmTrBE5B4N7lrMJKQ2ytWMiTO2o0v6Ew/w=="],
|
|
37
|
+
|
|
38
|
+
"cookie-signature": ["cookie-signature@1.2.2", "", {}, "sha512-D76uU73ulSXrD1UXF4KE2TMxVVwhsnCgfAyTg9k8P6KGZjlXKrOLe4dJQKI3Bxi5wjesZoFXJWElNWBjPZMbhg=="],
|
|
39
|
+
|
|
40
|
+
"cors": ["cors@2.8.5", "", { "dependencies": { "object-assign": "^4", "vary": "^1" } }, "sha512-KIHbLJqu73RGr/hnbrO9uBeixNGuvSQjul/jdFvS/KFSIH1hWVd1ng7zOHx+YrEfInLG7q4n6GHQ9cDtxv/P6g=="],
|
|
41
|
+
|
|
42
|
+
"cross-spawn": ["cross-spawn@7.0.6", "", { "dependencies": { "path-key": "^3.1.0", "shebang-command": "^2.0.0", "which": "^2.0.1" } }, "sha512-uV2QOWP2nWzsy2aMp8aRibhi9dlzF5Hgh5SHaB9OiTGEyDTiJJyx0uy51QXdyWbtAHNua4XJzUKca3OzKUd3vA=="],
|
|
43
|
+
|
|
44
|
+
"debug": ["debug@4.4.3", "", { "dependencies": { "ms": "^2.1.3" } }, "sha512-RGwwWnwQvkVfavKVt22FGLw+xYSdzARwm0ru6DhTVA3umU5hZc28V3kO4stgYryrTlLpuvgI9GiijltAjNbcqA=="],
|
|
45
|
+
|
|
46
|
+
"depd": ["depd@2.0.0", "", {}, "sha512-g7nH6P6dyDioJogAAGprGpCtVImJhpPk/roCzdb3fIh61/s/nPsfR6onyMwkCAR/OlC3yBC0lESvUoQEAssIrw=="],
|
|
47
|
+
|
|
48
|
+
"dunder-proto": ["dunder-proto@1.0.1", "", { "dependencies": { "call-bind-apply-helpers": "^1.0.1", "es-errors": "^1.3.0", "gopd": "^1.2.0" } }, "sha512-KIN/nDJBQRcXw0MLVhZE9iQHmG68qAVIBg9CqmUYjmQIhgij9U5MFvrqkUL5FbtyyzZuOeOt0zdeRe4UY7ct+A=="],
|
|
49
|
+
|
|
50
|
+
"ee-first": ["ee-first@1.1.1", "", {}, "sha512-WMwm9LhRUo+WUaRN+vRuETqG89IgZphVSNkdFgeb6sS/E4OrDIN7t48CAewSHXc6C8lefD8KKfr5vY61brQlow=="],
|
|
51
|
+
|
|
52
|
+
"encodeurl": ["encodeurl@2.0.0", "", {}, "sha512-Q0n9HRi4m6JuGIV1eFlmvJB7ZEVxu93IrMyiMsGC0lrMJMWzRgx6WGquyfQgZVb31vhGgXnfmPNNXmxnOkRBrg=="],
|
|
53
|
+
|
|
54
|
+
"es-define-property": ["es-define-property@1.0.1", "", {}, "sha512-e3nRfgfUZ4rNGL232gUgX06QNyyez04KdjFrF+LTRoOXmrOgFKDg4BCdsjW8EnT69eqdYGmRpJwiPVYNrCaW3g=="],
|
|
55
|
+
|
|
56
|
+
"es-errors": ["es-errors@1.3.0", "", {}, "sha512-Zf5H2Kxt2xjTvbJvP2ZWLEICxA6j+hAmMzIlypy4xcBg1vKVnx89Wy0GbS+kf5cwCVFFzdCFh2XSCFNULS6csw=="],
|
|
57
|
+
|
|
58
|
+
"es-object-atoms": ["es-object-atoms@1.1.1", "", { "dependencies": { "es-errors": "^1.3.0" } }, "sha512-FGgH2h8zKNim9ljj7dankFPcICIK9Cp5bm+c2gQSYePhpaG5+esrLODihIorn+Pe6FGJzWhXQotPv73jTaldXA=="],
|
|
59
|
+
|
|
60
|
+
"escape-html": ["escape-html@1.0.3", "", {}, "sha512-NiSupZ4OeuGwr68lGIeym/ksIZMJodUGOSCZ/FSnTxcrekbvqrgdUxlJOMpijaKZVjAJrWrGs/6Jy8OMuyj9ow=="],
|
|
61
|
+
|
|
62
|
+
"etag": ["etag@1.8.1", "", {}, "sha512-aIL5Fx7mawVa300al2BnEE4iNvo1qETxLrPI/o05L7z6go7fCw1J6EQmbK4FmJ2AS7kgVF/KEZWufBfdClMcPg=="],
|
|
63
|
+
|
|
64
|
+
"eventsource": ["eventsource@3.0.7", "", { "dependencies": { "eventsource-parser": "^3.0.1" } }, "sha512-CRT1WTyuQoD771GW56XEZFQ/ZoSfWid1alKGDYMmkt2yl8UXrVR4pspqWNEcqKvVIzg6PAltWjxcSSPrboA4iA=="],
|
|
65
|
+
|
|
66
|
+
"eventsource-parser": ["eventsource-parser@3.0.6", "", {}, "sha512-Vo1ab+QXPzZ4tCa8SwIHJFaSzy4R6SHf7BY79rFBDf0idraZWAkYrDjDj8uWaSm3S2TK+hJ7/t1CEmZ7jXw+pg=="],
|
|
67
|
+
|
|
68
|
+
"express": ["express@5.2.1", "", { "dependencies": { "accepts": "^2.0.0", "body-parser": "^2.2.1", "content-disposition": "^1.0.0", "content-type": "^1.0.5", "cookie": "^0.7.1", "cookie-signature": "^1.2.1", "debug": "^4.4.0", "depd": "^2.0.0", "encodeurl": "^2.0.0", "escape-html": "^1.0.3", "etag": "^1.8.1", "finalhandler": "^2.1.0", "fresh": "^2.0.0", "http-errors": "^2.0.0", "merge-descriptors": "^2.0.0", "mime-types": "^3.0.0", "on-finished": "^2.4.1", "once": "^1.4.0", "parseurl": "^1.3.3", "proxy-addr": "^2.0.7", "qs": "^6.14.0", "range-parser": "^1.2.1", "router": "^2.2.0", "send": "^1.1.0", "serve-static": "^2.2.0", "statuses": "^2.0.1", "type-is": "^2.0.1", "vary": "^1.1.2" } }, "sha512-hIS4idWWai69NezIdRt2xFVofaF4j+6INOpJlVOLDO8zXGpUVEVzIYk12UUi2JzjEzWL3IOAxcTubgz9Po0yXw=="],
|
|
69
|
+
|
|
70
|
+
"express-rate-limit": ["express-rate-limit@7.5.1", "", { "peerDependencies": { "express": ">= 4.11" } }, "sha512-7iN8iPMDzOMHPUYllBEsQdWVB6fPDMPqwjBaFrgr4Jgr/+okjvzAy+UHlYYL/Vs0OsOrMkwS6PJDkFlJwoxUnw=="],
|
|
71
|
+
|
|
72
|
+
"fast-deep-equal": ["fast-deep-equal@3.1.3", "", {}, "sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q=="],
|
|
73
|
+
|
|
74
|
+
"fast-uri": ["fast-uri@3.1.0", "", {}, "sha512-iPeeDKJSWf4IEOasVVrknXpaBV0IApz/gp7S2bb7Z4Lljbl2MGJRqInZiUrQwV16cpzw/D3S5j5Julj/gT52AA=="],
|
|
75
|
+
|
|
76
|
+
"finalhandler": ["finalhandler@2.1.1", "", { "dependencies": { "debug": "^4.4.0", "encodeurl": "^2.0.0", "escape-html": "^1.0.3", "on-finished": "^2.4.1", "parseurl": "^1.3.3", "statuses": "^2.0.1" } }, "sha512-S8KoZgRZN+a5rNwqTxlZZePjT/4cnm0ROV70LedRHZ0p8u9fRID0hJUZQpkKLzro8LfmC8sx23bY6tVNxv8pQA=="],
|
|
77
|
+
|
|
78
|
+
"forwarded": ["forwarded@0.2.0", "", {}, "sha512-buRG0fpBtRHSTCOASe6hD258tEubFoRLb4ZNA6NxMVHNw2gOcwHo9wyablzMzOA5z9xA9L1KNjk/Nt6MT9aYow=="],
|
|
79
|
+
|
|
80
|
+
"fresh": ["fresh@2.0.0", "", {}, "sha512-Rx/WycZ60HOaqLKAi6cHRKKI7zxWbJ31MhntmtwMoaTeF7XFH9hhBp8vITaMidfljRQ6eYWCKkaTK+ykVJHP2A=="],
|
|
81
|
+
|
|
82
|
+
"function-bind": ["function-bind@1.1.2", "", {}, "sha512-7XHNxH7qX9xG5mIwxkhumTox/MIRNcOgDrxWsMt2pAr23WHp6MrRlN7FBSFpCpr+oVO0F744iUgR82nJMfG2SA=="],
|
|
83
|
+
|
|
84
|
+
"get-intrinsic": ["get-intrinsic@1.3.0", "", { "dependencies": { "call-bind-apply-helpers": "^1.0.2", "es-define-property": "^1.0.1", "es-errors": "^1.3.0", "es-object-atoms": "^1.1.1", "function-bind": "^1.1.2", "get-proto": "^1.0.1", "gopd": "^1.2.0", "has-symbols": "^1.1.0", "hasown": "^2.0.2", "math-intrinsics": "^1.1.0" } }, "sha512-9fSjSaos/fRIVIp+xSJlE6lfwhES7LNtKaCBIamHsjr2na1BiABJPo0mOjjz8GJDURarmCPGqaiVg5mfjb98CQ=="],
|
|
85
|
+
|
|
86
|
+
"get-proto": ["get-proto@1.0.1", "", { "dependencies": { "dunder-proto": "^1.0.1", "es-object-atoms": "^1.0.0" } }, "sha512-sTSfBjoXBp89JvIKIefqw7U2CCebsc74kiY6awiGogKtoSGbgjYE/G/+l9sF3MWFPNc9IcoOC4ODfKHfxFmp0g=="],
|
|
87
|
+
|
|
88
|
+
"gopd": ["gopd@1.2.0", "", {}, "sha512-ZUKRh6/kUFoAiTAtTYPZJ3hw9wNxx+BIBOijnlG9PnrJsCcSjs1wyyD6vJpaYtgnzDrKYRSqf3OO6Rfa93xsRg=="],
|
|
89
|
+
|
|
90
|
+
"has-symbols": ["has-symbols@1.1.0", "", {}, "sha512-1cDNdwJ2Jaohmb3sg4OmKaMBwuC48sYni5HUw2DvsC8LjGTLK9h+eb1X6RyuOHe4hT0ULCW68iomhjUoKUqlPQ=="],
|
|
91
|
+
|
|
92
|
+
"hasown": ["hasown@2.0.2", "", { "dependencies": { "function-bind": "^1.1.2" } }, "sha512-0hJU9SCPvmMzIBdZFqNPXWa6dqh7WdH0cII9y+CyS8rG3nL48Bclra9HmKhVVUHyPWNH5Y7xDwAB7bfgSjkUMQ=="],
|
|
93
|
+
|
|
94
|
+
"hono": ["hono@4.11.5", "", {}, "sha512-WemPi9/WfyMwZs+ZUXdiwcCh9Y+m7L+8vki9MzDw3jJ+W9Lc+12HGsd368Qc1vZi1xwW8BWMMsnK5efYKPdt4g=="],
|
|
95
|
+
|
|
96
|
+
"http-errors": ["http-errors@2.0.1", "", { "dependencies": { "depd": "~2.0.0", "inherits": "~2.0.4", "setprototypeof": "~1.2.0", "statuses": "~2.0.2", "toidentifier": "~1.0.1" } }, "sha512-4FbRdAX+bSdmo4AUFuS0WNiPz8NgFt+r8ThgNWmlrjQjt1Q7ZR9+zTlce2859x4KSXrwIsaeTqDoKQmtP8pLmQ=="],
|
|
97
|
+
|
|
98
|
+
"iconv-lite": ["iconv-lite@0.7.2", "", { "dependencies": { "safer-buffer": ">= 2.1.2 < 3.0.0" } }, "sha512-im9DjEDQ55s9fL4EYzOAv0yMqmMBSZp6G0VvFyTMPKWxiSBHUj9NW/qqLmXUwXrrM7AvqSlTCfvqRb0cM8yYqw=="],
|
|
99
|
+
|
|
100
|
+
"inherits": ["inherits@2.0.4", "", {}, "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ=="],
|
|
101
|
+
|
|
102
|
+
"ipaddr.js": ["ipaddr.js@1.9.1", "", {}, "sha512-0KI/607xoxSToH7GjN1FfSbLoU0+btTicjsQSWQlh/hZykN8KpmMf7uYwPW3R+akZ6R/w18ZlXSHBYXiYUPO3g=="],
|
|
103
|
+
|
|
104
|
+
"is-promise": ["is-promise@4.0.0", "", {}, "sha512-hvpoI6korhJMnej285dSg6nu1+e6uxs7zG3BYAm5byqDsgJNWwxzM6z6iZiAgQR4TJ30JmBTOwqZUw3WlyH3AQ=="],
|
|
105
|
+
|
|
106
|
+
"isexe": ["isexe@2.0.0", "", {}, "sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw=="],
|
|
107
|
+
|
|
108
|
+
"jose": ["jose@6.1.3", "", {}, "sha512-0TpaTfihd4QMNwrz/ob2Bp7X04yuxJkjRGi4aKmOqwhov54i6u79oCv7T+C7lo70MKH6BesI3vscD1yb/yzKXQ=="],
|
|
109
|
+
|
|
110
|
+
"json-schema-traverse": ["json-schema-traverse@1.0.0", "", {}, "sha512-NM8/P9n3XjXhIZn1lLhkFaACTOURQXjWhV4BA/RnOv8xvgqtqpAX9IO4mRQxSx1Rlo4tqzeqb0sOlruaOy3dug=="],
|
|
111
|
+
|
|
112
|
+
"json-schema-typed": ["json-schema-typed@8.0.2", "", {}, "sha512-fQhoXdcvc3V28x7C7BMs4P5+kNlgUURe2jmUT1T//oBRMDrqy1QPelJimwZGo7Hg9VPV3EQV5Bnq4hbFy2vetA=="],
|
|
113
|
+
|
|
114
|
+
"math-intrinsics": ["math-intrinsics@1.1.0", "", {}, "sha512-/IXtbwEk5HTPyEwyKX6hGkYXxM9nbj64B+ilVJnC/R6B0pH5G4V3b0pVbL7DBj4tkhBAppbQUlf6F6Xl9LHu1g=="],
|
|
115
|
+
|
|
116
|
+
"media-typer": ["media-typer@1.1.0", "", {}, "sha512-aisnrDP4GNe06UcKFnV5bfMNPBUw4jsLGaWwWfnH3v02GnBuXX2MCVn5RbrWo0j3pczUilYblq7fQ7Nw2t5XKw=="],
|
|
117
|
+
|
|
118
|
+
"merge-descriptors": ["merge-descriptors@2.0.0", "", {}, "sha512-Snk314V5ayFLhp3fkUREub6WtjBfPdCPY1Ln8/8munuLuiYhsABgBVWsozAG+MWMbVEvcdcpbi9R7ww22l9Q3g=="],
|
|
119
|
+
|
|
120
|
+
"mime-db": ["mime-db@1.54.0", "", {}, "sha512-aU5EJuIN2WDemCcAp2vFBfp/m4EAhWJnUNSSw0ixs7/kXbd6Pg64EmwJkNdFhB8aWt1sH2CTXrLxo/iAGV3oPQ=="],
|
|
121
|
+
|
|
122
|
+
"mime-types": ["mime-types@3.0.2", "", { "dependencies": { "mime-db": "^1.54.0" } }, "sha512-Lbgzdk0h4juoQ9fCKXW4by0UJqj+nOOrI9MJ1sSj4nI8aI2eo1qmvQEie4VD1glsS250n15LsWsYtCugiStS5A=="],
|
|
123
|
+
|
|
124
|
+
"ms": ["ms@2.1.3", "", {}, "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA=="],
|
|
125
|
+
|
|
126
|
+
"negotiator": ["negotiator@1.0.0", "", {}, "sha512-8Ofs/AUQh8MaEcrlq5xOX0CQ9ypTF5dl78mjlMNfOK08fzpgTHQRQPBxcPlEtIw0yRpws+Zo/3r+5WRby7u3Gg=="],
|
|
127
|
+
|
|
128
|
+
"object-assign": ["object-assign@4.1.1", "", {}, "sha512-rJgTQnkUnH1sFw8yT6VSU3zD3sWmu6sZhIseY8VX+GRu3P6F7Fu+JNDoXfklElbLJSnc3FUQHVe4cU5hj+BcUg=="],
|
|
129
|
+
|
|
130
|
+
"object-inspect": ["object-inspect@1.13.4", "", {}, "sha512-W67iLl4J2EXEGTbfeHCffrjDfitvLANg0UlX3wFUUSTx92KXRFegMHUVgSqE+wvhAbi4WqjGg9czysTV2Epbew=="],
|
|
131
|
+
|
|
132
|
+
"on-finished": ["on-finished@2.4.1", "", { "dependencies": { "ee-first": "1.1.1" } }, "sha512-oVlzkg3ENAhCk2zdv7IJwd/QUD4z2RxRwpkcGY8psCVcCYZNq4wYnVWALHM+brtuJjePWiYF/ClmuDr8Ch5+kg=="],
|
|
133
|
+
|
|
134
|
+
"once": ["once@1.4.0", "", { "dependencies": { "wrappy": "1" } }, "sha512-lNaJgI+2Q5URQBkccEKHTQOPaXdUxnZZElQTZY0MFUAuaEqe1E+Nyvgdz/aIyNi6Z9MzO5dv1H8n58/GELp3+w=="],
|
|
135
|
+
|
|
136
|
+
"parseurl": ["parseurl@1.3.3", "", {}, "sha512-CiyeOxFT/JZyN5m0z9PfXw4SCBJ6Sygz1Dpl0wqjlhDEGGBP1GnsUVEL0p63hoG1fcj3fHynXi9NYO4nWOL+qQ=="],
|
|
137
|
+
|
|
138
|
+
"path-key": ["path-key@3.1.1", "", {}, "sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q=="],
|
|
139
|
+
|
|
140
|
+
"path-to-regexp": ["path-to-regexp@8.3.0", "", {}, "sha512-7jdwVIRtsP8MYpdXSwOS0YdD0Du+qOoF/AEPIt88PcCFrZCzx41oxku1jD88hZBwbNUIEfpqvuhjFaMAqMTWnA=="],
|
|
141
|
+
|
|
142
|
+
"pkce-challenge": ["pkce-challenge@5.0.1", "", {}, "sha512-wQ0b/W4Fr01qtpHlqSqspcj3EhBvimsdh0KlHhH8HRZnMsEa0ea2fTULOXOS9ccQr3om+GcGRk4e+isrZWV8qQ=="],
|
|
143
|
+
|
|
144
|
+
"proxy-addr": ["proxy-addr@2.0.7", "", { "dependencies": { "forwarded": "0.2.0", "ipaddr.js": "1.9.1" } }, "sha512-llQsMLSUDUPT44jdrU/O37qlnifitDP+ZwrmmZcoSKyLKvtZxpyV0n2/bD/N4tBAAZ/gJEdZU7KMraoK1+XYAg=="],
|
|
145
|
+
|
|
146
|
+
"qs": ["qs@6.14.1", "", { "dependencies": { "side-channel": "^1.1.0" } }, "sha512-4EK3+xJl8Ts67nLYNwqw/dsFVnCf+qR7RgXSK9jEEm9unao3njwMDdmsdvoKBKHzxd7tCYz5e5M+SnMjdtXGQQ=="],
|
|
147
|
+
|
|
148
|
+
"range-parser": ["range-parser@1.2.1", "", {}, "sha512-Hrgsx+orqoygnmhFbKaHE6c296J+HTAQXoxEF6gNupROmmGJRoyzfG3ccAveqCBrwr/2yxQ5BVd/GTl5agOwSg=="],
|
|
149
|
+
|
|
150
|
+
"raw-body": ["raw-body@3.0.2", "", { "dependencies": { "bytes": "~3.1.2", "http-errors": "~2.0.1", "iconv-lite": "~0.7.0", "unpipe": "~1.0.0" } }, "sha512-K5zQjDllxWkf7Z5xJdV0/B0WTNqx6vxG70zJE4N0kBs4LovmEYWJzQGxC9bS9RAKu3bgM40lrd5zoLJ12MQ5BA=="],
|
|
151
|
+
|
|
152
|
+
"require-from-string": ["require-from-string@2.0.2", "", {}, "sha512-Xf0nWe6RseziFMu+Ap9biiUbmplq6S9/p+7w7YXP/JBHhrUDDUhwa+vANyubuqfZWTveU//DYVGsDG7RKL/vEw=="],
|
|
153
|
+
|
|
154
|
+
"router": ["router@2.2.0", "", { "dependencies": { "debug": "^4.4.0", "depd": "^2.0.0", "is-promise": "^4.0.0", "parseurl": "^1.3.3", "path-to-regexp": "^8.0.0" } }, "sha512-nLTrUKm2UyiL7rlhapu/Zl45FwNgkZGaCpZbIHajDYgwlJCOzLSk+cIPAnsEqV955GjILJnKbdQC1nVPz+gAYQ=="],
|
|
155
|
+
|
|
156
|
+
"safer-buffer": ["safer-buffer@2.1.2", "", {}, "sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg=="],
|
|
157
|
+
|
|
158
|
+
"send": ["send@1.2.1", "", { "dependencies": { "debug": "^4.4.3", "encodeurl": "^2.0.0", "escape-html": "^1.0.3", "etag": "^1.8.1", "fresh": "^2.0.0", "http-errors": "^2.0.1", "mime-types": "^3.0.2", "ms": "^2.1.3", "on-finished": "^2.4.1", "range-parser": "^1.2.1", "statuses": "^2.0.2" } }, "sha512-1gnZf7DFcoIcajTjTwjwuDjzuz4PPcY2StKPlsGAQ1+YH20IRVrBaXSWmdjowTJ6u8Rc01PoYOGHXfP1mYcZNQ=="],
|
|
159
|
+
|
|
160
|
+
"serve-static": ["serve-static@2.2.1", "", { "dependencies": { "encodeurl": "^2.0.0", "escape-html": "^1.0.3", "parseurl": "^1.3.3", "send": "^1.2.0" } }, "sha512-xRXBn0pPqQTVQiC8wyQrKs2MOlX24zQ0POGaj0kultvoOCstBQM5yvOhAVSUwOMjQtTvsPWoNCHfPGwaaQJhTw=="],
|
|
161
|
+
|
|
162
|
+
"setprototypeof": ["setprototypeof@1.2.0", "", {}, "sha512-E5LDX7Wrp85Kil5bhZv46j8jOeboKq5JMmYM3gVGdGH8xFpPWXUMsNrlODCrkoxMEeNi/XZIwuRvY4XNwYMJpw=="],
|
|
163
|
+
|
|
164
|
+
"shebang-command": ["shebang-command@2.0.0", "", { "dependencies": { "shebang-regex": "^3.0.0" } }, "sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA=="],
|
|
165
|
+
|
|
166
|
+
"shebang-regex": ["shebang-regex@3.0.0", "", {}, "sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A=="],
|
|
167
|
+
|
|
168
|
+
"side-channel": ["side-channel@1.1.0", "", { "dependencies": { "es-errors": "^1.3.0", "object-inspect": "^1.13.3", "side-channel-list": "^1.0.0", "side-channel-map": "^1.0.1", "side-channel-weakmap": "^1.0.2" } }, "sha512-ZX99e6tRweoUXqR+VBrslhda51Nh5MTQwou5tnUDgbtyM0dBgmhEDtWGP/xbKn6hqfPRHujUNwz5fy/wbbhnpw=="],
|
|
169
|
+
|
|
170
|
+
"side-channel-list": ["side-channel-list@1.0.0", "", { "dependencies": { "es-errors": "^1.3.0", "object-inspect": "^1.13.3" } }, "sha512-FCLHtRD/gnpCiCHEiJLOwdmFP+wzCmDEkc9y7NsYxeF4u7Btsn1ZuwgwJGxImImHicJArLP4R0yX4c2KCrMrTA=="],
|
|
171
|
+
|
|
172
|
+
"side-channel-map": ["side-channel-map@1.0.1", "", { "dependencies": { "call-bound": "^1.0.2", "es-errors": "^1.3.0", "get-intrinsic": "^1.2.5", "object-inspect": "^1.13.3" } }, "sha512-VCjCNfgMsby3tTdo02nbjtM/ewra6jPHmpThenkTYh8pG9ucZ/1P8So4u4FGBek/BjpOVsDCMoLA/iuBKIFXRA=="],
|
|
173
|
+
|
|
174
|
+
"side-channel-weakmap": ["side-channel-weakmap@1.0.2", "", { "dependencies": { "call-bound": "^1.0.2", "es-errors": "^1.3.0", "get-intrinsic": "^1.2.5", "object-inspect": "^1.13.3", "side-channel-map": "^1.0.1" } }, "sha512-WPS/HvHQTYnHisLo9McqBHOJk2FkHO/tlpvldyrnem4aeQp4hai3gythswg6p01oSoTl58rcpiFAjF2br2Ak2A=="],
|
|
175
|
+
|
|
176
|
+
"statuses": ["statuses@2.0.2", "", {}, "sha512-DvEy55V3DB7uknRo+4iOGT5fP1slR8wQohVdknigZPMpMstaKJQWhwiYBACJE3Ul2pTnATihhBYnRhZQHGBiRw=="],
|
|
177
|
+
|
|
178
|
+
"toidentifier": ["toidentifier@1.0.1", "", {}, "sha512-o5sSPKEkg/DIQNmH43V0/uerLrpzVedkUh8tGNvaeXpfpuwjKenlSox/2O/BTlZUtEe+JG7s5YhEz608PlAHRA=="],
|
|
179
|
+
|
|
180
|
+
"type-is": ["type-is@2.0.1", "", { "dependencies": { "content-type": "^1.0.5", "media-typer": "^1.1.0", "mime-types": "^3.0.0" } }, "sha512-OZs6gsjF4vMp32qrCbiVSkrFmXtG/AZhY3t0iAMrMBiAZyV9oALtXO8hsrHbMXF9x6L3grlFuwW2oAz7cav+Gw=="],
|
|
181
|
+
|
|
182
|
+
"unpipe": ["unpipe@1.0.0", "", {}, "sha512-pjy2bYhSsufwWlKwPc+l3cN7+wuJlK6uz0YdJEOlQDbl6jo/YlPi4mb8agUkVC8BF7V8NuzeyPNqRksA3hztKQ=="],
|
|
183
|
+
|
|
184
|
+
"vary": ["vary@1.1.2", "", {}, "sha512-BNGbWLfd0eUPabhkXUVm0j8uuvREyTh5ovRa/dyow/BqAbZJyC+5fU+IzQOzmAKzYqYRAISoRhdQr3eIZ/PXqg=="],
|
|
185
|
+
|
|
186
|
+
"which": ["which@2.0.2", "", { "dependencies": { "isexe": "^2.0.0" }, "bin": { "node-which": "./bin/node-which" } }, "sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA=="],
|
|
187
|
+
|
|
188
|
+
"wrappy": ["wrappy@1.0.2", "", {}, "sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ=="],
|
|
189
|
+
|
|
190
|
+
"zod": ["zod@4.3.5", "", {}, "sha512-k7Nwx6vuWx1IJ9Bjuf4Zt1PEllcwe7cls3VNzm4CQ1/hgtFUK2bRNG3rvnpPUhFjmqJKAKtjV576KnUkHocg/g=="],
|
|
191
|
+
|
|
192
|
+
"zod-to-json-schema": ["zod-to-json-schema@3.25.1", "", { "peerDependencies": { "zod": "^3.25 || ^4" } }, "sha512-pM/SU9d3YAggzi6MtR4h7ruuQlqKtad8e9S0fmxcMi+ueAK5Korys/aWcV9LIIHTVbj01NdzxcnXSN+O74ZIVA=="],
|
|
193
|
+
}
|
|
194
|
+
}
|
package/package.json
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@kontexted/mcp-cli",
|
|
3
|
+
"version": "0.1.0",
|
|
4
|
+
"type": "module",
|
|
5
|
+
"repository": {
|
|
6
|
+
"type": "git",
|
|
7
|
+
"url": "https://github.com/kontexted/kontexted-mcp-cli"
|
|
8
|
+
},
|
|
9
|
+
"license": "MIT",
|
|
10
|
+
"bin": {
|
|
11
|
+
"kontexted-mcp": "./src/index.js"
|
|
12
|
+
},
|
|
13
|
+
"scripts": {
|
|
14
|
+
"start": "bun src/index.js",
|
|
15
|
+
"build": "bun build --compile --outfile dist/kontexted-mcp src/index.js"
|
|
16
|
+
},
|
|
17
|
+
"dependencies": {
|
|
18
|
+
"@modelcontextprotocol/sdk": "^1.25.3",
|
|
19
|
+
"zod": "^4.3.5"
|
|
20
|
+
}
|
|
21
|
+
}
|
package/src/index.js
ADDED
|
@@ -0,0 +1,506 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
import { createServer } from "node:http";
|
|
3
|
+
import { exec } from "node:child_process";
|
|
4
|
+
import { mkdir, readFile, rm, writeFile } from "node:fs/promises";
|
|
5
|
+
import { homedir } from "node:os";
|
|
6
|
+
import { dirname, join } from "node:path";
|
|
7
|
+
import process from "node:process";
|
|
8
|
+
import { URL } from "node:url";
|
|
9
|
+
|
|
10
|
+
import { Client } from "@modelcontextprotocol/sdk/client/index.js";
|
|
11
|
+
import { UnauthorizedError } from "@modelcontextprotocol/sdk/client/auth.js";
|
|
12
|
+
import { StreamableHTTPClientTransport } from "@modelcontextprotocol/sdk/client/streamableHttp.js";
|
|
13
|
+
import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
|
|
14
|
+
import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio.js";
|
|
15
|
+
import { z } from "zod";
|
|
16
|
+
|
|
17
|
+
const CONFIG_PATH = join(homedir(), ".kontexted", "mcp.json");
|
|
18
|
+
const CALLBACK_PORT = 8788;
|
|
19
|
+
const CALLBACK_URL = `http://localhost:${CALLBACK_PORT}/callback`;
|
|
20
|
+
|
|
21
|
+
const DEFAULT_CLIENT_METADATA = {
|
|
22
|
+
client_name: "Kontexted MCP CLI",
|
|
23
|
+
redirect_uris: [CALLBACK_URL],
|
|
24
|
+
grant_types: ["authorization_code", "refresh_token"],
|
|
25
|
+
response_types: ["code"],
|
|
26
|
+
token_endpoint_auth_method: "client_secret_post",
|
|
27
|
+
};
|
|
28
|
+
|
|
29
|
+
const parseArgs = (argv) => {
|
|
30
|
+
const args = {
|
|
31
|
+
command: undefined,
|
|
32
|
+
url: undefined,
|
|
33
|
+
workspace: undefined,
|
|
34
|
+
alias: undefined,
|
|
35
|
+
write: undefined,
|
|
36
|
+
writeOff: false,
|
|
37
|
+
};
|
|
38
|
+
|
|
39
|
+
const flags = new Set(["--url", "--workspace", "--alias", "--write", "--write-off", "--help"]);
|
|
40
|
+
const commands = new Set(["login", "logout", "show-config"]);
|
|
41
|
+
|
|
42
|
+
for (let index = 2; index < argv.length; index += 1) {
|
|
43
|
+
const arg = argv[index];
|
|
44
|
+
|
|
45
|
+
if (arg === "--help" || arg === "-h") {
|
|
46
|
+
args.help = true;
|
|
47
|
+
} else if (arg === "--url") {
|
|
48
|
+
args.url = argv[index + 1];
|
|
49
|
+
index += 1;
|
|
50
|
+
} else if (arg === "--workspace") {
|
|
51
|
+
args.workspace = argv[index + 1];
|
|
52
|
+
index += 1;
|
|
53
|
+
} else if (arg === "--alias") {
|
|
54
|
+
args.alias = argv[index + 1];
|
|
55
|
+
index += 1;
|
|
56
|
+
} else if (arg === "--write") {
|
|
57
|
+
args.write = true;
|
|
58
|
+
} else if (arg === "--write-off") {
|
|
59
|
+
args.writeOff = true;
|
|
60
|
+
} else if (commands.has(arg)) {
|
|
61
|
+
args.command = arg;
|
|
62
|
+
} else if (arg.startsWith("--")) {
|
|
63
|
+
throw new Error(`Unknown flag: ${arg}`);
|
|
64
|
+
}
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
return args;
|
|
68
|
+
};
|
|
69
|
+
|
|
70
|
+
const readConfig = async () => {
|
|
71
|
+
try {
|
|
72
|
+
const raw = await readFile(CONFIG_PATH, "utf8");
|
|
73
|
+
const parsed = JSON.parse(raw);
|
|
74
|
+
if (!parsed || typeof parsed !== "object") {
|
|
75
|
+
return { profiles: {} };
|
|
76
|
+
}
|
|
77
|
+
return parsed.profiles ? { profiles: parsed.profiles } : { profiles: {} };
|
|
78
|
+
} catch (error) {
|
|
79
|
+
if (error && typeof error === "object" && "code" in error && error.code === "ENOENT") {
|
|
80
|
+
return { profiles: {} };
|
|
81
|
+
}
|
|
82
|
+
throw error;
|
|
83
|
+
}
|
|
84
|
+
};
|
|
85
|
+
|
|
86
|
+
const writeConfig = async (config) => {
|
|
87
|
+
await mkdir(dirname(CONFIG_PATH), { recursive: true });
|
|
88
|
+
await writeFile(CONFIG_PATH, JSON.stringify(config, null, 2));
|
|
89
|
+
};
|
|
90
|
+
|
|
91
|
+
const getProfile = (config, aliasOrWorkspace) => {
|
|
92
|
+
if (config.profiles[aliasOrWorkspace]) {
|
|
93
|
+
return config.profiles[aliasOrWorkspace];
|
|
94
|
+
}
|
|
95
|
+
for (const profile of Object.values(config.profiles)) {
|
|
96
|
+
if (profile.workspace === aliasOrWorkspace) {
|
|
97
|
+
return profile;
|
|
98
|
+
}
|
|
99
|
+
}
|
|
100
|
+
return null;
|
|
101
|
+
};
|
|
102
|
+
|
|
103
|
+
const addProfile = (config, key, profile) => {
|
|
104
|
+
config.profiles[key] = profile;
|
|
105
|
+
};
|
|
106
|
+
|
|
107
|
+
const removeProfile = (config, key) => {
|
|
108
|
+
delete config.profiles[key];
|
|
109
|
+
};
|
|
110
|
+
|
|
111
|
+
const openBrowser = (url) => {
|
|
112
|
+
const platform = process.platform;
|
|
113
|
+
const command =
|
|
114
|
+
platform === "darwin"
|
|
115
|
+
? `open "${url}"`
|
|
116
|
+
: platform === "win32"
|
|
117
|
+
? `start "" "${url}"`
|
|
118
|
+
: `xdg-open "${url}"`;
|
|
119
|
+
exec(command, (error) => {
|
|
120
|
+
if (error) {
|
|
121
|
+
console.error(`Failed to open browser: ${error.message}`);
|
|
122
|
+
console.error(`Open this URL manually: ${url}`);
|
|
123
|
+
}
|
|
124
|
+
});
|
|
125
|
+
};
|
|
126
|
+
|
|
127
|
+
const waitForOAuthCallback = () =>
|
|
128
|
+
new Promise((resolve, reject) => {
|
|
129
|
+
const server = createServer((req, res) => {
|
|
130
|
+
if (req.url === "/favicon.ico") {
|
|
131
|
+
res.writeHead(404);
|
|
132
|
+
res.end();
|
|
133
|
+
return;
|
|
134
|
+
}
|
|
135
|
+
const parsedUrl = new URL(req.url ?? "", "http://localhost");
|
|
136
|
+
const code = parsedUrl.searchParams.get("code");
|
|
137
|
+
const error = parsedUrl.searchParams.get("error");
|
|
138
|
+
|
|
139
|
+
if (code) {
|
|
140
|
+
res.writeHead(200, { "Content-Type": "text/html" });
|
|
141
|
+
res.end("<p>Authorization complete. You can close this window.</p>");
|
|
142
|
+
resolve(code);
|
|
143
|
+
setTimeout(() => server.close(), 500);
|
|
144
|
+
return;
|
|
145
|
+
}
|
|
146
|
+
|
|
147
|
+
if (error) {
|
|
148
|
+
res.writeHead(400, { "Content-Type": "text/html" });
|
|
149
|
+
res.end(`<p>Authorization failed: ${error}</p>`);
|
|
150
|
+
reject(new Error(`OAuth authorization failed: ${error}`));
|
|
151
|
+
setTimeout(() => server.close(), 500);
|
|
152
|
+
return;
|
|
153
|
+
}
|
|
154
|
+
|
|
155
|
+
res.writeHead(400, { "Content-Type": "text/plain" });
|
|
156
|
+
res.end("Missing authorization code.");
|
|
157
|
+
reject(new Error("Missing authorization code."));
|
|
158
|
+
setTimeout(() => server.close(), 500);
|
|
159
|
+
});
|
|
160
|
+
|
|
161
|
+
server.listen(CALLBACK_PORT, () => {
|
|
162
|
+
console.log(`Waiting for OAuth callback on ${CALLBACK_URL}`);
|
|
163
|
+
});
|
|
164
|
+
});
|
|
165
|
+
|
|
166
|
+
const createOAuthProvider = (oauth, persist) => {
|
|
167
|
+
const provider = {
|
|
168
|
+
get redirectUrl() {
|
|
169
|
+
return oauth?.redirectUrl ?? CALLBACK_URL;
|
|
170
|
+
},
|
|
171
|
+
get clientMetadata() {
|
|
172
|
+
return oauth?.clientMetadata ?? DEFAULT_CLIENT_METADATA;
|
|
173
|
+
},
|
|
174
|
+
clientInformation() {
|
|
175
|
+
return oauth?.clientInformation;
|
|
176
|
+
},
|
|
177
|
+
async saveClientInformation(clientInformation) {
|
|
178
|
+
oauth.clientInformation = clientInformation;
|
|
179
|
+
await persist();
|
|
180
|
+
},
|
|
181
|
+
tokens() {
|
|
182
|
+
return oauth?.tokens;
|
|
183
|
+
},
|
|
184
|
+
async saveTokens(tokens) {
|
|
185
|
+
oauth.tokens = tokens;
|
|
186
|
+
await persist();
|
|
187
|
+
},
|
|
188
|
+
redirectToAuthorization(authorizationUrl) {
|
|
189
|
+
console.log("Opening browser for OAuth...");
|
|
190
|
+
openBrowser(authorizationUrl.toString());
|
|
191
|
+
},
|
|
192
|
+
async saveCodeVerifier(codeVerifier) {
|
|
193
|
+
oauth.codeVerifier = codeVerifier;
|
|
194
|
+
await persist();
|
|
195
|
+
},
|
|
196
|
+
codeVerifier() {
|
|
197
|
+
if (!oauth?.codeVerifier) {
|
|
198
|
+
throw new Error("Missing PKCE code verifier.");
|
|
199
|
+
}
|
|
200
|
+
return oauth.codeVerifier;
|
|
201
|
+
},
|
|
202
|
+
async invalidateCredentials(scope) {
|
|
203
|
+
if (!oauth) {
|
|
204
|
+
return;
|
|
205
|
+
}
|
|
206
|
+
if (scope === "tokens") {
|
|
207
|
+
delete oauth.tokens;
|
|
208
|
+
} else if (scope === "client") {
|
|
209
|
+
delete oauth.clientInformation;
|
|
210
|
+
} else if (scope === "verifier") {
|
|
211
|
+
delete oauth.codeVerifier;
|
|
212
|
+
} else {
|
|
213
|
+
return;
|
|
214
|
+
}
|
|
215
|
+
await persist();
|
|
216
|
+
},
|
|
217
|
+
};
|
|
218
|
+
|
|
219
|
+
return provider;
|
|
220
|
+
};
|
|
221
|
+
|
|
222
|
+
const connectRemoteClient = async (serverUrl, oauth, persist, { allowInteractive }) => {
|
|
223
|
+
const oauthProvider = createOAuthProvider(oauth, persist);
|
|
224
|
+
|
|
225
|
+
const client = new Client({ name: "kontexted-mcp-cli", version: "0.1.0" });
|
|
226
|
+
|
|
227
|
+
const createTransport = () =>
|
|
228
|
+
new StreamableHTTPClientTransport(new URL(serverUrl), {
|
|
229
|
+
authProvider: oauthProvider,
|
|
230
|
+
});
|
|
231
|
+
|
|
232
|
+
let transport = createTransport();
|
|
233
|
+
|
|
234
|
+
try {
|
|
235
|
+
await client.connect(transport);
|
|
236
|
+
} catch (error) {
|
|
237
|
+
if (error instanceof UnauthorizedError) {
|
|
238
|
+
if (!allowInteractive) {
|
|
239
|
+
throw error;
|
|
240
|
+
}
|
|
241
|
+
const authCode = await waitForOAuthCallback();
|
|
242
|
+
await transport.finishAuth(authCode);
|
|
243
|
+
await transport.close();
|
|
244
|
+
transport = createTransport();
|
|
245
|
+
await client.connect(transport);
|
|
246
|
+
} else {
|
|
247
|
+
throw error;
|
|
248
|
+
}
|
|
249
|
+
}
|
|
250
|
+
|
|
251
|
+
return { client, transport };
|
|
252
|
+
};
|
|
253
|
+
|
|
254
|
+
const removeWorkspaceSlugFromSchema = (jsonSchema) => {
|
|
255
|
+
if (!jsonSchema || typeof jsonSchema !== "object") return z.object({});
|
|
256
|
+
|
|
257
|
+
const properties = jsonSchema.properties ?? {};
|
|
258
|
+
const required = new Set(jsonSchema.required ?? []);
|
|
259
|
+
|
|
260
|
+
const { workspaceSlug, ...otherProperties } = properties;
|
|
261
|
+
|
|
262
|
+
const shape = {};
|
|
263
|
+
for (const [key, propSchema] of Object.entries(otherProperties)) {
|
|
264
|
+
if (propSchema?.type === "string") {
|
|
265
|
+
shape[key] = z.string();
|
|
266
|
+
if (propSchema.minLength === 1) shape[key] = shape[key].min(1);
|
|
267
|
+
} else if (propSchema?.type === "integer") {
|
|
268
|
+
shape[key] = z.number().int();
|
|
269
|
+
if (propSchema.exclusiveMinimum === 0) shape[key] = shape[key].positive();
|
|
270
|
+
if (propSchema.minimum !== undefined) shape[key] = shape[key].min(propSchema.minimum);
|
|
271
|
+
if (propSchema.maximum !== undefined) shape[key] = shape[key].max(propSchema.maximum);
|
|
272
|
+
} else {
|
|
273
|
+
shape[key] = z.any();
|
|
274
|
+
}
|
|
275
|
+
|
|
276
|
+
if (!required.has(key)) {
|
|
277
|
+
shape[key] = shape[key].optional();
|
|
278
|
+
}
|
|
279
|
+
}
|
|
280
|
+
|
|
281
|
+
return z.object(shape);
|
|
282
|
+
};
|
|
283
|
+
|
|
284
|
+
const WRITE_TOOLS = new Set(["createFolder", "createNote"]);
|
|
285
|
+
|
|
286
|
+
const startProxyServer = async (args) => {
|
|
287
|
+
const config = await readConfig();
|
|
288
|
+
|
|
289
|
+
const profileKey = args.alias ?? args.workspace;
|
|
290
|
+
if (!profileKey) {
|
|
291
|
+
throw new Error("Missing --alias or --workspace. Required for MCP mode.");
|
|
292
|
+
}
|
|
293
|
+
|
|
294
|
+
if (args.write && args.writeOff) {
|
|
295
|
+
throw new Error("Cannot specify both --write and --write-off");
|
|
296
|
+
}
|
|
297
|
+
|
|
298
|
+
const profile = getProfile(config, profileKey);
|
|
299
|
+
if (!profile) {
|
|
300
|
+
throw new Error(`Profile not found: ${profileKey}. Run 'kontexted-mcp login' first.`);
|
|
301
|
+
}
|
|
302
|
+
|
|
303
|
+
let writeEnabled = profile.write ?? false;
|
|
304
|
+
if (args.write) {
|
|
305
|
+
writeEnabled = true;
|
|
306
|
+
} else if (args.writeOff) {
|
|
307
|
+
writeEnabled = false;
|
|
308
|
+
}
|
|
309
|
+
|
|
310
|
+
const persist = async () => {
|
|
311
|
+
await writeConfig(config);
|
|
312
|
+
};
|
|
313
|
+
|
|
314
|
+
const { client } = await connectRemoteClient(profile.serverUrl, profile.oauth, persist, {
|
|
315
|
+
allowInteractive: false,
|
|
316
|
+
});
|
|
317
|
+
|
|
318
|
+
const toolList = await client.listTools();
|
|
319
|
+
const server = new McpServer({ name: "kontexted-mcp", version: "0.1.0" });
|
|
320
|
+
|
|
321
|
+
toolList.tools
|
|
322
|
+
.filter((tool) => {
|
|
323
|
+
if (writeEnabled) {
|
|
324
|
+
return true;
|
|
325
|
+
}
|
|
326
|
+
return !WRITE_TOOLS.has(tool.name);
|
|
327
|
+
})
|
|
328
|
+
.forEach((tool) => {
|
|
329
|
+
const inputSchemaWithoutWorkspace = removeWorkspaceSlugFromSchema(tool.inputSchema);
|
|
330
|
+
|
|
331
|
+
server.registerTool(
|
|
332
|
+
tool.name,
|
|
333
|
+
{
|
|
334
|
+
title: tool.title,
|
|
335
|
+
description: tool.description ?? "",
|
|
336
|
+
inputSchema: inputSchemaWithoutWorkspace,
|
|
337
|
+
},
|
|
338
|
+
async (args) => {
|
|
339
|
+
const finalArgs = { workspaceSlug: profile.workspace, ...(args ?? {}) };
|
|
340
|
+
return client.callTool({ name: tool.name, arguments: finalArgs });
|
|
341
|
+
}
|
|
342
|
+
);
|
|
343
|
+
});
|
|
344
|
+
|
|
345
|
+
const transport = new StdioServerTransport();
|
|
346
|
+
await server.connect(transport);
|
|
347
|
+
|
|
348
|
+
process.on("SIGINT", async () => {
|
|
349
|
+
await client.close();
|
|
350
|
+
await server.close();
|
|
351
|
+
process.exit(0);
|
|
352
|
+
});
|
|
353
|
+
};
|
|
354
|
+
|
|
355
|
+
const loginFlow = async (args) => {
|
|
356
|
+
if (!args.url) {
|
|
357
|
+
throw new Error("Missing --url. Required for login.");
|
|
358
|
+
}
|
|
359
|
+
if (!args.workspace) {
|
|
360
|
+
throw new Error("Missing --workspace. Required for login.");
|
|
361
|
+
}
|
|
362
|
+
|
|
363
|
+
const config = await readConfig();
|
|
364
|
+
|
|
365
|
+
const profileKey = args.alias ?? args.workspace;
|
|
366
|
+
|
|
367
|
+
const persist = async () => {
|
|
368
|
+
await writeConfig(config);
|
|
369
|
+
};
|
|
370
|
+
|
|
371
|
+
const oauth = {};
|
|
372
|
+
const { client } = await connectRemoteClient(args.url, oauth, persist, { allowInteractive: true });
|
|
373
|
+
|
|
374
|
+
const toolList = await client.listTools();
|
|
375
|
+
await client.close();
|
|
376
|
+
|
|
377
|
+
const profile = {
|
|
378
|
+
serverUrl: args.url,
|
|
379
|
+
workspace: args.workspace,
|
|
380
|
+
write: args.write ?? false,
|
|
381
|
+
oauth,
|
|
382
|
+
};
|
|
383
|
+
|
|
384
|
+
addProfile(config, profileKey, profile);
|
|
385
|
+
await writeConfig(config);
|
|
386
|
+
|
|
387
|
+
console.log(`Login successful. Profile stored as: ${profileKey}`);
|
|
388
|
+
console.log(`Available tools: ${toolList.tools.map((t) => t.name).join(", ")}`);
|
|
389
|
+
};
|
|
390
|
+
|
|
391
|
+
const logoutFlow = async (args) => {
|
|
392
|
+
const config = await readConfig();
|
|
393
|
+
|
|
394
|
+
if (!args.alias && !args.workspace) {
|
|
395
|
+
await rm(CONFIG_PATH, { force: true });
|
|
396
|
+
console.log("Removed all profiles.");
|
|
397
|
+
return;
|
|
398
|
+
}
|
|
399
|
+
|
|
400
|
+
const profileKey = args.alias ?? args.workspace;
|
|
401
|
+
|
|
402
|
+
if (args.alias && args.workspace) {
|
|
403
|
+
throw new Error("Cannot specify both --alias and --workspace for logout");
|
|
404
|
+
}
|
|
405
|
+
|
|
406
|
+
if (!config.profiles[profileKey]) {
|
|
407
|
+
throw new Error(`Profile not found: ${profileKey}`);
|
|
408
|
+
}
|
|
409
|
+
|
|
410
|
+
removeProfile(config, profileKey);
|
|
411
|
+
|
|
412
|
+
if (Object.keys(config.profiles).length === 0) {
|
|
413
|
+
await rm(CONFIG_PATH, { force: true });
|
|
414
|
+
console.log("Removed last profile. Config file removed.");
|
|
415
|
+
} else {
|
|
416
|
+
await writeConfig(config);
|
|
417
|
+
console.log(`Removed profile: ${profileKey}`);
|
|
418
|
+
}
|
|
419
|
+
};
|
|
420
|
+
|
|
421
|
+
const showConfig = async () => {
|
|
422
|
+
const config = await readConfig();
|
|
423
|
+
console.log(JSON.stringify(config, null, 2));
|
|
424
|
+
};
|
|
425
|
+
|
|
426
|
+
const showHelp = () => {
|
|
427
|
+
console.log(`kontexted-mcp usage:
|
|
428
|
+
|
|
429
|
+
Commands:
|
|
430
|
+
login --url <url> --workspace <slug> [--alias <name>] [--write]
|
|
431
|
+
Authenticate and store a new profile
|
|
432
|
+
--url: MCP server URL (e.g. https://app.example.com/api/mcp)
|
|
433
|
+
--workspace: Workspace slug
|
|
434
|
+
--alias: Optional alias for this profile (defaults to workspace name)
|
|
435
|
+
--write: Enable write operations for this profile by default
|
|
436
|
+
|
|
437
|
+
(--alias <name> | --workspace <slug>) [--write | --write-off]
|
|
438
|
+
Start MCP proxy server
|
|
439
|
+
--alias: Profile name to use
|
|
440
|
+
--workspace: Workspace name to find matching profile
|
|
441
|
+
--write: Override to enable write operations
|
|
442
|
+
--write-off: Override to disable write operations
|
|
443
|
+
Exactly one of --alias or --workspace is required
|
|
444
|
+
|
|
445
|
+
logout [--alias <name> | --workspace <slug>]
|
|
446
|
+
Remove profiles
|
|
447
|
+
No flags: Remove all profiles
|
|
448
|
+
--alias/--workspace: Remove specific profile
|
|
449
|
+
Exactly one or none of --alias/--workspace allowed
|
|
450
|
+
|
|
451
|
+
show-config
|
|
452
|
+
Display all stored profiles
|
|
453
|
+
|
|
454
|
+
--help
|
|
455
|
+
Show this help message
|
|
456
|
+
|
|
457
|
+
Examples:
|
|
458
|
+
kontexted-mcp login --url https://app.example.com/api/mcp --workspace my-workspace
|
|
459
|
+
kontexted-mcp login --url https://app.example.com/api/mcp --workspace my-workspace --alias prod --write
|
|
460
|
+
kontexted-mcp --alias prod
|
|
461
|
+
kontexted-mcp --workspace my-workspace --write
|
|
462
|
+
kontexted-mcp logout --alias prod
|
|
463
|
+
kontexted-mcp logout
|
|
464
|
+
`);
|
|
465
|
+
};
|
|
466
|
+
|
|
467
|
+
const main = async () => {
|
|
468
|
+
const args = parseArgs(process.argv);
|
|
469
|
+
|
|
470
|
+
if (args.help) {
|
|
471
|
+
showHelp();
|
|
472
|
+
return;
|
|
473
|
+
}
|
|
474
|
+
|
|
475
|
+
switch (args.command) {
|
|
476
|
+
case "login":
|
|
477
|
+
await loginFlow(args);
|
|
478
|
+
break;
|
|
479
|
+
case "logout":
|
|
480
|
+
await logoutFlow(args);
|
|
481
|
+
break;
|
|
482
|
+
case "show-config":
|
|
483
|
+
await showConfig();
|
|
484
|
+
break;
|
|
485
|
+
case undefined:
|
|
486
|
+
try {
|
|
487
|
+
await startProxyServer(args);
|
|
488
|
+
} catch (error) {
|
|
489
|
+
if (error instanceof UnauthorizedError) {
|
|
490
|
+
console.error("Unauthorized. Run 'kontexted-mcp login' first.");
|
|
491
|
+
process.exit(1);
|
|
492
|
+
}
|
|
493
|
+
throw error;
|
|
494
|
+
}
|
|
495
|
+
break;
|
|
496
|
+
default:
|
|
497
|
+
console.error(`Unknown command: ${args.command}`);
|
|
498
|
+
console.error("Run --help for usage information.");
|
|
499
|
+
process.exit(1);
|
|
500
|
+
}
|
|
501
|
+
};
|
|
502
|
+
|
|
503
|
+
main().catch((error) => {
|
|
504
|
+
console.error(error instanceof Error ? error.message : String(error));
|
|
505
|
+
process.exit(1);
|
|
506
|
+
});
|