Initial commit
This commit is contained in:
commit
56fb2646df
31 files changed
+3961
No files matched your search
@@ -0,0 +1 @@
|
||||
.git
|
||||
@@ -0,0 +1,10 @@
|
||||
root = true
|
||||
|
||||
[*]
|
||||
end_of_line = lf
|
||||
insert_final_newline = true
|
||||
|
||||
[*.{js,json,yml}]
|
||||
charset = utf-8
|
||||
indent_style = space
|
||||
indent_size = 2
|
||||
+14
@@ -0,0 +1,14 @@
|
||||
.yarn/*
|
||||
!.yarn/patches
|
||||
!.yarn/plugins
|
||||
!.yarn/releases
|
||||
!.yarn/sdks
|
||||
!.yarn/versions
|
||||
|
||||
node_modules
|
||||
.env
|
||||
|
||||
build/*
|
||||
|
||||
*.tgz
|
||||
.qodo
|
||||
@@ -0,0 +1,49 @@
|
||||
stages:
|
||||
- build
|
||||
- deploy
|
||||
|
||||
|
||||
variables:
|
||||
VERSION: 0.8.${CI_PIPELINE_ID}
|
||||
SERVER_USER: $SERVER_USER
|
||||
CI_REGISTRY: repo.mind-dev.com
|
||||
CONTAINER_IMAGE: $CI_REGISTRY/mind-dev/santiment-mcp/$CI_COMMIT_REF_NAME:$CI_COMMIT_SHORT_SHA
|
||||
CONTAINER_RELEASE_IMAGE: $CI_REGISTRY/mind-dev/santiment-mcp/$CI_COMMIT_REF_NAME:latest
|
||||
|
||||
build:
|
||||
image: docker:19-dind
|
||||
services:
|
||||
- docker:19-dind
|
||||
stage: build
|
||||
tags:
|
||||
- jenkins-build
|
||||
variables:
|
||||
DOCKER_DRIVER: overlay2
|
||||
only:
|
||||
- main
|
||||
before_script:
|
||||
- docker login -u "$CI_REGISTRY_USER" -p "$CI_REGISTRY_PASSWORD" $CI_REGISTRY
|
||||
script:
|
||||
- cat $ENV_FILE > .env
|
||||
- docker pull $CONTAINER_RELEASE_IMAGE || true
|
||||
- docker build --cache-from $CONTAINER_RELEASE_IMAGE --tag $CONTAINER_IMAGE --tag $CONTAINER_RELEASE_IMAGE . -f Dockerfile
|
||||
- docker push $CONTAINER_IMAGE
|
||||
- docker push $CONTAINER_RELEASE_IMAGE
|
||||
|
||||
.deploy:
|
||||
stage: deploy
|
||||
before_script:
|
||||
- docker login -u "$CI_REGISTRY_USER" -p "$CI_REGISTRY_PASSWORD" $CI_REGISTRY
|
||||
script:
|
||||
- docker pull $CONTAINER_RELEASE_IMAGE
|
||||
- cd $path
|
||||
- docker-compose up -d frontend
|
||||
|
||||
deploy:
|
||||
extends: .deploy
|
||||
tags:
|
||||
- gitlab-runner
|
||||
only:
|
||||
- main
|
||||
variables:
|
||||
path: /var/www/santiment-mcp
|
||||
+24
@@ -0,0 +1,24 @@
|
||||
# Source files (since we're publishing the compiled output)
|
||||
src/
|
||||
|
||||
# Development files
|
||||
.editorconfig
|
||||
.gitignore
|
||||
.yarnrc.yml
|
||||
tsconfig.json
|
||||
yarn.lock
|
||||
node_modules/
|
||||
|
||||
# Environment and configuration files
|
||||
.env
|
||||
.env.*
|
||||
claude_desktop_config.json
|
||||
|
||||
# Test files
|
||||
test-mcp.js
|
||||
|
||||
# Misc
|
||||
.DS_Store
|
||||
.vscode/
|
||||
.idea/
|
||||
*.log
|
||||
@@ -0,0 +1,8 @@
|
||||
{
|
||||
"plugins": ["@ianvs/prettier-plugin-sort-imports"],
|
||||
"importOrder": ["<THIRD_PARTY_MODULES>", "^@/(.*)$", "^[./]"],
|
||||
"importOrderParserPlugins": ["typescript", "jsx", "decorators-legacy"],
|
||||
"semi": true,
|
||||
"singleQuote": true,
|
||||
"trailingComma": "all"
|
||||
}
|
||||
Vendored
+5
@@ -0,0 +1,5 @@
|
||||
{
|
||||
"editor.codeActionsOnSave": {
|
||||
"source.fixAll.eslint": "explicit"
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1 @@
|
||||
nodeLinker: node-modules
|
||||
+28
@@ -0,0 +1,28 @@
|
||||
# Generated by https://smithery.ai. See: https://smithery.ai/docs/config#dockerfile
|
||||
FROM node:23.10.0-alpine3.21
|
||||
|
||||
# Create app directory
|
||||
WORKDIR /usr/src/app
|
||||
|
||||
# Copy package files and config first
|
||||
COPY package.json yarn.lock tsconfig.json ./
|
||||
|
||||
# Copy source code
|
||||
COPY src/ ./src/
|
||||
COPY .env ./
|
||||
COPY patches/ ./patches/
|
||||
|
||||
# Install dependencies including TypeScript
|
||||
RUN yarn install --frozen-lockfile
|
||||
|
||||
# Build the project (using local tsc from node_modules)
|
||||
RUN yarn build
|
||||
|
||||
# Expose port for the SSE server
|
||||
EXPOSE 3000
|
||||
|
||||
# Set environment variables
|
||||
ENV SSE_PORT=3000
|
||||
|
||||
# Run the server using the correct build path
|
||||
CMD ["node", "build/index.js"]
|
||||
@@ -0,0 +1,21 @@
|
||||
MIT License
|
||||
|
||||
Copyright (c) 2025 Liquidswap MCP Server Contributors
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in all
|
||||
copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
SOFTWARE.
|
||||
@@ -0,0 +1,35 @@
|
||||
import pluginJs from '@eslint/js';
|
||||
import globals from 'globals';
|
||||
import tseslint from 'typescript-eslint';
|
||||
|
||||
/** @type {import('eslint').Linter.Config[]} */
|
||||
export default [
|
||||
{ files: ['**/*.{js,mjs,cjs,ts}'] },
|
||||
{ languageOptions: { globals: globals.node } },
|
||||
pluginJs.configs.recommended,
|
||||
...tseslint.configs.recommended,
|
||||
{
|
||||
ignores: [
|
||||
'**/node_modules/**',
|
||||
'**/build/**',
|
||||
'scripts/**',
|
||||
'.yarn/**',
|
||||
'**/*.json',
|
||||
'**/*.md',
|
||||
],
|
||||
},
|
||||
{
|
||||
rules: {
|
||||
// Disallow console.log but allow console.error, console.warn, and console.info
|
||||
'no-console': ['error', { allow: ['error', 'warn', 'info'] }],
|
||||
|
||||
// TypeScript specific rules
|
||||
'@typescript-eslint/no-unused-vars': [
|
||||
'error',
|
||||
{ argsIgnorePattern: '^_' },
|
||||
],
|
||||
'@typescript-eslint/no-explicit-any': 'warn',
|
||||
'@typescript-eslint/explicit-module-boundary-types': 'off',
|
||||
},
|
||||
},
|
||||
];
|
||||
@@ -0,0 +1,13 @@
|
||||
{
|
||||
"mcpServers": {
|
||||
"liquidswap-mcp": {
|
||||
"command": "node",
|
||||
"args": ["PATH_TO_INDEX_JS"],
|
||||
"env": {
|
||||
"SSE_PORT": "3000"
|
||||
},
|
||||
"disabled": false,
|
||||
"autoApprove": []
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,66 @@
|
||||
{
|
||||
"name": "liquidswap-mcp",
|
||||
"version": "1.0.0",
|
||||
"description": "A Model Context Protocol (MCP) server that provides for Liquidswap",
|
||||
"bin": "./build/index.js",
|
||||
"type": "module",
|
||||
"scripts": {
|
||||
"postinstall": "patch-package",
|
||||
"build": "npx rimraf build && tsc -p tsconfig.json && node -e \"require('fs').chmodSync('build/index.js', '755')\"",
|
||||
"start": "node build/index.js",
|
||||
"lint": "eslint src/**/*.ts",
|
||||
"lint:fix": "eslint src/**/*.ts --fix",
|
||||
"format": "prettier --write .",
|
||||
"prepare": "npm run build",
|
||||
"publish": "rm -rf dist && rm -rf node_modules && npm i && npm run build && npm publish"
|
||||
},
|
||||
"files": [
|
||||
"build"
|
||||
],
|
||||
"repository": {
|
||||
"type": "git",
|
||||
"url": ""
|
||||
},
|
||||
"keywords": [
|
||||
"mcp",
|
||||
"liquidswap",
|
||||
"aptos",
|
||||
"ai"
|
||||
],
|
||||
"author": "odiinnn",
|
||||
"license": "MIT",
|
||||
"packageManager": "yarn@1.22.21",
|
||||
"dependencies": {
|
||||
"@modelcontextprotocol/sdk": "^1.6.1",
|
||||
"dotenv": "^16.4.7",
|
||||
"express": "^4.21.2",
|
||||
"fastmcp": "^1.21.0",
|
||||
"graphql": "^16.10.0",
|
||||
"graphql-request": "^7.1.2",
|
||||
"node-fetch": "^3.3.2",
|
||||
"patch-package": "^8.0.0",
|
||||
"postinstall-postinstall": "^2.1.0",
|
||||
"reflect-metadata": "^0.2.2",
|
||||
"zod": "^3.24.2"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@eslint/js": "^9.22.0",
|
||||
"@ianvs/prettier-plugin-sort-imports": "^4.4.1",
|
||||
"@types/express": "^5.0.1",
|
||||
"@types/node": "^22.13.9",
|
||||
"@types/react": "^19",
|
||||
"@types/react-dom": "^19",
|
||||
"@typescript-eslint/eslint-plugin": "^8.26.1",
|
||||
"@typescript-eslint/parser": "^8.26.1",
|
||||
"eslint": "^9.22.0",
|
||||
"eslint-config-prettier": "^10.1.1",
|
||||
"eslint-plugin-import": "^2.31.0",
|
||||
"globals": "^16.0.0",
|
||||
"nodemon": "^3.1.9",
|
||||
"prettier": "^3.5.3",
|
||||
"ts-node": "^10.9.2",
|
||||
"typescript": "^5.8.2",
|
||||
"typescript-eslint": "^8.26.1",
|
||||
"zod-to-json-schema": "^3.24.4"
|
||||
}
|
||||
}
|
||||
Vendored
BIN
Binary file not shown.
@@ -0,0 +1,4 @@
|
||||
import { config } from "dotenv";
|
||||
config();
|
||||
|
||||
export const BE_URL = process.env.BE_URL || 'https://api.liquidswap.com';
|
||||
@@ -0,0 +1,22 @@
|
||||
import { BE_URL } from "../constants.js";
|
||||
|
||||
export class Liquidswap {
|
||||
private readonly url = BE_URL
|
||||
|
||||
private async fetch(url: string) {
|
||||
const response = await fetch(`${this.url}${url}`)
|
||||
return response.json()
|
||||
}
|
||||
|
||||
public async getTokens() {
|
||||
const response = await this.fetch(`/coins/registered`)
|
||||
return response
|
||||
}
|
||||
|
||||
public async getPools() {
|
||||
const response = await this.fetch(`/pools/registered?networkId=1&cl=true`)
|
||||
return response
|
||||
}
|
||||
}
|
||||
|
||||
export const liquidswap = new Liquidswap()
|
||||
@@ -0,0 +1,27 @@
|
||||
#!/usr/bin/env node
|
||||
|
||||
import { config } from "dotenv";
|
||||
|
||||
config();
|
||||
|
||||
import { setupServer } from "./transports/setup-server.js";
|
||||
|
||||
const SSE_PORT = process.env.SSE_PORT || 3001;
|
||||
|
||||
// Start the server
|
||||
async function main() {
|
||||
await setupServer().then((app) => {
|
||||
app.start({
|
||||
transportType: "sse",
|
||||
sse: {
|
||||
endpoint: "/sse",
|
||||
port: Number(SSE_PORT),
|
||||
},
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
main().catch((error) => {
|
||||
console.error(error);
|
||||
process.exit(1);
|
||||
});
|
||||
@@ -0,0 +1,4 @@
|
||||
|
||||
import { Resource } from "../types/resources.js";
|
||||
|
||||
export const resourses: Resource[] = []
|
||||
@@ -0,0 +1,23 @@
|
||||
import type { Tool } from "../../types/tools.js";
|
||||
import { liquidswap } from "../../core/liquidswap.js";
|
||||
import { z } from "zod";
|
||||
|
||||
const getPools: Tool<typeof parameters>['execute'] = async () => {
|
||||
const data = await liquidswap.getPools();
|
||||
|
||||
return {
|
||||
type: "text",
|
||||
text: JSON.stringify(data, null, 2),
|
||||
};
|
||||
};
|
||||
|
||||
|
||||
const parameters = z.object({});
|
||||
|
||||
|
||||
export const getPoolsTool: Tool<typeof parameters> = {
|
||||
name: "get_pools",
|
||||
description: "Get all pools registered on Liquidswap",
|
||||
execute: getPools,
|
||||
parameters,
|
||||
};
|
||||
@@ -0,0 +1 @@
|
||||
export * from "./get-pools.js";
|
||||
@@ -0,0 +1,23 @@
|
||||
import type { Tool } from "../../types/tools.js";
|
||||
import { liquidswap } from "../../core/liquidswap.js";
|
||||
import { z } from "zod";
|
||||
|
||||
const getTokens: Tool<typeof parameters>['execute'] = async () => {
|
||||
const data = await liquidswap.getTokens();
|
||||
|
||||
return {
|
||||
type: "text",
|
||||
text: JSON.stringify(data, null, 2),
|
||||
};
|
||||
};
|
||||
|
||||
|
||||
const parameters = z.object({});
|
||||
|
||||
|
||||
export const getTokensTool: Tool<typeof parameters> = {
|
||||
name: "get_tokens",
|
||||
description: "Get all tokens registered on Liquidswap",
|
||||
execute: getTokens,
|
||||
parameters,
|
||||
};
|
||||
@@ -0,0 +1 @@
|
||||
export * from "./get-tokens.js";
|
||||
@@ -0,0 +1,10 @@
|
||||
import { Tool } from "../types/tools.js";
|
||||
import { getTokensTool } from "./get-tokens/get-tokens.js";
|
||||
import { getPoolsTool } from "./get-pools/get-pools.js";
|
||||
|
||||
const tools: Tool<any>[] = [
|
||||
getTokensTool,
|
||||
getPoolsTool,
|
||||
];
|
||||
|
||||
export default tools;
|
||||
@@ -0,0 +1,72 @@
|
||||
import { resourses } from "../resources/all-resources.js";
|
||||
import { FastMCP } from "fastmcp";
|
||||
import * as fastmcp from "fastmcp";
|
||||
import { name, version } from "../version.js";
|
||||
import tools from "../tools/index.js";
|
||||
import { liquidswap } from "../core/liquidswap.js";
|
||||
|
||||
function setupServerHandlers(server: FastMCP) {
|
||||
for (const resource of resourses) {
|
||||
if ('arguments' in resource && resource.arguments) {
|
||||
server.addResourceTemplate({
|
||||
uriTemplate: `liquidswap://${resource.pathname}`,
|
||||
name: resource.name,
|
||||
mimeType: resource.mimeType,
|
||||
arguments: resource.arguments,
|
||||
load: async (args) => {
|
||||
return resource.handler(liquidswap, args);
|
||||
},
|
||||
|
||||
|
||||
});
|
||||
}
|
||||
|
||||
server.addResource({
|
||||
uri: `liquidswap://${resource.pathname}`,
|
||||
name: resource.name,
|
||||
mimeType: resource.mimeType,
|
||||
async load() {
|
||||
return resource.handler(liquidswap, {});
|
||||
},
|
||||
});
|
||||
}
|
||||
|
||||
for (const tool of tools) {
|
||||
server.addTool(tool);
|
||||
}
|
||||
}
|
||||
|
||||
class FastMCPSession extends fastmcp.FastMCPSession {
|
||||
originalEmit = fastmcp.FastMCPSession.prototype.emit;
|
||||
}
|
||||
|
||||
Object.defineProperty(fastmcp.FastMCPSession.prototype, "originalEmit", {
|
||||
value: fastmcp.FastMCPSession.prototype.emit,
|
||||
writable: false,
|
||||
});
|
||||
|
||||
// suppress error event
|
||||
fastmcp.FastMCPSession.prototype.emit = function (
|
||||
this: FastMCPSession,
|
||||
event: any,
|
||||
...args: any[]
|
||||
) {
|
||||
if (event !== "error") {
|
||||
return this.originalEmit(event, ...args);
|
||||
}
|
||||
};
|
||||
|
||||
export async function setupServer() {
|
||||
const server = new FastMCP(
|
||||
{
|
||||
name,
|
||||
version
|
||||
},
|
||||
);
|
||||
|
||||
setupServerHandlers(server);
|
||||
|
||||
return server;
|
||||
}
|
||||
|
||||
export default setupServer;
|
||||
@@ -0,0 +1,23 @@
|
||||
import { Liquidswap } from "../core/liquidswap.js";
|
||||
import type { ResourceResult, ResourceTemplateArgument } from "fastmcp";
|
||||
|
||||
type ResourceTemplateArgumentsToObject<T extends {
|
||||
name: string;
|
||||
}[]> = {
|
||||
[K in T[number]["name"]]: string;
|
||||
};
|
||||
export type ResourceHandler<Arguments extends ResourceTemplateArgument[] = ResourceTemplateArgument[]> = (santiment: Liquidswap, args: ResourceTemplateArgumentsToObject<Arguments>) => Promise<Arguments extends (ResourceResult | ResourceResult[]) ? (ResourceResult | ResourceResult[]) : ResourceResult>;
|
||||
export type Resource<Arguments extends ResourceTemplateArgument[] = ResourceTemplateArgument[]> = {
|
||||
pathname: string;
|
||||
name: string;
|
||||
description: string;
|
||||
mimeType: `text/${string}` | `application/${string}`;
|
||||
handler: ResourceHandler<Arguments>;
|
||||
arguments?: Arguments;
|
||||
} | {
|
||||
pathname: string;
|
||||
name: string;
|
||||
description: string;
|
||||
mimeType: `text/${string}` | `application/${string}`;
|
||||
handler: ResourceHandler;
|
||||
}
|
||||
@@ -0,0 +1,3 @@
|
||||
import type { Tool as fastmcpTool, ToolParameters } from "fastmcp";
|
||||
|
||||
export type Tool<Parameters extends ToolParameters = ToolParameters> = fastmcpTool<undefined, Parameters>;
|
||||
@@ -0,0 +1,2 @@
|
||||
export const version = "1.0.0";
|
||||
export const name = "liquidswap-mcp-server";
|
||||
@@ -0,0 +1,18 @@
|
||||
{
|
||||
"compilerOptions": {
|
||||
"target": "ES2022",
|
||||
"module": "NodeNext",
|
||||
"moduleResolution": "NodeNext",
|
||||
"outDir": "./build",
|
||||
"rootDir": "./src",
|
||||
"strict": true,
|
||||
"esModuleInterop": true,
|
||||
"skipLibCheck": true,
|
||||
"forceConsistentCasingInFileNames": true,
|
||||
"experimentalDecorators": true,
|
||||
"emitDecoratorMetadata": true,
|
||||
"resolveJsonModule": true
|
||||
},
|
||||
"include": ["src/**/*"],
|
||||
"exclude": ["node_modules"]
|
||||
}
|
||||
Reference in new issue
Block a user