@expandai/mcp-server 0.1.1 → 0.1.4
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/LICENSE +1 -1
- package/README.md +1 -1
- package/dist/Server.cjs +831 -0
- package/dist/Server.d.cts +15 -0
- package/dist/Server.d.ts +15 -0
- package/dist/Server.js +1 -0
- package/dist/chunk-TUBB4OP4.js +802 -0
- package/dist/main.cjs +66 -11
- package/dist/main.d.cts +1 -0
- package/dist/main.d.ts +1 -0
- package/dist/main.js +47 -0
- package/package.json +14 -3
- package/src/ExpandClient.ts +19 -4
- package/src/{tools/Fetch.ts → Fetch.ts} +7 -2
- package/src/Server.ts +17 -0
- package/src/Toolkit.ts +23 -0
- package/src/main.ts +40 -9
- package/src/tools/index.ts +0 -33
- /package/src/{resources/ExpandDocs.ts → ExpandDocs.ts} +0 -0
- /package/src/{generated/ExpandClient.ts → Generated.ts} +0 -0
package/dist/main.cjs
CHANGED
|
@@ -39,7 +39,7 @@ var S__namespace = /*#__PURE__*/_interopNamespace(S);
|
|
|
39
39
|
|
|
40
40
|
// package.json
|
|
41
41
|
var package_default = {
|
|
42
|
-
version: "0.1.
|
|
42
|
+
version: "0.1.4"};
|
|
43
43
|
var ExpandDocs = ai.McpServer.resource({
|
|
44
44
|
uri: "expand://about",
|
|
45
45
|
name: "About expand.ai",
|
|
@@ -690,7 +690,7 @@ var ClientError = (tag, cause, response) => new ClientErrorImpl({
|
|
|
690
690
|
|
|
691
691
|
// src/ExpandClient.ts
|
|
692
692
|
var ExpandConfig = effect.Config.all({
|
|
693
|
-
apiKey: effect.Config.redacted("EXPAND_API_KEY"),
|
|
693
|
+
apiKey: effect.Config.option(effect.Config.redacted("EXPAND_API_KEY")),
|
|
694
694
|
baseUrl: effect.Config.withDefault(effect.Config.string("EXPAND_BASE_URL"), "https://api.expand.ai")
|
|
695
695
|
});
|
|
696
696
|
var ExpandClient = class extends effect.Effect.Service()("ExpandClient", {
|
|
@@ -698,11 +698,24 @@ var ExpandClient = class extends effect.Effect.Service()("ExpandClient", {
|
|
|
698
698
|
scoped: effect.Effect.gen(function* () {
|
|
699
699
|
const config = yield* ExpandConfig;
|
|
700
700
|
const httpClient = yield* platform.HttpClient.HttpClient;
|
|
701
|
+
const requestHeaders = yield* effect.Effect.serviceOption(CurrentRequestHeaders);
|
|
702
|
+
yield* effect.Effect.logInfo(`ExpandClient connected to ${config.baseUrl}`);
|
|
701
703
|
return make(httpClient, {
|
|
702
704
|
transformClient: (client) => effect.Effect.succeed(
|
|
703
705
|
client.pipe(
|
|
704
706
|
platform.HttpClient.mapRequest(platform.HttpClientRequest.prependUrl(config.baseUrl)),
|
|
705
|
-
platform.HttpClient.mapRequest(
|
|
707
|
+
platform.HttpClient.mapRequest((req) => {
|
|
708
|
+
if (effect.Option.isSome(requestHeaders)) {
|
|
709
|
+
const auth = requestHeaders.value["authorization"];
|
|
710
|
+
if (auth) {
|
|
711
|
+
return platform.HttpClientRequest.setHeader("authorization", auth)(req);
|
|
712
|
+
}
|
|
713
|
+
}
|
|
714
|
+
if (effect.Option.isSome(config.apiKey)) {
|
|
715
|
+
return platform.HttpClientRequest.setHeader("x-expand-api-key", effect.Redacted.value(config.apiKey.value))(req);
|
|
716
|
+
}
|
|
717
|
+
return req;
|
|
718
|
+
})
|
|
706
719
|
)
|
|
707
720
|
)
|
|
708
721
|
});
|
|
@@ -765,6 +778,8 @@ var Fetch = class extends effect.Effect.Service()("Fetch", {
|
|
|
765
778
|
scoped: effect.Effect.gen(function* () {
|
|
766
779
|
const client = yield* ExpandClient;
|
|
767
780
|
const fetch = effect.Effect.fn("Fetch.fetch")(function* ({ url, format, includeMeta }) {
|
|
781
|
+
const formatLabel = format instanceof SnippetsFormat ? "snippets" : format;
|
|
782
|
+
yield* effect.Effect.logDebug(`Fetching: ${url}`).pipe(effect.Effect.annotateLogs({ format: formatLabel, includeMeta }));
|
|
768
783
|
const result = yield* client.fetch({
|
|
769
784
|
url,
|
|
770
785
|
select: {
|
|
@@ -776,6 +791,7 @@ var Fetch = class extends effect.Effect.Service()("Fetch", {
|
|
|
776
791
|
}
|
|
777
792
|
});
|
|
778
793
|
const content = result.data.markdown ?? result.data.html ?? result.data.summary ?? result.data.snippets?.map((snippet) => `${snippet.text} (Score: ${snippet.score})`).join("\n") ?? "";
|
|
794
|
+
yield* effect.Effect.logDebug(`\u{1F4E4} Fetched successfully: ${result.data.response.url}`);
|
|
779
795
|
return new FetchResult2({
|
|
780
796
|
content,
|
|
781
797
|
url: result.data.response.url,
|
|
@@ -787,28 +803,67 @@ var Fetch = class extends effect.Effect.Service()("Fetch", {
|
|
|
787
803
|
}) {
|
|
788
804
|
};
|
|
789
805
|
|
|
790
|
-
// src/
|
|
806
|
+
// src/Toolkit.ts
|
|
791
807
|
var toolkit = ai.Toolkit.make(FetchTool);
|
|
792
808
|
var ToolkitLayer = toolkit.toLayer(
|
|
793
809
|
effect.Effect.gen(function* () {
|
|
810
|
+
yield* effect.Effect.logInfo("Registering tools: fetch");
|
|
794
811
|
const fetchService = yield* Fetch;
|
|
795
812
|
return toolkit.of({
|
|
796
813
|
fetch: fetchService.fetch
|
|
797
814
|
});
|
|
798
815
|
})
|
|
799
816
|
).pipe(effect.Layer.provide(Fetch.Default), effect.Layer.provide(ExpandClient.Default), effect.Layer.provide(platformNode.NodeHttpClient.layerUndici));
|
|
800
|
-
var
|
|
817
|
+
var ExpandToolKit = ai.McpServer.toolkit(toolkit).pipe(effect.Layer.provide(ToolkitLayer));
|
|
818
|
+
|
|
819
|
+
// src/Server.ts
|
|
820
|
+
var ServerInfo = {
|
|
821
|
+
name: "expandai-mcp-server",
|
|
822
|
+
version: package_default.version
|
|
823
|
+
};
|
|
824
|
+
var CurrentRequestHeaders = class extends effect.Context.Tag("CurrentRequestHeaders")() {
|
|
825
|
+
};
|
|
826
|
+
var makeServerLayer = (options = {}) => options.includeDocs ? effect.Layer.mergeAll(ExpandToolKit, ExpandDocs) : ExpandToolKit;
|
|
801
827
|
|
|
802
828
|
// src/main.ts
|
|
803
|
-
var enableDocs = effect.Config.withDefault(effect.Config.boolean("EXPAND_ENABLE_DOCS"),
|
|
829
|
+
var enableDocs = effect.Config.withDefault(effect.Config.boolean("EXPAND_ENABLE_DOCS"), false);
|
|
830
|
+
var logLevelConfig = effect.Config.withDefault(
|
|
831
|
+
effect.Config.literal("debug", "info", "warning", "error", "none")("LOG_LEVEL"),
|
|
832
|
+
"info"
|
|
833
|
+
);
|
|
834
|
+
var logLevelMap = {
|
|
835
|
+
debug: effect.LogLevel.Debug,
|
|
836
|
+
info: effect.LogLevel.Info,
|
|
837
|
+
warning: effect.LogLevel.Warning,
|
|
838
|
+
error: effect.LogLevel.Error,
|
|
839
|
+
none: effect.LogLevel.None
|
|
840
|
+
};
|
|
841
|
+
var startupBanner = `
|
|
842
|
+
\u2554\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2557
|
|
843
|
+
\u2551 \u2551
|
|
844
|
+
\u2551 \u{1F310} expand.ai MCP Server \u2551
|
|
845
|
+
\u2551 \u2551
|
|
846
|
+
\u255A\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u255D`;
|
|
804
847
|
var program = effect.Effect.gen(function* () {
|
|
805
848
|
const docsEnabled = yield* enableDocs;
|
|
806
|
-
const
|
|
807
|
-
yield*
|
|
808
|
-
|
|
809
|
-
|
|
849
|
+
const logLevel = yield* logLevelConfig;
|
|
850
|
+
yield* effect.Effect.logInfo(startupBanner);
|
|
851
|
+
yield* effect.Effect.logInfo(`Starting v${ServerInfo.version}`);
|
|
852
|
+
yield* effect.Effect.logInfo(`Documentation resources: ${docsEnabled ? "enabled" : "disabled"}`);
|
|
853
|
+
const McpLayer = ai.McpServer.layerStdio({
|
|
854
|
+
...ServerInfo,
|
|
810
855
|
stdin: platformNode.NodeStream.stdin,
|
|
811
856
|
stdout: platformNode.NodeSink.stdout
|
|
812
|
-
}).pipe(effect.Layer.provide(
|
|
857
|
+
}).pipe(effect.Layer.provide(makeServerLayer({ includeDocs: docsEnabled })));
|
|
858
|
+
const LifecycleLayer = effect.Layer.scopedDiscard(
|
|
859
|
+
effect.Effect.acquireRelease(
|
|
860
|
+
effect.Effect.logInfo("Server ready and listening on stdio"),
|
|
861
|
+
() => effect.Effect.logInfo("Server shutting down gracefully...")
|
|
862
|
+
)
|
|
863
|
+
);
|
|
864
|
+
yield* effect.Layer.merge(McpLayer, LifecycleLayer).pipe(
|
|
865
|
+
effect.Layer.provide(effect.Logger.minimumLogLevel(logLevelMap[logLevel])),
|
|
866
|
+
effect.Layer.launch
|
|
867
|
+
);
|
|
813
868
|
});
|
|
814
869
|
program.pipe(platformNode.NodeRuntime.runMain);
|
package/dist/main.d.cts
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
package/dist/main.d.ts
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
package/dist/main.js
ADDED
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
import { ServerInfo, makeServerLayer } from './chunk-TUBB4OP4.js';
|
|
3
|
+
import { McpServer } from '@effect/ai';
|
|
4
|
+
import { NodeSink, NodeStream, NodeRuntime } from '@effect/platform-node';
|
|
5
|
+
import { Config, Effect, Layer, Logger, LogLevel } from 'effect';
|
|
6
|
+
|
|
7
|
+
var enableDocs = Config.withDefault(Config.boolean("EXPAND_ENABLE_DOCS"), false);
|
|
8
|
+
var logLevelConfig = Config.withDefault(
|
|
9
|
+
Config.literal("debug", "info", "warning", "error", "none")("LOG_LEVEL"),
|
|
10
|
+
"info"
|
|
11
|
+
);
|
|
12
|
+
var logLevelMap = {
|
|
13
|
+
debug: LogLevel.Debug,
|
|
14
|
+
info: LogLevel.Info,
|
|
15
|
+
warning: LogLevel.Warning,
|
|
16
|
+
error: LogLevel.Error,
|
|
17
|
+
none: LogLevel.None
|
|
18
|
+
};
|
|
19
|
+
var startupBanner = `
|
|
20
|
+
\u2554\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2557
|
|
21
|
+
\u2551 \u2551
|
|
22
|
+
\u2551 \u{1F310} expand.ai MCP Server \u2551
|
|
23
|
+
\u2551 \u2551
|
|
24
|
+
\u255A\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u255D`;
|
|
25
|
+
var program = Effect.gen(function* () {
|
|
26
|
+
const docsEnabled = yield* enableDocs;
|
|
27
|
+
const logLevel = yield* logLevelConfig;
|
|
28
|
+
yield* Effect.logInfo(startupBanner);
|
|
29
|
+
yield* Effect.logInfo(`Starting v${ServerInfo.version}`);
|
|
30
|
+
yield* Effect.logInfo(`Documentation resources: ${docsEnabled ? "enabled" : "disabled"}`);
|
|
31
|
+
const McpLayer = McpServer.layerStdio({
|
|
32
|
+
...ServerInfo,
|
|
33
|
+
stdin: NodeStream.stdin,
|
|
34
|
+
stdout: NodeSink.stdout
|
|
35
|
+
}).pipe(Layer.provide(makeServerLayer({ includeDocs: docsEnabled })));
|
|
36
|
+
const LifecycleLayer = Layer.scopedDiscard(
|
|
37
|
+
Effect.acquireRelease(
|
|
38
|
+
Effect.logInfo("Server ready and listening on stdio"),
|
|
39
|
+
() => Effect.logInfo("Server shutting down gracefully...")
|
|
40
|
+
)
|
|
41
|
+
);
|
|
42
|
+
yield* Layer.merge(McpLayer, LifecycleLayer).pipe(
|
|
43
|
+
Layer.provide(Logger.minimumLogLevel(logLevelMap[logLevel])),
|
|
44
|
+
Layer.launch
|
|
45
|
+
);
|
|
46
|
+
});
|
|
47
|
+
program.pipe(NodeRuntime.runMain);
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@expandai/mcp-server",
|
|
3
|
-
"version": "0.1.
|
|
3
|
+
"version": "0.1.4",
|
|
4
4
|
"description": "MCP server for expand.ai - Give AI agents access to the web",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"publishConfig": {
|
|
@@ -9,6 +9,14 @@
|
|
|
9
9
|
"bin": {
|
|
10
10
|
"expandai-mcp-server": "./dist/main.cjs"
|
|
11
11
|
},
|
|
12
|
+
"exports": {
|
|
13
|
+
".": "./dist/main.cjs",
|
|
14
|
+
"./Server": {
|
|
15
|
+
"types": "./dist/Server.d.ts",
|
|
16
|
+
"import": "./dist/Server.js",
|
|
17
|
+
"require": "./dist/Server.cjs"
|
|
18
|
+
}
|
|
19
|
+
},
|
|
12
20
|
"files": [
|
|
13
21
|
"dist",
|
|
14
22
|
"src",
|
|
@@ -17,10 +25,13 @@
|
|
|
17
25
|
],
|
|
18
26
|
"repository": {
|
|
19
27
|
"type": "git",
|
|
20
|
-
"url": "https://github.com/expandai/expandai-mcp-server.git"
|
|
28
|
+
"url": "git+https://github.com/expandai/expandai-mcp-server.git"
|
|
29
|
+
},
|
|
30
|
+
"bugs": {
|
|
31
|
+
"url": "https://github.com/expandai/expandai-mcp-server/issues"
|
|
21
32
|
},
|
|
22
33
|
"homepage": "https://expand.ai",
|
|
23
|
-
"author": "expand.ai",
|
|
34
|
+
"author": "expand.ai <support@expand.ai>",
|
|
24
35
|
"license": "Apache-2.0",
|
|
25
36
|
"keywords": [
|
|
26
37
|
"mcp",
|
package/src/ExpandClient.ts
CHANGED
|
@@ -1,9 +1,10 @@
|
|
|
1
1
|
import { HttpClient, HttpClientRequest } from '@effect/platform'
|
|
2
|
-
import { Config, Effect, Redacted } from 'effect'
|
|
3
|
-
import * as GeneratedClient from './
|
|
2
|
+
import { Config, Effect, Option, Redacted } from 'effect'
|
|
3
|
+
import * as GeneratedClient from './Generated.js'
|
|
4
|
+
import { CurrentRequestHeaders } from './Server.js'
|
|
4
5
|
|
|
5
6
|
export const ExpandConfig = Config.all({
|
|
6
|
-
apiKey: Config.redacted('EXPAND_API_KEY'),
|
|
7
|
+
apiKey: Config.option(Config.redacted('EXPAND_API_KEY')),
|
|
7
8
|
baseUrl: Config.withDefault(Config.string('EXPAND_BASE_URL'), 'https://api.expand.ai'),
|
|
8
9
|
})
|
|
9
10
|
|
|
@@ -12,13 +13,27 @@ export class ExpandClient extends Effect.Service<ExpandClient>()('ExpandClient',
|
|
|
12
13
|
scoped: Effect.gen(function* () {
|
|
13
14
|
const config = yield* ExpandConfig
|
|
14
15
|
const httpClient = yield* HttpClient.HttpClient
|
|
16
|
+
const requestHeaders = yield* Effect.serviceOption(CurrentRequestHeaders)
|
|
17
|
+
|
|
18
|
+
yield* Effect.logInfo(`ExpandClient connected to ${config.baseUrl}`)
|
|
15
19
|
|
|
16
20
|
return GeneratedClient.make(httpClient, {
|
|
17
21
|
transformClient: (client) =>
|
|
18
22
|
Effect.succeed(
|
|
19
23
|
client.pipe(
|
|
20
24
|
HttpClient.mapRequest(HttpClientRequest.prependUrl(config.baseUrl)),
|
|
21
|
-
HttpClient.mapRequest(
|
|
25
|
+
HttpClient.mapRequest((req) => {
|
|
26
|
+
if (Option.isSome(requestHeaders)) {
|
|
27
|
+
const auth = requestHeaders.value['authorization']
|
|
28
|
+
if (auth) {
|
|
29
|
+
return HttpClientRequest.setHeader('authorization', auth)(req)
|
|
30
|
+
}
|
|
31
|
+
}
|
|
32
|
+
if (Option.isSome(config.apiKey)) {
|
|
33
|
+
return HttpClientRequest.setHeader('x-expand-api-key', Redacted.value(config.apiKey.value))(req)
|
|
34
|
+
}
|
|
35
|
+
return req
|
|
36
|
+
}),
|
|
22
37
|
),
|
|
23
38
|
),
|
|
24
39
|
})
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { Tool } from '@effect/ai'
|
|
2
2
|
import { Effect, Schema } from 'effect'
|
|
3
|
-
import { ExpandClient } from '
|
|
4
|
-
import { PageMeta } from '
|
|
3
|
+
import { ExpandClient } from './ExpandClient.js'
|
|
4
|
+
import { PageMeta } from './Generated.js'
|
|
5
5
|
|
|
6
6
|
export class SnippetsFormat extends Schema.Class<SnippetsFormat>('SnippetsFormat')({
|
|
7
7
|
query: Schema.String.annotations({
|
|
@@ -64,6 +64,9 @@ export class Fetch extends Effect.Service<Fetch>()('Fetch', {
|
|
|
64
64
|
const client = yield* ExpandClient
|
|
65
65
|
|
|
66
66
|
const fetch = Effect.fn('Fetch.fetch')(function* ({ url, format, includeMeta }: FetchParams) {
|
|
67
|
+
const formatLabel = format instanceof SnippetsFormat ? 'snippets' : format
|
|
68
|
+
yield* Effect.logDebug(`Fetching: ${url}`).pipe(Effect.annotateLogs({ format: formatLabel, includeMeta }))
|
|
69
|
+
|
|
67
70
|
const result = yield* client.fetch({
|
|
68
71
|
url,
|
|
69
72
|
select: {
|
|
@@ -82,6 +85,8 @@ export class Fetch extends Effect.Service<Fetch>()('Fetch', {
|
|
|
82
85
|
result.data.snippets?.map((snippet) => `${snippet.text} (Score: ${snippet.score})`).join('\n') ??
|
|
83
86
|
''
|
|
84
87
|
|
|
88
|
+
yield* Effect.logDebug(`📤 Fetched successfully: ${result.data.response.url}`)
|
|
89
|
+
|
|
85
90
|
return new FetchResult({
|
|
86
91
|
content,
|
|
87
92
|
url: result.data.response.url,
|
package/src/Server.ts
ADDED
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
import { Context, Layer } from 'effect'
|
|
2
|
+
import packageJson from '../package.json' with { type: 'json' }
|
|
3
|
+
import { ExpandDocs } from './ExpandDocs.js'
|
|
4
|
+
import { ExpandToolKit } from './Toolkit.js'
|
|
5
|
+
|
|
6
|
+
export const ServerInfo = {
|
|
7
|
+
name: 'expandai-mcp-server',
|
|
8
|
+
version: packageJson.version,
|
|
9
|
+
} as const
|
|
10
|
+
|
|
11
|
+
export class CurrentRequestHeaders extends Context.Tag('CurrentRequestHeaders')<
|
|
12
|
+
CurrentRequestHeaders,
|
|
13
|
+
Record<string, string>
|
|
14
|
+
>() {}
|
|
15
|
+
|
|
16
|
+
export const makeServerLayer = (options: { readonly includeDocs?: boolean } = {}) =>
|
|
17
|
+
options.includeDocs ? Layer.mergeAll(ExpandToolKit, ExpandDocs) : ExpandToolKit
|
package/src/Toolkit.ts
ADDED
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
import { McpServer, Toolkit } from '@effect/ai'
|
|
2
|
+
import { NodeHttpClient } from '@effect/platform-node'
|
|
3
|
+
import { Effect, Layer } from 'effect'
|
|
4
|
+
import { ExpandClient } from './ExpandClient.js'
|
|
5
|
+
import { Fetch, FetchTool } from './Fetch.js'
|
|
6
|
+
|
|
7
|
+
const toolkit = Toolkit.make(FetchTool)
|
|
8
|
+
|
|
9
|
+
const ToolkitLayer = toolkit
|
|
10
|
+
.toLayer(
|
|
11
|
+
Effect.gen(function* () {
|
|
12
|
+
yield* Effect.logInfo('Registering tools: fetch')
|
|
13
|
+
|
|
14
|
+
const fetchService = yield* Fetch
|
|
15
|
+
|
|
16
|
+
return toolkit.of({
|
|
17
|
+
fetch: fetchService.fetch,
|
|
18
|
+
})
|
|
19
|
+
}),
|
|
20
|
+
)
|
|
21
|
+
.pipe(Layer.provide(Fetch.Default), Layer.provide(ExpandClient.Default), Layer.provide(NodeHttpClient.layerUndici))
|
|
22
|
+
|
|
23
|
+
export const ExpandToolKit = McpServer.toolkit(toolkit).pipe(Layer.provide(ToolkitLayer))
|
package/src/main.ts
CHANGED
|
@@ -2,23 +2,54 @@
|
|
|
2
2
|
import { McpServer } from '@effect/ai'
|
|
3
3
|
import { NodeRuntime, NodeSink, NodeStream } from '@effect/platform-node'
|
|
4
4
|
import { Config, Effect, Layer, Logger, LogLevel } from 'effect'
|
|
5
|
-
import
|
|
6
|
-
import { ExpandDocs } from './resources/ExpandDocs.js'
|
|
7
|
-
import { ExpandTools } from './tools/index.js'
|
|
5
|
+
import { makeServerLayer, ServerInfo } from './Server.js'
|
|
8
6
|
|
|
9
|
-
const enableDocs = Config.withDefault(Config.boolean('EXPAND_ENABLE_DOCS'),
|
|
7
|
+
const enableDocs = Config.withDefault(Config.boolean('EXPAND_ENABLE_DOCS'), false)
|
|
8
|
+
|
|
9
|
+
const logLevelConfig = Config.withDefault(
|
|
10
|
+
Config.literal('debug', 'info', 'warning', 'error', 'none')('LOG_LEVEL'),
|
|
11
|
+
'info',
|
|
12
|
+
)
|
|
13
|
+
|
|
14
|
+
const logLevelMap = {
|
|
15
|
+
debug: LogLevel.Debug,
|
|
16
|
+
info: LogLevel.Info,
|
|
17
|
+
warning: LogLevel.Warning,
|
|
18
|
+
error: LogLevel.Error,
|
|
19
|
+
none: LogLevel.None,
|
|
20
|
+
} as const
|
|
21
|
+
|
|
22
|
+
const startupBanner = `
|
|
23
|
+
╔═══════════════════════════════════════════════════╗
|
|
24
|
+
║ ║
|
|
25
|
+
║ 🌐 expand.ai MCP Server ║
|
|
26
|
+
║ ║
|
|
27
|
+
╚═══════════════════════════════════════════════════╝`
|
|
10
28
|
|
|
11
29
|
const program = Effect.gen(function* () {
|
|
12
30
|
const docsEnabled = yield* enableDocs
|
|
31
|
+
const logLevel = yield* logLevelConfig
|
|
13
32
|
|
|
14
|
-
|
|
33
|
+
yield* Effect.logInfo(startupBanner)
|
|
34
|
+
yield* Effect.logInfo(`Starting v${ServerInfo.version}`)
|
|
35
|
+
yield* Effect.logInfo(`Documentation resources: ${docsEnabled ? 'enabled' : 'disabled'}`)
|
|
15
36
|
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
version: packageJson.version,
|
|
37
|
+
const McpLayer = McpServer.layerStdio({
|
|
38
|
+
...ServerInfo,
|
|
19
39
|
stdin: NodeStream.stdin,
|
|
20
40
|
stdout: NodeSink.stdout,
|
|
21
|
-
}).pipe(Layer.provide(
|
|
41
|
+
}).pipe(Layer.provide(makeServerLayer({ includeDocs: docsEnabled })))
|
|
42
|
+
|
|
43
|
+
const LifecycleLayer = Layer.scopedDiscard(
|
|
44
|
+
Effect.acquireRelease(Effect.logInfo('Server ready and listening on stdio'), () =>
|
|
45
|
+
Effect.logInfo('Server shutting down gracefully...'),
|
|
46
|
+
),
|
|
47
|
+
)
|
|
48
|
+
|
|
49
|
+
yield* Layer.merge(McpLayer, LifecycleLayer).pipe(
|
|
50
|
+
Layer.provide(Logger.minimumLogLevel(logLevelMap[logLevel])),
|
|
51
|
+
Layer.launch,
|
|
52
|
+
)
|
|
22
53
|
})
|
|
23
54
|
|
|
24
55
|
program.pipe(NodeRuntime.runMain)
|
package/src/tools/index.ts
DELETED
|
@@ -1,33 +0,0 @@
|
|
|
1
|
-
import { McpServer, Toolkit } from '@effect/ai'
|
|
2
|
-
import { NodeHttpClient } from '@effect/platform-node'
|
|
3
|
-
import { Effect, Layer } from 'effect'
|
|
4
|
-
import { ExpandClient } from '../ExpandClient.js'
|
|
5
|
-
import { Fetch, FetchTool } from './Fetch.js'
|
|
6
|
-
|
|
7
|
-
// =============================================================================
|
|
8
|
-
// Toolkit (add more tools here)
|
|
9
|
-
// =============================================================================
|
|
10
|
-
|
|
11
|
-
const toolkit = Toolkit.make(FetchTool)
|
|
12
|
-
|
|
13
|
-
// =============================================================================
|
|
14
|
-
// Toolkit Layer
|
|
15
|
-
// =============================================================================
|
|
16
|
-
|
|
17
|
-
const ToolkitLayer = toolkit
|
|
18
|
-
.toLayer(
|
|
19
|
-
Effect.gen(function* () {
|
|
20
|
-
const fetchService = yield* Fetch
|
|
21
|
-
|
|
22
|
-
return toolkit.of({
|
|
23
|
-
fetch: fetchService.fetch,
|
|
24
|
-
})
|
|
25
|
-
}),
|
|
26
|
-
)
|
|
27
|
-
.pipe(Layer.provide(Fetch.Default), Layer.provide(ExpandClient.Default), Layer.provide(NodeHttpClient.layerUndici))
|
|
28
|
-
|
|
29
|
-
// =============================================================================
|
|
30
|
-
// Export
|
|
31
|
-
// =============================================================================
|
|
32
|
-
|
|
33
|
-
export const ExpandTools = McpServer.toolkit(toolkit).pipe(Layer.provide(ToolkitLayer))
|
|
File without changes
|
|
File without changes
|