Movatterモバイル変換


[0]ホーム

URL:


Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Sign up
Appearance settings

Draft: Basic MCP implementation#4982

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to ourterms of service andprivacy statement. We’ll occasionally send you account related emails.

Already on GitHub?Sign in to your account

Open
DavertMik wants to merge1 commit into3.x
base:3.x
Choose a base branch
Loading
fromfeat/mcp
Open

Draft: Basic MCP implementation#4982

DavertMik wants to merge1 commit into3.xfromfeat/mcp

Conversation

DavertMik
Copy link
Contributor

  • list tests & suites
  • list all available actions
  • tool to open and close browser
  • ability to control browser via actions
  • tool to collect HTML / page info
  • tool for screenshot

Copy link
Contributor

@CopilotCopilotAI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others.Learn more.

Pull Request Overview

This PR introduces documentation for integrating CodeceptJS with Cursor using the Model Context Protocol (MCP), outlining how to start the MCP server and utilize its available tools.

  • Added a dedicated markdown file (docs/MCP.md) detailing MCP usage with Cursor
  • Provided step-by-step instructions for starting the MCP server and connecting via Cursor
  • Outlined available tools and included troubleshooting guidance for common issues
Files not reviewed (1)
  • package.json: Language not supported


The server provides these tools:

- `list-tests`: List all availble tests
Copy link
Preview

CopilotAIApr 29, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others.Learn more.

Typo detected in the word 'availble'; please update it to 'available'.

Suggested change
-`list-tests`: List allavailble tests
-`list-tests`: List allavailable tests

Copilot uses AI. Check for mistakes.

Copy link
Collaborator

@kobenguyentkobenguyent left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others.Learn more.

What do you think if we do like this to keep the server.tool clean and reusable?

@@ -0,0 +1,185 @@
#!/usr/bin/env node
Copy link
Collaborator

@kobenguyentkobenguyentMay 1, 2025
edited
Loading

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others.Learn more.

