poi-plugin-mcp 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/README.md +76 -0
- package/index.js +25 -0
- package/lib/bridge-controller.js +118 -0
- package/lib/poi-http-bridge.js +669 -0
- package/lib/settings-view.js +184 -0
- package/lib/settings.js +51 -0
- package/mcp-server.js +397 -0
- package/package.json +32 -0
package/README.md
ADDED
|
@@ -0,0 +1,76 @@
|
|
|
1
|
+
# poi-plugin-mcp
|
|
2
|
+
|
|
3
|
+
Poi plugin that starts a local HTTP bridge inside Poi so CLI/MCP agents can read current KanColle data.
|
|
4
|
+
|
|
5
|
+
This package is maintained inside the repository root. Do not install it manually from this folder unless you know what you are doing; prefer the root setup flow.
|
|
6
|
+
|
|
7
|
+
## Install From Repo Root
|
|
8
|
+
|
|
9
|
+
```powershell
|
|
10
|
+
npm install
|
|
11
|
+
npm run install:poi
|
|
12
|
+
```
|
|
13
|
+
|
|
14
|
+
Then restart Poi and enable `MCP 数据桥` / `KanColle Data Bridge` if needed.
|
|
15
|
+
|
|
16
|
+
The installer creates:
|
|
17
|
+
|
|
18
|
+
```text
|
|
19
|
+
%APPDATA%\poi\plugins\node_modules\poi-plugin-mcp -> <repo>\packages\poi-plugin-mcp
|
|
20
|
+
```
|
|
21
|
+
|
|
22
|
+
## Settings
|
|
23
|
+
|
|
24
|
+
The Poi plugin settings panel supports:
|
|
25
|
+
|
|
26
|
+
- changing the HTTP port, saved in `~/.poi-mcp/settings.json`
|
|
27
|
+
- manually starting and stopping the local bridge
|
|
28
|
+
|
|
29
|
+
The default port is `17777`.
|
|
30
|
+
|
|
31
|
+
## HTTP Endpoints
|
|
32
|
+
|
|
33
|
+
| Endpoint | Data |
|
|
34
|
+
|---|---|
|
|
35
|
+
| `/health` | Bridge status |
|
|
36
|
+
| `/basic` | Admiral profile |
|
|
37
|
+
| `/fleets` | Raw Poi fleet data |
|
|
38
|
+
| `/ships` | Raw owned ship instance data |
|
|
39
|
+
| `/equipment` | Raw owned equipment instance data |
|
|
40
|
+
| `/resources` | Resource array |
|
|
41
|
+
| `/quests` | Active quests and quest records |
|
|
42
|
+
| `/airbase` | Land base air squadron data |
|
|
43
|
+
| `/names` | Ship, equipment, and mission name maps |
|
|
44
|
+
| `/master` | Master ship, equipment, ship type, equipment type, and mission data |
|
|
45
|
+
| `/event` | Event ship tag definitions plus owned ships' current sally area |
|
|
46
|
+
| `/planner` | Ship Info deck planner areas and ship assignments |
|
|
47
|
+
| `/all` | Combined basic runtime data |
|
|
48
|
+
|
|
49
|
+
## MCP Endpoint
|
|
50
|
+
|
|
51
|
+
The same local server also exposes a JSON-RPC MCP endpoint:
|
|
52
|
+
|
|
53
|
+
```text
|
|
54
|
+
POST http://127.0.0.1:17777/mcp
|
|
55
|
+
```
|
|
56
|
+
|
|
57
|
+
It supports `initialize`, `ping`, `resources/list`, `resources/read`,
|
|
58
|
+
`tools/list`, and `tools/call`. Resource URIs mirror the HTTP endpoints,
|
|
59
|
+
including `poi://ships`, `poi://equipment`, `poi://resources`, `poi://master`,
|
|
60
|
+
`poi://event`, and `poi://planner`.
|
|
61
|
+
|
|
62
|
+
Available tools:
|
|
63
|
+
|
|
64
|
+
- `get_fleet_status`
|
|
65
|
+
- `search_ships`
|
|
66
|
+
- `search_equipment`
|
|
67
|
+
- `get_resources`
|
|
68
|
+
- `get_all`
|
|
69
|
+
|
|
70
|
+
## Verification
|
|
71
|
+
|
|
72
|
+
From the repo root:
|
|
73
|
+
|
|
74
|
+
```powershell
|
|
75
|
+
npm run test:plugin
|
|
76
|
+
```
|
package/index.js
ADDED
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
const { createBridgeController } = require('./lib/bridge-controller')
|
|
2
|
+
const { createSettingsClass } = require('./lib/settings-view')
|
|
3
|
+
|
|
4
|
+
const controller = createBridgeController()
|
|
5
|
+
const settingsClass = createSettingsClass(controller)
|
|
6
|
+
|
|
7
|
+
function pluginDidLoad() {
|
|
8
|
+
controller.load().catch((error) => {
|
|
9
|
+
console.error('[poi-plugin-mcp] Failed to start:', error.message)
|
|
10
|
+
})
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
function pluginWillUnload() {
|
|
14
|
+
controller.unload().catch((error) => {
|
|
15
|
+
console.error('[poi-plugin-mcp] Failed to stop:', error.message)
|
|
16
|
+
})
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
module.exports = {
|
|
20
|
+
pluginDidLoad,
|
|
21
|
+
pluginWillUnload,
|
|
22
|
+
settingClass: settingsClass,
|
|
23
|
+
settingsClass,
|
|
24
|
+
_controller: controller,
|
|
25
|
+
}
|
|
@@ -0,0 +1,118 @@
|
|
|
1
|
+
const { createPoiDataBridge } = require('./poi-http-bridge')
|
|
2
|
+
const {
|
|
3
|
+
DEFAULT_SETTINGS_FILE,
|
|
4
|
+
loadSettings,
|
|
5
|
+
normalizeSettings,
|
|
6
|
+
saveSettings,
|
|
7
|
+
} = require('./settings')
|
|
8
|
+
|
|
9
|
+
function createBridgeController(options = {}) {
|
|
10
|
+
const settingsPath = options.settingsPath || DEFAULT_SETTINGS_FILE
|
|
11
|
+
const logger = options.logger || console
|
|
12
|
+
const createBridge = options.createBridge || createPoiDataBridge
|
|
13
|
+
|
|
14
|
+
let settings = loadSettings(settingsPath)
|
|
15
|
+
let bridge = null
|
|
16
|
+
let pending = Promise.resolve()
|
|
17
|
+
|
|
18
|
+
function enqueue(action) {
|
|
19
|
+
pending = pending.then(action, action)
|
|
20
|
+
return pending
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
function createCurrentBridge() {
|
|
24
|
+
return createBridge({
|
|
25
|
+
getStore: options.getStore,
|
|
26
|
+
port: settings.port,
|
|
27
|
+
portFile: options.portFile,
|
|
28
|
+
logger,
|
|
29
|
+
})
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
async function ensureStarted() {
|
|
33
|
+
if (!bridge) {
|
|
34
|
+
bridge = createCurrentBridge()
|
|
35
|
+
}
|
|
36
|
+
await bridge.start()
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
async function stopCurrentBridge() {
|
|
40
|
+
if (!bridge) return
|
|
41
|
+
|
|
42
|
+
const runningBridge = bridge
|
|
43
|
+
bridge = null
|
|
44
|
+
await runningBridge.stop()
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
function persist(nextSettings) {
|
|
48
|
+
settings = saveSettings(normalizeSettings(nextSettings), settingsPath)
|
|
49
|
+
return settings
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
return {
|
|
53
|
+
load() {
|
|
54
|
+
return enqueue(async () => {
|
|
55
|
+
settings = loadSettings(settingsPath)
|
|
56
|
+
if (settings.enabled) await ensureStarted()
|
|
57
|
+
})
|
|
58
|
+
},
|
|
59
|
+
|
|
60
|
+
unload() {
|
|
61
|
+
return enqueue(async () => {
|
|
62
|
+
await stopCurrentBridge()
|
|
63
|
+
})
|
|
64
|
+
},
|
|
65
|
+
|
|
66
|
+
startBridge() {
|
|
67
|
+
return enqueue(async () => {
|
|
68
|
+
persist({ ...settings, enabled: true })
|
|
69
|
+
await ensureStarted()
|
|
70
|
+
})
|
|
71
|
+
},
|
|
72
|
+
|
|
73
|
+
stopBridge() {
|
|
74
|
+
return enqueue(async () => {
|
|
75
|
+
persist({ ...settings, enabled: false })
|
|
76
|
+
await stopCurrentBridge()
|
|
77
|
+
})
|
|
78
|
+
},
|
|
79
|
+
|
|
80
|
+
applySettings(nextSettings) {
|
|
81
|
+
return enqueue(async () => {
|
|
82
|
+
const normalized = normalizeSettings({ ...settings, ...nextSettings })
|
|
83
|
+
const portChanged = normalized.port !== settings.port
|
|
84
|
+
const enabledChanged = normalized.enabled !== settings.enabled
|
|
85
|
+
|
|
86
|
+
persist(normalized)
|
|
87
|
+
|
|
88
|
+
if (!settings.enabled) {
|
|
89
|
+
await stopCurrentBridge()
|
|
90
|
+
return
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
if (portChanged || enabledChanged || !bridge) {
|
|
94
|
+
await stopCurrentBridge()
|
|
95
|
+
await ensureStarted()
|
|
96
|
+
}
|
|
97
|
+
})
|
|
98
|
+
},
|
|
99
|
+
|
|
100
|
+
getSettings() {
|
|
101
|
+
return { ...settings }
|
|
102
|
+
},
|
|
103
|
+
|
|
104
|
+
getStatus() {
|
|
105
|
+
const actualPort = bridge ? bridge.getPort() : 0
|
|
106
|
+
return {
|
|
107
|
+
enabled: settings.enabled,
|
|
108
|
+
running: actualPort > 0,
|
|
109
|
+
port: settings.port,
|
|
110
|
+
actualPort,
|
|
111
|
+
}
|
|
112
|
+
},
|
|
113
|
+
}
|
|
114
|
+
}
|
|
115
|
+
|
|
116
|
+
module.exports = {
|
|
117
|
+
createBridgeController,
|
|
118
|
+
}
|