agent-vision-mcp 0.1.0 → 0.1.2

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 CHANGED
@@ -1,13 +1,16 @@
1
1
  <div align="center">
2
2
  <h1>Agent Vision</h1>
3
3
  <p align="center">
4
- <img src="./docs/banner.png" width="800" />
4
+ <img src="https://github.com/kedarvartak/agent-vision/blob/main/docs/banner.png?raw=true" alt="Agent Vision Banner"/>
5
5
  </p>
6
6
  <p>
7
7
  <img alt="TypeScript" src="https://img.shields.io/badge/TypeScript-ES2022-3178C6?style=flat-square" />
8
8
  <img alt="Chrome CDP" src="https://img.shields.io/badge/Chrome-CDP-4285F4?style=flat-square" />
9
9
  <img alt="MCP" src="https://img.shields.io/badge/MCP-stdio-7C3AED?style=flat-square" />
10
10
  <img alt="License" src="https://img.shields.io/badge/License-MIT-22C55E?style=flat-square" />
11
+ <a href="https://www.npmjs.com/package/agent-vision-mcp">
12
+ <img src="https://img.shields.io/npm/v/agent-vision-mcp" />
13
+ </a>
11
14
  </p>
12
15
  </div>
13
16
 
@@ -3,17 +3,6 @@ import type { VisualContextServer } from "../server.js";
3
3
  export declare class McpStdioServer {
4
4
  private readonly app;
5
5
  private readonly logger;
6
- private readonly input;
7
- private readonly output;
8
- private buffer;
9
- private initialized;
10
- constructor(app: VisualContextServer, logger: Logger, input?: NodeJS.ReadStream & {
11
- fd: 0;
12
- }, output?: NodeJS.WriteStream & {
13
- fd: 1;
14
- });
15
- start(): void;
16
- private processBuffer;
17
- private handleMessage;
18
- private writeMessage;
6
+ constructor(app: VisualContextServer, logger: Logger);
7
+ start(): Promise<void>;
19
8
  }
@@ -1,19 +1,9 @@
1
+ import { Server } from "@modelcontextprotocol/sdk/server/index.js";
2
+ import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio.js";
3
+ import { CallToolRequestSchema, ListToolsRequestSchema, McpError, ErrorCode } from "@modelcontextprotocol/sdk/types.js";
1
4
  import { isAppError } from "../errors/app-error.js";
2
- const MCP_PROTOCOL_VERSION = "2025-03-26";
3
5
  const SERVER_NAME = "agent-vision-mcp";
