poi-plugin-mcp 0.2.1 → 0.2.3
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 +7 -0
- package/lib/bridge-controller.js +1 -0
- package/lib/poi-http-bridge.js +102 -11
- package/lib/poi-screenshot.js +104 -0
- package/mcp-server.js +68 -9
- package/package.json +3 -3
package/README.md
CHANGED
|
@@ -61,8 +61,15 @@ The default port is `17777`.
|
|
|
61
61
|
| `/master` | Master ship, equipment, ship type, equipment type, and mission data |
|
|
62
62
|
| `/event` | Event ship tag definitions plus owned ships' current sally area |
|
|
63
63
|
| `/planner` | Ship Info deck planner areas and ship assignments |
|
|
64
|
+
| `/screenshot` | In-memory PNG capture of the game WebView |
|
|
64
65
|
| `/all` | Combined basic runtime data |
|
|
65
66
|
|
|
67
|
+
`/screenshot` accepts `GET` only. It uses Poi's existing
|
|
68
|
+
`screenshot::get` WebContents capture path and returns PNG base64 in JSON. It
|
|
69
|
+
does not save a file, write the clipboard, capture the desktop, or appear in
|
|
70
|
+
MCP resources and tools. Its response disables CORS and uses
|
|
71
|
+
`Cache-Control: no-store`.
|
|
72
|
+
|
|
66
73
|
## MCP Endpoint
|
|
67
74
|
|
|
68
75
|
The same local server also exposes a JSON-RPC MCP endpoint:
|
package/lib/bridge-controller.js
CHANGED
package/lib/poi-http-bridge.js
CHANGED
|
@@ -2,6 +2,8 @@ const fs = require('fs')
|
|
|
2
2
|
const http = require('http')
|
|
3
3
|
const os = require('os')
|
|
4
4
|
const path = require('path')
|
|
5
|
+
const packageJson = require('../package.json')
|
|
6
|
+
const { createPoiScreenshotProvider } = require('./poi-screenshot')
|
|
5
7
|
|
|
6
8
|
const DEFAULT_PORT = 17777
|
|
7
9
|
const DEFAULT_PORT_FILE = path.join(os.homedir(), '.poi-mcp', 'port')
|
|
@@ -19,6 +21,7 @@ function createPoiDataBridge(options = {}) {
|
|
|
19
21
|
const portFile = options.portFile || DEFAULT_PORT_FILE
|
|
20
22
|
const plannerFile = options.plannerFile || DEFAULT_PLANNER_FILE
|
|
21
23
|
const logger = options.logger || console
|
|
24
|
+
let captureScreenshot = options.captureScreenshot || null
|
|
22
25
|
|
|
23
26
|
let server = null
|
|
24
27
|
let actualPort = 0
|
|
@@ -31,11 +34,17 @@ function createPoiDataBridge(options = {}) {
|
|
|
31
34
|
return store
|
|
32
35
|
}
|
|
33
36
|
|
|
34
|
-
function sendJson(res, statusCode, data) {
|
|
35
|
-
|
|
36
|
-
'Access-Control-Allow-Origin': '*',
|
|
37
|
+
function sendJson(res, statusCode, data, options = {}) {
|
|
38
|
+
const headers = {
|
|
37
39
|
'Content-Type': 'application/json',
|
|
38
|
-
}
|
|
40
|
+
}
|
|
41
|
+
if (options.allowCors !== false) {
|
|
42
|
+
headers['Access-Control-Allow-Origin'] = '*'
|
|
43
|
+
}
|
|
44
|
+
if (options.noStore) {
|
|
45
|
+
headers['Cache-Control'] = 'no-store'
|
|
46
|
+
}
|
|
47
|
+
res.writeHead(statusCode, headers)
|
|
39
48
|
res.end(JSON.stringify(data))
|
|
40
49
|
}
|
|
41
50
|
|
|
@@ -66,7 +75,7 @@ function createPoiDataBridge(options = {}) {
|
|
|
66
75
|
})
|
|
67
76
|
}
|
|
68
77
|
|
|
69
|
-
function handleRequest(req, res) {
|
|
78
|
+
async function handleRequest(req, res) {
|
|
70
79
|
try {
|
|
71
80
|
if (req.url === '/shutdown') {
|
|
72
81
|
sendJson(res, 200, { status: 'shutting down' })
|
|
@@ -86,6 +95,37 @@ function createPoiDataBridge(options = {}) {
|
|
|
86
95
|
return
|
|
87
96
|
}
|
|
88
97
|
|
|
98
|
+
if (endpoint === '/screenshot') {
|
|
99
|
+
if (req.method !== 'GET') {
|
|
100
|
+
sendJson(
|
|
101
|
+
res,
|
|
102
|
+
405,
|
|
103
|
+
{ error: 'Screenshot endpoint only accepts GET requests.' },
|
|
104
|
+
{ allowCors: false, noStore: true },
|
|
105
|
+
)
|
|
106
|
+
return
|
|
107
|
+
}
|
|
108
|
+
try {
|
|
109
|
+
if (!captureScreenshot) {
|
|
110
|
+
captureScreenshot = createPoiScreenshotProvider()
|
|
111
|
+
}
|
|
112
|
+
sendJson(
|
|
113
|
+
res,
|
|
114
|
+
200,
|
|
115
|
+
await captureScreenshot(),
|
|
116
|
+
{ allowCors: false, noStore: true },
|
|
117
|
+
)
|
|
118
|
+
} catch (error) {
|
|
119
|
+
sendJson(
|
|
120
|
+
res,
|
|
121
|
+
503,
|
|
122
|
+
{ error: error.message },
|
|
123
|
+
{ allowCors: false, noStore: true },
|
|
124
|
+
)
|
|
125
|
+
}
|
|
126
|
+
return
|
|
127
|
+
}
|
|
128
|
+
|
|
89
129
|
const store = readStore()
|
|
90
130
|
const info = store.info
|
|
91
131
|
|
|
@@ -228,7 +268,7 @@ function handleMcpMessage(message, readStore, plannerFile) {
|
|
|
228
268
|
resources: { subscribe: false },
|
|
229
269
|
tools: {},
|
|
230
270
|
},
|
|
231
|
-
serverInfo: { name: 'poi-plugin-mcp', version:
|
|
271
|
+
serverInfo: { name: 'poi-plugin-mcp', version: packageJson.version },
|
|
232
272
|
})
|
|
233
273
|
|
|
234
274
|
case 'notifications/initialized':
|
|
@@ -333,8 +373,16 @@ const MCP_TOOLS = [
|
|
|
333
373
|
},
|
|
334
374
|
{
|
|
335
375
|
name: 'get_all',
|
|
336
|
-
description: 'Get account basics, fleets, ships, equipment, resources, quests, airbase, and names.',
|
|
337
|
-
inputSchema: {
|
|
376
|
+
description: 'Get account basics, fleets, ships, equipment, resources, quests, airbase, and names. Optionally include master, event, and planner data.',
|
|
377
|
+
inputSchema: {
|
|
378
|
+
type: 'object',
|
|
379
|
+
properties: {
|
|
380
|
+
include: {
|
|
381
|
+
type: 'array',
|
|
382
|
+
items: { type: 'string', enum: ['master', 'event', 'planner'] },
|
|
383
|
+
},
|
|
384
|
+
},
|
|
385
|
+
},
|
|
338
386
|
},
|
|
339
387
|
]
|
|
340
388
|
|
|
@@ -349,7 +397,7 @@ function callMcpTool(toolName, args, readStore, plannerFile) {
|
|
|
349
397
|
case 'get_resources':
|
|
350
398
|
return { value: readBridgeData('/resources', readStore, plannerFile) }
|
|
351
399
|
case 'get_all':
|
|
352
|
-
return { value:
|
|
400
|
+
return { value: buildAllPayload(args || {}, readStore, plannerFile) }
|
|
353
401
|
default:
|
|
354
402
|
return { error: `Unknown tool: ${toolName}` }
|
|
355
403
|
}
|
|
@@ -446,28 +494,69 @@ function buildFleetStatus(args, readStore) {
|
|
|
446
494
|
|
|
447
495
|
function searchShips(args, readStore) {
|
|
448
496
|
const store = readStore()
|
|
497
|
+
const master = extractMasterData(store)
|
|
449
498
|
const ships = Object.values((store.info && store.info.ships) || {}).filter((ship) => {
|
|
450
499
|
if (!ship) return false
|
|
451
500
|
if (args.minLevel != null && ship.api_lv < Number(args.minLevel)) return false
|
|
452
501
|
if (args.maxLevel != null && ship.api_lv > Number(args.maxLevel)) return false
|
|
453
502
|
if (args.minMorale != null && ship.api_cond < Number(args.minMorale)) return false
|
|
454
503
|
return true
|
|
455
|
-
})
|
|
504
|
+
}).map((ship) => enrichShip(ship, master))
|
|
456
505
|
|
|
457
506
|
return { total: ships.length, ships }
|
|
458
507
|
}
|
|
459
508
|
|
|
460
509
|
function searchEquipment(args, readStore) {
|
|
461
510
|
const store = readStore()
|
|
511
|
+
const master = extractMasterData(store)
|
|
462
512
|
const equipment = Object.values((store.info && store.info.equips) || {}).filter((equip) => {
|
|
463
513
|
if (!equip) return false
|
|
464
514
|
if (args.minLevel != null && (equip.api_level || 0) < Number(args.minLevel)) return false
|
|
465
515
|
return true
|
|
466
|
-
})
|
|
516
|
+
}).map((equip) => enrichEquipment(equip, master))
|
|
467
517
|
|
|
468
518
|
return { total: equipment.length, equipment }
|
|
469
519
|
}
|
|
470
520
|
|
|
521
|
+
function buildAllPayload(args, readStore, plannerFile) {
|
|
522
|
+
const payload = readBridgeData('/all', readStore, plannerFile)
|
|
523
|
+
const include = Array.isArray(args.include) ? new Set(args.include) : new Set()
|
|
524
|
+
|
|
525
|
+
if (include.has('master')) payload.master = readBridgeData('/master', readStore, plannerFile)
|
|
526
|
+
if (include.has('event')) payload.event = readBridgeData('/event', readStore, plannerFile)
|
|
527
|
+
if (include.has('planner')) payload.planner = readBridgeData('/planner', readStore, plannerFile)
|
|
528
|
+
|
|
529
|
+
return payload
|
|
530
|
+
}
|
|
531
|
+
|
|
532
|
+
function enrichShip(ship, master) {
|
|
533
|
+
const masterShip = master.ships && master.ships[ship.api_ship_id]
|
|
534
|
+
const shipType = masterShip && master.shipTypes && master.shipTypes[masterShip.api_stype]
|
|
535
|
+
|
|
536
|
+
return {
|
|
537
|
+
...ship,
|
|
538
|
+
instanceId: ship.api_id,
|
|
539
|
+
masterId: ship.api_ship_id,
|
|
540
|
+
name: (masterShip && masterShip.api_name) || '',
|
|
541
|
+
typeName: (shipType && shipType.api_name) || '',
|
|
542
|
+
}
|
|
543
|
+
}
|
|
544
|
+
|
|
545
|
+
function enrichEquipment(equip, master) {
|
|
546
|
+
const masterEquip = master.equipment && master.equipment[equip.api_slotitem_id]
|
|
547
|
+
const typeIds = masterEquip && Array.isArray(masterEquip.api_type) ? masterEquip.api_type : []
|
|
548
|
+
const typeId = typeIds[2] || typeIds[1] || typeIds[0]
|
|
549
|
+
const equipType = typeId && master.equipmentTypes && master.equipmentTypes[typeId]
|
|
550
|
+
|
|
551
|
+
return {
|
|
552
|
+
...equip,
|
|
553
|
+
instanceId: equip.api_id,
|
|
554
|
+
masterId: equip.api_slotitem_id,
|
|
555
|
+
name: (masterEquip && masterEquip.api_name) || '',
|
|
556
|
+
typeName: (equipType && equipType.api_name) || '',
|
|
557
|
+
}
|
|
558
|
+
}
|
|
559
|
+
|
|
471
560
|
function jsonRpcResult(id, result) {
|
|
472
561
|
return { jsonrpc: JSONRPC_VERSION, id, result }
|
|
473
562
|
}
|
|
@@ -547,6 +636,8 @@ function extractEventData(store) {
|
|
|
547
636
|
const tag = tags[area - 1] || emptyTag(area)
|
|
548
637
|
|
|
549
638
|
ships[ship.api_id] = {
|
|
639
|
+
instanceId: ship.api_id,
|
|
640
|
+
masterId: ship.api_ship_id,
|
|
550
641
|
shipId: ship.api_id,
|
|
551
642
|
modelId: ship.api_ship_id,
|
|
552
643
|
area,
|
|
@@ -0,0 +1,104 @@
|
|
|
1
|
+
const DEFAULT_MAX_BASE64_LENGTH = 16 * 1024 * 1024
|
|
2
|
+
|
|
3
|
+
function createPoiScreenshotProvider(options = {}) {
|
|
4
|
+
const getStore = options.getStore || defaultGetStore
|
|
5
|
+
const ipcRenderer = options.ipcRenderer || require('electron').ipcRenderer
|
|
6
|
+
const devicePixelRatio = options.devicePixelRatio == null
|
|
7
|
+
? defaultDevicePixelRatio()
|
|
8
|
+
: options.devicePixelRatio
|
|
9
|
+
const now = options.now || (() => new Date())
|
|
10
|
+
const maxBase64Length = options.maxBase64Length == null
|
|
11
|
+
? DEFAULT_MAX_BASE64_LENGTH
|
|
12
|
+
: options.maxBase64Length
|
|
13
|
+
|
|
14
|
+
if (!Number.isFinite(devicePixelRatio) || devicePixelRatio <= 0) {
|
|
15
|
+
throw new Error('devicePixelRatio must be a positive finite number')
|
|
16
|
+
}
|
|
17
|
+
if (!Number.isInteger(maxBase64Length) || maxBase64Length <= 0) {
|
|
18
|
+
throw new Error('maxBase64Length must be a positive integer')
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
return async function capturePoiScreenshot() {
|
|
22
|
+
const layout = getStore('layout.webview')
|
|
23
|
+
if (
|
|
24
|
+
!layout ||
|
|
25
|
+
!layout.ref ||
|
|
26
|
+
typeof layout.ref.getWebContentsId !== 'function'
|
|
27
|
+
) {
|
|
28
|
+
throw new Error('Poi game WebView is not ready')
|
|
29
|
+
}
|
|
30
|
+
if (
|
|
31
|
+
!Number.isInteger(layout.width) ||
|
|
32
|
+
layout.width <= 0 ||
|
|
33
|
+
!Number.isInteger(layout.height) ||
|
|
34
|
+
layout.height <= 0
|
|
35
|
+
) {
|
|
36
|
+
throw new Error('Poi game WebView dimensions must be positive integers')
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
const webContentsId = layout.ref.getWebContentsId()
|
|
40
|
+
if (!Number.isInteger(webContentsId) || webContentsId <= 0) {
|
|
41
|
+
throw new Error('Poi game WebContents id is invalid')
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
const rect = {
|
|
45
|
+
x: 0,
|
|
46
|
+
y: 0,
|
|
47
|
+
width: Math.floor(layout.width * devicePixelRatio),
|
|
48
|
+
height: Math.floor(layout.height * devicePixelRatio),
|
|
49
|
+
}
|
|
50
|
+
const actualSize = {
|
|
51
|
+
width: layout.width,
|
|
52
|
+
height: layout.height,
|
|
53
|
+
}
|
|
54
|
+
const dataUrl = await ipcRenderer.invoke(
|
|
55
|
+
'screenshot::get',
|
|
56
|
+
webContentsId,
|
|
57
|
+
rect,
|
|
58
|
+
actualSize,
|
|
59
|
+
)
|
|
60
|
+
const prefix = 'data:image/png;base64,'
|
|
61
|
+
if (typeof dataUrl !== 'string' || !dataUrl.startsWith(prefix)) {
|
|
62
|
+
throw new Error('Poi screenshot did not return a PNG data URL')
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
const dataBase64 = dataUrl.slice(prefix.length)
|
|
66
|
+
if (
|
|
67
|
+
dataBase64.length === 0 ||
|
|
68
|
+
!/^[A-Za-z0-9+/]+={0,2}$/.test(dataBase64)
|
|
69
|
+
) {
|
|
70
|
+
throw new Error('Poi screenshot returned invalid base64 data')
|
|
71
|
+
}
|
|
72
|
+
if (dataBase64.length > maxBase64Length) {
|
|
73
|
+
throw new Error(`Poi screenshot exceeds ${maxBase64Length} base64 characters`)
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
return {
|
|
77
|
+
capturedAt: now().toISOString(),
|
|
78
|
+
mimeType: 'image/png',
|
|
79
|
+
dataBase64,
|
|
80
|
+
}
|
|
81
|
+
}
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
function defaultGetStore(path) {
|
|
85
|
+
if (typeof window !== 'undefined' && typeof window.getStore === 'function') {
|
|
86
|
+
return window.getStore(path)
|
|
87
|
+
}
|
|
88
|
+
return null
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
function defaultDevicePixelRatio() {
|
|
92
|
+
if (
|
|
93
|
+
typeof window !== 'undefined' &&
|
|
94
|
+
Number.isFinite(window.devicePixelRatio) &&
|
|
95
|
+
window.devicePixelRatio > 0
|
|
96
|
+
) {
|
|
97
|
+
return window.devicePixelRatio
|
|
98
|
+
}
|
|
99
|
+
return 1
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
module.exports = {
|
|
103
|
+
createPoiScreenshotProvider,
|
|
104
|
+
}
|
package/mcp-server.js
CHANGED
|
@@ -57,6 +57,7 @@ const os = require('os')
|
|
|
57
57
|
const path = require('path')
|
|
58
58
|
const fs = require('fs')
|
|
59
59
|
const http = require('http')
|
|
60
|
+
const packageJson = require('./package.json')
|
|
60
61
|
|
|
61
62
|
const PORT_FILE = path.join(os.homedir(), '.poi-mcp', 'port')
|
|
62
63
|
|
|
@@ -139,6 +140,53 @@ function getInjectScript() {
|
|
|
139
140
|
].join('\n')
|
|
140
141
|
}
|
|
141
142
|
|
|
143
|
+
async function fetchMasterData() {
|
|
144
|
+
try {
|
|
145
|
+
return await fetchFromPoi('/master')
|
|
146
|
+
} catch (_) {
|
|
147
|
+
return { ships: {}, equipment: {}, shipTypes: {}, equipmentTypes: {} }
|
|
148
|
+
}
|
|
149
|
+
}
|
|
150
|
+
|
|
151
|
+
function enrichShip(ship, master) {
|
|
152
|
+
const masterShip = master.ships && master.ships[ship.api_ship_id]
|
|
153
|
+
const shipType = masterShip && master.shipTypes && master.shipTypes[masterShip.api_stype]
|
|
154
|
+
|
|
155
|
+
return {
|
|
156
|
+
...ship,
|
|
157
|
+
instanceId: ship.api_id,
|
|
158
|
+
masterId: ship.api_ship_id,
|
|
159
|
+
name: (masterShip && masterShip.api_name) || '',
|
|
160
|
+
typeName: (shipType && shipType.api_name) || '',
|
|
161
|
+
}
|
|
162
|
+
}
|
|
163
|
+
|
|
164
|
+
function enrichEquipment(equip, master) {
|
|
165
|
+
const masterEquip = master.equipment && master.equipment[equip.api_slotitem_id]
|
|
166
|
+
const typeIds = masterEquip && Array.isArray(masterEquip.api_type) ? masterEquip.api_type : []
|
|
167
|
+
const typeId = typeIds[2] || typeIds[1] || typeIds[0]
|
|
168
|
+
const equipType = typeId && master.equipmentTypes && master.equipmentTypes[typeId]
|
|
169
|
+
|
|
170
|
+
return {
|
|
171
|
+
...equip,
|
|
172
|
+
instanceId: equip.api_id,
|
|
173
|
+
masterId: equip.api_slotitem_id,
|
|
174
|
+
name: (masterEquip && masterEquip.api_name) || '',
|
|
175
|
+
typeName: (equipType && equipType.api_name) || '',
|
|
176
|
+
}
|
|
177
|
+
}
|
|
178
|
+
|
|
179
|
+
async function fetchAllData(args = {}) {
|
|
180
|
+
const payload = await fetchFromPoi('/all')
|
|
181
|
+
const include = Array.isArray(args.include) ? new Set(args.include) : new Set()
|
|
182
|
+
|
|
183
|
+
if (include.has('master')) payload.master = await fetchFromPoi('/master')
|
|
184
|
+
if (include.has('event')) payload.event = await fetchFromPoi('/event')
|
|
185
|
+
if (include.has('planner')) payload.planner = await fetchFromPoi('/planner')
|
|
186
|
+
|
|
187
|
+
return payload
|
|
188
|
+
}
|
|
189
|
+
|
|
142
190
|
// ─── MCP Protocol ────────────────────────────────────────────────────────────
|
|
143
191
|
|
|
144
192
|
// Minimum viable MCP stdio server — no external dependencies
|
|
@@ -161,7 +209,7 @@ function sendLog(text) {
|
|
|
161
209
|
// ─── Main ────────────────────────────────────────────────────────────────────
|
|
162
210
|
|
|
163
211
|
async function main() {
|
|
164
|
-
sendLog(
|
|
212
|
+
sendLog(`POI MCP Server v${packageJson.version}`)
|
|
165
213
|
sendLog('Checking POI data API...')
|
|
166
214
|
|
|
167
215
|
const port = getPoiPort()
|
|
@@ -226,23 +274,25 @@ async function main() {
|
|
|
226
274
|
|
|
227
275
|
search_ships: async (args) => {
|
|
228
276
|
const ships = await fetchFromPoi('/ships')
|
|
277
|
+
const master = await fetchMasterData()
|
|
229
278
|
const results = Object.values(ships).filter(s => {
|
|
230
279
|
if (!s) return false
|
|
231
280
|
if (args.minLevel != null && s.api_lv < args.minLevel) return false
|
|
232
281
|
if (args.maxLevel != null && s.api_lv > args.maxLevel) return false
|
|
233
282
|
if (args.minMorale != null && s.api_cond < args.minMorale) return false
|
|
234
283
|
return true
|
|
235
|
-
})
|
|
284
|
+
}).map(s => enrichShip(s, master))
|
|
236
285
|
return { total: results.length, ships: results }
|
|
237
286
|
},
|
|
238
287
|
|
|
239
288
|
search_equipment: async (args) => {
|
|
240
289
|
const equips = await fetchFromPoi('/equipment')
|
|
290
|
+
const master = await fetchMasterData()
|
|
241
291
|
const results = Object.values(equips).filter(e => {
|
|
242
292
|
if (!e) return false
|
|
243
293
|
if (args.minLevel != null && (e.api_level || 0) < args.minLevel) return false
|
|
244
294
|
return true
|
|
245
|
-
})
|
|
295
|
+
}).map(e => enrichEquipment(e, master))
|
|
246
296
|
return { total: results.length, equipment: results }
|
|
247
297
|
},
|
|
248
298
|
|
|
@@ -250,14 +300,15 @@ async function main() {
|
|
|
250
300
|
return await fetchFromPoi('/resources')
|
|
251
301
|
},
|
|
252
302
|
|
|
253
|
-
get_all: async () => {
|
|
254
|
-
return await
|
|
303
|
+
get_all: async (args) => {
|
|
304
|
+
return await fetchAllData(args)
|
|
255
305
|
}
|
|
256
306
|
}
|
|
257
307
|
|
|
258
308
|
const resourceUris = [
|
|
259
309
|
'poi://fleets', 'poi://ships', 'poi://equipment',
|
|
260
|
-
'poi://resources', 'poi://quests', 'poi://airbase', 'poi://basic',
|
|
310
|
+
'poi://resources', 'poi://quests', 'poi://airbase', 'poi://basic',
|
|
311
|
+
'poi://names', 'poi://master', 'poi://event', 'poi://planner', 'poi://all'
|
|
261
312
|
]
|
|
262
313
|
|
|
263
314
|
// ── JSON-RPC over stdio ──────────────────────────────────────────────
|
|
@@ -282,7 +333,7 @@ async function main() {
|
|
|
282
333
|
resources: { subscribe: false },
|
|
283
334
|
tools: {}
|
|
284
335
|
},
|
|
285
|
-
serverInfo: { name: 'poi-mcp', version:
|
|
336
|
+
serverInfo: { name: 'poi-mcp', version: packageJson.version }
|
|
286
337
|
})
|
|
287
338
|
break
|
|
288
339
|
|
|
@@ -357,8 +408,16 @@ async function main() {
|
|
|
357
408
|
},
|
|
358
409
|
{
|
|
359
410
|
name: 'get_all',
|
|
360
|
-
description: '
|
|
361
|
-
inputSchema: {
|
|
411
|
+
description: '获取所有数据(舰队/舰娘/装备/资源/任务/陆航),可选包含 master/event/planner',
|
|
412
|
+
inputSchema: {
|
|
413
|
+
type: 'object',
|
|
414
|
+
properties: {
|
|
415
|
+
include: {
|
|
416
|
+
type: 'array',
|
|
417
|
+
items: { type: 'string', enum: ['master', 'event', 'planner'] }
|
|
418
|
+
}
|
|
419
|
+
}
|
|
420
|
+
}
|
|
362
421
|
}
|
|
363
422
|
]
|
|
364
423
|
})
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "poi-plugin-mcp",
|
|
3
|
-
"version": "0.2.
|
|
4
|
-
"description": "Poi data bridge for local KanColle
|
|
3
|
+
"version": "0.2.3",
|
|
4
|
+
"description": "Poi read-only data and game WebView capture bridge for local KanColle tools.",
|
|
5
5
|
"main": "index.js",
|
|
6
6
|
"keywords": [
|
|
7
7
|
"poi-plugin",
|
|
@@ -24,7 +24,7 @@
|
|
|
24
24
|
"poiPlugin": {
|
|
25
25
|
"title": "MCP 数据桥",
|
|
26
26
|
"id": "mcp_data_bridge",
|
|
27
|
-
"description": "Expose Poi
|
|
27
|
+
"description": "Expose Poi state and in-memory game WebView captures on a local read-only bridge.",
|
|
28
28
|
"icon": "fa/database",
|
|
29
29
|
"priority": 53
|
|
30
30
|
},
|