@aigne/example-mcp-blocklet 1.7.3 → 1.9.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/README.md +6 -0
- package/index.ts +27 -17
- package/oauth.ts +5 -3
- package/package.json +6 -3
package/README.md
CHANGED
package/index.ts
CHANGED
|
@@ -2,11 +2,11 @@
|
|
|
2
2
|
|
|
3
3
|
import assert from "node:assert";
|
|
4
4
|
import { runChatLoopInTerminal } from "@aigne/cli/utils/run-chat-loop.js";
|
|
5
|
-
import { AIAgent,
|
|
5
|
+
import { AIAgent, AIGNE, MCPAgent, PromptBuilder } from "@aigne/core";
|
|
6
6
|
import { loadModel } from "@aigne/core/loader/index.js";
|
|
7
7
|
import { logger } from "@aigne/core/utils/logger.js";
|
|
8
8
|
import { UnauthorizedError, refreshAuthorization } from "@modelcontextprotocol/sdk/client/auth.js";
|
|
9
|
-
import {
|
|
9
|
+
import { StreamableHTTPClientTransport } from "@modelcontextprotocol/sdk/client/streamableHttp.js";
|
|
10
10
|
// @ts-ignore
|
|
11
11
|
import JWT from "jsonwebtoken";
|
|
12
12
|
|
|
@@ -14,20 +14,28 @@ import { TerminalOAuthProvider } from "./oauth.js";
|
|
|
14
14
|
|
|
15
15
|
logger.enable(`aigne:mcp,${process.env.DEBUG}`);
|
|
16
16
|
|
|
17
|
-
const
|
|
18
|
-
assert(
|
|
19
|
-
|
|
17
|
+
const rawUrl = process.argv[2] || process.env.BLOCKLET_APP_URL;
|
|
18
|
+
assert(
|
|
19
|
+
rawUrl,
|
|
20
|
+
"Please provide a blocklet url as an argument or set the BLOCKLET_APP_URL environment variable",
|
|
21
|
+
);
|
|
20
22
|
|
|
21
|
-
const appUrl = new URL(
|
|
22
|
-
appUrl.pathname = "/.well-known/service/mcp
|
|
23
|
+
const appUrl = new URL(rawUrl);
|
|
24
|
+
appUrl.pathname = "/.well-known/service/mcp";
|
|
25
|
+
console.info("Connecting to blocklet", appUrl.href);
|
|
26
|
+
|
|
27
|
+
let transport: StreamableHTTPClientTransport;
|
|
23
28
|
|
|
24
29
|
const provider = new TerminalOAuthProvider(appUrl.host);
|
|
25
30
|
const authCodePromise = new Promise((resolve, reject) => {
|
|
26
|
-
provider.once("authorized",
|
|
31
|
+
provider.once("authorized", async (code) => {
|
|
32
|
+
await transport.finishAuth(code);
|
|
33
|
+
resolve(code);
|
|
34
|
+
});
|
|
27
35
|
provider.once("error", reject);
|
|
28
36
|
});
|
|
29
37
|
|
|
30
|
-
|
|
38
|
+
transport = new StreamableHTTPClientTransport(appUrl, {
|
|
31
39
|
authProvider: provider,
|
|
32
40
|
});
|
|
33
41
|
|
|
@@ -35,22 +43,25 @@ try {
|
|
|
35
43
|
let tokens = await provider.tokens();
|
|
36
44
|
if (tokens) {
|
|
37
45
|
let decoded = JWT.decode(tokens.access_token);
|
|
38
|
-
console.info("Decoded access token:", decoded);
|
|
39
46
|
if (decoded) {
|
|
40
47
|
const now = Date.now();
|
|
41
48
|
const expiresAt = decoded.exp * 1000;
|
|
42
49
|
if (now < expiresAt) {
|
|
43
50
|
console.info("Tokens already exist and not expired, skipping authorization");
|
|
44
51
|
} else if (tokens.refresh_token) {
|
|
52
|
+
console.info("Access token expired:", { now, expiresAt, decoded });
|
|
45
53
|
decoded = JWT.decode(tokens.refresh_token);
|
|
46
|
-
console.info("Decoded refresh token:", decoded);
|
|
47
54
|
if (decoded) {
|
|
48
55
|
const now = Date.now();
|
|
49
56
|
const expiresAt = decoded.exp * 1000;
|
|
50
57
|
if (now < expiresAt) {
|
|
51
58
|
console.info("Refresh token already exists and not expired, refreshing authorization");
|
|
52
59
|
try {
|
|
60
|
+
const oauthUrl = new URL(appUrl.href);
|
|
61
|
+
oauthUrl.pathname = "/.well-known/oauth-authorization-server";
|
|
62
|
+
const metadata = await fetch(oauthUrl.href).then((res) => res.json());
|
|
53
63
|
tokens = await refreshAuthorization(appUrl.href, {
|
|
64
|
+
metadata,
|
|
54
65
|
// biome-ignore lint/style/noNonNullAssertion: <explanation>
|
|
55
66
|
clientInformation: (await provider.clientInformation())!,
|
|
56
67
|
refreshToken: tokens.refresh_token,
|
|
@@ -72,7 +83,7 @@ try {
|
|
|
72
83
|
}
|
|
73
84
|
}
|
|
74
85
|
} else {
|
|
75
|
-
console.info("No tokens found, starting authorization");
|
|
86
|
+
console.info("No tokens found, starting authorization...");
|
|
76
87
|
await transport.start();
|
|
77
88
|
}
|
|
78
89
|
} catch (error) {
|
|
@@ -87,21 +98,20 @@ try {
|
|
|
87
98
|
}
|
|
88
99
|
}
|
|
89
100
|
|
|
90
|
-
console.info("Starting connecting to blocklet mcp...");
|
|
91
|
-
|
|
92
101
|
const model = await loadModel();
|
|
93
102
|
|
|
94
103
|
const blocklet = await MCPAgent.from({
|
|
95
104
|
url: appUrl.href,
|
|
96
105
|
timeout: 8000,
|
|
106
|
+
transport: "streamableHttp",
|
|
97
107
|
opts: {
|
|
98
108
|
authProvider: provider,
|
|
99
109
|
},
|
|
100
110
|
});
|
|
101
111
|
|
|
102
|
-
const
|
|
112
|
+
const aigne = new AIGNE({
|
|
103
113
|
model,
|
|
104
|
-
|
|
114
|
+
skills: [blocklet],
|
|
105
115
|
});
|
|
106
116
|
|
|
107
117
|
const agent = AIAgent.from({
|
|
@@ -111,7 +121,7 @@ const agent = AIAgent.from({
|
|
|
111
121
|
memory: true,
|
|
112
122
|
});
|
|
113
123
|
|
|
114
|
-
const userAgent =
|
|
124
|
+
const userAgent = aigne.invoke(agent);
|
|
115
125
|
|
|
116
126
|
await runChatLoopInTerminal(userAgent, {
|
|
117
127
|
welcome:
|
package/oauth.ts
CHANGED
|
@@ -147,8 +147,10 @@ export class TerminalOAuthProvider extends EventEmitter implements OAuthClientPr
|
|
|
147
147
|
|
|
148
148
|
if (code) {
|
|
149
149
|
this.emit("authorized", code);
|
|
150
|
-
console.info("Authorization
|
|
151
|
-
|
|
150
|
+
console.info("Authorization code received, exchanging for tokens...");
|
|
151
|
+
setTimeout(() => {
|
|
152
|
+
resolve();
|
|
153
|
+
}, 3000);
|
|
152
154
|
} else {
|
|
153
155
|
this.emit("error", new Error("No authorization code received"));
|
|
154
156
|
reject(new Error("No authorization code received"));
|
|
@@ -158,7 +160,7 @@ export class TerminalOAuthProvider extends EventEmitter implements OAuthClientPr
|
|
|
158
160
|
|
|
159
161
|
// Start the local server
|
|
160
162
|
server.listen(this.localServerPort, async () => {
|
|
161
|
-
console.log("Please
|
|
163
|
+
console.log("Please complete the authorization in your browser...");
|
|
162
164
|
// Open the authorization URL in the default browser
|
|
163
165
|
await open(authorizationUrl.toString());
|
|
164
166
|
});
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@aigne/example-mcp-blocklet",
|
|
3
|
-
"version": "1.
|
|
3
|
+
"version": "1.9.0",
|
|
4
4
|
"description": "A demonstration of using AIGNE Framework and MCP Server hosted by the Blocklet platform",
|
|
5
5
|
"author": "Arcblock <blocklet@arcblock.io> https://github.com/blocklet",
|
|
6
6
|
"homepage": "https://github.com/AIGNE-io/aigne-framework/tree/main/examples/mcp-blocklet",
|
|
@@ -20,8 +20,11 @@
|
|
|
20
20
|
"jsonwebtoken": "^9.0.2",
|
|
21
21
|
"open": "^10.1.0",
|
|
22
22
|
"zod": "^3.24.2",
|
|
23
|
-
"@aigne/cli": "^1.
|
|
24
|
-
"@aigne/core": "^1.
|
|
23
|
+
"@aigne/cli": "^1.8.1",
|
|
24
|
+
"@aigne/core": "^1.13.0"
|
|
25
|
+
},
|
|
26
|
+
"devDependencies": {
|
|
27
|
+
"@aigne/test-utils": "^0.1.0"
|
|
25
28
|
},
|
|
26
29
|
"scripts": {
|
|
27
30
|
"start": "bun run index.ts",
|