4
- const SERVER_VERSION = "0.1.0";
5
- const JSON_RPC_VERSION = "2.0";
6
- const JSON_PARSE_ERROR = -32700;
7
- const JSON_INVALID_REQUEST = -32600;
8
- const JSON_METHOD_NOT_FOUND = -32601;
9
- const JSON_INVALID_PARAMS = -32602;
10
- const JSON_INTERNAL_ERROR = -32603;
11
- const toRecord = (value) => {
12
- if (!value || typeof value !== "object" || Array.isArray(value)) {
13
- return {};
14
- }
15
- return value;
16
- };
6
+ const SERVER_VERSION = "0.1.1";
17
7
  const isImagePayload = (value) => {
18
8
  if (!value || typeof value !== "object") {
19
9
  return false;
@@ -94,179 +84,63 @@ const toToolErrorResult = (error) => {
94
84
  isError: true
95
85
  };
96
86
  };
97
- const toJsonRpcError = (id, code, message, data) => ({
98
- jsonrpc: JSON_RPC_VERSION,
99
- id,
100
- error: {
101
- code,
102
- message,
103
- ...(data !== undefined ? { data } : {})
87
+ const toMcpError = (error) => {
88
+ if (isAppError(error)) {
89
+ return new McpError(ErrorCode.InternalError, error.message, error.details);
90
+ }
91
+ if (error instanceof McpError) {
92
+ return error;
104
93
  }
105
- });
106
- const encodeMessage = (message) => {
107
- const body = Buffer.from(JSON.stringify(message), "utf8");
108
- const header = Buffer.from(`Content-Length: ${body.byteLength}\r\n\r\n`, "utf8");
109
- return Buffer.concat([header, body]);
94
+ return new McpError(ErrorCode.InternalError, error instanceof Error ? error.message : String(error));
110
95
  };
111
96
  export class McpStdioServer {
112
97
  app;
113
98
  logger;
114
- input;
115
- output;
116
- buffer = Buffer.alloc(0);
117
- initialized = false;
118
- constructor(app, logger, input = process.stdin, output = process.stdout) {
99
+ constructor(app, logger) {
119
100
  this.app = app;
120
101
  this.logger = logger;
121
- this.input = input;
122
- this.output = output;
123
102
  }
124
- start() {
125
- this.input.on("data", (chunk) => {
126
- this.buffer = Buffer.concat([
127
- this.buffer,
128
- typeof chunk === "string" ? Buffer.from(chunk, "utf8") : chunk
129
- ]);
130
- this.processBuffer();
131
- });
132
- this.input.on("error", (error) => {
133
- this.logger.error("MCP stdio input error", {
134
- errorMessage: error instanceof Error ? error.message : String(error)
135
- });
103
+ async start() {
104
+ const server = new Server({
105
+ name: SERVER_NAME,
106
+ version: SERVER_VERSION
107
+ }, {
108
+ capabilities: {
109
+ tools: {}
110
+ }
136
111
  });
137
- this.output.on("error", (error) => {
138
- this.logger.error("MCP stdio output error", {
139
- errorMessage: error instanceof Error ? error.message : String(error)
140
- });
112
+ server.setRequestHandler(ListToolsRequestSchema, async () => ({
113
+ tools: this.app.listTools().map((tool) => ({
114
+ name: tool.name,
115
+ description: tool.description,
116
+ inputSchema: (tool.inputSchema ?? {
117
+ type: "object",
118
+ properties: {},
119
+ additionalProperties: false
120
+ }),
121
+ ...(tool.annotations ? { annotations: tool.annotations } : {})
122
+ }))
123
+ }));
124
+ server.setRequestHandler(CallToolRequestSchema, async (request) => {
125
+ const toolName = request.params.name;
126
+ const args = (request.params.arguments ?? {});
127
+ try {
128
+ const result = await this.app.callTool(toolName, args);
129
+ return toToolResult(result);
130
+ }
131
+ catch (error) {
132
+ this.logger.error("MCP tool call failed", {
133
+ toolName,
134
+ errorMessage: error instanceof Error ? error.message : String(error)
135
+ });
136
+ return toToolErrorResult(error);
137
+ }
141
138
  });
142
- this.logger.info("MCP stdio server listening", {
143
- protocolVersion: MCP_PROTOCOL_VERSION,
139
+ const transport = new StdioServerTransport();
140
+ await server.connect(transport);
141
+ this.logger.info("Official MCP stdio server listening", {
144
142
  serverName: SERVER_NAME,
145
143
  serverVersion: SERVER_VERSION
146
144
  });
147
145
  }
148
- processBuffer() {
149
- while (true) {
150
- const headerEnd = this.buffer.indexOf("\r\n\r\n");
151
- if (headerEnd === -1) {
152
- return;
153
- }
154
- const headerText = this.buffer.subarray(0, headerEnd).toString("utf8");
155
- const match = headerText.match(/Content-Length:\s*(\d+)/i);
156
- if (!match) {
157
- this.buffer = Buffer.alloc(0);
158
- this.writeMessage(toJsonRpcError(null, JSON_INVALID_REQUEST, "Missing Content-Length header"));
159
- return;
160
- }
161
- const contentLength = Number.parseInt(match[1], 10);
162
- const bodyStart = headerEnd + 4;
163
- const bodyEnd = bodyStart + contentLength;
164
- if (this.buffer.byteLength < bodyEnd) {
165
- return;
166
- }
167
- const bodyBuffer = this.buffer.subarray(bodyStart, bodyEnd);
168
- this.buffer = this.buffer.subarray(bodyEnd);
169
- let parsed;
170
- try {
171
- parsed = JSON.parse(bodyBuffer.toString("utf8"));
172
- }
173
- catch {
174
- this.writeMessage(toJsonRpcError(null, JSON_PARSE_ERROR, "Invalid JSON payload"));
175
- continue;
176
- }
177
- void this.handleMessage(parsed);
178
- }
179
- }
180
- async handleMessage(message) {
181
- if (message.jsonrpc !== JSON_RPC_VERSION || typeof message.method !== "string") {
182
- if (message.id !== undefined) {
183
- this.writeMessage(toJsonRpcError(message.id ?? null, JSON_INVALID_REQUEST, "Invalid JSON-RPC request"));
184
- }
185
- return;
186
- }
187
- const id = message.id ?? null;
188
- try {
189
- switch (message.method) {
190
- case "initialize": {
191
- this.initialized = true;
192
- this.writeMessage({
193
- jsonrpc: JSON_RPC_VERSION,
194
- id,
195
- result: {
196
- protocolVersion: MCP_PROTOCOL_VERSION,
197
- capabilities: {
198
- tools: {
199
- listChanged: false
200
- }
201
- },
202
- serverInfo: {
203
- name: SERVER_NAME,
204
- version: SERVER_VERSION
205
- }
206
- }
207
- });
208
- return;
209
- }
210
- case "notifications/initialized": {
211
- return;
212
- }
213
- case "ping": {
214
- this.writeMessage({
215
- jsonrpc: JSON_RPC_VERSION,
216
- id,
217
- result: {}
218
- });
219
- return;
220
- }
221
- case "tools/list": {
222
- this.writeMessage({
223
- jsonrpc: JSON_RPC_VERSION,
224
- id,
225
- result: {
226
- tools: this.app.listTools().map((tool) => ({
227
- name: tool.name,
228
- description: tool.description,
229
- inputSchema: tool.inputSchema ?? { type: "object", properties: {}, additionalProperties: false },
230
- ...(tool.annotations ? { annotations: tool.annotations } : {})
231
- }))
232
- }
233
- });
234
- return;
235
- }
236
- case "tools/call": {
237
- const params = toRecord(message.params);
238
- const toolName = params.name;
239
- if (typeof toolName !== "string") {
240
- this.writeMessage(toJsonRpcError(id, JSON_INVALID_PARAMS, "tools/call requires a string name"));
241
- return;
242
- }
243
- try {
244
- const result = await this.app.callTool(toolName, toRecord(params.arguments));
245
- this.writeMessage({
246
- jsonrpc: JSON_RPC_VERSION,
247
- id,
248
- result: toToolResult(result)
249
- });
250
- }
251
- catch (error) {
252
- this.writeMessage({
253
- jsonrpc: JSON_RPC_VERSION,
254
- id,
255
- result: toToolErrorResult(error)
256
- });
257
- }
258
- return;
259
- }
260
- default: {
261
- this.writeMessage(toJsonRpcError(id, JSON_METHOD_NOT_FOUND, `Method not found: ${message.method}`));
262
- }
263
- }
264
- }
265
- catch (error) {
266
- this.writeMessage(toJsonRpcError(id, JSON_INTERNAL_ERROR, "Internal MCP server error", error instanceof Error ? { message: error.message } : { message: String(error) }));
267
- }
268
- }
269
- writeMessage(message) {
270
- this.output.write(encodeMessage(message));
271
- }
272
146
  }
@@ -1,5 +1,17 @@
1
1
  import type { Logger } from "../logging/logger.js";
2
- export type JsonSchema = Record<string, unknown>;
2
+ export type JsonSchemaProperty = {
3
+ type: string;
4
+ description?: string;
5
+ [key: string]: unknown;
6
+ };
7
+ export type JsonSchema = {
8
+ type: "object";
9
+ properties?: Record<string, JsonSchemaProperty>;
10
+ required?: string[];
11
+ additionalProperties?: boolean;
12
+ description?: string;
13
+ [key: string]: unknown;
14
+ };
3
15
  export type ToolHandler = (args: Record<string, unknown>) => Promise<unknown> | unknown;
4
16
  export type ToolAnnotations = {
5
17
  readOnlyHint?: boolean;
package/dist/mcp-stdio.js CHANGED
@@ -2,7 +2,16 @@
2
2
  import { ConsoleLogger } from "./logging/logger.js";
3
3
  import { McpStdioServer } from "./mcp/stdio-server.js";
4
4
  import { VisualContextServer } from "./server.js";
5
- const app = new VisualContextServer();
6
- const logger = new ConsoleLogger("agent-vision-mcp");
7
- app.start();
8
- new McpStdioServer(app, logger).start();
5
+ const main = async () => {
6
+ const app = new VisualContextServer();
7
+ const logger = new ConsoleLogger("agent-vision-mcp");
8
+ app.start();
9
+ await new McpStdioServer(app, logger).start();
10
+ };
11
+ void main().catch((error) => {
12
+ const logger = new ConsoleLogger("agent-vision-mcp");
13
+ logger.error("Failed to start MCP stdio server", {
14
+ errorMessage: error instanceof Error ? error.message : String(error)
15
+ });
16
+ process.exit(1);
17
+ });
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "agent-vision-mcp",
3
- "version": "0.1.0",
3
+ "version": "0.1.2",
4
4
  "type": "module",
5
5
  "description": "Browser-first MCP server that gives agents visual access to live tabs through Chrome DevTools Protocol.",
6
6
  "bin": {
@@ -27,7 +27,16 @@
27
27
  "agent"
28
28
  ],
29
29
  "license": "MIT",
30
+ "repository": {
31
+ "type": "git",
32
+ "url": "git+https://github.com/kedarvartak/agent-vision.git"
33
+ },
34
+ "homepage": "https://github.com/kedarvartak/agent-vision#readme",
35
+ "bugs": {
36
+ "url": "https://github.com/kedarvartak/agent-vision/issues"
37
+ },
30
38
  "dependencies": {
39
+ "@modelcontextprotocol/sdk": "^1.17.5",
31
40
  "ws": "^8.18.0"
32
41
  },
33
42
  "devDependencies": {