Commit 4b44f971 authored by LongLD's avatar LongLD

update docs

parent d7b5a5d1
{
"recommendations": ["esbenp.prettier-vscode", "EditorConfig.EditorConfig"]
}
{
// Use IntelliSense to learn about possible attributes.
// Hover to view descriptions of existing attributes.
// For more information, visit: https://go.microsoft.com/fwlink/?linkid=830387
"version": "0.2.0",
"configurations": [
{
"type": "chrome",
"request": "launch",
"name": "Launch Chrome against localhost",
"url": "http://localhost:8087",
"webRoot": "${workspaceFolder}"
}
]
}
\ No newline at end of file
{
"servers": {
// The "servers" section defines the MCP servers you want to use.
"fetch": {
"command": "uvx",
"args": ["mcp-server-fetch"]
},
"acm-graphql-mcp": {
"command": "npx",
"args": [
"-y",
"acm-graphql-mcp@https://gitlab.awing.vn/awing-mcp/graphql-mcp/-/raw/master/acm-graphql-mcp-1.0.0.tgz"
],
"env": {
"GRAPHQL_ENDPOINT": "https://acm.awifi.com.vn/graphql",
"AUTH_TOKEN": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ0b2tlbklkIjoiNzBkNDQyMjZiNzRkYjI2Yjg1NjE1NDljNjUwYjA4MTUiLCJkZXZpY2VJZCI6IjcwZDQ0MjI2Yjc0ZGIyNmI4NTYxNTQ5YzY1MGIwODE1IiwidXNlcklkIjoiMSIsImNsaWVudElkIjoiMjAwIiwiaW5pdEF0IjoiMTc2OTIyMDY3ODEzNCIsImV4cGlyZXMiOiIxNzY5MjYzODc4MTM0IiwiYnJvd3NlckRldmljZSI6Ik90aGVyIiwiYnJvd3Nlck9zIjoiV2luZG93cyAxMCIsImlwIjoiMTAuMjQ0LjIzNS4xMzAifQ.RILX7y7L6hDHuEaq1JOwCCut8FjZWTHF3K2LzMeTYpw",
"WORKSPACE_ID": "11"
}
},
}
}
{
"git.ignoreLimitWarning": true,
"files.eol": "\r\n",
"editor.formatOnSave": false, // Không Tự động định dạng khi lưu
"editor.defaultFormatter": "esbenp.prettier-vscode", // Đặt Prettier làm định dạng mặc định (nếu bạn sử dụng Prettier)
"editor.codeActionsOnSave": {
"source.fixAll": "never",
},
"editor.tabSize": 4,
"liveServer.settings.port": 5501,
"[typescript]": {
"editor.defaultFormatter": "vscode.typescript-language-features"
}
}
...@@ -2,7 +2,7 @@ ...@@ -2,7 +2,7 @@
"mcpServers": { "mcpServers": {
"acm-graphql": { "acm-graphql": {
"command": "node", "command": "node",
"args": ["e:/Project/ProjectByAuthor/Awing/acm/mcp-server/dist/index.js"], "args": ["d:/Project/Awing/graphql-mcp/dist/index.js"],
"env": { "env": {
"GRAPHQL_ENDPOINT": "https://acm.awifi.com.vn/graphql", "GRAPHQL_ENDPOINT": "https://acm.awifi.com.vn/graphql",
"AUTH_TOKEN": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ0b2tlbklkIjoiNzBkNDQyMjZiNzRkYjI2Yjg1NjE1NDljNjUwYjA4MTUiLCJkZXZpY2VJZCI6IjcwZDQ0MjI2Yjc0ZGIyNmI4NTYxNTQ5YzY1MGIwODE1IiwidXNlcklkIjoiMSIsImNsaWVudElkIjoiMjAwIiwiaW5pdEF0IjoiMTc2OTIyMDY3ODEzNCIsImV4cGlyZXMiOiIxNzY5MjYzODc4MTM0IiwiYnJvd3NlckRldmljZSI6Ik90aGVyIiwiYnJvd3Nlck9zIjoiV2luZG93cyAxMCIsImlwIjoiMTAuMjQ0LjIzNS4xMzAifQ.RILX7y7L6hDHuEaq1JOwCCut8FjZWTHF3K2LzMeTYpw", "AUTH_TOKEN": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ0b2tlbklkIjoiNzBkNDQyMjZiNzRkYjI2Yjg1NjE1NDljNjUwYjA4MTUiLCJkZXZpY2VJZCI6IjcwZDQ0MjI2Yjc0ZGIyNmI4NTYxNTQ5YzY1MGIwODE1IiwidXNlcklkIjoiMSIsImNsaWVudElkIjoiMjAwIiwiaW5pdEF0IjoiMTc2OTIyMDY3ODEzNCIsImV4cGlyZXMiOiIxNzY5MjYzODc4MTM0IiwiYnJvd3NlckRldmljZSI6Ik90aGVyIiwiYnJvd3Nlck9zIjoiV2luZG93cyAxMCIsImlwIjoiMTAuMjQ0LjIzNS4xMzAifQ.RILX7y7L6hDHuEaq1JOwCCut8FjZWTHF3K2LzMeTYpw",
......
This diff is collapsed.
# ACM GraphQL MCP Server
MCP (Model Context Protocol) Server để gọi GraphQL API của ACM.
## Cài đặt
```bash
cd mcp-server
npm install
npm run build
```
## Cấu hình MCP
Thêm vào file cấu hình MCP của bạn (thường là `mcp.json` hoặc trong settings của AI assistant):
```json
{
"mcpServers": {
"acm-graphql": {
"command": "node",
"args": ["e:/Project/ProjectByAuthor/Awing/acm/mcp-server/dist/index.js"],
"env": {
"GRAPHQL_ENDPOINT": "https://acm.awifi.com.vn/graphql",
"AUTH_TOKEN": "YOUR_BEARER_TOKEN_HERE",
"WORKSPACE_ID": "11"
}
}
}
}
```
## Tools có sẵn
### Query Tools (15 tools)
| Tool | Mô tả |
|------|-------|
| `get_role_by_id` | Lấy Role theo ID |
| `get_roles` | Lấy danh sách Roles |
| `get_user_by_id` | Lấy User theo ID |
| `get_users` | Lấy danh sách Users |
| `get_place_by_id` | Lấy Place theo ID |
| `get_places` | Lấy danh sách Places |
| `get_group_by_id` | Lấy Group theo ID |
| `get_groups` | Lấy danh sách Groups |
| `get_campaign_by_id` | Lấy Campaign theo ID |
| `get_campaigns` | Lấy danh sách Campaigns |
| `get_template_by_id` | Lấy Template theo ID |
| `get_templates` | Lấy danh sách Templates |
| `get_workspace_by_id` | Lấy Workspace theo ID |
| `get_workspaces` | Lấy danh sách Workspaces |
| `execute_graphql` | Thực thi custom GraphQL query/mutation |
### Mutation Tools (14 tools)
| Tool | Mô tả |
|------|-------|
| `create_role` | Tạo mới Role |
| `update_role` | Cập nhật Role |
| `delete_role` | Xóa Role |
| `create_group` | Tạo mới Group |
| `update_group` | Cập nhật Group |
| `delete_group` | Xóa Group |
| `update_user` | Cập nhật User |
| `delete_user` | Xóa User |
| `add_user_to_workspace` | Thêm User vào Workspace |
| `create_place` | Tạo mới Place |
| `update_place` | Cập nhật Place |
| `create_campaign` | Tạo mới Campaign |
| `update_campaign` | Cập nhật Campaign |
| `delete_campaign` | Xóa Campaign |
## Ví dụ sử dụng
### Queries
```
"Lấy role có id là 10"
→ Gọi get_role_by_id(id: 10)
"Lấy 20 users đầu tiên"
→ Gọi get_users(pageSize: 20, pageIndex: 0)
```
### Mutations
```
"Tạo role mới tên Admin"
→ Gọi create_role(name: "Admin", description: "Admin role")
"Xóa role có id 5"
→ Gọi delete_role(id: 5)
```
### Custom GraphQL
```
"Thực thi query: { menus { id name } }"
→ Gọi execute_graphql(query: "{ menus { id name } }")
```
## Development
```bash
# Chạy trực tiếp TypeScript (dev mode)
npm run dev
# Build production
npm run build
# Start production
npm start
```
#!/usr/bin/env node
export {};
#!/usr/bin/env node
import { Server } from '@modelcontextprotocol/sdk/server/index.js';
import { StdioServerTransport } from '@modelcontextprotocol/sdk/server/stdio.js';
import { CallToolRequestSchema, ListToolsRequestSchema } from '@modelcontextprotocol/sdk/types.js';
import { GraphQLClient } from 'graphql-request';
import { tools, executeQuery } from './tools/index.js';
// Configuration from environment variables
const GRAPHQL_ENDPOINT = process.env.GRAPHQL_ENDPOINT || 'https://acm.awifi.com.vn/graphql';
const AUTH_TOKEN = process.env.AUTH_TOKEN || '';
const WORKSPACE_ID = process.env.WORKSPACE_ID || '11';
// Create GraphQL client
const graphqlClient = new GraphQLClient(GRAPHQL_ENDPOINT, {
headers: {
Authorization: `Bearer ${AUTH_TOKEN}`,
workspaceid: WORKSPACE_ID
}
});
// Create MCP server
const server = new Server({
name: 'acm-graphql-mcp',
version: '1.0.0'
}, {
capabilities: {
tools: {}
}
});
// List available tools
server.setRequestHandler(ListToolsRequestSchema, async () => {
return {
tools: tools
};
});
// Handle tool calls
server.setRequestHandler(CallToolRequestSchema, async (request) => {
const { name, arguments: args } = request.params;
try {
const result = await executeQuery(graphqlClient, name, args);
return {
content: [
{
type: 'text',
text: JSON.stringify(result, null, 2)
}
]
};
}
catch (error) {
const errorMessage = error instanceof Error ? error.message : String(error);
return {
content: [
{
type: 'text',
text: `Error: ${errorMessage}`
}
],
isError: true
};
}
});
// Start the server
async function main() {
const transport = new StdioServerTransport();
await server.connect(transport);
console.error('ACM GraphQL MCP Server running on stdio');
}
main().catch((error) => {
console.error('Server error:', error);
process.exit(1);
});
import { GraphQLClient } from 'graphql-request';
import { Tool } from '@modelcontextprotocol/sdk/types.js';
export declare const tools: Tool[];
export declare function executeQuery(client: GraphQLClient, toolName: string, args: Record<string, unknown>): Promise<unknown>;
// GraphQL Queries
const GET_ROLE_BY_ID = `
query getRoleById($id: ID!) {
role(id: $id) {
description
id
name
workspaceId
roleAuthens {
groupId
id
roleId
userId
}
versionId
roleTagDetails {
roleId
roleTagId
roleTag {
id
name
}
}
}
}
`;
const GET_ROLES = `
query getRoles($input: PagingInput) {
roles(input: $input) {
items {
description
id
name
workspaceId
roleAuthens {
groupId
id
roleId
userId
}
roleTagDetails {
roleId
roleTagId
roleTag {
id
name
}
}
}
totalCount
}
}
`;
const GET_USER_BY_ID = `
query getUserById($id: ID!) {
user(id: $id) {
id
name
username
description
gender
image
versionId
}
}
`;
const GET_USERS = `
query getUsers($input: PagingInput) {
users(input: $input) {
items {
id
name
username
description
gender
image
}
totalCount
}
}
`;
const GET_PLACES = `
query getPlaces($input: PagingInput) {
places(input: $input) {
items {
id
name
code
description
address
directoryPath
}
totalCount
}
}
`;
const GET_PLACE_BY_ID = `
query getPlaceById($id: ID!) {
place(id: $id) {
id
name
code
description
address
directoryPath
versionId
}
}
`;
const GET_GROUPS = `
query getGroups($input: PagingInput) {
groups(input: $input) {
items {
id
name
description
versionId
}
totalCount
}
}
`;
const GET_GROUP_BY_ID = `
query getGroupById($id: ID!) {
group(id: $id) {
id
name
description
versionId
}
}
`;
const GET_CAMPAIGNS = `
query getCampaigns($input: PagingInput) {
campaigns(input: $input) {
items {
id
name
description
state
directoryPath
}
totalCount
}
}
`;
const GET_CAMPAIGN_BY_ID = `
query getCampaignById($id: ID!) {
campaign(id: $id) {
id
name
description
state
directoryPath
versionId
}
}
`;
const GET_TEMPLATES = `
query getTemplates($input: PagingInput) {
templates(input: $input) {
items {
id
name
description
templateTypeId
directoryPath
}
totalCount
}
}
`;
const GET_TEMPLATE_BY_ID = `
query getTemplateById($id: ID!) {
template(id: $id) {
id
name
description
templateTypeId
templateHtml
directoryPath
versionId
}
}
`;
const GET_WORKSPACES = `
query getWorkspaces($input: PagingInput) {
workspaces(input: $input) {
items {
id
name
description
directoryPath
type
}
totalCount
}
}
`;
const GET_WORKSPACE_BY_ID = `
query getWorkspaceById($id: ID!) {
workspace(id: $id) {
id
name
description
directoryPath
type
versionId
}
}
`;
// Query mapping
const queryMap = {
get_role_by_id: GET_ROLE_BY_ID,
get_roles: GET_ROLES,
get_user_by_id: GET_USER_BY_ID,
get_users: GET_USERS,
get_place_by_id: GET_PLACE_BY_ID,
get_places: GET_PLACES,
get_group_by_id: GET_GROUP_BY_ID,
get_groups: GET_GROUPS,
get_campaign_by_id: GET_CAMPAIGN_BY_ID,
get_campaigns: GET_CAMPAIGNS,
get_template_by_id: GET_TEMPLATE_BY_ID,
get_templates: GET_TEMPLATES,
get_workspace_by_id: GET_WORKSPACE_BY_ID,
get_workspaces: GET_WORKSPACES
};
// ==================== MUTATIONS ====================
const CREATE_ROLE = `
mutation createRole($input: RoleRequestGqlInput!) {
createRole(input: $input) {
id
}
}
`;
const UPDATE_ROLE = `
mutation updateRole($id: ID!, $input: RoleRequestGqlInput!, $versionId: Int!) {
updateRole(id: $id, input: $input, versionId: $versionId) {
id
}
}
`;
const DELETE_ROLE = `
mutation deleteRole($id: ID!) {
deleteRole(id: $id) {
id
}
}
`;
const CREATE_GROUP = `
mutation createGroup($input: GroupRequestGqlInput!) {
createGroup(input: $input) {
id
}
}
`;
const UPDATE_GROUP = `
mutation updateGroup($id: ID!, $input: GroupRequestGqlInput!, $versionId: Int!) {
updateGroup(input: $input, id: $id, versionId: $versionId) {
id
}
}
`;
const DELETE_GROUP = `
mutation deleteGroup($id: ID!) {
deleteGroup(id: $id) {
id
}
}
`;
const UPDATE_USER = `
mutation updateUser($id: ID!, $input: UserRequestPayloadGqlInput!, $versionId: Int!) {
updateUser(input: $input, id: $id, versionId: $versionId) {
id
}
}
`;
const DELETE_USER = `
mutation deleteUser($id: ID!) {
deleteUser(id: $id) {
id
}
}
`;
const ADD_USER_TO_WORKSPACE = `
mutation addUserToWorkspace($username: String!, $roleAuthenInput: RoleAuthenRequestGqlInput, $groupIds: [Int!]) {
addUserToWorkspace(username: $username, roleAuthenInput: $roleAuthenInput, groupIds: $groupIds) {
id
}
}
`;
const CREATE_PLACE = `
mutation createPlace($aliasInput: AliasWithRelativePathGqlInput!, $input: PlaceRequestGqlInput!) {
createPlace(aliasInput: $aliasInput, input: $input) {
id
}
}
`;
const UPDATE_PLACE = `
mutation updatePlace($id: ID!, $input: PlaceRequestGqlInput!, $aliasInput: AliasWithRelativePathGqlInput, $versionId: Int!) {
updatePlace(id: $id, input: $input, aliasInput: $aliasInput, versionId: $versionId) {
id
}
}
`;
const DELETE_CAMPAIGN = `
mutation deleteCampaign($id: Int!) {
deleteCampaign(id: $id) {
id
}
}
`;
const CREATE_CAMPAIGN = `
mutation createCampaign($input: CampaignRequestGqlInput!, $aliasInput: AliasWithRelativePathGqlInput!) {
createCampaign(input: $input, aliasInput: $aliasInput) {
id
}
}
`;
const UPDATE_CAMPAIGN = `
mutation updateCampaign($id: Int!, $input: CampaignRequestGqlInput!, $aliasInput: AliasWithRelativePathGqlInput, $versionId: Int!) {
updateCampaign(id: $id, input: $input, aliasInput: $aliasInput, versionId: $versionId) {
id
}
}
`;
// Mutation mapping
const mutationMap = {
create_role: CREATE_ROLE,
update_role: UPDATE_ROLE,
delete_role: DELETE_ROLE,
create_group: CREATE_GROUP,
update_group: UPDATE_GROUP,
delete_group: DELETE_GROUP,
update_user: UPDATE_USER,
delete_user: DELETE_USER,
add_user_to_workspace: ADD_USER_TO_WORKSPACE,
create_place: CREATE_PLACE,
update_place: UPDATE_PLACE,
delete_campaign: DELETE_CAMPAIGN,
create_campaign: CREATE_CAMPAIGN,
update_campaign: UPDATE_CAMPAIGN
};
// Tool definitions
export const tools = [
{
name: 'get_role_by_id',
description: 'Lấy thông tin Role theo ID',
inputSchema: {
type: 'object',
properties: {
id: {
type: 'number',
description: 'ID của Role cần lấy'
}
},
required: ['id']
}
},
{
name: 'get_roles',
description: 'Lấy danh sách Roles với phân trang',
inputSchema: {
type: 'object',
properties: {
pageSize: {
type: 'number',
description: 'Số lượng items mỗi trang (mặc định 10)'
},
pageIndex: {
type: 'number',
description: 'Số thứ tự trang (bắt đầu từ 0)'
}
}
}
},
{
name: 'get_user_by_id',
description: 'Lấy thông tin User theo ID',
inputSchema: {
type: 'object',
properties: {
id: {
type: 'number',
description: 'ID của User cần lấy'
}
},
required: ['id']
}
},
{
name: 'get_users',
description: 'Lấy danh sách Users với phân trang',
inputSchema: {
type: 'object',
properties: {
pageSize: {
type: 'number',
description: 'Số lượng items mỗi trang (mặc định 10)'
},
pageIndex: {
type: 'number',
description: 'Số thứ tự trang (bắt đầu từ 0)'
}
}
}
},
{
name: 'get_place_by_id',
description: 'Lấy thông tin Place (địa điểm) theo ID',
inputSchema: {
type: 'object',
properties: {
id: {
type: 'number',
description: 'ID của Place cần lấy'
}
},
required: ['id']
}
},
{
name: 'get_places',
description: 'Lấy danh sách Places với phân trang',
inputSchema: {
type: 'object',
properties: {
pageSize: {
type: 'number',
description: 'Số lượng items mỗi trang (mặc định 10)'
},
pageIndex: {
type: 'number',
description: 'Số thứ tự trang (bắt đầu từ 0)'
}
}
}
},
{
name: 'get_group_by_id',
description: 'Lấy thông tin Group theo ID',
inputSchema: {
type: 'object',
properties: {
id: {
type: 'number',
description: 'ID của Group cần lấy'
}
},
required: ['id']
}
},
{
name: 'get_groups',
description: 'Lấy danh sách Groups với phân trang',
inputSchema: {
type: 'object',
properties: {
pageSize: {
type: 'number',
description: 'Số lượng items mỗi trang (mặc định 10)'
},
pageIndex: {
type: 'number',
description: 'Số thứ tự trang (bắt đầu từ 0)'
}
}
}
},
{
name: 'get_campaign_by_id',
description: 'Lấy thông tin Campaign theo ID',
inputSchema: {
type: 'object',
properties: {
id: {
type: 'number',
description: 'ID của Campaign cần lấy'
}
},
required: ['id']
}
},
{
name: 'get_campaigns',
description: 'Lấy danh sách Campaigns với phân trang',
inputSchema: {
type: 'object',
properties: {
pageSize: {
type: 'number',
description: 'Số lượng items mỗi trang (mặc định 10)'
},
pageIndex: {
type: 'number',
description: 'Số thứ tự trang (bắt đầu từ 0)'
}
}
}
},
{
name: 'get_template_by_id',
description: 'Lấy thông tin Template theo ID',
inputSchema: {
type: 'object',
properties: {
id: {
type: 'number',
description: 'ID của Template cần lấy'
}
},
required: ['id']
}
},
{
name: 'get_templates',
description: 'Lấy danh sách Templates với phân trang',
inputSchema: {
type: 'object',
properties: {
pageSize: {
type: 'number',
description: 'Số lượng items mỗi trang (mặc định 10)'
},
pageIndex: {
type: 'number',
description: 'Số thứ tự trang (bắt đầu từ 0)'
}
}
}
},
{
name: 'get_workspace_by_id',
description: 'Lấy thông tin Workspace theo ID',
inputSchema: {
type: 'object',
properties: {
id: {
type: 'number',
description: 'ID của Workspace cần lấy'
}
},
required: ['id']
}
},
{
name: 'get_workspaces',
description: 'Lấy danh sách Workspaces với phân trang',
inputSchema: {
type: 'object',
properties: {
pageSize: {
type: 'number',
description: 'Số lượng items mỗi trang (mặc định 10)'
},
pageIndex: {
type: 'number',
description: 'Số thứ tự trang (bắt đầu từ 0)'
}
}
}
},
// ==================== MUTATION TOOLS ====================
{
name: 'create_role',
description: 'Tạo mới một Role',
inputSchema: {
type: 'object',
properties: {
name: {
type: 'string',
description: 'Tên của Role'
},
description: {
type: 'string',
description: 'Mô tả Role'
}
},
required: ['name']
}
},
{
name: 'update_role',
description: 'Cập nhật Role theo ID',
inputSchema: {
type: 'object',
properties: {
id: {
type: 'number',
description: 'ID của Role cần cập nhật'
},
name: {
type: 'string',
description: 'Tên mới của Role'
},
description: {
type: 'string',
description: 'Mô tả mới'
},
versionId: {
type: 'number',
description: 'Version ID để kiểm tra conflict'
}
},
required: ['id', 'versionId']
}
},
{
name: 'delete_role',
description: 'Xóa Role theo ID',
inputSchema: {
type: 'object',
properties: {
id: {
type: 'number',
description: 'ID của Role cần xóa'
}
},
required: ['id']
}
},
{
name: 'create_group',
description: 'Tạo mới một Group',
inputSchema: {
type: 'object',
properties: {
name: {
type: 'string',
description: 'Tên của Group'
},
description: {
type: 'string',
description: 'Mô tả Group'
}
},
required: ['name']
}
},
{
name: 'update_group',
description: 'Cập nhật Group theo ID',
inputSchema: {
type: 'object',
properties: {
id: {
type: 'number',
description: 'ID của Group cần cập nhật'
},
name: {
type: 'string',
description: 'Tên mới của Group'
},
description: {
type: 'string',
description: 'Mô tả mới'
},
versionId: {
type: 'number',
description: 'Version ID để kiểm tra conflict'
}
},
required: ['id', 'versionId']
}
},
{
name: 'delete_group',
description: 'Xóa Group theo ID',
inputSchema: {
type: 'object',
properties: {
id: {
type: 'number',
description: 'ID của Group cần xóa'
}
},
required: ['id']
}
},
{
name: 'update_user',
description: 'Cập nhật User theo ID',
inputSchema: {
type: 'object',
properties: {
id: {
type: 'number',
description: 'ID của User cần cập nhật'
},
name: {
type: 'string',
description: 'Tên mới của User'
},
description: {
type: 'string',
description: 'Mô tả mới'
},
versionId: {
type: 'number',
description: 'Version ID để kiểm tra conflict'
}
},
required: ['id', 'versionId']
}
},
{
name: 'delete_user',
description: 'Xóa User theo ID',
inputSchema: {
type: 'object',
properties: {
id: {
type: 'number',
description: 'ID của User cần xóa'
}
},
required: ['id']
}
},
{
name: 'add_user_to_workspace',
description: 'Thêm User vào Workspace hiện tại',
inputSchema: {
type: 'object',
properties: {
username: {
type: 'string',
description: 'Username của User cần thêm'
},
roleId: {
type: 'number',
description: 'ID của Role gán cho User'
},
groupIds: {
type: 'array',
items: { type: 'number' },
description: 'Danh sách ID các Group của User'
}
},
required: ['username']
}
},
{
name: 'create_place',
description: 'Tạo mới một Place (địa điểm)',
inputSchema: {
type: 'object',
properties: {
name: {
type: 'string',
description: 'Tên Place'
},
code: {
type: 'string',
description: 'Mã code của Place'
},
description: {
type: 'string',
description: 'Mô tả Place'
},
address: {
type: 'string',
description: 'Địa chỉ'
},
directoryPath: {
type: 'string',
description: 'Đường dẫn thư mục'
}
},
required: ['name', 'directoryPath']
}
},
{
name: 'update_place',
description: 'Cập nhật Place theo ID',
inputSchema: {
type: 'object',
properties: {
id: {
type: 'number',
description: 'ID của Place cần cập nhật'
},
name: {
type: 'string',
description: 'Tên mới'
},
description: {
type: 'string',
description: 'Mô tả mới'
},
address: {
type: 'string',
description: 'Địa chỉ mới'
},
versionId: {
type: 'number',
description: 'Version ID để kiểm tra conflict'
}
},
required: ['id', 'versionId']
}
},
{
name: 'create_campaign',
description: 'Tạo mới một Campaign',
inputSchema: {
type: 'object',
properties: {
name: {
type: 'string',
description: 'Tên Campaign'
},
description: {
type: 'string',
description: 'Mô tả Campaign'
},
directoryPath: {
type: 'string',
description: 'Đường dẫn thư mục'
}
},
required: ['name', 'directoryPath']
}
},
{
name: 'update_campaign',
description: 'Cập nhật Campaign theo ID',
inputSchema: {
type: 'object',
properties: {
id: {
type: 'number',
description: 'ID của Campaign cần cập nhật'
},
name: {
type: 'string',
description: 'Tên mới'
},
description: {
type: 'string',
description: 'Mô tả mới'
},
versionId: {
type: 'number',
description: 'Version ID để kiểm tra conflict'
}
},
required: ['id', 'versionId']
}
},
{
name: 'delete_campaign',
description: 'Xóa Campaign theo ID',
inputSchema: {
type: 'object',
properties: {
id: {
type: 'number',
description: 'ID của Campaign cần xóa'
}
},
required: ['id']
}
},
{
name: 'execute_graphql',
description: 'Thực thi một GraphQL query hoặc mutation tùy chỉnh',
inputSchema: {
type: 'object',
properties: {
query: {
type: 'string',
description: 'GraphQL query hoặc mutation string'
},
variables: {
type: 'object',
description: 'Variables cho query/mutation'
}
},
required: ['query']
}
}
];
// Execute query function
export async function executeQuery(client, toolName, args) {
// Handle custom GraphQL query
if (toolName === 'execute_graphql') {
const query = args.query;
const variables = args.variables;
return client.request(query, variables);
}
// Check if it's a query
const query = queryMap[toolName];
if (query) {
let variables = {};
if (toolName.endsWith('_by_id')) {
// Single entity query
variables = { id: args.id };
}
else {
// List query with pagination
variables = {
input: {
pageSize: args.pageSize || 10,
pageIndex: args.pageIndex || 0
}
};
}
return client.request(query, variables);
}
// Check if it's a mutation
const mutation = mutationMap[toolName];
if (mutation) {
let variables = {};
// Handle different mutation types
if (toolName.startsWith('create_')) {
// Create mutations
const { name, description, code, address, directoryPath } = args;
const input = {};
if (name !== undefined)
input.name = name;
if (description !== undefined)
input.description = description;
if (code !== undefined)
input.code = code;
if (address !== undefined)
input.address = address;
if (toolName === 'create_place' || toolName === 'create_campaign') {
variables = {
input,
aliasInput: {
alias: name,
relativePath: directoryPath || '/'
}
};
}
else {
variables = { input };
}
}
else if (toolName.startsWith('update_')) {
// Update mutations
const { id, versionId, name, description, code, address, directoryPath } = args;
const input = {};
if (name !== undefined)
input.name = name;
if (description !== undefined)
input.description = description;
if (code !== undefined)
input.code = code;
if (address !== undefined)
input.address = address;
variables = { id, input, versionId };
if (toolName === 'update_place' || toolName === 'update_campaign') {
if (directoryPath) {
variables.aliasInput = {
alias: name || '',
relativePath: directoryPath
};
}
}
}
else if (toolName.startsWith('delete_')) {
// Delete mutations
variables = { id: args.id };
}
else if (toolName === 'add_user_to_workspace') {
// Special case
const { username, roleId, groupIds } = args;
variables = {
username,
roleAuthenInput: roleId ? { roleId } : undefined,
groupIds: groupIds || []
};
}
return client.request(mutation, variables);
}
throw new Error(`Unknown tool: ${toolName}`);
}
{
"name": "acm-graphql-mcp",
"version": "1.0.0",
"type": "module",
"description": "MCP Server cho ACM GraphQL API",
"bin": {
"acm-graphql-mcp": "dist/index.js"
},
"files": ["dist"],
"scripts": {
"build": "tsc",
"prepublishOnly": "npm run build",
"start": "node dist/index.js",
"dev": "tsx src/index.ts"
},
"dependencies": {
"@modelcontextprotocol/sdk": "^1.0.0",
"graphql": "^16.9.0",
"graphql-request": "^7.0.0"
},
"devDependencies": {
"@types/node": "^22.0.0",
"tsx": "^4.0.0",
"typescript": "^5.6.0"
},
"engines": {
"node": ">=18"
}
}
...@@ -16,7 +16,7 @@ Thêm vào file cấu hình MCP của bạn (thường là `mcp.json` hoặc tro ...@@ -16,7 +16,7 @@ Thêm vào file cấu hình MCP của bạn (thường là `mcp.json` hoặc tro
```json ```json
{ {
"mcpServers": { "servers": {
"acm-graphql": { "acm-graphql": {
"command": "node", "command": "node",
"args": ["e:/Project/ProjectByAuthor/Awing/acm/mcp-server/dist/index.js"], "args": ["e:/Project/ProjectByAuthor/Awing/acm/mcp-server/dist/index.js"],
......
File added
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment