@tamago-labs/wayfind-mcp 0.0.0-stage → 0.2.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/dist/index.d.mts +1 -0
- package/dist/index.d.ts +1 -0
- package/dist/index.js +179 -0
- package/dist/index.js.map +1 -0
- package/dist/index.mjs +156 -0
- package/dist/index.mjs.map +1 -0
- package/package.json +24 -4
- package/src/agent/index.ts +32 -0
- package/src/config.ts +17 -0
- package/src/index.ts +40 -0
- package/src/mcp/index.ts +16 -0
- package/src/mcp/solana/get_wallet_address_tool.ts +14 -0
- package/src/mcp/wayfind/get_market_overview_tool.ts +11 -0
- package/src/mcp/wayfind/get_pre_ipo_tool.ts +11 -0
- package/src/mcp/wayfind/get_risk_profile_tool.ts +11 -0
- package/src/mcp/wayfind/get_tokenized_stocks_tool.ts +14 -0
- package/src/mcp/wayfind/get_tokens_tool.ts +14 -0
- package/src/types.ts +8 -0
- package/tsconfig.json +16 -0
- package/tsup.config.ts +10 -0
- package/README.md +0 -3
package/dist/index.d.mts
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
package/dist/index.js
ADDED
|
@@ -0,0 +1,179 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
"use strict";
|
|
3
|
+
var __create = Object.create;
|
|
4
|
+
var __defProp = Object.defineProperty;
|
|
5
|
+
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
|
|
6
|
+
var __getOwnPropNames = Object.getOwnPropertyNames;
|
|
7
|
+
var __getProtoOf = Object.getPrototypeOf;
|
|
8
|
+
var __hasOwnProp = Object.prototype.hasOwnProperty;
|
|
9
|
+
var __copyProps = (to, from, except, desc) => {
|
|
10
|
+
if (from && typeof from === "object" || typeof from === "function") {
|
|
11
|
+
for (let key of __getOwnPropNames(from))
|
|
12
|
+
if (!__hasOwnProp.call(to, key) && key !== except)
|
|
13
|
+
__defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
|
|
14
|
+
}
|
|
15
|
+
return to;
|
|
16
|
+
};
|
|
17
|
+
var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps(
|
|
18
|
+
// If the importer is in node compatibility mode or this is not an ESM
|
|
19
|
+
// file that has been converted to a CommonJS file using a Babel-
|
|
20
|
+
// compatible transform (i.e. "__esModule" has not been set), then set
|
|
21
|
+
// "default" to the CommonJS "module.exports" for node compatibility.
|
|
22
|
+
isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { value: mod, enumerable: true }) : target,
|
|
23
|
+
mod
|
|
24
|
+
));
|
|
25
|
+
|
|
26
|
+
// src/index.ts
|
|
27
|
+
var import_mcp = require("@modelcontextprotocol/sdk/server/mcp.js");
|
|
28
|
+
var import_stdio = require("@modelcontextprotocol/sdk/server/stdio.js");
|
|
29
|
+
|
|
30
|
+
// src/mcp/solana/get_wallet_address_tool.ts
|
|
31
|
+
var GetWalletAddressTool = {
|
|
32
|
+
name: "solana_get_wallet_address",
|
|
33
|
+
description: "Get the Solana wallet address derived from the configured private key",
|
|
34
|
+
schema: {},
|
|
35
|
+
handler: async (agent, _input) => {
|
|
36
|
+
return {
|
|
37
|
+
walletAddress: agent.walletAddress
|
|
38
|
+
};
|
|
39
|
+
}
|
|
40
|
+
};
|
|
41
|
+
|
|
42
|
+
// src/mcp/wayfind/get_tokens_tool.ts
|
|
43
|
+
var import_zod = require("zod");
|
|
44
|
+
var WayfindGetTokensTool = {
|
|
45
|
+
name: "wayfind_get_tokens",
|
|
46
|
+
description: "List all tokenized stocks with prices and market data",
|
|
47
|
+
schema: {
|
|
48
|
+
chain: import_zod.z.string().optional().describe("Filter by blockchain (e.g., 'solana', 'ethereum')")
|
|
49
|
+
},
|
|
50
|
+
handler: async (agent, input) => {
|
|
51
|
+
return agent.wayfindFetch("/tokens", input?.chain ? { chain: input.chain } : void 0);
|
|
52
|
+
}
|
|
53
|
+
};
|
|
54
|
+
|
|
55
|
+
// src/mcp/wayfind/get_tokenized_stocks_tool.ts
|
|
56
|
+
var import_zod2 = require("zod");
|
|
57
|
+
var WayfindGetTokenizedStocksTool = {
|
|
58
|
+
name: "wayfind_get_tokenized_stocks",
|
|
59
|
+
description: "Get all tokenized versions of a stock ticker across blockchains (e.g. 'AAPL' returns AAPL on Solana, Ethereum, etc.)",
|
|
60
|
+
schema: {
|
|
61
|
+
ticker: import_zod2.z.string().describe("Stock ticker symbol (e.g., 'AAPL', 'GOOG', 'TSLA')")
|
|
62
|
+
},
|
|
63
|
+
handler: async (agent, input) => {
|
|
64
|
+
return agent.wayfindFetch(`/tokens/${encodeURIComponent(input.ticker)}`);
|
|
65
|
+
}
|
|
66
|
+
};
|
|
67
|
+
|
|
68
|
+
// src/mcp/wayfind/get_risk_profile_tool.ts
|
|
69
|
+
var WayfindGetRiskProfileTool = {
|
|
70
|
+
name: "wayfind_get_risk_profile",
|
|
71
|
+
description: "Get the user's portfolio risk profile including overall score, label, and answers",
|
|
72
|
+
schema: {},
|
|
73
|
+
handler: async (agent, _input) => {
|
|
74
|
+
return agent.wayfindFetch("/risk-profile");
|
|
75
|
+
}
|
|
76
|
+
};
|
|
77
|
+
|
|
78
|
+
// src/mcp/wayfind/get_market_overview_tool.ts
|
|
79
|
+
var WayfindGetMarketOverviewTool = {
|
|
80
|
+
name: "wayfind_get_market_overview",
|
|
81
|
+
description: "Get market overview including total market cap, 24h volume, gainers, losers, and trending tokens",
|
|
82
|
+
schema: {},
|
|
83
|
+
handler: async (agent, _input) => {
|
|
84
|
+
return agent.wayfindFetch("/market-overview");
|
|
85
|
+
}
|
|
86
|
+
};
|
|
87
|
+
|
|
88
|
+
// src/mcp/wayfind/get_pre_ipo_tool.ts
|
|
89
|
+
var WayfindGetPreIpoTool = {
|
|
90
|
+
name: "wayfind_get_pre_ipo",
|
|
91
|
+
description: "List pre-IPO markets with mark prices and valuations",
|
|
92
|
+
schema: {},
|
|
93
|
+
handler: async (agent, _input) => {
|
|
94
|
+
return agent.wayfindFetch("/pre-ipo");
|
|
95
|
+
}
|
|
96
|
+
};
|
|
97
|
+
|
|
98
|
+
// src/mcp/index.ts
|
|
99
|
+
var McpTools = {
|
|
100
|
+
SolanaGetWalletAddress: GetWalletAddressTool,
|
|
101
|
+
WayfindGetTokens: WayfindGetTokensTool,
|
|
102
|
+
WayfindGetTokenizedStocks: WayfindGetTokenizedStocksTool,
|
|
103
|
+
WayfindGetRiskProfile: WayfindGetRiskProfileTool,
|
|
104
|
+
WayfindGetMarketOverview: WayfindGetMarketOverviewTool,
|
|
105
|
+
WayfindGetPreIpo: WayfindGetPreIpoTool
|
|
106
|
+
};
|
|
107
|
+
|
|
108
|
+
// src/agent/index.ts
|
|
109
|
+
var import_kit = require("@solana/kit");
|
|
110
|
+
var import_bs58 = __toESM(require("bs58"));
|
|
111
|
+
|
|
112
|
+
// src/config.ts
|
|
113
|
+
function validateEnvironment() {
|
|
114
|
+
const privateKey = process.env.SOLANA_PRIVATE_KEY;
|
|
115
|
+
if (!privateKey) {
|
|
116
|
+
throw new Error("Missing required env: SOLANA_PRIVATE_KEY (base58 encoded, standard Solana format)");
|
|
117
|
+
}
|
|
118
|
+
const rpcUrl = process.env.SOLANA_RPC_URL || "https://api.mainnet-beta.solana.com";
|
|
119
|
+
const wayfindApiKey = process.env.WAYFIND_API_KEY || "e1ee8520-305a-49b5-a2de-3e1a7e6078c0";
|
|
120
|
+
const wayfindApiUrl = process.env.WAYFIND_API_URL || "https://o3qftki5dtnlhqlrtvswt336bq0mwdye.lambda-url.ap-southeast-1.on.aws";
|
|
121
|
+
return { privateKey, rpcUrl, wayfindApiKey, wayfindApiUrl };
|
|
122
|
+
}
|
|
123
|
+
|
|
124
|
+
// src/agent/index.ts
|
|
125
|
+
var Agent = class _Agent {
|
|
126
|
+
constructor(walletAddress, config) {
|
|
127
|
+
this.walletAddress = walletAddress;
|
|
128
|
+
this.config = config;
|
|
129
|
+
}
|
|
130
|
+
static async create() {
|
|
131
|
+
const config = validateEnvironment();
|
|
132
|
+
const decoded = import_bs58.default.decode(config.privateKey);
|
|
133
|
+
const seed = decoded.slice(0, 32);
|
|
134
|
+
const signer = await (0, import_kit.createKeyPairSignerFromPrivateKeyBytes)(seed, false);
|
|
135
|
+
return new _Agent(signer.address, config);
|
|
136
|
+
}
|
|
137
|
+
async wayfindFetch(path, params) {
|
|
138
|
+
const url = new URL(`${this.config.wayfindApiUrl}${path}`);
|
|
139
|
+
if (params) {
|
|
140
|
+
for (const [k, v] of Object.entries(params)) url.searchParams.set(k, v);
|
|
141
|
+
}
|
|
142
|
+
const res = await fetch(url.toString(), {
|
|
143
|
+
headers: { "x-api-key": this.config.wayfindApiKey }
|
|
144
|
+
});
|
|
145
|
+
return res.json();
|
|
146
|
+
}
|
|
147
|
+
};
|
|
148
|
+
|
|
149
|
+
// src/index.ts
|
|
150
|
+
function createMcpServer(agent) {
|
|
151
|
+
const server = new import_mcp.McpServer({
|
|
152
|
+
name: "wayfind-solana-mcp",
|
|
153
|
+
version: "0.1.0"
|
|
154
|
+
});
|
|
155
|
+
for (const [_key, tool] of Object.entries(McpTools)) {
|
|
156
|
+
server.tool(tool.name, tool.description, tool.schema, async (params) => {
|
|
157
|
+
try {
|
|
158
|
+
const result = await tool.handler(agent, params);
|
|
159
|
+
return {
|
|
160
|
+
content: [{ type: "text", text: JSON.stringify(result, null, 2) }]
|
|
161
|
+
};
|
|
162
|
+
} catch (error) {
|
|
163
|
+
return {
|
|
164
|
+
isError: true,
|
|
165
|
+
content: [{ type: "text", text: error instanceof Error ? error.message : "Unknown error" }]
|
|
166
|
+
};
|
|
167
|
+
}
|
|
168
|
+
});
|
|
169
|
+
}
|
|
170
|
+
return server;
|
|
171
|
+
}
|
|
172
|
+
async function main() {
|
|
173
|
+
const agent = await Agent.create();
|
|
174
|
+
const server = createMcpServer(agent);
|
|
175
|
+
const transport = new import_stdio.StdioServerTransport();
|
|
176
|
+
await server.connect(transport);
|
|
177
|
+
}
|
|
178
|
+
main();
|
|
179
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/index.ts","../src/mcp/solana/get_wallet_address_tool.ts","../src/mcp/wayfind/get_tokens_tool.ts","../src/mcp/wayfind/get_tokenized_stocks_tool.ts","../src/mcp/wayfind/get_risk_profile_tool.ts","../src/mcp/wayfind/get_market_overview_tool.ts","../src/mcp/wayfind/get_pre_ipo_tool.ts","../src/mcp/index.ts","../src/agent/index.ts","../src/config.ts"],"sourcesContent":["#!/usr/bin/env node\n\nimport { McpServer } from \"@modelcontextprotocol/sdk/server/mcp.js\";\nimport { StdioServerTransport } from \"@modelcontextprotocol/sdk/server/stdio.js\";\nimport { McpTools } from \"./mcp\";\nimport { Agent } from \"./agent\";\n\nfunction createMcpServer(agent: Agent) {\n const server = new McpServer({\n name: \"wayfind-solana-mcp\",\n version: \"0.1.0\",\n });\n\n for (const [_key, tool] of Object.entries(McpTools)) {\n server.tool(tool.name, tool.description, tool.schema, async (params: any): Promise<any> => {\n try {\n const result = await tool.handler(agent, params);\n return {\n content: [{ type: \"text\" as const, text: JSON.stringify(result, null, 2) }],\n };\n } catch (error) {\n return {\n isError: true,\n content: [{ type: \"text\" as const, text: error instanceof Error ? error.message : \"Unknown error\" }],\n };\n }\n });\n }\n\n return server;\n}\n\nasync function main() {\n const agent = await Agent.create();\n const server = createMcpServer(agent);\n const transport = new StdioServerTransport();\n await server.connect(transport);\n}\n\nmain();\n","import { z } from \"zod\";\nimport { Agent } from \"../../agent\";\nimport type { McpTool } from \"../../types\";\n\nexport const GetWalletAddressTool: McpTool = {\n name: \"solana_get_wallet_address\",\n description: \"Get the Solana wallet address derived from the configured private key\",\n schema: {},\n handler: async (agent: Agent, _input: Record<string, any>) => {\n return {\n walletAddress: agent.walletAddress,\n };\n },\n};\n","import { z } from \"zod\";\nimport { Agent } from \"../../agent\";\nimport type { McpTool } from \"../../types\";\n\nexport const WayfindGetTokensTool: McpTool = {\n name: \"wayfind_get_tokens\",\n description: \"List all tokenized stocks with prices and market data\",\n schema: {\n chain: z.string().optional().describe(\"Filter by blockchain (e.g., 'solana', 'ethereum')\"),\n },\n handler: async (agent: Agent, input: Record<string, any>) => {\n return agent.wayfindFetch(\"/tokens\", input?.chain ? { chain: input.chain } : undefined);\n },\n};\n","import { z } from \"zod\";\nimport { Agent } from \"../../agent\";\nimport type { McpTool } from \"../../types\";\n\nexport const WayfindGetTokenizedStocksTool: McpTool = {\n name: \"wayfind_get_tokenized_stocks\",\n description: \"Get all tokenized versions of a stock ticker across blockchains (e.g. 'AAPL' returns AAPL on Solana, Ethereum, etc.)\",\n schema: {\n ticker: z.string().describe(\"Stock ticker symbol (e.g., 'AAPL', 'GOOG', 'TSLA')\"),\n },\n handler: async (agent: Agent, input: Record<string, any>) => {\n return agent.wayfindFetch(`/tokens/${encodeURIComponent(input.ticker)}`);\n },\n};\n","import { Agent } from \"../../agent\";\nimport type { McpTool } from \"../../types\";\n\nexport const WayfindGetRiskProfileTool: McpTool = {\n name: \"wayfind_get_risk_profile\",\n description: \"Get the user's portfolio risk profile including overall score, label, and answers\",\n schema: {},\n handler: async (agent: Agent, _input: Record<string, any>) => {\n return agent.wayfindFetch(\"/risk-profile\");\n },\n};\n","import { Agent } from \"../../agent\";\nimport type { McpTool } from \"../../types\";\n\nexport const WayfindGetMarketOverviewTool: McpTool = {\n name: \"wayfind_get_market_overview\",\n description: \"Get market overview including total market cap, 24h volume, gainers, losers, and trending tokens\",\n schema: {},\n handler: async (agent: Agent, _input: Record<string, any>) => {\n return agent.wayfindFetch(\"/market-overview\");\n },\n};\n","import { Agent } from \"../../agent\";\nimport type { McpTool } from \"../../types\";\n\nexport const WayfindGetPreIpoTool: McpTool = {\n name: \"wayfind_get_pre_ipo\",\n description: \"List pre-IPO markets with mark prices and valuations\",\n schema: {},\n handler: async (agent: Agent, _input: Record<string, any>) => {\n return agent.wayfindFetch(\"/pre-ipo\");\n },\n};\n","import type { McpTool } from \"../types\";\nimport { GetWalletAddressTool } from \"./solana/get_wallet_address_tool\";\nimport { WayfindGetTokensTool } from \"./wayfind/get_tokens_tool\";\nimport { WayfindGetTokenizedStocksTool } from \"./wayfind/get_tokenized_stocks_tool\";\nimport { WayfindGetRiskProfileTool } from \"./wayfind/get_risk_profile_tool\";\nimport { WayfindGetMarketOverviewTool } from \"./wayfind/get_market_overview_tool\";\nimport { WayfindGetPreIpoTool } from \"./wayfind/get_pre_ipo_tool\";\n\nexport const McpTools: Record<string, McpTool> = {\n SolanaGetWalletAddress: GetWalletAddressTool,\n WayfindGetTokens: WayfindGetTokensTool,\n WayfindGetTokenizedStocks: WayfindGetTokenizedStocksTool,\n WayfindGetRiskProfile: WayfindGetRiskProfileTool,\n WayfindGetMarketOverview: WayfindGetMarketOverviewTool,\n WayfindGetPreIpo: WayfindGetPreIpoTool,\n};\n","import { createKeyPairSignerFromPrivateKeyBytes } from \"@solana/kit\";\nimport bs58 from \"bs58\";\nimport { validateEnvironment, type AppConfig } from \"../config\";\n\nexport class Agent {\n public walletAddress: string;\n private config: AppConfig;\n\n private constructor(walletAddress: string, config: AppConfig) {\n this.walletAddress = walletAddress;\n this.config = config;\n }\n\n static async create(): Promise<Agent> {\n const config = validateEnvironment();\n const decoded = bs58.decode(config.privateKey);\n const seed = decoded.slice(0, 32);\n const signer = await createKeyPairSignerFromPrivateKeyBytes(seed, false);\n return new Agent(signer.address, config);\n }\n\n async wayfindFetch(path: string, params?: Record<string, string>) {\n const url = new URL(`${this.config.wayfindApiUrl}${path}`);\n if (params) {\n for (const [k, v] of Object.entries(params)) url.searchParams.set(k, v);\n }\n const res = await fetch(url.toString(), {\n headers: { \"x-api-key\": this.config.wayfindApiKey },\n });\n return res.json();\n }\n}\n","export interface AppConfig {\n privateKey: string;\n rpcUrl: string;\n wayfindApiKey: string;\n wayfindApiUrl: string;\n}\n\nexport function validateEnvironment(): AppConfig {\n const privateKey = process.env.SOLANA_PRIVATE_KEY;\n if (!privateKey) {\n throw new Error(\"Missing required env: SOLANA_PRIVATE_KEY (base58 encoded, standard Solana format)\");\n }\n const rpcUrl = process.env.SOLANA_RPC_URL || \"https://api.mainnet-beta.solana.com\";\n const wayfindApiKey = process.env.WAYFIND_API_KEY || \"e1ee8520-305a-49b5-a2de-3e1a7e6078c0\";\n const wayfindApiUrl = process.env.WAYFIND_API_URL || \"https://o3qftki5dtnlhqlrtvswt336bq0mwdye.lambda-url.ap-southeast-1.on.aws\";\n return { privateKey, rpcUrl, wayfindApiKey, wayfindApiUrl };\n}\n"],"mappings":"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","names":["import_zod","bs58"]}
|
package/dist/index.mjs
ADDED
|
@@ -0,0 +1,156 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
|
|
3
|
+
// src/index.ts
|
|
4
|
+
import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
|
|
5
|
+
import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio.js";
|
|
6
|
+
|
|
7
|
+
// src/mcp/solana/get_wallet_address_tool.ts
|
|
8
|
+
var GetWalletAddressTool = {
|
|
9
|
+
name: "solana_get_wallet_address",
|
|
10
|
+
description: "Get the Solana wallet address derived from the configured private key",
|
|
11
|
+
schema: {},
|
|
12
|
+
handler: async (agent, _input) => {
|
|
13
|
+
return {
|
|
14
|
+
walletAddress: agent.walletAddress
|
|
15
|
+
};
|
|
16
|
+
}
|
|
17
|
+
};
|
|
18
|
+
|
|
19
|
+
// src/mcp/wayfind/get_tokens_tool.ts
|
|
20
|
+
import { z } from "zod";
|
|
21
|
+
var WayfindGetTokensTool = {
|
|
22
|
+
name: "wayfind_get_tokens",
|
|
23
|
+
description: "List all tokenized stocks with prices and market data",
|
|
24
|
+
schema: {
|
|
25
|
+
chain: z.string().optional().describe("Filter by blockchain (e.g., 'solana', 'ethereum')")
|
|
26
|
+
},
|
|
27
|
+
handler: async (agent, input) => {
|
|
28
|
+
return agent.wayfindFetch("/tokens", input?.chain ? { chain: input.chain } : void 0);
|
|
29
|
+
}
|
|
30
|
+
};
|
|
31
|
+
|
|
32
|
+
// src/mcp/wayfind/get_tokenized_stocks_tool.ts
|
|
33
|
+
import { z as z2 } from "zod";
|
|
34
|
+
var WayfindGetTokenizedStocksTool = {
|
|
35
|
+
name: "wayfind_get_tokenized_stocks",
|
|
36
|
+
description: "Get all tokenized versions of a stock ticker across blockchains (e.g. 'AAPL' returns AAPL on Solana, Ethereum, etc.)",
|
|
37
|
+
schema: {
|
|
38
|
+
ticker: z2.string().describe("Stock ticker symbol (e.g., 'AAPL', 'GOOG', 'TSLA')")
|
|
39
|
+
},
|
|
40
|
+
handler: async (agent, input) => {
|
|
41
|
+
return agent.wayfindFetch(`/tokens/${encodeURIComponent(input.ticker)}`);
|
|
42
|
+
}
|
|
43
|
+
};
|
|
44
|
+
|
|
45
|
+
// src/mcp/wayfind/get_risk_profile_tool.ts
|
|
46
|
+
var WayfindGetRiskProfileTool = {
|
|
47
|
+
name: "wayfind_get_risk_profile",
|
|
48
|
+
description: "Get the user's portfolio risk profile including overall score, label, and answers",
|
|
49
|
+
schema: {},
|
|
50
|
+
handler: async (agent, _input) => {
|
|
51
|
+
return agent.wayfindFetch("/risk-profile");
|
|
52
|
+
}
|
|
53
|
+
};
|
|
54
|
+
|
|
55
|
+
// src/mcp/wayfind/get_market_overview_tool.ts
|
|
56
|
+
var WayfindGetMarketOverviewTool = {
|
|
57
|
+
name: "wayfind_get_market_overview",
|
|
58
|
+
description: "Get market overview including total market cap, 24h volume, gainers, losers, and trending tokens",
|
|
59
|
+
schema: {},
|
|
60
|
+
handler: async (agent, _input) => {
|
|
61
|
+
return agent.wayfindFetch("/market-overview");
|
|
62
|
+
}
|
|
63
|
+
};
|
|
64
|
+
|
|
65
|
+
// src/mcp/wayfind/get_pre_ipo_tool.ts
|
|
66
|
+
var WayfindGetPreIpoTool = {
|
|
67
|
+
name: "wayfind_get_pre_ipo",
|
|
68
|
+
description: "List pre-IPO markets with mark prices and valuations",
|
|
69
|
+
schema: {},
|
|
70
|
+
handler: async (agent, _input) => {
|
|
71
|
+
return agent.wayfindFetch("/pre-ipo");
|
|
72
|
+
}
|
|
73
|
+
};
|
|
74
|
+
|
|
75
|
+
// src/mcp/index.ts
|
|
76
|
+
var McpTools = {
|
|
77
|
+
SolanaGetWalletAddress: GetWalletAddressTool,
|
|
78
|
+
WayfindGetTokens: WayfindGetTokensTool,
|
|
79
|
+
WayfindGetTokenizedStocks: WayfindGetTokenizedStocksTool,
|
|
80
|
+
WayfindGetRiskProfile: WayfindGetRiskProfileTool,
|
|
81
|
+
WayfindGetMarketOverview: WayfindGetMarketOverviewTool,
|
|
82
|
+
WayfindGetPreIpo: WayfindGetPreIpoTool
|
|
83
|
+
};
|
|
84
|
+
|
|
85
|
+
// src/agent/index.ts
|
|
86
|
+
import { createKeyPairSignerFromPrivateKeyBytes } from "@solana/kit";
|
|
87
|
+
import bs58 from "bs58";
|
|
88
|
+
|
|
89
|
+
// src/config.ts
|
|
90
|
+
function validateEnvironment() {
|
|
91
|
+
const privateKey = process.env.SOLANA_PRIVATE_KEY;
|
|
92
|
+
if (!privateKey) {
|
|
93
|
+
throw new Error("Missing required env: SOLANA_PRIVATE_KEY (base58 encoded, standard Solana format)");
|
|
94
|
+
}
|
|
95
|
+
const rpcUrl = process.env.SOLANA_RPC_URL || "https://api.mainnet-beta.solana.com";
|
|
96
|
+
const wayfindApiKey = process.env.WAYFIND_API_KEY || "e1ee8520-305a-49b5-a2de-3e1a7e6078c0";
|
|
97
|
+
const wayfindApiUrl = process.env.WAYFIND_API_URL || "https://o3qftki5dtnlhqlrtvswt336bq0mwdye.lambda-url.ap-southeast-1.on.aws";
|
|
98
|
+
return { privateKey, rpcUrl, wayfindApiKey, wayfindApiUrl };
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
// src/agent/index.ts
|
|
102
|
+
var Agent = class _Agent {
|
|
103
|
+
constructor(walletAddress, config) {
|
|
104
|
+
this.walletAddress = walletAddress;
|
|
105
|
+
this.config = config;
|
|
106
|
+
}
|
|
107
|
+
static async create() {
|
|
108
|
+
const config = validateEnvironment();
|
|
109
|
+
const decoded = bs58.decode(config.privateKey);
|
|
110
|
+
const seed = decoded.slice(0, 32);
|
|
111
|
+
const signer = await createKeyPairSignerFromPrivateKeyBytes(seed, false);
|
|
112
|
+
return new _Agent(signer.address, config);
|
|
113
|
+
}
|
|
114
|
+
async wayfindFetch(path, params) {
|
|
115
|
+
const url = new URL(`${this.config.wayfindApiUrl}${path}`);
|
|
116
|
+
if (params) {
|
|
117
|
+
for (const [k, v] of Object.entries(params)) url.searchParams.set(k, v);
|
|
118
|
+
}
|
|
119
|
+
const res = await fetch(url.toString(), {
|
|
120
|
+
headers: { "x-api-key": this.config.wayfindApiKey }
|
|
121
|
+
});
|
|
122
|
+
return res.json();
|
|
123
|
+
}
|
|
124
|
+
};
|
|
125
|
+
|
|
126
|
+
// src/index.ts
|
|
127
|
+
function createMcpServer(agent) {
|
|
128
|
+
const server = new McpServer({
|
|
129
|
+
name: "wayfind-solana-mcp",
|
|
130
|
+
version: "0.1.0"
|
|
131
|
+
});
|
|
132
|
+
for (const [_key, tool] of Object.entries(McpTools)) {
|
|
133
|
+
server.tool(tool.name, tool.description, tool.schema, async (params) => {
|
|
134
|
+
try {
|
|
135
|
+
const result = await tool.handler(agent, params);
|
|
136
|
+
return {
|
|
137
|
+
content: [{ type: "text", text: JSON.stringify(result, null, 2) }]
|
|
138
|
+
};
|
|
139
|
+
} catch (error) {
|
|
140
|
+
return {
|
|
141
|
+
isError: true,
|
|
142
|
+
content: [{ type: "text", text: error instanceof Error ? error.message : "Unknown error" }]
|
|
143
|
+
};
|
|
144
|
+
}
|
|
145
|
+
});
|
|
146
|
+
}
|
|
147
|
+
return server;
|
|
148
|
+
}
|
|
149
|
+
async function main() {
|
|
150
|
+
const agent = await Agent.create();
|
|
151
|
+
const server = createMcpServer(agent);
|
|
152
|
+
const transport = new StdioServerTransport();
|
|
153
|
+
await server.connect(transport);
|
|
154
|
+
}
|
|
155
|
+
main();
|
|
156
|
+
//# sourceMappingURL=index.mjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/index.ts","../src/mcp/solana/get_wallet_address_tool.ts","../src/mcp/wayfind/get_tokens_tool.ts","../src/mcp/wayfind/get_tokenized_stocks_tool.ts","../src/mcp/wayfind/get_risk_profile_tool.ts","../src/mcp/wayfind/get_market_overview_tool.ts","../src/mcp/wayfind/get_pre_ipo_tool.ts","../src/mcp/index.ts","../src/agent/index.ts","../src/config.ts"],"sourcesContent":["#!/usr/bin/env node\n\nimport { McpServer } from \"@modelcontextprotocol/sdk/server/mcp.js\";\nimport { StdioServerTransport } from \"@modelcontextprotocol/sdk/server/stdio.js\";\nimport { McpTools } from \"./mcp\";\nimport { Agent } from \"./agent\";\n\nfunction createMcpServer(agent: Agent) {\n const server = new McpServer({\n name: \"wayfind-solana-mcp\",\n version: \"0.1.0\",\n });\n\n for (const [_key, tool] of Object.entries(McpTools)) {\n server.tool(tool.name, tool.description, tool.schema, async (params: any): Promise<any> => {\n try {\n const result = await tool.handler(agent, params);\n return {\n content: [{ type: \"text\" as const, text: JSON.stringify(result, null, 2) }],\n };\n } catch (error) {\n return {\n isError: true,\n content: [{ type: \"text\" as const, text: error instanceof Error ? error.message : \"Unknown error\" }],\n };\n }\n });\n }\n\n return server;\n}\n\nasync function main() {\n const agent = await Agent.create();\n const server = createMcpServer(agent);\n const transport = new StdioServerTransport();\n await server.connect(transport);\n}\n\nmain();\n","import { z } from \"zod\";\nimport { Agent } from \"../../agent\";\nimport type { McpTool } from \"../../types\";\n\nexport const GetWalletAddressTool: McpTool = {\n name: \"solana_get_wallet_address\",\n description: \"Get the Solana wallet address derived from the configured private key\",\n schema: {},\n handler: async (agent: Agent, _input: Record<string, any>) => {\n return {\n walletAddress: agent.walletAddress,\n };\n },\n};\n","import { z } from \"zod\";\nimport { Agent } from \"../../agent\";\nimport type { McpTool } from \"../../types\";\n\nexport const WayfindGetTokensTool: McpTool = {\n name: \"wayfind_get_tokens\",\n description: \"List all tokenized stocks with prices and market data\",\n schema: {\n chain: z.string().optional().describe(\"Filter by blockchain (e.g., 'solana', 'ethereum')\"),\n },\n handler: async (agent: Agent, input: Record<string, any>) => {\n return agent.wayfindFetch(\"/tokens\", input?.chain ? { chain: input.chain } : undefined);\n },\n};\n","import { z } from \"zod\";\nimport { Agent } from \"../../agent\";\nimport type { McpTool } from \"../../types\";\n\nexport const WayfindGetTokenizedStocksTool: McpTool = {\n name: \"wayfind_get_tokenized_stocks\",\n description: \"Get all tokenized versions of a stock ticker across blockchains (e.g. 'AAPL' returns AAPL on Solana, Ethereum, etc.)\",\n schema: {\n ticker: z.string().describe(\"Stock ticker symbol (e.g., 'AAPL', 'GOOG', 'TSLA')\"),\n },\n handler: async (agent: Agent, input: Record<string, any>) => {\n return agent.wayfindFetch(`/tokens/${encodeURIComponent(input.ticker)}`);\n },\n};\n","import { Agent } from \"../../agent\";\nimport type { McpTool } from \"../../types\";\n\nexport const WayfindGetRiskProfileTool: McpTool = {\n name: \"wayfind_get_risk_profile\",\n description: \"Get the user's portfolio risk profile including overall score, label, and answers\",\n schema: {},\n handler: async (agent: Agent, _input: Record<string, any>) => {\n return agent.wayfindFetch(\"/risk-profile\");\n },\n};\n","import { Agent } from \"../../agent\";\nimport type { McpTool } from \"../../types\";\n\nexport const WayfindGetMarketOverviewTool: McpTool = {\n name: \"wayfind_get_market_overview\",\n description: \"Get market overview including total market cap, 24h volume, gainers, losers, and trending tokens\",\n schema: {},\n handler: async (agent: Agent, _input: Record<string, any>) => {\n return agent.wayfindFetch(\"/market-overview\");\n },\n};\n","import { Agent } from \"../../agent\";\nimport type { McpTool } from \"../../types\";\n\nexport const WayfindGetPreIpoTool: McpTool = {\n name: \"wayfind_get_pre_ipo\",\n description: \"List pre-IPO markets with mark prices and valuations\",\n schema: {},\n handler: async (agent: Agent, _input: Record<string, any>) => {\n return agent.wayfindFetch(\"/pre-ipo\");\n },\n};\n","import type { McpTool } from \"../types\";\nimport { GetWalletAddressTool } from \"./solana/get_wallet_address_tool\";\nimport { WayfindGetTokensTool } from \"./wayfind/get_tokens_tool\";\nimport { WayfindGetTokenizedStocksTool } from \"./wayfind/get_tokenized_stocks_tool\";\nimport { WayfindGetRiskProfileTool } from \"./wayfind/get_risk_profile_tool\";\nimport { WayfindGetMarketOverviewTool } from \"./wayfind/get_market_overview_tool\";\nimport { WayfindGetPreIpoTool } from \"./wayfind/get_pre_ipo_tool\";\n\nexport const McpTools: Record<string, McpTool> = {\n SolanaGetWalletAddress: GetWalletAddressTool,\n WayfindGetTokens: WayfindGetTokensTool,\n WayfindGetTokenizedStocks: WayfindGetTokenizedStocksTool,\n WayfindGetRiskProfile: WayfindGetRiskProfileTool,\n WayfindGetMarketOverview: WayfindGetMarketOverviewTool,\n WayfindGetPreIpo: WayfindGetPreIpoTool,\n};\n","import { createKeyPairSignerFromPrivateKeyBytes } from \"@solana/kit\";\nimport bs58 from \"bs58\";\nimport { validateEnvironment, type AppConfig } from \"../config\";\n\nexport class Agent {\n public walletAddress: string;\n private config: AppConfig;\n\n private constructor(walletAddress: string, config: AppConfig) {\n this.walletAddress = walletAddress;\n this.config = config;\n }\n\n static async create(): Promise<Agent> {\n const config = validateEnvironment();\n const decoded = bs58.decode(config.privateKey);\n const seed = decoded.slice(0, 32);\n const signer = await createKeyPairSignerFromPrivateKeyBytes(seed, false);\n return new Agent(signer.address, config);\n }\n\n async wayfindFetch(path: string, params?: Record<string, string>) {\n const url = new URL(`${this.config.wayfindApiUrl}${path}`);\n if (params) {\n for (const [k, v] of Object.entries(params)) url.searchParams.set(k, v);\n }\n const res = await fetch(url.toString(), {\n headers: { \"x-api-key\": this.config.wayfindApiKey },\n });\n return res.json();\n }\n}\n","export interface AppConfig {\n privateKey: string;\n rpcUrl: string;\n wayfindApiKey: string;\n wayfindApiUrl: string;\n}\n\nexport function validateEnvironment(): AppConfig {\n const privateKey = process.env.SOLANA_PRIVATE_KEY;\n if (!privateKey) {\n throw new Error(\"Missing required env: SOLANA_PRIVATE_KEY (base58 encoded, standard Solana format)\");\n }\n const rpcUrl = process.env.SOLANA_RPC_URL || \"https://api.mainnet-beta.solana.com\";\n const wayfindApiKey = process.env.WAYFIND_API_KEY || \"e1ee8520-305a-49b5-a2de-3e1a7e6078c0\";\n const wayfindApiUrl = process.env.WAYFIND_API_URL || \"https://o3qftki5dtnlhqlrtvswt336bq0mwdye.lambda-url.ap-southeast-1.on.aws\";\n return { privateKey, rpcUrl, wayfindApiKey, wayfindApiUrl };\n}\n"],"mappings":"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","names":["z"]}
|
package/package.json
CHANGED
|
@@ -1,6 +1,26 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@tamago-labs/wayfind-mcp",
|
|
3
|
-
"version": "0.
|
|
4
|
-
"
|
|
5
|
-
"
|
|
6
|
-
|
|
3
|
+
"version": "0.2.0",
|
|
4
|
+
"main": "dist/index.js",
|
|
5
|
+
"module": "./dist/index.mjs",
|
|
6
|
+
"types": "./dist/index.d.ts",
|
|
7
|
+
"bin": {
|
|
8
|
+
"wayfind-solana-mcp": "dist/index.js"
|
|
9
|
+
},
|
|
10
|
+
"scripts": {
|
|
11
|
+
"build": "tsup",
|
|
12
|
+
"dev": "tsup --watch",
|
|
13
|
+
"start": "node dist/index.js"
|
|
14
|
+
},
|
|
15
|
+
"dependencies": {
|
|
16
|
+
"@modelcontextprotocol/sdk": "^1.10.2",
|
|
17
|
+
"@solana/kit": "^2.0.0",
|
|
18
|
+
"bs58": "^6.0.0",
|
|
19
|
+
"zod": "^3.24.3"
|
|
20
|
+
},
|
|
21
|
+
"devDependencies": {
|
|
22
|
+
"@types/node": "^22.10.0",
|
|
23
|
+
"tsup": "^8.4.0",
|
|
24
|
+
"typescript": "^5.8.3"
|
|
25
|
+
}
|
|
26
|
+
}
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
import { createKeyPairSignerFromPrivateKeyBytes } from "@solana/kit";
|
|
2
|
+
import bs58 from "bs58";
|
|
3
|
+
import { validateEnvironment, type AppConfig } from "../config";
|
|
4
|
+
|
|
5
|
+
export class Agent {
|
|
6
|
+
public walletAddress: string;
|
|
7
|
+
private config: AppConfig;
|
|
8
|
+
|
|
9
|
+
private constructor(walletAddress: string, config: AppConfig) {
|
|
10
|
+
this.walletAddress = walletAddress;
|
|
11
|
+
this.config = config;
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
static async create(): Promise<Agent> {
|
|
15
|
+
const config = validateEnvironment();
|
|
16
|
+
const decoded = bs58.decode(config.privateKey);
|
|
17
|
+
const seed = decoded.slice(0, 32);
|
|
18
|
+
const signer = await createKeyPairSignerFromPrivateKeyBytes(seed, false);
|
|
19
|
+
return new Agent(signer.address, config);
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
async wayfindFetch(path: string, params?: Record<string, string>) {
|
|
23
|
+
const url = new URL(`${this.config.wayfindApiUrl}${path}`);
|
|
24
|
+
if (params) {
|
|
25
|
+
for (const [k, v] of Object.entries(params)) url.searchParams.set(k, v);
|
|
26
|
+
}
|
|
27
|
+
const res = await fetch(url.toString(), {
|
|
28
|
+
headers: { "x-api-key": this.config.wayfindApiKey },
|
|
29
|
+
});
|
|
30
|
+
return res.json();
|
|
31
|
+
}
|
|
32
|
+
}
|
package/src/config.ts
ADDED
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
export interface AppConfig {
|
|
2
|
+
privateKey: string;
|
|
3
|
+
rpcUrl: string;
|
|
4
|
+
wayfindApiKey: string;
|
|
5
|
+
wayfindApiUrl: string;
|
|
6
|
+
}
|
|
7
|
+
|
|
8
|
+
export function validateEnvironment(): AppConfig {
|
|
9
|
+
const privateKey = process.env.SOLANA_PRIVATE_KEY;
|
|
10
|
+
if (!privateKey) {
|
|
11
|
+
throw new Error("Missing required env: SOLANA_PRIVATE_KEY (base58 encoded, standard Solana format)");
|
|
12
|
+
}
|
|
13
|
+
const rpcUrl = process.env.SOLANA_RPC_URL || "https://api.mainnet-beta.solana.com";
|
|
14
|
+
const wayfindApiKey = process.env.WAYFIND_API_KEY || "e1ee8520-305a-49b5-a2de-3e1a7e6078c0";
|
|
15
|
+
const wayfindApiUrl = process.env.WAYFIND_API_URL || "https://o3qftki5dtnlhqlrtvswt336bq0mwdye.lambda-url.ap-southeast-1.on.aws";
|
|
16
|
+
return { privateKey, rpcUrl, wayfindApiKey, wayfindApiUrl };
|
|
17
|
+
}
|
package/src/index.ts
ADDED
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
|
|
3
|
+
import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
|
|
4
|
+
import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio.js";
|
|
5
|
+
import { McpTools } from "./mcp";
|
|
6
|
+
import { Agent } from "./agent";
|
|
7
|
+
|
|
8
|
+
function createMcpServer(agent: Agent) {
|
|
9
|
+
const server = new McpServer({
|
|
10
|
+
name: "wayfind-solana-mcp",
|
|
11
|
+
version: "0.1.0",
|
|
12
|
+
});
|
|
13
|
+
|
|
14
|
+
for (const [_key, tool] of Object.entries(McpTools)) {
|
|
15
|
+
server.tool(tool.name, tool.description, tool.schema, async (params: any): Promise<any> => {
|
|
16
|
+
try {
|
|
17
|
+
const result = await tool.handler(agent, params);
|
|
18
|
+
return {
|
|
19
|
+
content: [{ type: "text" as const, text: JSON.stringify(result, null, 2) }],
|
|
20
|
+
};
|
|
21
|
+
} catch (error) {
|
|
22
|
+
return {
|
|
23
|
+
isError: true,
|
|
24
|
+
content: [{ type: "text" as const, text: error instanceof Error ? error.message : "Unknown error" }],
|
|
25
|
+
};
|
|
26
|
+
}
|
|
27
|
+
});
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
return server;
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
async function main() {
|
|
34
|
+
const agent = await Agent.create();
|
|
35
|
+
const server = createMcpServer(agent);
|
|
36
|
+
const transport = new StdioServerTransport();
|
|
37
|
+
await server.connect(transport);
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
main();
|
package/src/mcp/index.ts
ADDED
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
import type { McpTool } from "../types";
|
|
2
|
+
import { GetWalletAddressTool } from "./solana/get_wallet_address_tool";
|
|
3
|
+
import { WayfindGetTokensTool } from "./wayfind/get_tokens_tool";
|
|
4
|
+
import { WayfindGetTokenizedStocksTool } from "./wayfind/get_tokenized_stocks_tool";
|
|
5
|
+
import { WayfindGetRiskProfileTool } from "./wayfind/get_risk_profile_tool";
|
|
6
|
+
import { WayfindGetMarketOverviewTool } from "./wayfind/get_market_overview_tool";
|
|
7
|
+
import { WayfindGetPreIpoTool } from "./wayfind/get_pre_ipo_tool";
|
|
8
|
+
|
|
9
|
+
export const McpTools: Record<string, McpTool> = {
|
|
10
|
+
SolanaGetWalletAddress: GetWalletAddressTool,
|
|
11
|
+
WayfindGetTokens: WayfindGetTokensTool,
|
|
12
|
+
WayfindGetTokenizedStocks: WayfindGetTokenizedStocksTool,
|
|
13
|
+
WayfindGetRiskProfile: WayfindGetRiskProfileTool,
|
|
14
|
+
WayfindGetMarketOverview: WayfindGetMarketOverviewTool,
|
|
15
|
+
WayfindGetPreIpo: WayfindGetPreIpoTool,
|
|
16
|
+
};
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
import { z } from "zod";
|
|
2
|
+
import { Agent } from "../../agent";
|
|
3
|
+
import type { McpTool } from "../../types";
|
|
4
|
+
|
|
5
|
+
export const GetWalletAddressTool: McpTool = {
|
|
6
|
+
name: "solana_get_wallet_address",
|
|
7
|
+
description: "Get the Solana wallet address derived from the configured private key",
|
|
8
|
+
schema: {},
|
|
9
|
+
handler: async (agent: Agent, _input: Record<string, any>) => {
|
|
10
|
+
return {
|
|
11
|
+
walletAddress: agent.walletAddress,
|
|
12
|
+
};
|
|
13
|
+
},
|
|
14
|
+
};
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
import { Agent } from "../../agent";
|
|
2
|
+
import type { McpTool } from "../../types";
|
|
3
|
+
|
|
4
|
+
export const WayfindGetMarketOverviewTool: McpTool = {
|
|
5
|
+
name: "wayfind_get_market_overview",
|
|
6
|
+
description: "Get market overview including total market cap, 24h volume, gainers, losers, and trending tokens",
|
|
7
|
+
schema: {},
|
|
8
|
+
handler: async (agent: Agent, _input: Record<string, any>) => {
|
|
9
|
+
return agent.wayfindFetch("/market-overview");
|
|
10
|
+
},
|
|
11
|
+
};
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
import { Agent } from "../../agent";
|
|
2
|
+
import type { McpTool } from "../../types";
|
|
3
|
+
|
|
4
|
+
export const WayfindGetPreIpoTool: McpTool = {
|
|
5
|
+
name: "wayfind_get_pre_ipo",
|
|
6
|
+
description: "List pre-IPO markets with mark prices and valuations",
|
|
7
|
+
schema: {},
|
|
8
|
+
handler: async (agent: Agent, _input: Record<string, any>) => {
|
|
9
|
+
return agent.wayfindFetch("/pre-ipo");
|
|
10
|
+
},
|
|
11
|
+
};
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
import { Agent } from "../../agent";
|
|
2
|
+
import type { McpTool } from "../../types";
|
|
3
|
+
|
|
4
|
+
export const WayfindGetRiskProfileTool: McpTool = {
|
|
5
|
+
name: "wayfind_get_risk_profile",
|
|
6
|
+
description: "Get the user's portfolio risk profile including overall score, label, and answers",
|
|
7
|
+
schema: {},
|
|
8
|
+
handler: async (agent: Agent, _input: Record<string, any>) => {
|
|
9
|
+
return agent.wayfindFetch("/risk-profile");
|
|
10
|
+
},
|
|
11
|
+
};
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
import { z } from "zod";
|
|
2
|
+
import { Agent } from "../../agent";
|
|
3
|
+
import type { McpTool } from "../../types";
|
|
4
|
+
|
|
5
|
+
export const WayfindGetTokenizedStocksTool: McpTool = {
|
|
6
|
+
name: "wayfind_get_tokenized_stocks",
|
|
7
|
+
description: "Get all tokenized versions of a stock ticker across blockchains (e.g. 'AAPL' returns AAPL on Solana, Ethereum, etc.)",
|
|
8
|
+
schema: {
|
|
9
|
+
ticker: z.string().describe("Stock ticker symbol (e.g., 'AAPL', 'GOOG', 'TSLA')"),
|
|
10
|
+
},
|
|
11
|
+
handler: async (agent: Agent, input: Record<string, any>) => {
|
|
12
|
+
return agent.wayfindFetch(`/tokens/${encodeURIComponent(input.ticker)}`);
|
|
13
|
+
},
|
|
14
|
+
};
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
import { z } from "zod";
|
|
2
|
+
import { Agent } from "../../agent";
|
|
3
|
+
import type { McpTool } from "../../types";
|
|
4
|
+
|
|
5
|
+
export const WayfindGetTokensTool: McpTool = {
|
|
6
|
+
name: "wayfind_get_tokens",
|
|
7
|
+
description: "List all tokenized stocks with prices and market data",
|
|
8
|
+
schema: {
|
|
9
|
+
chain: z.string().optional().describe("Filter by blockchain (e.g., 'solana', 'ethereum')"),
|
|
10
|
+
},
|
|
11
|
+
handler: async (agent: Agent, input: Record<string, any>) => {
|
|
12
|
+
return agent.wayfindFetch("/tokens", input?.chain ? { chain: input.chain } : undefined);
|
|
13
|
+
},
|
|
14
|
+
};
|
package/src/types.ts
ADDED
package/tsconfig.json
ADDED
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
{
|
|
2
|
+
"compilerOptions": {
|
|
3
|
+
"target": "ES2020",
|
|
4
|
+
"lib": ["ES2020"],
|
|
5
|
+
"module": "commonjs",
|
|
6
|
+
"rootDir": "./src",
|
|
7
|
+
"outDir": "./dist",
|
|
8
|
+
"forceConsistentCasingInFileNames": true,
|
|
9
|
+
"strict": true,
|
|
10
|
+
"skipLibCheck": true,
|
|
11
|
+
"esModuleInterop": true,
|
|
12
|
+
"resolveJsonModule": true
|
|
13
|
+
},
|
|
14
|
+
"include": ["src/**/*"],
|
|
15
|
+
"exclude": ["node_modules", "dist"]
|
|
16
|
+
}
|
package/tsup.config.ts
ADDED
package/README.md
DELETED