fa-mcp-sdk 0.2.146 → 0.2.174
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/README.md +1 -1
- package/bin/fa-mcp.js +66 -54
- package/cli-template/.env.example +2 -2
- package/cli-template/README.md +2 -2
- package/cli-template/fa-mcp-sdk-spec.md +122 -41
- package/cli-template/package.json +3 -3
- package/cli-template/r/TEST HTTP.xml +9 -0
- package/cli-template/{run/TEST SSE.run.xml → r/TEST SSE.xml } +2 -2
- package/cli-template/{run/TEST STDIO.run.xml → r/TEST STDIO.xml } +2 -2
- package/cli-template/r/generate-token.xml +14 -0
- package/cli-template/{run/kill-server.run.xml → r/kill-server.xml} +2 -2
- package/cli-template/{run/kill-token-gen-server.xml → r/remove-nul.xml} +4 -5
- package/{cli-template/config → config}/_local.yaml +28 -14
- package/{cli-template/config → config}/custom-environment-variables.yaml +3 -0
- package/{cli-template/config → config}/default.yaml +50 -10
- package/{cli-template/config → config}/development.yaml +4 -4
- package/config/local.yaml +81 -0
- package/{cli-template/config → config}/production.yaml +4 -4
- package/dist/core/_types_/active-directory-config.d.ts +3 -0
- package/dist/core/_types_/active-directory-config.d.ts.map +1 -1
- package/dist/core/_types_/config.d.ts +5 -1
- package/dist/core/_types_/config.d.ts.map +1 -1
- package/dist/core/_types_/types.d.ts +5 -1
- package/dist/core/_types_/types.d.ts.map +1 -1
- package/dist/core/ad/group-checker.d.ts +13 -0
- package/dist/core/ad/group-checker.d.ts.map +1 -0
- package/dist/core/ad/group-checker.js +86 -0
- package/dist/core/ad/group-checker.js.map +1 -0
- package/dist/core/auth/admin-auth.d.ts +16 -0
- package/dist/core/auth/admin-auth.d.ts.map +1 -0
- package/dist/core/auth/admin-auth.js +159 -0
- package/dist/core/auth/admin-auth.js.map +1 -0
- package/dist/core/auth/basic.d.ts +6 -0
- package/dist/core/auth/basic.d.ts.map +1 -0
- package/dist/core/auth/basic.js +26 -0
- package/dist/core/auth/basic.js.map +1 -0
- package/dist/core/auth/{jwt-validation.d.ts → jwt.d.ts} +4 -3
- package/dist/core/auth/jwt.d.ts.map +1 -0
- package/dist/core/auth/{jwt-validation.js → jwt.js} +9 -19
- package/dist/core/auth/jwt.js.map +1 -0
- package/dist/core/auth/middleware.d.ts.map +1 -1
- package/dist/core/auth/middleware.js +3 -3
- package/dist/core/auth/middleware.js.map +1 -1
- package/dist/core/auth/multi-auth.d.ts +14 -6
- package/dist/core/auth/multi-auth.d.ts.map +1 -1
- package/dist/core/auth/multi-auth.js +151 -141
- package/dist/core/auth/multi-auth.js.map +1 -1
- package/dist/core/auth/permanent.d.ts +6 -0
- package/dist/core/auth/permanent.d.ts.map +1 -0
- package/dist/core/auth/permanent.js +15 -0
- package/dist/core/auth/permanent.js.map +1 -0
- package/dist/core/auth/token-generator/ntlm/ntlm-domain-config.d.ts +1 -1
- package/dist/core/auth/token-generator/ntlm/ntlm-domain-config.d.ts.map +1 -1
- package/dist/core/auth/token-generator/ntlm/ntlm-domain-config.js +8 -10
- package/dist/core/auth/token-generator/ntlm/ntlm-domain-config.js.map +1 -1
- package/dist/core/auth/token-generator/ntlm/ntlm-integration.d.ts.map +1 -1
- package/dist/core/auth/token-generator/ntlm/ntlm-integration.js +9 -2
- package/dist/core/auth/token-generator/ntlm/ntlm-integration.js.map +1 -1
- package/dist/core/auth/token-generator/server.d.ts.map +1 -1
- package/dist/core/auth/token-generator/server.js +59 -25
- package/dist/core/auth/token-generator/server.js.map +1 -1
- package/dist/core/auth/types.d.ts +4 -3
- package/dist/core/auth/types.d.ts.map +1 -1
- package/dist/core/bootstrap/startup-info.d.ts.map +1 -1
- package/dist/core/bootstrap/startup-info.js +19 -0
- package/dist/core/bootstrap/startup-info.js.map +1 -1
- package/dist/core/consul/access-points-updater.js +1 -1
- package/dist/core/consul/access-points-updater.js.map +1 -1
- package/dist/core/consul/get-consul-api.d.ts +1 -1
- package/dist/core/consul/get-consul-api.d.ts.map +1 -1
- package/dist/core/consul/get-consul-api.js +1 -1
- package/dist/core/consul/get-consul-api.js.map +1 -1
- package/dist/core/consul/register.d.ts +1 -1
- package/dist/core/consul/register.d.ts.map +1 -1
- package/dist/core/index.d.ts +3 -1
- package/dist/core/index.d.ts.map +1 -1
- package/dist/core/index.js +3 -1
- package/dist/core/index.js.map +1 -1
- package/dist/core/init-mcp-server.d.ts.map +1 -1
- package/dist/core/init-mcp-server.js +1 -1
- package/dist/core/init-mcp-server.js.map +1 -1
- package/dist/core/utils/testing/McpSseClient.js.map +1 -1
- package/dist/core/web/admin-router.d.ts +10 -0
- package/dist/core/web/admin-router.d.ts.map +1 -0
- package/dist/core/web/admin-router.js +227 -0
- package/dist/core/web/admin-router.js.map +1 -0
- package/dist/core/web/favicon-svg.d.ts +1 -1
- package/dist/core/web/favicon-svg.d.ts.map +1 -1
- package/dist/core/web/favicon-svg.js +21 -3
- package/dist/core/web/favicon-svg.js.map +1 -1
- package/dist/core/web/home-api.d.ts +7 -0
- package/dist/core/web/home-api.d.ts.map +1 -0
- package/dist/core/web/home-api.js +93 -0
- package/dist/core/web/home-api.js.map +1 -0
- package/dist/core/web/server-http.d.ts +1 -0
- package/dist/core/web/server-http.d.ts.map +1 -1
- package/dist/core/web/server-http.js +60 -25
- package/dist/core/web/server-http.js.map +1 -1
- package/dist/core/web/static/home/index.html +206 -0
- package/dist/core/web/static/home/script.js +636 -0
- package/dist/core/web/{about-page/css.js → static/styles.css} +435 -105
- package/dist/core/web/static/token-gen/index.html +82 -0
- package/dist/core/web/static/token-gen/jwt-icon.svg +3 -0
- package/dist/core/web/static/token-gen/logout.svg +4 -0
- package/dist/core/web/static/token-gen/script.js +365 -0
- package/dist/core/web/static/token-gen/user.svg +4 -0
- package/dist/core/web/svg-icons.d.ts +7 -0
- package/dist/core/web/svg-icons.d.ts.map +1 -0
- package/dist/core/web/svg-icons.js +78 -0
- package/dist/core/web/svg-icons.js.map +1 -0
- package/package.json +7 -3
- package/scripts/copy-static.js +31 -0
- package/src/template/_examples/multi-auth-examples.ts +14 -47
- package/src/template/_types_/custom-config.ts +83 -0
- package/src/template/asset/logo.svg +4 -0
- package/src/template/start.ts +3 -3
- package/src/template/tools/handle-tool-call.ts +2 -1
- package/src/tests/mcp/test-http.js +10 -2
- package/src/tests/mcp/test-sse.js +10 -2
- package/src/tests/mcp/test-stdio.js +1 -2
- package/cli-template/run/TEST HTTP.run.xml +0 -5
- package/cli-template/run/TEST search.run.xml +0 -11
- package/cli-template/run/remove-nul.js.run.xml +0 -5
- package/dist/core/auth/jwt-validation.d.ts.map +0 -1
- package/dist/core/auth/jwt-validation.js.map +0 -1
- package/dist/core/auth/token-generator/html.d.ts +0 -9
- package/dist/core/auth/token-generator/html.d.ts.map +0 -1
- package/dist/core/auth/token-generator/html.js +0 -862
- package/dist/core/auth/token-generator/html.js.map +0 -1
- package/dist/core/web/about-page/css.d.ts +0 -2
- package/dist/core/web/about-page/css.d.ts.map +0 -1
- package/dist/core/web/about-page/css.js.map +0 -1
- package/dist/core/web/about-page/render.d.ts +0 -2
- package/dist/core/web/about-page/render.d.ts.map +0 -1
- package/dist/core/web/about-page/render.js +0 -773
- package/dist/core/web/about-page/render.js.map +0 -1
- /package/cli-template/{run/== START ==.run.xml → r/== START ==.xml} +0 -0
- /package/cli-template/{run/cb.run.xml → r/cb.xml} +0 -0
- /package/cli-template/{run/ci.run.xml → r/ci.xml} +0 -0
- /package/cli-template/{run/lint.run.xml → r/lint.xml} +0 -0
- /package/cli-template/{run/lint_fix.run.xml → r/lint_fix.xml} +0 -0
- /package/cli-template/{run/reinstall.run.xml → r/reinstall.xml} +0 -0
- /package/{cli-template/config → config}/test.yaml +0 -0
- /package/{src/template/asset/favicon.svg → dist/core/web/static/logo.svg} +0 -0
- /package/{cli-template/scripts → scripts}/kill-port.js +0 -0
- /package/{cli-template/scripts → scripts}/npm/patch_node_modules.js +0 -0
- /package/{cli-template/scripts → scripts}/npm/run.js +0 -0
- /package/{cli-template/scripts → scripts}/npm/yarn-ci.ps1 +0 -0
- /package/{cli-template/scripts → scripts}/npm/yarn-ci.sh +0 -0
- /package/{cli-template/scripts → scripts}/npm/yarn-reinstall.ps1 +0 -0
- /package/{cli-template/scripts → scripts}/npm/yarn-reinstall.sh +0 -0
- /package/{cli-template/scripts → scripts}/pre-commit +0 -0
- /package/{cli-template/scripts → scripts}/remove-nul.js +0 -0
package/README.md
CHANGED
|
@@ -174,7 +174,7 @@ npm start
|
|
|
174
174
|
|
|
175
175
|
Provides endpoints:
|
|
176
176
|
|
|
177
|
-
- `GET /` -
|
|
177
|
+
- `GET /` - Home page with server info
|
|
178
178
|
- `GET /health` - Health check
|
|
179
179
|
- `GET /sse` - Server-Sent Events for MCP communication
|
|
180
180
|
- `POST /mcp` - Direct MCP JSON-RPC endpoint
|
package/bin/fa-mcp.js
CHANGED
|
@@ -46,6 +46,7 @@ const ALLOWED_FILES = [
|
|
|
46
46
|
'__misc',
|
|
47
47
|
'_tmp',
|
|
48
48
|
'~last-cli-config.json',
|
|
49
|
+
'yarn.lock',
|
|
49
50
|
];
|
|
50
51
|
|
|
51
52
|
const getAsk = () => {
|
|
@@ -227,6 +228,11 @@ class MCPGenerator {
|
|
|
227
228
|
defaultValue: '***',
|
|
228
229
|
title: 'Token for registering service with Consul agent',
|
|
229
230
|
},
|
|
231
|
+
{
|
|
232
|
+
name: 'consul.agent.reg.host',
|
|
233
|
+
defaultValue: '',
|
|
234
|
+
title: 'The host of the consul agent where the service will be registered',
|
|
235
|
+
},
|
|
230
236
|
{
|
|
231
237
|
name: 'consul.envCode.dev',
|
|
232
238
|
defaultValue: '<envCode.dev>',
|
|
@@ -730,6 +736,9 @@ certificate's public and private keys`,
|
|
|
730
736
|
|
|
731
737
|
async copyDirectory (source, target) {
|
|
732
738
|
const entries = await fs.readdir(source, { withFileTypes: true });
|
|
739
|
+
if (!fss.existsSync(target)) {
|
|
740
|
+
await fs.mkdir(target, { recursive: true });
|
|
741
|
+
}
|
|
733
742
|
|
|
734
743
|
for (const entry of entries) {
|
|
735
744
|
if (entry.name === 'node_modules' || entry.name === 'dist') {
|
|
@@ -845,6 +854,10 @@ certificate's public and private keys`,
|
|
|
845
854
|
content = content.replace(/http:\/\/localhost:9876/g, `http://localhost:${config.port}`);
|
|
846
855
|
modified = true;
|
|
847
856
|
}
|
|
857
|
+
if (filePath.endsWith('test-stdio.js')) {
|
|
858
|
+
content = content.replace('../dist/template/start.js', 'dist/src/start.js');
|
|
859
|
+
modified = true;
|
|
860
|
+
}
|
|
848
861
|
|
|
849
862
|
if (modified) {
|
|
850
863
|
await fs.writeFile(filePath, content, 'utf8');
|
|
@@ -854,40 +867,14 @@ certificate's public and private keys`,
|
|
|
854
867
|
await this.transformTargetFile(config, '.env', (c) => c.replace(/^(NODE_CONSUL_ENV)=([^\r\n]*)/m, '#$1=$2'));
|
|
855
868
|
}
|
|
856
869
|
if (config['claude.isBypassPermissions'] === 'true') {
|
|
870
|
+
const c1 = ['sudo cp', 'sudo', 'bash', 'chmod', 'curl', 'dir', 'echo', 'git', 'find', 'grep', 'jest',
|
|
871
|
+
'mkdir', 'node', 'npm install', 'npm run', 'npm test', 'npm', 'npx', 'pkill', 'set', 'playwright', 'powershell',
|
|
872
|
+
'rm', 'taskkill', 'tasklist', 'timeout', 'turbo run', 'wc'];
|
|
873
|
+
const c2 = ['jobs', 'npm start', 'unset http_proxy'];
|
|
874
|
+
const i = ' '.repeat(8);
|
|
875
|
+
const allowBashLines = [...c1.map((c) => `${i}"Bash(${c}:*)",`), ...c2.map((c) => `${i}"Bash(${c})",`)].join('\n');
|
|
857
876
|
const transformFn = (c) => c.replace('"acceptEdits"', '"bypassPermissions"')
|
|
858
|
-
.replace(/"allow": \[\s+"Edit",/, `"allow": [
|
|
859
|
-
"Bash(sudo cp:*)",
|
|
860
|
-
"Bash(sudo:*)",
|
|
861
|
-
"Bash(bash:*)",
|
|
862
|
-
"Bash(chmod:*)",
|
|
863
|
-
"Bash(curl:*)",
|
|
864
|
-
"Bash(dir:*)",
|
|
865
|
-
"Bash(echo:*)",
|
|
866
|
-
"Bash(git:*)",
|
|
867
|
-
"Bash(find:*)",
|
|
868
|
-
"Bash(grep:*)",
|
|
869
|
-
"Bash(jest:*)",
|
|
870
|
-
"Bash(jobs)",
|
|
871
|
-
"Bash(mkdir:*)",
|
|
872
|
-
"Bash(node:*)",
|
|
873
|
-
"Bash(npm install:*)",
|
|
874
|
-
"Bash(npm run:*)",
|
|
875
|
-
"Bash(npm start)",
|
|
876
|
-
"Bash(npm test:*)",
|
|
877
|
-
"Bash(npm:*)",
|
|
878
|
-
"Bash(npx:*)",
|
|
879
|
-
"Bash(pkill:*)",
|
|
880
|
-
"Bash(set:*)",
|
|
881
|
-
"Bash(playwright:*)",
|
|
882
|
-
"Bash(powershell:*)",
|
|
883
|
-
"Bash(rm:*)",
|
|
884
|
-
"Bash(taskkill:*)",
|
|
885
|
-
"Bash(tasklist:*)",
|
|
886
|
-
"Bash(timeout:*)",
|
|
887
|
-
"Bash(turbo run:*)",
|
|
888
|
-
"Bash(unset http_proxy)",
|
|
889
|
-
"Bash(wc:*)",
|
|
890
|
-
"Edit",`);
|
|
877
|
+
.replace(/"allow": \[\s+"Edit",/, `"allow": [\n${allowBashLines}\n${i}"Edit",`);
|
|
891
878
|
await this.transformTargetFile(config, '.claude/settings.json', transformFn);
|
|
892
879
|
}
|
|
893
880
|
}
|
|
@@ -897,12 +884,32 @@ certificate's public and private keys`,
|
|
|
897
884
|
// Copy template files
|
|
898
885
|
await this.copyDirectory(path.join(PROJ_ROOT, 'cli-template'), targetPath);
|
|
899
886
|
await this.copyDirectory(path.join(PROJ_ROOT, 'src/template'), path.join(targetPath, 'src'));
|
|
900
|
-
|
|
901
|
-
|
|
887
|
+
|
|
888
|
+
const testsTargetPath = path.join(targetPath, 'tests');
|
|
889
|
+
|
|
902
890
|
await this.copyDirectory(path.join(PROJ_ROOT, 'src/tests'), testsTargetPath);
|
|
903
891
|
await fs.copyFile(path.join(targetPath, '.env.example'), path.join(targetPath, '.env'));
|
|
904
892
|
await fs.rename(path.join(targetPath, 'gitignore'), path.join(targetPath, '.gitignore'));
|
|
905
|
-
await fs.rename(path.join(targetPath, '
|
|
893
|
+
await fs.rename(path.join(targetPath, 'r'), path.join(targetPath, '.run'));
|
|
894
|
+
|
|
895
|
+
await this.copyDirectory(path.join(PROJ_ROOT, 'config'), path.join(targetPath, 'config'));
|
|
896
|
+
|
|
897
|
+
const scriptsTargetPath = path.join(targetPath, 'scripts');
|
|
898
|
+
await this.copyDirectory(path.join(PROJ_ROOT, 'scripts'), scriptsTargetPath);
|
|
899
|
+
await fs.rm(path.join(targetPath, 'scripts/copy-static.js'), { force: true });
|
|
900
|
+
|
|
901
|
+
// Rename all .xml files in .run directory to .run.xml
|
|
902
|
+
const runDirPath = path.join(targetPath, '.run');
|
|
903
|
+
const files = await fs.readdir(runDirPath);
|
|
904
|
+
|
|
905
|
+
for (const file of files) {
|
|
906
|
+
if (file.endsWith('.xml')) {
|
|
907
|
+
const oldFilePath = path.join(runDirPath, file);
|
|
908
|
+
const newFileName = file.slice(0, -4) + '.run.xml';
|
|
909
|
+
const newFilePath = path.join(runDirPath, newFileName);
|
|
910
|
+
await fs.rename(oldFilePath, newFilePath);
|
|
911
|
+
}
|
|
912
|
+
}
|
|
906
913
|
|
|
907
914
|
// Rename mcp-template.com.conf if mcp.domain is provided
|
|
908
915
|
const mcpDomain = config['mcp.domain'];
|
|
@@ -920,15 +927,13 @@ certificate's public and private keys`,
|
|
|
920
927
|
}
|
|
921
928
|
|
|
922
929
|
// Read _local.yaml into memory and rename it to local.yaml
|
|
923
|
-
let
|
|
930
|
+
let localYamlExampleContent = '';
|
|
931
|
+
const localYamlExamplePath = path.join(targetPath, 'config', '_local.yaml');
|
|
932
|
+
const localYamlPath = path.join(targetPath, 'config', 'local.yaml');
|
|
924
933
|
try {
|
|
925
|
-
const localYamlPath = path.join(targetPath, 'config', '_local.yaml');
|
|
926
|
-
const localYamlNewPath = path.join(targetPath, 'config', 'local.yaml');
|
|
927
934
|
|
|
928
|
-
|
|
929
|
-
await fs.rename(localYamlPath, localYamlNewPath);
|
|
935
|
+
localYamlExampleContent = await fs.readFile(localYamlExamplePath, 'utf8');
|
|
930
936
|
} catch (error) {
|
|
931
|
-
// _local.yaml doesn't exist, which might be fine
|
|
932
937
|
console.log('⚠️ Warning: Could not process config/_local.yaml file:', error.message);
|
|
933
938
|
}
|
|
934
939
|
|
|
@@ -936,35 +941,40 @@ certificate's public and private keys`,
|
|
|
936
941
|
await this.replaceTemplateParameters(config);
|
|
937
942
|
|
|
938
943
|
// Replace template placeholders with defaultValue from optionalParams and save as _local.yaml
|
|
939
|
-
if (
|
|
944
|
+
if (localYamlExampleContent) {
|
|
940
945
|
try {
|
|
941
|
-
let
|
|
942
|
-
|
|
946
|
+
let localYamlExampleModifiedContent = localYamlExampleContent;
|
|
947
|
+
let localYamlModifiedContent = localYamlExampleContent;
|
|
943
948
|
// Replace with defaultValue from optionalParams
|
|
944
949
|
for (const param of this.optionalParams) {
|
|
945
950
|
const template = `{{${param.name}}}`;
|
|
946
|
-
if (
|
|
951
|
+
if (localYamlExampleModifiedContent.includes(template)) {
|
|
947
952
|
const defaultValue = param.defaultValue || '';
|
|
948
|
-
|
|
953
|
+
localYamlExampleModifiedContent = localYamlExampleModifiedContent.replace(new RegExp(escapeRegExp(template), 'g'), defaultValue);
|
|
949
954
|
}
|
|
950
955
|
}
|
|
956
|
+
|
|
951
957
|
// Replacement of the remaining substitution places with what is in the config
|
|
952
958
|
for (const [paramName, value] of Object.entries(config)) {
|
|
953
959
|
const template = `{{${paramName}}}`;
|
|
954
|
-
if (
|
|
955
|
-
|
|
960
|
+
if (localYamlExampleModifiedContent.includes(template)) {
|
|
961
|
+
localYamlExampleModifiedContent = localYamlExampleModifiedContent.replace(new RegExp(escapeRegExp(template), 'g'), value);
|
|
962
|
+
}
|
|
963
|
+
if (localYamlModifiedContent.includes(template)) {
|
|
964
|
+
localYamlModifiedContent = localYamlModifiedContent.replace(new RegExp(escapeRegExp(template), 'g'), value);
|
|
956
965
|
}
|
|
957
966
|
}
|
|
967
|
+
if (!config['consul.agent.reg.host']) {
|
|
968
|
+
localYamlModifiedContent = localYamlModifiedContent.replace(/(\n +)host: '[^']*'( # The host of the consul agent)/, '$1# host: \'\'$2');
|
|
969
|
+
}
|
|
958
970
|
|
|
959
|
-
|
|
960
|
-
await fs.writeFile(
|
|
971
|
+
await fs.writeFile(localYamlPath, localYamlModifiedContent, 'utf8');
|
|
972
|
+
await fs.writeFile(localYamlExamplePath, localYamlExampleModifiedContent, 'utf8');
|
|
961
973
|
} catch (error) {
|
|
962
974
|
console.log('⚠️ Warning: Could not create config/_local.yaml file:', error.message);
|
|
963
975
|
}
|
|
964
976
|
}
|
|
965
977
|
const pathsToRemove = [
|
|
966
|
-
{ rel: 'node_modules' },
|
|
967
|
-
{ rel: 'yarn.lock' },
|
|
968
978
|
{ rel: 'package-lock.json' },
|
|
969
979
|
];
|
|
970
980
|
|
|
@@ -994,7 +1004,9 @@ certificate's public and private keys`,
|
|
|
994
1004
|
process.exit(0);
|
|
995
1005
|
|
|
996
1006
|
} catch (error) {
|
|
997
|
-
|
|
1007
|
+
if (error.message && !(error.stack || '').includes(String(error.message))) {
|
|
1008
|
+
console.error('\n❌ Error:', error.message);
|
|
1009
|
+
}
|
|
998
1010
|
console.error(error.stack);
|
|
999
1011
|
process.exit(1);
|
|
1000
1012
|
}
|
|
@@ -16,8 +16,8 @@ DEBUG=config-info
|
|
|
16
16
|
|
|
17
17
|
## DEBUG patterns ##
|
|
18
18
|
# AP-UPDATER - consul/access-points-updater
|
|
19
|
-
#
|
|
20
|
-
#
|
|
19
|
+
# fa-consul:reg | fa-consul:* - consul/cyclic-register
|
|
20
|
+
# fa-consul:curl - consul/prepare-consul-api
|
|
21
21
|
# token:auth
|
|
22
22
|
|
|
23
23
|
# The address of the mcp server for testing. Default: http://localhost:<config.webServer.port>
|
package/cli-template/README.md
CHANGED
|
@@ -39,7 +39,7 @@ npm run test:mcp-simple # Simple test
|
|
|
39
39
|
|
|
40
40
|
**HTTP Mode** (web integration):
|
|
41
41
|
- HTTP server with Server-Sent Events (SSE)
|
|
42
|
-
-
|
|
42
|
+
- Home page with server status at `http://localhost:{{port}}/`
|
|
43
43
|
- Health check endpoint at `/health`
|
|
44
44
|
- Direct JSON-RPC 2.0 endpoint at `/mcp`
|
|
45
45
|
|
|
@@ -97,7 +97,7 @@ Add to `claude_desktop_config.json`:
|
|
|
97
97
|
|
|
98
98
|
## HTTP Mode Endpoints
|
|
99
99
|
|
|
100
|
-
- **/** -
|
|
100
|
+
- **/** - Home page
|
|
101
101
|
- **/health** - Health check
|
|
102
102
|
- **/sse** - Server-Sent Events
|
|
103
103
|
- **/mcp** - JSON-RPC 2.0
|
|
@@ -79,7 +79,6 @@ const customAuthValidator: CustomAuthValidator = async (req): Promise<AuthResult
|
|
|
79
79
|
return {
|
|
80
80
|
success: true,
|
|
81
81
|
authType: 'basic',
|
|
82
|
-
tokenType: 'custom',
|
|
83
82
|
username: userID || 'unknown',
|
|
84
83
|
};
|
|
85
84
|
} else {
|
|
@@ -451,7 +450,7 @@ consul:
|
|
|
451
450
|
description: <description> # <description> will be replaced by <package.json>.description at initialization
|
|
452
451
|
tags: [] # If null or empty array - Will be pulled up from package.keywords at initialization
|
|
453
452
|
meta:
|
|
454
|
-
# "
|
|
453
|
+
# "Home" page link template
|
|
455
454
|
who: 'http://{address}:{port}/'
|
|
456
455
|
envCode: # Used to generate the service ID
|
|
457
456
|
prod: {{consul.envCode.prod}} # Production environment code
|
|
@@ -497,7 +496,7 @@ swagger:
|
|
|
497
496
|
description: "PROD server"
|
|
498
497
|
|
|
499
498
|
uiColor:
|
|
500
|
-
# Font color of the header and a number of interface elements on the
|
|
499
|
+
# Font color of the header and a number of interface elements on the HOME page
|
|
501
500
|
primary: '#0f65dc'
|
|
502
501
|
|
|
503
502
|
webServer:
|
|
@@ -870,13 +869,12 @@ addErrorMessage(originalError, 'Database operation failed');
|
|
|
870
869
|
```typescript
|
|
871
870
|
import {
|
|
872
871
|
ICheckTokenResult,
|
|
873
|
-
|
|
872
|
+
checkJwtToken,
|
|
874
873
|
generateToken
|
|
875
874
|
} from 'fa-mcp-sdk';
|
|
876
875
|
|
|
877
876
|
// Types used:
|
|
878
877
|
export interface ICheckTokenResult {
|
|
879
|
-
inTokenType?: TTokenType // 'permanent' | 'JWT'
|
|
880
878
|
payload?: ITokenPayload, // Token payload with user data
|
|
881
879
|
errorReason?: string, // Error message if validation failed
|
|
882
880
|
isTokenDecrypted?: boolean, // Whether token was successfully decrypted
|
|
@@ -888,16 +886,16 @@ export interface ITokenPayload {
|
|
|
888
886
|
[key: string]: any, // Additional payload data
|
|
889
887
|
}
|
|
890
888
|
|
|
891
|
-
//
|
|
889
|
+
// checkJwtToken - validate token and return detailed result
|
|
892
890
|
// Function Signature:
|
|
893
|
-
const
|
|
891
|
+
const checkJwtToken = (arg: {
|
|
894
892
|
token: string,
|
|
895
893
|
expectedUser?: string,
|
|
896
894
|
expectedService?: string,
|
|
897
895
|
}): ICheckTokenResult {...}
|
|
898
896
|
|
|
899
897
|
// Example:
|
|
900
|
-
const tokenResult =
|
|
898
|
+
const tokenResult = checkJwtToken({
|
|
901
899
|
token: 'user_provided_token',
|
|
902
900
|
expectedUser: 'john_doe',
|
|
903
901
|
expectedService: 'my-mcp-server'
|
|
@@ -966,6 +964,86 @@ await generateTokenApp(); // Uses default configuration from appConfig
|
|
|
966
964
|
// domainController: 'dc.domain.com'
|
|
967
965
|
```
|
|
968
966
|
|
|
967
|
+
#### Test Authentication Headers
|
|
968
|
+
|
|
969
|
+
```typescript
|
|
970
|
+
import { getAuthHeadersForTests } from 'fa-mcp-sdk';
|
|
971
|
+
|
|
972
|
+
// getAuthHeadersForTests - automatically generate authentication headers for testing
|
|
973
|
+
// Function Signature:
|
|
974
|
+
function getAuthHeadersForTests(): object {...}
|
|
975
|
+
|
|
976
|
+
// Determines authentication headers based on appConfig.webServer.auth configuration.
|
|
977
|
+
// Returns Authorization header using the first valid auth method found.
|
|
978
|
+
//
|
|
979
|
+
// Priority order (CPU-optimized, fastest first):
|
|
980
|
+
// 1. permanentServerTokens - if at least one token is defined
|
|
981
|
+
// 2. basic auth - if username AND password are both set
|
|
982
|
+
// 3. JWT token - if jwtToken.encryptKey is set, generates token on the fly
|
|
983
|
+
//
|
|
984
|
+
// Returns empty object if auth is not enabled or no valid method configured.
|
|
985
|
+
|
|
986
|
+
// Examples:
|
|
987
|
+
const headers = getAuthHeadersForTests();
|
|
988
|
+
|
|
989
|
+
// Use in fetch requests
|
|
990
|
+
const response = await fetch('http://localhost:3000/mcp', {
|
|
991
|
+
method: 'POST',
|
|
992
|
+
headers: {
|
|
993
|
+
'Content-Type': 'application/json',
|
|
994
|
+
...headers // Automatically adds Authorization header if auth is enabled
|
|
995
|
+
},
|
|
996
|
+
body: JSON.stringify(requestBody)
|
|
997
|
+
});
|
|
998
|
+
|
|
999
|
+
// Use with test clients
|
|
1000
|
+
import { McpHttpClient } from 'fa-mcp-sdk';
|
|
1001
|
+
|
|
1002
|
+
const client = new McpHttpClient('http://localhost:3000');
|
|
1003
|
+
const authHeaders = getAuthHeadersForTests();
|
|
1004
|
+
const result = await client.callTool('my_tool', { query: 'test' }, authHeaders);
|
|
1005
|
+
|
|
1006
|
+
// Return value examples based on configuration:
|
|
1007
|
+
|
|
1008
|
+
// If permanentServerTokens configured:
|
|
1009
|
+
// { Authorization: 'Bearer server-token-1' }
|
|
1010
|
+
|
|
1011
|
+
// If basic auth configured:
|
|
1012
|
+
// { Authorization: 'Basic YWRtaW46cGFzc3dvcmQ=' } // base64 of 'admin:password'
|
|
1013
|
+
|
|
1014
|
+
// If JWT encryptKey configured:
|
|
1015
|
+
// { Authorization: 'Bearer eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9...' }
|
|
1016
|
+
|
|
1017
|
+
// If auth.enabled = false or no valid method:
|
|
1018
|
+
// {}
|
|
1019
|
+
|
|
1020
|
+
// Typical test setup:
|
|
1021
|
+
import { getAuthHeadersForTests, appConfig } from 'fa-mcp-sdk';
|
|
1022
|
+
|
|
1023
|
+
describe('MCP Server Tests', () => {
|
|
1024
|
+
const baseUrl = `http://localhost:${appConfig.webServer.port}`;
|
|
1025
|
+
const authHeaders = getAuthHeadersForTests();
|
|
1026
|
+
|
|
1027
|
+
it('should call tool with authentication', async () => {
|
|
1028
|
+
const response = await fetch(`${baseUrl}/mcp`, {
|
|
1029
|
+
method: 'POST',
|
|
1030
|
+
headers: {
|
|
1031
|
+
'Content-Type': 'application/json',
|
|
1032
|
+
...authHeaders
|
|
1033
|
+
},
|
|
1034
|
+
body: JSON.stringify({
|
|
1035
|
+
jsonrpc: '2.0',
|
|
1036
|
+
method: 'tools/call',
|
|
1037
|
+
params: { name: 'my_tool', arguments: { query: 'test' } },
|
|
1038
|
+
id: 1
|
|
1039
|
+
})
|
|
1040
|
+
});
|
|
1041
|
+
|
|
1042
|
+
expect(response.ok).toBe(true);
|
|
1043
|
+
});
|
|
1044
|
+
});
|
|
1045
|
+
```
|
|
1046
|
+
|
|
969
1047
|
#### Multi-Authentication System
|
|
970
1048
|
|
|
971
1049
|
The FA-MCP-SDK supports a comprehensive multi-authentication system that allows multiple authentication methods to work together with CPU-optimized performance ordering.
|
|
@@ -979,7 +1057,6 @@ import {
|
|
|
979
1057
|
AuthDetectionResult,
|
|
980
1058
|
CustomAuthValidator,
|
|
981
1059
|
checkMultiAuth,
|
|
982
|
-
checkCombinedAuth,
|
|
983
1060
|
detectAuthConfiguration,
|
|
984
1061
|
logAuthConfiguration,
|
|
985
1062
|
createAuthMW, // Universal authentication middleware
|
|
@@ -994,12 +1071,12 @@ export type CustomAuthValidator = (req: any) => Promise<AuthResult> | AuthResult
|
|
|
994
1071
|
|
|
995
1072
|
// Authentication result interface
|
|
996
1073
|
export interface AuthResult {
|
|
997
|
-
|
|
998
|
-
|
|
999
|
-
|
|
1000
|
-
|
|
1001
|
-
|
|
1002
|
-
|
|
1074
|
+
success: boolean;
|
|
1075
|
+
error?: string;
|
|
1076
|
+
authType?: AuthType;
|
|
1077
|
+
username?: string;
|
|
1078
|
+
isTokenDecrypted?: boolean; // only for JWT
|
|
1079
|
+
payload?: any;
|
|
1003
1080
|
}
|
|
1004
1081
|
|
|
1005
1082
|
// Authentication detection result
|
|
@@ -1026,24 +1103,6 @@ if (result.success) {
|
|
|
1026
1103
|
console.log('Authentication failed:', result.error);
|
|
1027
1104
|
}
|
|
1028
1105
|
|
|
1029
|
-
// checkCombinedAuth - validate using configured auth + custom validator
|
|
1030
|
-
// Function Signature:
|
|
1031
|
-
async function checkCombinedAuth( req: any ): Promise<AuthResult> {...}
|
|
1032
|
-
|
|
1033
|
-
// This is the enhanced function that:
|
|
1034
|
-
// 1. Runs standard MCP auth methods (if configured)
|
|
1035
|
-
// 2. Additionally runs custom validator (if configured)
|
|
1036
|
-
// 3. Can use custom validator as fallback if standard auth fails
|
|
1037
|
-
|
|
1038
|
-
// Example:
|
|
1039
|
-
const authResult = await checkCombinedAuth(req);
|
|
1040
|
-
|
|
1041
|
-
if (authResult.success) {
|
|
1042
|
-
console.log(`Authentication successful via ${authResult.authType}`);
|
|
1043
|
-
} else {
|
|
1044
|
-
console.log('Combined authentication failed:', authResult.error);
|
|
1045
|
-
}
|
|
1046
|
-
|
|
1047
1106
|
// detectAuthConfiguration - analyze auth configuration
|
|
1048
1107
|
// Function Signature:
|
|
1049
1108
|
function detectAuthConfiguration(): AuthDetectionResult {...}
|
|
@@ -1088,7 +1147,6 @@ app.get('/api/protected', (req, res) => {
|
|
|
1088
1147
|
message: 'Access granted',
|
|
1089
1148
|
authType: authInfo?.authType,
|
|
1090
1149
|
username: authInfo?.username,
|
|
1091
|
-
tokenType: authInfo?.tokenType
|
|
1092
1150
|
});
|
|
1093
1151
|
});
|
|
1094
1152
|
|
|
@@ -1119,7 +1177,7 @@ function createAuthMW(options?: {
|
|
|
1119
1177
|
async function getMultiAuthError(req: Request): Promise<{ code: number, message: string } | undefined>
|
|
1120
1178
|
|
|
1121
1179
|
// Returns error object if authentication failed, undefined if successful
|
|
1122
|
-
// Uses
|
|
1180
|
+
// Uses checkMultiAuth internally - supports all authentication methods
|
|
1123
1181
|
|
|
1124
1182
|
// Example - Custom middleware with different auth levels
|
|
1125
1183
|
app.use('/api/custom', async (req, res, next) => {
|
|
@@ -1174,7 +1232,6 @@ const databaseAuthValidator: CustomAuthValidator = async (req): Promise<AuthResu
|
|
|
1174
1232
|
return {
|
|
1175
1233
|
success: true,
|
|
1176
1234
|
authType: 'basic',
|
|
1177
|
-
tokenType: 'basic',
|
|
1178
1235
|
username: dbUser.username,
|
|
1179
1236
|
payload: { userId: dbUser.id, roles: dbUser.roles }
|
|
1180
1237
|
};
|
|
@@ -1187,7 +1244,6 @@ const databaseAuthValidator: CustomAuthValidator = async (req): Promise<AuthResu
|
|
|
1187
1244
|
return {
|
|
1188
1245
|
success: true,
|
|
1189
1246
|
authType: 'basic',
|
|
1190
|
-
tokenType: 'apiKey',
|
|
1191
1247
|
username: username,
|
|
1192
1248
|
payload: { apiKey: apiKey.substring(0, 8) + '...' }
|
|
1193
1249
|
};
|
|
@@ -1226,7 +1282,6 @@ const ipBasedAuthValidator: CustomAuthValidator = async (req): Promise<AuthResul
|
|
|
1226
1282
|
return {
|
|
1227
1283
|
success: true,
|
|
1228
1284
|
authType: 'basic',
|
|
1229
|
-
tokenType: 'ipBased',
|
|
1230
1285
|
username: `ip-${clientIP}`,
|
|
1231
1286
|
payload: { clientIP, userAgent, accessTime: new Date().toISOString() }
|
|
1232
1287
|
};
|
|
@@ -1261,7 +1316,6 @@ const externalServiceAuthValidator: CustomAuthValidator = async (req): Promise<A
|
|
|
1261
1316
|
return {
|
|
1262
1317
|
success: true,
|
|
1263
1318
|
authType: 'basic',
|
|
1264
|
-
tokenType: 'external',
|
|
1265
1319
|
username: result.username || clientId,
|
|
1266
1320
|
payload: {
|
|
1267
1321
|
clientId,
|
|
@@ -1303,7 +1357,6 @@ const mfaAuthValidator: CustomAuthValidator = async (req): Promise<AuthResult> =
|
|
|
1303
1357
|
return {
|
|
1304
1358
|
success: true,
|
|
1305
1359
|
authType: 'basic',
|
|
1306
|
-
tokenType: 'mfa',
|
|
1307
1360
|
username: username,
|
|
1308
1361
|
payload: {
|
|
1309
1362
|
userId: user.id,
|
|
@@ -1351,7 +1404,6 @@ app.post('/test-token', async (req, res) => {
|
|
|
1351
1404
|
res.json({
|
|
1352
1405
|
valid: result.success,
|
|
1353
1406
|
authType: result.authType,
|
|
1354
|
-
tokenType: result.tokenType,
|
|
1355
1407
|
error: result.error,
|
|
1356
1408
|
username: result.username,
|
|
1357
1409
|
hasPayload: !!result.payload
|
|
@@ -1412,6 +1464,35 @@ curl -H "Authorization: Bearer token123" \
|
|
|
1412
1464
|
|
|
1413
1465
|
The multi-authentication system automatically tries authentication methods in CPU-optimized order (fastest first) and returns on the first successful match, providing both performance and flexibility.
|
|
1414
1466
|
|
|
1467
|
+
### Check if a user belongs to an AD group
|
|
1468
|
+
|
|
1469
|
+
#### Configuration (`config/local.yaml`)
|
|
1470
|
+
|
|
1471
|
+
```yaml
|
|
1472
|
+
ad:
|
|
1473
|
+
domains:
|
|
1474
|
+
MYDOMAIN:
|
|
1475
|
+
default: true
|
|
1476
|
+
controllers: ['ldap://dc1.corp.com']
|
|
1477
|
+
username: 'svc_account@corp.com'
|
|
1478
|
+
password: '***'
|
|
1479
|
+
# baseDn: 'DC=corp,DC=com' # Optional, auto-derived from controller URL
|
|
1480
|
+
```
|
|
1481
|
+
|
|
1482
|
+
#### Usage
|
|
1483
|
+
|
|
1484
|
+
```typescript
|
|
1485
|
+
import { initADGroupChecker } from 'fa-mcp-sdk';
|
|
1486
|
+
|
|
1487
|
+
const { isUserInGroup, groupChecker } = initADGroupChecker();
|
|
1488
|
+
|
|
1489
|
+
const isAdmin = await isUserInGroup('john.doe', 'Admins');
|
|
1490
|
+
const isDeveloper = await isUserInGroup('john.doe', 'Developers');
|
|
1491
|
+
|
|
1492
|
+
groupChecker.clearCache(); // Clear cache if needed
|
|
1493
|
+
```
|
|
1494
|
+
|
|
1495
|
+
|
|
1415
1496
|
### Utility Functions
|
|
1416
1497
|
|
|
1417
1498
|
#### General Utilities
|
|
@@ -13,15 +13,15 @@
|
|
|
13
13
|
"build": "tsc",
|
|
14
14
|
"clean": "rimraf dist",
|
|
15
15
|
"cb": "npm run clean && npm run build",
|
|
16
|
-
"ci": "node --no-deprecation
|
|
17
|
-
"reinstall": "node --no-deprecation
|
|
16
|
+
"ci": "node --no-deprecation ../scripts/npm/run.js",
|
|
17
|
+
"reinstall": "node --no-deprecation ../scripts/npm/run.js reinstall",
|
|
18
18
|
"typecheck": "tsc --noEmit",
|
|
19
19
|
"lint": "eslint .",
|
|
20
20
|
"lint:fix": "eslint --fix .",
|
|
21
21
|
"generate-token": "node node_modules/fa-mcp-sdk/dist/core/auth/token-generator/server.js",
|
|
22
22
|
"dead:exports": "ts-prune",
|
|
23
23
|
"dead:files": "knip",
|
|
24
|
-
"postinstall": "node scripts/npm/patch_node_modules.js",
|
|
24
|
+
"postinstall": "node ../scripts/npm/patch_node_modules.js",
|
|
25
25
|
"consul:unreg": "node node_modules/fa-mcp-sdk/dist/core/consul/deregister.js",
|
|
26
26
|
"test": "jest",
|
|
27
27
|
"test:mcp": "node scripts/test-mcp-tools.js",
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
<component name="ProjectRunConfigurationManager">
|
|
2
|
-
<configuration default="false" name="TEST SSE" type="NodeJSConfigurationType" path-to-js-file="
|
|
2
|
+
<configuration default="false" name="TEST SSE" type="NodeJSConfigurationType" path-to-js-file="tests/mcp/test-sse.js" working-dir="$PROJECT_DIR$/">
|
|
3
3
|
<method v="2" />
|
|
4
4
|
</configuration>
|
|
5
|
-
</component>
|
|
5
|
+
</component>
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
<component name="ProjectRunConfigurationManager">
|
|
2
|
-
<configuration default="false" name="TEST STDIO" type="NodeJSConfigurationType" path-to-js-file="
|
|
2
|
+
<configuration default="false" name="TEST STDIO" type="NodeJSConfigurationType" path-to-js-file="tests/mcp/test-stdio.js" working-dir="$PROJECT_DIR$">
|
|
3
3
|
<method v="2" />
|
|
4
4
|
</configuration>
|
|
5
|
-
</component>
|
|
5
|
+
</component>
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
<component name="ProjectRunConfigurationManager">
|
|
2
|
+
<configuration default="false" name="generate-token" type="js.build_tools.npm" nameIsGenerated="true">
|
|
3
|
+
<package-json value="$PROJECT_DIR$/package.json" />
|
|
4
|
+
<command value="run" />
|
|
5
|
+
<scripts>
|
|
6
|
+
<script value="generate-token" />
|
|
7
|
+
</scripts>
|
|
8
|
+
<node-interpreter value="project" />
|
|
9
|
+
<envs>
|
|
10
|
+
<env name="DEBUG" value="ntlm:auth-flow,ntlm:ldap-proxy,ntlm:ldap-proxy-id" />
|
|
11
|
+
</envs>
|
|
12
|
+
<method v="2" />
|
|
13
|
+
</configuration>
|
|
14
|
+
</component>
|
|
@@ -4,8 +4,8 @@
|
|
|
4
4
|
name="kill-server"
|
|
5
5
|
type="NodeJSConfigurationType"
|
|
6
6
|
application-parameters="{{port}}"
|
|
7
|
-
path-to-js-file="kill-port.js"
|
|
8
|
-
working-dir="$PROJECT_DIR
|
|
7
|
+
path-to-js-file="scripts/kill-port.js"
|
|
8
|
+
working-dir="$PROJECT_DIR$"
|
|
9
9
|
>
|
|
10
10
|
<method v="2"/>
|
|
11
11
|
</configuration>
|
|
@@ -1,12 +1,11 @@
|
|
|
1
1
|
<component name="ProjectRunConfigurationManager">
|
|
2
2
|
<configuration
|
|
3
3
|
default="false"
|
|
4
|
-
name="
|
|
4
|
+
name="remove-nul.js"
|
|
5
5
|
type="NodeJSConfigurationType"
|
|
6
|
-
|
|
7
|
-
path-to-js-file="
|
|
8
|
-
working-dir="$PROJECT_DIR
|
|
9
|
-
>
|
|
6
|
+
nameIsGenerated="true"
|
|
7
|
+
path-to-js-file="scripts/remove-nul.js"
|
|
8
|
+
working-dir="$PROJECT_DIR$">
|
|
10
9
|
<method v="2"/>
|
|
11
10
|
</configuration>
|
|
12
11
|
</component>
|