appium-mcp 1.76.0 → 1.77.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/CHANGELOG.md +6 -0
- package/README.md +146 -70
- package/dist/command.js +1 -1
- package/dist/command.js.map +1 -1
- package/dist/core.d.ts +12 -0
- package/dist/core.d.ts.map +1 -0
- package/dist/core.js +10 -0
- package/dist/core.js.map +1 -0
- package/dist/create-server.d.ts +50 -0
- package/dist/create-server.d.ts.map +1 -0
- package/dist/create-server.js +180 -0
- package/dist/create-server.js.map +1 -0
- package/dist/plugin.d.ts +176 -0
- package/dist/plugin.d.ts.map +1 -0
- package/dist/plugin.js +239 -0
- package/dist/plugin.js.map +1 -0
- package/dist/server.d.ts +1 -2
- package/dist/server.d.ts.map +1 -1
- package/dist/server.js +2 -67
- package/dist/server.js.map +1 -1
- package/dist/session-store.d.ts +8 -8
- package/dist/session-store.d.ts.map +1 -1
- package/dist/session-store.js +3 -2
- package/dist/session-store.js.map +1 -1
- package/dist/tests/__mocks__/@appium/support.d.ts +54 -61
- package/dist/tests/__mocks__/@appium/support.d.ts.map +1 -1
- package/dist/tests/__mocks__/@appium/support.js +42 -70
- package/dist/tests/__mocks__/@appium/support.js.map +1 -1
- package/dist/tests/create-server.test.d.ts +2 -0
- package/dist/tests/create-server.test.d.ts.map +1 -0
- package/dist/tests/create-server.test.js +253 -0
- package/dist/tests/create-server.test.js.map +1 -0
- package/dist/tests/plugin.test.d.ts +2 -0
- package/dist/tests/plugin.test.d.ts.map +1 -0
- package/dist/tests/plugin.test.js +337 -0
- package/dist/tests/plugin.test.js.map +1 -0
- package/dist/tests/tools/llm-wording.test.js +4 -1
- package/dist/tests/tools/llm-wording.test.js.map +1 -1
- package/dist/tests/vision-finder.test.d.ts +1 -1
- package/dist/tests/vision-finder.test.js +24 -6
- package/dist/tests/vision-finder.test.js.map +1 -1
- package/package.json +12 -1
- package/server.json +2 -2
- package/src/command.ts +1 -1
- package/src/core.ts +17 -0
- package/src/create-server.ts +252 -0
- package/src/plugin.ts +368 -0
- package/src/resources/submodules.zip +0 -0
- package/src/server.ts +2 -87
- package/src/session-store.ts +12 -11
|
@@ -0,0 +1,180 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* createAppiumMcpServer — public factory for custom Appium MCP servers.
|
|
3
|
+
*
|
|
4
|
+
* Usage:
|
|
5
|
+
* ```ts
|
|
6
|
+
* import { createAppiumMcpServer } from 'appium-mcp/core';
|
|
7
|
+
*
|
|
8
|
+
* const server = createAppiumMcpServer({
|
|
9
|
+
* plugins: [new CheckoutPlugin(), new LoginGuardPlugin()],
|
|
10
|
+
* });
|
|
11
|
+
*
|
|
12
|
+
* await server.start({ transportType: 'stdio' });
|
|
13
|
+
* ```
|
|
14
|
+
*/
|
|
15
|
+
import { FastMCP } from 'fastmcp';
|
|
16
|
+
import pkg from '../package.json' with { type: 'json' };
|
|
17
|
+
import registerTools from './tools/index.js';
|
|
18
|
+
import registerResources from './resources/index.js';
|
|
19
|
+
import { safeDeleteAllSessions, listSessions } from './session-store.js';
|
|
20
|
+
import log from './logger.js';
|
|
21
|
+
import { PluginManager } from './plugin.js';
|
|
22
|
+
const SERVER_VERSION = pkg.version;
|
|
23
|
+
const SERVER_INSTRUCTIONS = [
|
|
24
|
+
'Appium mobile automation through MCP. Defaults that avoid broken flows:',
|
|
25
|
+
'- Establish a driver session first: select_device and appium_session_management (action=create) for local/embedded mode, or attach to a remote session when the user supplies a server URL.',
|
|
26
|
+
'- Call only tools this server actually registers (appium_find_element, appium_gesture, appium_session_management, etc.); do not invent tool names or aliases.',
|
|
27
|
+
'- Prefer stable locators: accessibility id and id before long xpath; use xpath only when nothing else works.',
|
|
28
|
+
'- Use appium_gesture for taps and drags; when something is off-screen, use action=scroll_to_element instead of spamming appium_find_element alone.',
|
|
29
|
+
'- For local Appium install, doctor, or smoke tests, run appium_skills before guessing commands.',
|
|
30
|
+
].join('\n');
|
|
31
|
+
// ---------------------------------------------------------------------------
|
|
32
|
+
// Internal helpers
|
|
33
|
+
// ---------------------------------------------------------------------------
|
|
34
|
+
/**
|
|
35
|
+
* Factory function that creates and wires a fully-configured Appium MCP server,
|
|
36
|
+
* with optional plugin support.
|
|
37
|
+
*
|
|
38
|
+
* This is the main public entry point for building a custom Appium-based MCP
|
|
39
|
+
* server. It replicates the setup that the default `server.ts` performs, while
|
|
40
|
+
* also registering plugin tools and lifecycle hooks.
|
|
41
|
+
*
|
|
42
|
+
* @returns A configured `FastMCP` instance ready to be `start()`-ed.
|
|
43
|
+
*/
|
|
44
|
+
export function createAppiumMcpServer(options = {}) {
|
|
45
|
+
const { plugins = [], serverName = 'MCP Appium', serverVersion = SERVER_VERSION, additionalInstructions, } = options;
|
|
46
|
+
const instructions = additionalInstructions
|
|
47
|
+
? `${SERVER_INSTRUCTIONS}\n${additionalInstructions}`
|
|
48
|
+
: SERVER_INSTRUCTIONS;
|
|
49
|
+
const server = new FastMCP({
|
|
50
|
+
name: serverName,
|
|
51
|
+
version: serverVersion,
|
|
52
|
+
instructions,
|
|
53
|
+
});
|
|
54
|
+
// -------------------------------------------------------------------------
|
|
55
|
+
// 1. Install plugin hooks BEFORE registering any tools so that every built-in
|
|
56
|
+
// and plugin tool is wrapped with beforeCall / afterCall.
|
|
57
|
+
// -------------------------------------------------------------------------
|
|
58
|
+
const manager = new PluginManager(server);
|
|
59
|
+
if (plugins.length > 0) {
|
|
60
|
+
manager.register(plugins);
|
|
61
|
+
}
|
|
62
|
+
// -------------------------------------------------------------------------
|
|
63
|
+
// 2. Register plugin tools (before built-ins so plugins appear first in the
|
|
64
|
+
// tool list, but either order is fine – adjust if needed).
|
|
65
|
+
// -------------------------------------------------------------------------
|
|
66
|
+
manager.registerPluginCapabilities();
|
|
67
|
+
// -------------------------------------------------------------------------
|
|
68
|
+
// 3. Register built-in Appium MCP resources and tools.
|
|
69
|
+
// -------------------------------------------------------------------------
|
|
70
|
+
registerResources(server);
|
|
71
|
+
registerTools(server);
|
|
72
|
+
// -------------------------------------------------------------------------
|
|
73
|
+
// 4. Initialize plugins (after all tools are registered so plugins can look
|
|
74
|
+
// up built-in tools via the PluginContext if needed).
|
|
75
|
+
// -------------------------------------------------------------------------
|
|
76
|
+
let activeClientCount = 0;
|
|
77
|
+
let pluginInitialized = false;
|
|
78
|
+
// Track plugin initialization and destruction promises to avoid race conditions
|
|
79
|
+
// when clients connect/disconnect in quick succession.
|
|
80
|
+
let pluginInitializePromise = null;
|
|
81
|
+
let pluginDestroyPromise = null;
|
|
82
|
+
/**
|
|
83
|
+
* To avoid unnecessary plugin initialization and destruction when clients connect and disconnect,
|
|
84
|
+
* we lazily initialize plugins on the first client connection, and only destroy plugins
|
|
85
|
+
* after the last client disconnects.
|
|
86
|
+
* @returns
|
|
87
|
+
*/
|
|
88
|
+
const ensurePluginsInitialized = async () => {
|
|
89
|
+
if (plugins.length === 0) {
|
|
90
|
+
return;
|
|
91
|
+
}
|
|
92
|
+
if (pluginDestroyPromise != null) {
|
|
93
|
+
await pluginDestroyPromise;
|
|
94
|
+
}
|
|
95
|
+
if (pluginInitialized) {
|
|
96
|
+
return;
|
|
97
|
+
}
|
|
98
|
+
pluginInitializePromise ??= (async () => {
|
|
99
|
+
try {
|
|
100
|
+
await manager.initialize();
|
|
101
|
+
pluginInitialized = true;
|
|
102
|
+
}
|
|
103
|
+
finally {
|
|
104
|
+
pluginInitializePromise = null;
|
|
105
|
+
}
|
|
106
|
+
})();
|
|
107
|
+
await pluginInitializePromise;
|
|
108
|
+
};
|
|
109
|
+
/**
|
|
110
|
+
* Destroys plugins only if there are no active clients and plugins have been initialized.
|
|
111
|
+
* @returns
|
|
112
|
+
*/
|
|
113
|
+
const destroyPluginsIfIdle = async () => {
|
|
114
|
+
if (plugins.length === 0) {
|
|
115
|
+
return;
|
|
116
|
+
}
|
|
117
|
+
if (pluginInitializePromise != null) {
|
|
118
|
+
await pluginInitializePromise;
|
|
119
|
+
}
|
|
120
|
+
if (activeClientCount > 0 || !pluginInitialized) {
|
|
121
|
+
return;
|
|
122
|
+
}
|
|
123
|
+
pluginDestroyPromise ??= (async () => {
|
|
124
|
+
try {
|
|
125
|
+
await manager.destroy();
|
|
126
|
+
pluginInitialized = false;
|
|
127
|
+
}
|
|
128
|
+
finally {
|
|
129
|
+
pluginDestroyPromise = null;
|
|
130
|
+
}
|
|
131
|
+
})();
|
|
132
|
+
await pluginDestroyPromise;
|
|
133
|
+
};
|
|
134
|
+
// -------------------------------------------------------------------------
|
|
135
|
+
// 5. Wire connect / disconnect lifecycle events.
|
|
136
|
+
// -------------------------------------------------------------------------
|
|
137
|
+
server.on('connect', async (event) => {
|
|
138
|
+
log.info('Client connected:', event.session);
|
|
139
|
+
activeClientCount += 1;
|
|
140
|
+
// Lazy plugin initialization on first connection.
|
|
141
|
+
await ensurePluginsInitialized();
|
|
142
|
+
});
|
|
143
|
+
server.on('disconnect', async (event) => {
|
|
144
|
+
log.info('Client disconnected:', event.session);
|
|
145
|
+
activeClientCount = Math.max(0, activeClientCount - 1);
|
|
146
|
+
if (activeClientCount > 0) {
|
|
147
|
+
return;
|
|
148
|
+
}
|
|
149
|
+
const policy = disconnectSessionPolicyFromEnv();
|
|
150
|
+
const ownedSessions = listSessions().filter((session) => session.ownership === 'owned');
|
|
151
|
+
if (ownedSessions.length > 0 && policy === 'skip') {
|
|
152
|
+
log.info(`${ownedSessions.length} owned session(s) retained after MCP disconnect ` +
|
|
153
|
+
'(APPIUM_MCP_ON_CLIENT_DISCONNECT=skip).');
|
|
154
|
+
}
|
|
155
|
+
else if (ownedSessions.length > 0) {
|
|
156
|
+
try {
|
|
157
|
+
log.info(`${ownedSessions.length} owned session(s) detected on disconnect, cleaning up...`);
|
|
158
|
+
const deletedCount = await safeDeleteAllSessions();
|
|
159
|
+
log.info(`${deletedCount} session(s) cleaned up successfully on disconnect.`);
|
|
160
|
+
}
|
|
161
|
+
catch (error) {
|
|
162
|
+
log.error('Error cleaning up session on disconnect:', error);
|
|
163
|
+
}
|
|
164
|
+
}
|
|
165
|
+
// Destroy plugins when the last MCP client disconnects.
|
|
166
|
+
await destroyPluginsIfIdle();
|
|
167
|
+
});
|
|
168
|
+
return server;
|
|
169
|
+
}
|
|
170
|
+
function disconnectSessionPolicyFromEnv() {
|
|
171
|
+
const raw = process.env.APPIUM_MCP_ON_CLIENT_DISCONNECT?.trim().toLowerCase();
|
|
172
|
+
if (raw === 'skip') {
|
|
173
|
+
return 'skip';
|
|
174
|
+
}
|
|
175
|
+
if (raw !== 'delete_all') {
|
|
176
|
+
log.warn(`APPIUM_MCP_ON_CLIENT_DISCONNECT="${raw}" is not recognized; defaulting to delete_all`);
|
|
177
|
+
}
|
|
178
|
+
return 'delete_all';
|
|
179
|
+
}
|
|
180
|
+
//# sourceMappingURL=create-server.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"create-server.js","sourceRoot":"","sources":["../src/create-server.ts"],"names":[],"mappings":"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"}
|
package/dist/plugin.d.ts
ADDED
|
@@ -0,0 +1,176 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Plugin system for Appium MCP.
|
|
3
|
+
*
|
|
4
|
+
* This module defines the `AppiumMcpPlugin` interface and related types, as well
|
|
5
|
+
* as the `PluginManager` class which handles plugin registration, lifecycle, and
|
|
6
|
+
* tool call interception.
|
|
7
|
+
*/
|
|
8
|
+
import type { ContentResult, FastMCP, FastMCPSessionAuth, Tool, ToolParameters } from 'fastmcp';
|
|
9
|
+
import { listSessions } from './session-store.js';
|
|
10
|
+
import type { DriverInstance, SessionInfo } from './session-store.js';
|
|
11
|
+
/**
|
|
12
|
+
* Context passed to plugin lifecycle methods.
|
|
13
|
+
*
|
|
14
|
+
* This is intentionally smaller than the underlying FastMCP server. Plugins
|
|
15
|
+
* should use `McpRegistry` during `register()` for MCP capabilities and
|
|
16
|
+
* `AppiumMcpCore` for Appium MCP state.
|
|
17
|
+
*/
|
|
18
|
+
export interface PluginContext {
|
|
19
|
+
readonly core: AppiumMcpCore;
|
|
20
|
+
readonly plugins: ReadonlyMap<string, AppiumMcpPlugin>;
|
|
21
|
+
}
|
|
22
|
+
/**
|
|
23
|
+
* Session helpers available to call hooks.
|
|
24
|
+
*/
|
|
25
|
+
export interface PluginSessionContext {
|
|
26
|
+
getSessionInfo(sessionId?: string): SessionInfo | null;
|
|
27
|
+
getSessionId(): string | null;
|
|
28
|
+
getDriver(sessionId?: string): DriverInstance | null;
|
|
29
|
+
listSessions(): ReturnType<typeof listSessions>;
|
|
30
|
+
}
|
|
31
|
+
/**
|
|
32
|
+
* Context passed to `beforeCall` and `afterCall` for each MCP tool execution.
|
|
33
|
+
*/
|
|
34
|
+
export interface ToolCallContext {
|
|
35
|
+
readonly toolName: string;
|
|
36
|
+
readonly args: Readonly<Record<string, unknown>>;
|
|
37
|
+
readonly session: PluginSessionContext;
|
|
38
|
+
}
|
|
39
|
+
/**
|
|
40
|
+
* Tool result shape plugins may return to short-circuit or modify a tool call.
|
|
41
|
+
*/
|
|
42
|
+
export interface ToolCallResult {
|
|
43
|
+
isError: boolean;
|
|
44
|
+
content: ContentResult['content'];
|
|
45
|
+
}
|
|
46
|
+
/**
|
|
47
|
+
* Extension point for composing app-specific behavior into Appium MCP.
|
|
48
|
+
*/
|
|
49
|
+
export interface AppiumMcpPlugin {
|
|
50
|
+
/**
|
|
51
|
+
* Unique plugin identifier within a server instance.
|
|
52
|
+
*
|
|
53
|
+
* Duplicate plugin names are skipped with a warning, so prefer stable
|
|
54
|
+
* package-style or organization-prefixed names.
|
|
55
|
+
*/
|
|
56
|
+
readonly name: string;
|
|
57
|
+
readonly version: string;
|
|
58
|
+
initialize?(ctx: PluginContext): Promise<void>;
|
|
59
|
+
register?(registry: McpRegistry, core: AppiumMcpCore): void;
|
|
60
|
+
beforeCall?(ctx: ToolCallContext): Promise<ToolCallResult | void>;
|
|
61
|
+
afterCall?(ctx: ToolCallContext, result: ToolCallResult): Promise<ToolCallResult | void>;
|
|
62
|
+
destroy?(): Promise<void>;
|
|
63
|
+
}
|
|
64
|
+
type AddToolParam = Parameters<FastMCP['addTool']>[0];
|
|
65
|
+
type AddPromptParam = Parameters<FastMCP['addPrompt']>[0];
|
|
66
|
+
type AddResourceParam = Parameters<FastMCP['addResource']>[0];
|
|
67
|
+
type AddResourceTemplateParam = Parameters<FastMCP['addResourceTemplate']>[0];
|
|
68
|
+
export declare class McpRegistry {
|
|
69
|
+
private readonly server;
|
|
70
|
+
constructor(server: FastMCP);
|
|
71
|
+
/**
|
|
72
|
+
* Register one MCP tool. Tool calls are wrapped by plugin call hooks.
|
|
73
|
+
*
|
|
74
|
+
* Delegates to FastMCP `addTool`.
|
|
75
|
+
*
|
|
76
|
+
* @see https://github.com/punkpeye/fastmcp#tools
|
|
77
|
+
*/
|
|
78
|
+
addTool<Params extends ToolParameters>(name: string, description: string, parameters: Params, execute: Tool<FastMCPSessionAuth, Params>['execute']): void;
|
|
79
|
+
/**
|
|
80
|
+
* Register multiple MCP tools.
|
|
81
|
+
*
|
|
82
|
+
* Delegates to FastMCP `addTool` for each definition.
|
|
83
|
+
*
|
|
84
|
+
* @see https://github.com/punkpeye/fastmcp#tools
|
|
85
|
+
*/
|
|
86
|
+
addTools(defs: Array<{
|
|
87
|
+
name: string;
|
|
88
|
+
description: string;
|
|
89
|
+
parameters: ToolParameters;
|
|
90
|
+
execute: AddToolParam['execute'];
|
|
91
|
+
}>): void;
|
|
92
|
+
/**
|
|
93
|
+
* Register one MCP prompt.
|
|
94
|
+
*
|
|
95
|
+
* Delegates to FastMCP `addPrompt`.
|
|
96
|
+
*
|
|
97
|
+
* @see https://github.com/punkpeye/fastmcp#prompts
|
|
98
|
+
*/
|
|
99
|
+
addPrompt(prompt: AddPromptParam): void;
|
|
100
|
+
/**
|
|
101
|
+
* Register multiple MCP prompts.
|
|
102
|
+
*
|
|
103
|
+
* Delegates to FastMCP `addPrompt` for each definition.
|
|
104
|
+
*
|
|
105
|
+
* @see https://github.com/punkpeye/fastmcp#prompts
|
|
106
|
+
*/
|
|
107
|
+
addPrompts(prompts: AddPromptParam[]): void;
|
|
108
|
+
/**
|
|
109
|
+
* Register one MCP resource.
|
|
110
|
+
*
|
|
111
|
+
* Delegates to FastMCP `addResource`.
|
|
112
|
+
*
|
|
113
|
+
* @see https://github.com/punkpeye/fastmcp#resources
|
|
114
|
+
*/
|
|
115
|
+
addResource(resource: AddResourceParam): void;
|
|
116
|
+
/**
|
|
117
|
+
* Register multiple MCP resources.
|
|
118
|
+
*
|
|
119
|
+
* Delegates to FastMCP `addResource` for each definition.
|
|
120
|
+
*
|
|
121
|
+
* @see https://github.com/punkpeye/fastmcp#resources
|
|
122
|
+
*/
|
|
123
|
+
addResources(resources: AddResourceParam[]): void;
|
|
124
|
+
/**
|
|
125
|
+
* Register one MCP resource template.
|
|
126
|
+
*
|
|
127
|
+
* Delegates to FastMCP `addResourceTemplate`.
|
|
128
|
+
*
|
|
129
|
+
* @see https://github.com/punkpeye/fastmcp#resource-templates
|
|
130
|
+
*/
|
|
131
|
+
addResourceTemplate(resourceTemplate: AddResourceTemplateParam): void;
|
|
132
|
+
/**
|
|
133
|
+
* Register multiple MCP resource templates.
|
|
134
|
+
*
|
|
135
|
+
* Delegates to FastMCP `addResourceTemplate` for each definition.
|
|
136
|
+
*
|
|
137
|
+
* @see https://github.com/punkpeye/fastmcp#resource-templates
|
|
138
|
+
*/
|
|
139
|
+
addResourceTemplates(resourceTemplates: AddResourceTemplateParam[]): void;
|
|
140
|
+
}
|
|
141
|
+
/**
|
|
142
|
+
* Safe Appium MCP primitives exposed to plugins.
|
|
143
|
+
*/
|
|
144
|
+
export declare class AppiumMcpCore {
|
|
145
|
+
/**
|
|
146
|
+
* Return the currently active Appium session id, if one exists.
|
|
147
|
+
*/
|
|
148
|
+
getSessionId(): string | null;
|
|
149
|
+
/**
|
|
150
|
+
* Return metadata for a specific session, or the active session if `sessionId` is not provided.
|
|
151
|
+
*/
|
|
152
|
+
getSessionInfo(sessionId?: string): SessionInfo | null;
|
|
153
|
+
/**
|
|
154
|
+
* Return the active driver, or a driver for a specific Appium session id.
|
|
155
|
+
*/
|
|
156
|
+
getDriver(sessionId?: string): DriverInstance | null;
|
|
157
|
+
/**
|
|
158
|
+
* Return metadata for all Appium sessions tracked by this server.
|
|
159
|
+
*/
|
|
160
|
+
listSessions(): ReturnType<typeof listSessions>;
|
|
161
|
+
}
|
|
162
|
+
export declare class PluginManager {
|
|
163
|
+
private readonly pluginMap;
|
|
164
|
+
private readonly server;
|
|
165
|
+
private readonly core;
|
|
166
|
+
private readonly capabilityPluginNames;
|
|
167
|
+
private addToolInterceptorInstalled;
|
|
168
|
+
constructor(server: FastMCP);
|
|
169
|
+
register(plugins: AppiumMcpPlugin[]): void;
|
|
170
|
+
registerPluginCapabilities(): void;
|
|
171
|
+
initialize(): Promise<void>;
|
|
172
|
+
destroy(): Promise<void>;
|
|
173
|
+
private installAddToolInterceptor;
|
|
174
|
+
}
|
|
175
|
+
export {};
|
|
176
|
+
//# sourceMappingURL=plugin.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"plugin.d.ts","sourceRoot":"","sources":["../src/plugin.ts"],"names":[],"mappings":"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"}
|
package/dist/plugin.js
ADDED
|
@@ -0,0 +1,239 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Plugin system for Appium MCP.
|
|
3
|
+
*
|
|
4
|
+
* This module defines the `AppiumMcpPlugin` interface and related types, as well
|
|
5
|
+
* as the `PluginManager` class which handles plugin registration, lifecycle, and
|
|
6
|
+
* tool call interception.
|
|
7
|
+
*/
|
|
8
|
+
import { getDriver, getSessionId, getSessionInfo, listSessions, } from './session-store.js';
|
|
9
|
+
import log from './logger.js';
|
|
10
|
+
export class McpRegistry {
|
|
11
|
+
server;
|
|
12
|
+
constructor(server) {
|
|
13
|
+
this.server = server;
|
|
14
|
+
}
|
|
15
|
+
/**
|
|
16
|
+
* Register one MCP tool. Tool calls are wrapped by plugin call hooks.
|
|
17
|
+
*
|
|
18
|
+
* Delegates to FastMCP `addTool`.
|
|
19
|
+
*
|
|
20
|
+
* @see https://github.com/punkpeye/fastmcp#tools
|
|
21
|
+
*/
|
|
22
|
+
addTool(name, description, parameters, execute) {
|
|
23
|
+
this.server.addTool({ name, description, parameters, execute });
|
|
24
|
+
}
|
|
25
|
+
/**
|
|
26
|
+
* Register multiple MCP tools.
|
|
27
|
+
*
|
|
28
|
+
* Delegates to FastMCP `addTool` for each definition.
|
|
29
|
+
*
|
|
30
|
+
* @see https://github.com/punkpeye/fastmcp#tools
|
|
31
|
+
*/
|
|
32
|
+
addTools(defs) {
|
|
33
|
+
for (const def of defs) {
|
|
34
|
+
this.addTool(def.name, def.description, def.parameters, def.execute);
|
|
35
|
+
}
|
|
36
|
+
}
|
|
37
|
+
/**
|
|
38
|
+
* Register one MCP prompt.
|
|
39
|
+
*
|
|
40
|
+
* Delegates to FastMCP `addPrompt`.
|
|
41
|
+
*
|
|
42
|
+
* @see https://github.com/punkpeye/fastmcp#prompts
|
|
43
|
+
*/
|
|
44
|
+
addPrompt(prompt) {
|
|
45
|
+
this.server.addPrompt(prompt);
|
|
46
|
+
}
|
|
47
|
+
/**
|
|
48
|
+
* Register multiple MCP prompts.
|
|
49
|
+
*
|
|
50
|
+
* Delegates to FastMCP `addPrompt` for each definition.
|
|
51
|
+
*
|
|
52
|
+
* @see https://github.com/punkpeye/fastmcp#prompts
|
|
53
|
+
*/
|
|
54
|
+
addPrompts(prompts) {
|
|
55
|
+
for (const prompt of prompts) {
|
|
56
|
+
this.addPrompt(prompt);
|
|
57
|
+
}
|
|
58
|
+
}
|
|
59
|
+
/**
|
|
60
|
+
* Register one MCP resource.
|
|
61
|
+
*
|
|
62
|
+
* Delegates to FastMCP `addResource`.
|
|
63
|
+
*
|
|
64
|
+
* @see https://github.com/punkpeye/fastmcp#resources
|
|
65
|
+
*/
|
|
66
|
+
addResource(resource) {
|
|
67
|
+
this.server.addResource(resource);
|
|
68
|
+
}
|
|
69
|
+
/**
|
|
70
|
+
* Register multiple MCP resources.
|
|
71
|
+
*
|
|
72
|
+
* Delegates to FastMCP `addResource` for each definition.
|
|
73
|
+
*
|
|
74
|
+
* @see https://github.com/punkpeye/fastmcp#resources
|
|
75
|
+
*/
|
|
76
|
+
addResources(resources) {
|
|
77
|
+
for (const resource of resources) {
|
|
78
|
+
this.addResource(resource);
|
|
79
|
+
}
|
|
80
|
+
}
|
|
81
|
+
/**
|
|
82
|
+
* Register one MCP resource template.
|
|
83
|
+
*
|
|
84
|
+
* Delegates to FastMCP `addResourceTemplate`.
|
|
85
|
+
*
|
|
86
|
+
* @see https://github.com/punkpeye/fastmcp#resource-templates
|
|
87
|
+
*/
|
|
88
|
+
addResourceTemplate(resourceTemplate) {
|
|
89
|
+
this.server.addResourceTemplate(resourceTemplate);
|
|
90
|
+
}
|
|
91
|
+
/**
|
|
92
|
+
* Register multiple MCP resource templates.
|
|
93
|
+
*
|
|
94
|
+
* Delegates to FastMCP `addResourceTemplate` for each definition.
|
|
95
|
+
*
|
|
96
|
+
* @see https://github.com/punkpeye/fastmcp#resource-templates
|
|
97
|
+
*/
|
|
98
|
+
addResourceTemplates(resourceTemplates) {
|
|
99
|
+
for (const resourceTemplate of resourceTemplates) {
|
|
100
|
+
this.addResourceTemplate(resourceTemplate);
|
|
101
|
+
}
|
|
102
|
+
}
|
|
103
|
+
}
|
|
104
|
+
/**
|
|
105
|
+
* Safe Appium MCP primitives exposed to plugins.
|
|
106
|
+
*/
|
|
107
|
+
export class AppiumMcpCore {
|
|
108
|
+
/**
|
|
109
|
+
* Return the currently active Appium session id, if one exists.
|
|
110
|
+
*/
|
|
111
|
+
getSessionId() {
|
|
112
|
+
return getSessionId();
|
|
113
|
+
}
|
|
114
|
+
/**
|
|
115
|
+
* Return metadata for a specific session, or the active session if `sessionId` is not provided.
|
|
116
|
+
*/
|
|
117
|
+
getSessionInfo(sessionId) {
|
|
118
|
+
return getSessionInfo(sessionId);
|
|
119
|
+
}
|
|
120
|
+
/**
|
|
121
|
+
* Return the active driver, or a driver for a specific Appium session id.
|
|
122
|
+
*/
|
|
123
|
+
getDriver(sessionId) {
|
|
124
|
+
return getDriver(sessionId);
|
|
125
|
+
}
|
|
126
|
+
/**
|
|
127
|
+
* Return metadata for all Appium sessions tracked by this server.
|
|
128
|
+
*/
|
|
129
|
+
listSessions() {
|
|
130
|
+
return listSessions();
|
|
131
|
+
}
|
|
132
|
+
}
|
|
133
|
+
export class PluginManager {
|
|
134
|
+
pluginMap = new Map();
|
|
135
|
+
server;
|
|
136
|
+
core;
|
|
137
|
+
capabilityPluginNames = new Set();
|
|
138
|
+
addToolInterceptorInstalled = false;
|
|
139
|
+
constructor(server) {
|
|
140
|
+
this.server = server;
|
|
141
|
+
this.core = new AppiumMcpCore();
|
|
142
|
+
}
|
|
143
|
+
register(plugins) {
|
|
144
|
+
for (const plugin of plugins) {
|
|
145
|
+
if (this.pluginMap.has(plugin.name)) {
|
|
146
|
+
log.warn(`[PluginManager] Duplicate plugin name "${plugin.name}" – skipping.`);
|
|
147
|
+
continue;
|
|
148
|
+
}
|
|
149
|
+
this.pluginMap.set(plugin.name, plugin);
|
|
150
|
+
log.info(`[PluginManager] Registered plugin "${plugin.name}" v${plugin.version}`);
|
|
151
|
+
}
|
|
152
|
+
this.installAddToolInterceptor();
|
|
153
|
+
}
|
|
154
|
+
registerPluginCapabilities() {
|
|
155
|
+
const registry = new McpRegistry(this.server);
|
|
156
|
+
for (const plugin of this.pluginMap.values()) {
|
|
157
|
+
if (this.capabilityPluginNames.has(plugin.name)) {
|
|
158
|
+
log.warn(`[PluginManager] Duplicate plugin name "${plugin.name}" – skipping.`);
|
|
159
|
+
continue;
|
|
160
|
+
}
|
|
161
|
+
this.capabilityPluginNames.add(plugin.name);
|
|
162
|
+
if (typeof plugin.register === 'function') {
|
|
163
|
+
plugin.register(registry, this.core);
|
|
164
|
+
}
|
|
165
|
+
}
|
|
166
|
+
}
|
|
167
|
+
async initialize() {
|
|
168
|
+
const ctx = {
|
|
169
|
+
core: this.core,
|
|
170
|
+
plugins: this.pluginMap,
|
|
171
|
+
};
|
|
172
|
+
for (const plugin of this.pluginMap.values()) {
|
|
173
|
+
if (typeof plugin.initialize === 'function') {
|
|
174
|
+
await plugin.initialize(ctx);
|
|
175
|
+
}
|
|
176
|
+
}
|
|
177
|
+
}
|
|
178
|
+
async destroy() {
|
|
179
|
+
for (const plugin of Array.from(this.pluginMap.values()).reverse()) {
|
|
180
|
+
if (typeof plugin.destroy === 'function') {
|
|
181
|
+
await plugin.destroy();
|
|
182
|
+
}
|
|
183
|
+
}
|
|
184
|
+
}
|
|
185
|
+
installAddToolInterceptor() {
|
|
186
|
+
if (this.addToolInterceptorInstalled) {
|
|
187
|
+
return;
|
|
188
|
+
}
|
|
189
|
+
this.addToolInterceptorInstalled = true;
|
|
190
|
+
const originalAddTool = this.server.addTool.bind(this.server);
|
|
191
|
+
this.server.addTool = (toolDef) => {
|
|
192
|
+
const wrappedExecute = async (args, mcpCtx) => {
|
|
193
|
+
const sessionCtx = {
|
|
194
|
+
getSessionId: () => getSessionId(),
|
|
195
|
+
getSessionInfo: (sessionId) => getSessionInfo(sessionId),
|
|
196
|
+
getDriver: (sessionId) => getDriver(sessionId),
|
|
197
|
+
listSessions,
|
|
198
|
+
};
|
|
199
|
+
const toolCtx = {
|
|
200
|
+
toolName: toolDef.name,
|
|
201
|
+
args: (args || {}),
|
|
202
|
+
session: sessionCtx,
|
|
203
|
+
};
|
|
204
|
+
for (const plugin of this.pluginMap.values()) {
|
|
205
|
+
if (typeof plugin.beforeCall !== 'function') {
|
|
206
|
+
continue;
|
|
207
|
+
}
|
|
208
|
+
const override = await plugin.beforeCall(toolCtx);
|
|
209
|
+
if (override != null) {
|
|
210
|
+
return {
|
|
211
|
+
content: override.content,
|
|
212
|
+
isError: override.isError,
|
|
213
|
+
};
|
|
214
|
+
}
|
|
215
|
+
}
|
|
216
|
+
const rawResult = (await toolDef.execute(args, mcpCtx));
|
|
217
|
+
let hookResult = {
|
|
218
|
+
isError: rawResult.isError ?? false,
|
|
219
|
+
content: rawResult.content,
|
|
220
|
+
};
|
|
221
|
+
for (const plugin of this.pluginMap.values()) {
|
|
222
|
+
if (typeof plugin.afterCall !== 'function') {
|
|
223
|
+
continue;
|
|
224
|
+
}
|
|
225
|
+
const modified = await plugin.afterCall(toolCtx, hookResult);
|
|
226
|
+
if (modified != null) {
|
|
227
|
+
hookResult = modified;
|
|
228
|
+
}
|
|
229
|
+
}
|
|
230
|
+
return {
|
|
231
|
+
content: hookResult.content,
|
|
232
|
+
isError: hookResult.isError,
|
|
233
|
+
};
|
|
234
|
+
};
|
|
235
|
+
return originalAddTool({ ...toolDef, execute: wrappedExecute });
|
|
236
|
+
};
|
|
237
|
+
}
|
|
238
|
+
}
|
|
239
|
+
//# sourceMappingURL=plugin.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"plugin.js","sourceRoot":"","sources":["../src/plugin.ts"],"names":[],"mappings":"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"}
|
package/dist/server.d.ts
CHANGED
package/dist/server.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"server.d.ts","sourceRoot":"","sources":["../src/server.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"server.d.ts","sourceRoot":"","sources":["../src/server.ts"],"names":[],"mappings":"AAEA,QAAA,MAAM,MAAM,iEAA0B,CAAC;AACvC,eAAe,MAAM,CAAC"}
|