#!/usr/bin/env nodeconst { McpServer, ResourceTemplate } = require('@modelcontextprotocol/sdk/server/mcp.js');const { StdioServerTransport } = require('@modelcontextprotocol/sdk/server/stdio.js');// Import specific CodeceptJS modules directlyconst Codecept = require('../lib/codecept');const container = require('../lib/container');const { getParamsToString } = require('../lib/parser');const { methodsOfObject } = require('../lib/utils');const output = require('../lib/output');const { getConfig, getTestRoot } = require('../lib/command/utils');// Determine the project pathconst projectPath = process.argv.slice(2).find(arg => !arg.includes('mcp.js')) || process.cwd();/** * Initializes CodeceptJS and loads tests. * @param {string} customPath - The project path. * @returns {object} - The initialized CodeceptJS instance and its configuration. */async function initializeCodeceptJS(customPath) {  output.print = () => {}; // Disable default output  const testsPath = getTestRoot(customPath);  const config = getConfig(customPath);  const codecept = new Codecept(config, {});  await codecept.init(testsPath);  codecept.loadTests();  return { codecept, config };}/** * Extracts test information from the loaded CodeceptJS instance. * @param {object} codecept - The initialized CodeceptJS instance. * @returns {Array<object>} - An array of test objects. */function extractTestInfo(codecept) {  const mocha = container.mocha();  mocha.files = codecept.testFiles;  mocha.loadFiles();  const tests = [];  for (const suite of mocha.suite.suites) {    for (const test of suite.tests) {      tests.push({        title: test.title,        fullTitle: test.fullTitle(),        body: test.body ? test.body.toString() : '',        file: suite.file,        suiteName: suite.title,        meta: test.meta,        tags: test.tags,      });    }  }  return tests;}/** * Formats test information into a readable text block. * @param {Array<object>} tests - An array of test objects. * @returns {object} - An MCP content object containing the formatted text. */function formatTestsAsText(tests) {  const formattedText = tests    .map(test => [      `Test: ${test.fullTitle}`,      `File: ${test.file}`,      `Suite: ${test.suiteName}`,      test.tags && test.tags.length ? `Tags: ${test.tags.join(', ')}` : '',      '',      'Body:',      test.body,      '---',    ]      .filter(Boolean)      .join('\n'))    .join('\n\n');  return { content: [{ type: 'text', text: formattedText }] };}/** * Extracts suite information from the loaded CodeceptJS instance. * @param {object} codecept - The initialized CodeceptJS instance. * @returns {Array<object>} - An array of suite objects. */function extractSuiteInfo(codecept) {  const mocha = container.mocha();  mocha.files = codecept.testFiles;  mocha.loadFiles();  const suites = [];  for (const suite of mocha.suite.suites) {    suites.push({      title: suite.title,      file: suite.file,      testCount: suite.tests.length,      tests: suite.tests.map(test => ({        title: test.title,        fullTitle: test.fullTitle(),      })),    });  }  return suites;}/** * Formats suite information into a readable text block. * @param {Array<object>} suites - An array of suite objects. * @returns {object} - An MCP content object containing the formatted text. */function formatSuitesAsText(suites) {  const formattedText = suites    .map(suite => {      const testList = suite.tests.map(test => `  - ${test.title}`).join('\n');      return [`Suite: ${suite.title}`, `File: ${suite.file}`, `Tests (${suite.testCount}):`, testList, '---'].join('\n');    })    .join('\n\n');  return { content: [{ type: 'text', text: formattedText }] };}/** * Extracts action information from CodeceptJS helpers and support objects. * @returns {Array<object>} - An array of action objects. */function extractActionInfo() {  const helpers = container.helpers();  const supportI = container.support('I');  const actions = [];  // Get actions from helpers  for (const name in helpers) {    const helper = helpers[name];    methodsOfObject(helper).forEach(action => {      const params = getParamsToString(helper[action]);      actions.push({        name: action,        source: name,        params,        type: 'helper',      });    });  }  // Get actions from I  for (const name in supportI) {    if (actions.some(a => a.name === name)) {      continue;    }    const actor = supportI[name];    const params = getParamsToString(actor);    actions.push({      name,      source: 'I',      params,      type: 'support',    });  }  return actions;}/** * Formats action information into a readable text block. * @param {Array<object>} actions - An array of action objects. * @returns {object} - An MCP content object containing the formatted text. */function formatActionsAsText(actions) {  const helperActions = actions    .filter(a => a.type === 'helper')    .sort((a, b) => (a.source === b.source ? a.name.localeCompare(b.name) : a.source.localeCompare(b.source)));  const supportActions = actions.filter(a => a.type === 'support').sort((a, b) => a.name.localeCompare(b.name));  const formattedText = [    '# Helper Actions',    ...helperActions.map(a => `${a.source}.${a.name}(${a.params})`),    '',    '# Support Actions',    ...supportActions.map(a => `I.${a.name}(${a.params})`),  ].join('\n');  return { content: [{ type: 'text', text: formattedText }] };}/** * Starts the MCP Server. */async function startServer() {  const { codecept } = await initializeCodeceptJS(projectPath);  const server = new McpServer({    name: 'CodeceptJS',    version: '1.0.0',    url: 'https://codecept.io',    description: 'CodeceptJS Model Context Protocol Server',  });  server.tool('list-tests', {}, async () => {    const tests = extractTestInfo(codecept);    return formatTestsAsText(tests);  });  server.tool('list-suites', {}, async () => {    const suites = extractSuiteInfo(codecept);    return formatSuitesAsText(suites);  });  server.tool('list-actions', {}, async () => {    const actions = extractActionInfo();    return formatActionsAsText(actions);  });  const transport = new StdioServerTransport();  await server.connect(transport);}// Start the serverstartServer().catch(err => {  console.error('Error starting MCP server:', err);  process.exit(1);});

// Setup MCP server
const server = new McpServer({
name: 'CodeceptJS',
version: '1.0.0',
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others.Learn more.

Shall we get the current version of codeceptjs?

Sign up for freeto join this conversation on GitHub. Already have an account?Sign in to comment
Reviewers

@kobenguyentkobenguyentkobenguyent left review comments

Copilot code reviewCopilotCopilot left review comments

Assignees
No one assigned
Labels
None yet
Projects
None yet
Milestone
No milestone
Development

Successfully merging this pull request may close these issues.

2 participants
@DavertMik@kobenguyent

[8]ページ先頭

©2009-2025 Movatter.jp