Merge branch 'main' into fix-puppeteer-async-eval

This commit is contained in:
Mati Horovitz
2024-12-05 20:12:07 +02:00
50 changed files with 3324 additions and 1557 deletions

View File

@@ -3,8 +3,8 @@
## Description ## Description
## Server Details ## Server Details
<!-- If modifying an existing server or adding a new one, provide details --> <!-- If modifying an existing server, provide details -->
- Server: <!-- e.g., filesystem, github, new-server-name --> - Server: <!-- e.g., filesystem, github -->
- Changes to: <!-- e.g., tools, resources, prompts --> - Changes to: <!-- e.g., tools, resources, prompts -->
## Motivation and Context ## Motivation and Context
@@ -18,7 +18,6 @@
## Types of changes ## Types of changes
<!-- What types of changes does your code introduce? Put an `x` in all the boxes that apply: --> <!-- What types of changes does your code introduce? Put an `x` in all the boxes that apply: -->
- [ ] New MCP Server
- [ ] Bug fix (non-breaking change which fixes an issue) - [ ] Bug fix (non-breaking change which fixes an issue)
- [ ] New feature (non-breaking change which adds functionality) - [ ] New feature (non-breaking change which adds functionality)
- [ ] Breaking change (fix or feature that would cause existing functionality to change) - [ ] Breaking change (fix or feature that would cause existing functionality to change)
@@ -27,7 +26,7 @@
## Checklist ## Checklist
<!-- Go over all the following points, and put an `x` in all the boxes that apply. --> <!-- Go over all the following points, and put an `x` in all the boxes that apply. -->
- [ ] I have read the [MCP Protocol Documentation](https://modelcontextprotocol.io) - [ ] I have read the [MCP Protocol Documentation](https://modelcontextprotocol.io)
- [ ] My server follows MCP security best practices - [ ] My changes follows MCP security best practices
- [ ] I have updated the server's README accordingly - [ ] I have updated the server's README accordingly
- [ ] I have tested this with an LLM client - [ ] I have tested this with an LLM client
- [ ] My code follows the repository's style guidelines - [ ] My code follows the repository's style guidelines

View File

@@ -74,6 +74,6 @@ jobs:
- name: Publish package - name: Publish package
working-directory: src/${{ matrix.package }} working-directory: src/${{ matrix.package }}
run: npm publish # --provenance run: npm publish --access public
env: env:
NODE_AUTH_TOKEN: ${{ secrets.NPM_TOKEN }} NODE_AUTH_TOKEN: ${{ secrets.NPM_TOKEN }}

View File

@@ -5,12 +5,16 @@ Thank you for your interest in contributing to the Model Context Protocol (MCP)
## Types of Contributions ## Types of Contributions
### 1. New Servers ### 1. New Servers
Adding a new server is a valuable way to contribute. Before creating a new server:
The repository contains reference implementations, as well as a list of community servers.
We generally don't accept new servers into the repository. We do accept pull requests to the [README.md](./README.md)
adding a reference to your servers.
- Check the [modelcontextprotocol.io](https://modelcontextprotocol.io) documentation - Check the [modelcontextprotocol.io](https://modelcontextprotocol.io) documentation
- Ensure your server doesn't duplicate existing functionality - Ensure your server doesn't duplicate existing functionality
- Consider whether your server would be generally useful to others - Consider whether your server would be generally useful to others
- Follow [security best practices](https://modelcontextprotocol.io/docs/concepts/transports#security-considerations) from the MCP documentation - Follow [security best practices](https://modelcontextprotocol.io/docs/concepts/transports#security-considerations) from the MCP documentation
- Create a PR adding a link to your server to the [README.md](./README.md).
### 2. Improvements to Existing Servers ### 2. Improvements to Existing Servers
Enhancements to existing servers are welcome! This includes: Enhancements to existing servers are welcome! This includes:

View File

@@ -1,42 +1,90 @@
# MCP servers # Model Context Protocol servers
A collection of reference implementations and community-contributed servers for the [Model Context Protocol](https://modelcontextprotocol.io/) (MCP). This repository showcases the versatility and extensibility of MCP, demonstrating how it can be used to give Large Language Models (LLMs) secure, controlled access to tools and data sources. This repository is a collection of *reference implementations* for the [Model Context Protocol](https://modelcontextprotocol.io/) (MCP), as well as references
to community built servers and additional resources.
The servers in this repository showcase the versatility and extensibility of MCP, demonstrating how it can be used to give Large Language Models (LLMs) secure, controlled access to tools and data sources.
Each MCP server is implemented with either the [Typescript MCP SDK](https://github.com/modelcontextprotocol/typescript-sdk) or [Python MCP SDK](https://github.com/modelcontextprotocol/python-sdk). Each MCP server is implemented with either the [Typescript MCP SDK](https://github.com/modelcontextprotocol/typescript-sdk) or [Python MCP SDK](https://github.com/modelcontextprotocol/python-sdk).
## 🌟 Featured Servers ## 🌟 Reference Servers
These servers aim to demonstrate MCP features and the Typescript and Python SDK.
- **[AWS KB Retrieval](src/aws-kb-retrieval)** - Retrieval from AWS Knowledge Base using Bedrock Agent Runtime
- **[Brave Search](src/brave-search)** - Web and local search using Brave's Search API
- **[EverArt](src/everart)** - AI image generation using various models
- **[Fetch](src/fetch)** - Web content fetching and conversion for efficient LLM usage
- **[Filesystem](src/filesystem)** - Secure file operations with configurable access controls - **[Filesystem](src/filesystem)** - Secure file operations with configurable access controls
- **[Git](src/git)** - Tools to read, search, and manipulate Git repositories
- **[GitHub](src/github)** - Repository management, file operations, and GitHub API integration - **[GitHub](src/github)** - Repository management, file operations, and GitHub API integration
- **[GitLab](src/gitlab)** - GitLab API, enabling project management - **[GitLab](src/gitlab)** - GitLab API, enabling project management
- **[Git](src/git)** - Tools to read, search, and manipulate Git repositories
- **[Google Drive](src/gdrive)** - File access and search capabilities for Google Drive - **[Google Drive](src/gdrive)** - File access and search capabilities for Google Drive
- **[PostgreSQL](src/postgres)** - Read-only database access with schema inspection
- **[Sqlite](src/sqlite)** - Database interaction and business intelligence capabilities
- **[Slack](src/slack)** - Channel management and messaging capabilities
- **[Sentry](src/sentry)** - Retrieving and analyzing issues from Sentry.io
- **[Memory](src/memory)** - Knowledge graph-based persistent memory system
- **[Puppeteer](src/puppeteer)** - Browser automation and web scraping
- **[Brave Search](src/brave-search)** - Web and local search using Brave's Search API
- **[Google Maps](src/google-maps)** - Location services, directions, and place details - **[Google Maps](src/google-maps)** - Location services, directions, and place details
- **[Fetch](src/fetch)** - Web content fetching and conversion for efficient LLM usage - **[Memory](src/memory)** - Knowledge graph-based persistent memory system
- **[PostgreSQL](src/postgres)** - Read-only database access with schema inspection
- **[Puppeteer](src/puppeteer)** - Browser automation and web scraping
- **[Sentry](src/sentry)** - Retrieving and analyzing issues from Sentry.io
- **[Sequential Thinking](src/sequentialthinking)** - Dynamic and reflective problem-solving through thought sequences
- **[Slack](src/slack)** - Channel management and messaging capabilities
- **[Sqlite](src/sqlite)** - Database interaction and business intelligence capabilities
## 🌎 Community Servers ## 🤝 Third-Party Servers
- **[Cloudflare](https://github.com/cloudflare/mcp-server-cloudflare)** - Deploy, configure & interrogate your resources on the Cloudflare developer platform (e.g. Workers/KV/R2/D1) ### 🎖️ Official Integrations
Official integrations are maintained by companies building production ready MCP servers for their platforms.
- <img height="12" width="12" src="https://cdn.simpleicons.org/cloudflare" /> **[Cloudflare](https://github.com/cloudflare/mcp-server-cloudflare)** - Deploy, configure & interrogate your resources on the Cloudflare developer platform (e.g. Workers/KV/R2/D1)
- **[Raygun](https://github.com/MindscapeHQ/mcp-server-raygun)** - Interact with your crash reporting and real using monitoring data on your Raygun account - **[Raygun](https://github.com/MindscapeHQ/mcp-server-raygun)** - Interact with your crash reporting and real using monitoring data on your Raygun account
- <img height="12" width="12" src="https://e2b.dev/favicon.ico" alt="E2B Logo" /> **[E2B](https://github.com/e2b-dev/mcp-server)** - Run code in secure sandboxes hosted by [E2B](https://e2b.dev)
- **[Neon](https://github.com/neondatabase/mcp-server-neon)** - Interact with the Neon serverless Postgres platform
- <img height="12" width="12" src="https://www.tinybird.co/favicon.ico" alt="Tinybird Logo" /> **[Tinybird](https://github.com/tinybirdco/mcp-tinybird)** - Interact with Tinybird serverless ClickHouse platform
- <img height="12" width="12" src="https://pics.fatwang2.com/56912e614b35093426c515860f9f2234.svg" /> [Search1API](https://github.com/fatwang2/search1api-mcp) - One API for Search, Crawling, and Sitemaps
- <img height="12" width="12" src="https://qdrant.tech/img/brand-resources-logos/logomark.svg" /> **[Qdrant](https://github.com/qdrant/mcp-server-qdrant/)** - Implement semantic memory layer on top of the Qdrant vector search engine
### 🌎 Community Servers
A growing set of community-developed and maintained servers demonstrates various applications of MCP across different domains.
> **Note:** Community servers are **untested** and should be used at **your own risk**. They are not affiliated with or endorsed by Anthropic.
- **[MCP Installer](https://github.com/anaisbetts/mcp-installer)** - This server is a server that installs other MCP servers for you.
- **[Spotify MCP](https://github.com/varunneal/spotify-mcp)** - This MCP allows an LLM to play and use Spotify.
- **[Inoyu](https://github.com/sergehuber/inoyu-mcp-unomi-server)** - Interact with an Apache Unomi CDP customer data platform to retrieve and update customer profiles
- **[MySQL](https://github.com/designcomputer/mysql_mcp_server)** - MySQL database integration with configurable access controls and schema inspection
- **[BigQuery](https://github.com/LucasHild/mcp-server-bigquery)** (by LucasHild) - This server enables LLMs to inspect database schemas and execute queries on BigQuery.
- **[BigQuery](https://github.com/ergut/mcp-bigquery-server)** (by ergut) - Server implementation for Google BigQuery integration that enables direct BigQuery database access and querying capabilities
- **[Todoist](https://github.com/abhiz123/todoist-mcp-server)** - Interact with Todoist to manage your tasks.
- **[Tavily search](https://github.com/RamXX/mcp-tavily")** - An MCP server for Tavily's search & news API, with explicit site inclusions/exclusions
- **[Linear](https://github.com/jerhadf/linear-mcp-server)** - Allows LLM to interact with Linear's API for project management, including searching, creating, and updating issues.
- **[Playwright MCP](https://github.com/executeautomation/mcp-playwright)** - This MCP Server will help you run browser automation and webscraping using Playwright
- **[AWS](https://github.com/rishikavikondala/mcp-server-aws)** - Perform operations on your AWS resources using an LLM
- **[LlamaCloud](https://github.com/run-llama/mcp-server-llamacloud)** (by marcusschiesser) - Integrate the data stored in a managed index on [LlamaCloud](https://cloud.llamaindex.ai/)
- **[Any Chat Completions](https://github.com/pyroprompts/any-chat-completions-mcp)** - Interact with any OpenAI SDK Compatible Chat Completions API like OpenAI, Perplexity, Groq, xAI and many more.
- **[Windows CLI](https://github.com/SimonB97/win-cli-mcp-server)** - MCP server for secure command-line interactions on Windows systems, enabling controlled access to PowerShell, CMD, and Git Bash shells.
- **[OpenRPC](https://github.com/shanejonas/openrpc-mpc-server)** - Interact with and discover JSON-RPC APIs via [OpenRPC](https://open-rpc.org).
## 📚 Resources
Additional resources on MCP.
- **[Awesome MCP Servers by punkpeye](https://github.com/punkpeye/awesome-mcp-servers)** - A curated list of MCP servers by **[Frank Fiegel](https://github.com/punkpeye)**
- **[Awesome MCP Servers by wong2](https://github.com/wong2/awesome-mcp-servers)** - A curated list of MCP servers by **[wong2](https://github.com/wong2)**
- **[Awesome MCP Servers by appcypher](https://github.com/appcypher/awesome-mcp-servers)** - A curated list of MCP servers by **[Stephen Akinyemi](https://github.com/appcypher)**
- **[mcp-get](https://mcp-get.com)** - Command line tool for installing and managing MCP servers by **[Michael Latman](https://github.com/michaellatman)**
- **[mcp-cli](https://github.com/wong2/mcp-cli)** - A CLI inspector for the Model Context Protocol by **[wong2](https://github.com/wong2)**
## 🚀 Getting Started ## 🚀 Getting Started
### Using MCP Servers in this Repository ### Using MCP Servers in this Repository
Typescript-based servers in this repository can be used directly with `npx`. Typescript-based servers in this repository can be used directly with `npx`.
For example, this will start the [Memory](src/memory) server: For example, this will start the [Memory](src/memory) server:
```sh ```sh
npx -y @modelcontextprotocol/server-memory npx -y @modelcontextprotocol/server-memory
``` ```
Python-based servers in this repository can be used directly with [`uvx`](https://docs.astral.sh/uv/concepts/tools/) or [`pip`](https://pypi.org/project/pip/). `uvx` is recommended for ease of use and setup. Python-based servers in this repository can be used directly with [`uvx`](https://docs.astral.sh/uv/concepts/tools/) or [`pip`](https://pypi.org/project/pip/). `uvx` is recommended for ease of use and setup.
For example, this will start the [Git](src/git) server: For example, this will start the [Git](src/git) server:
```sh ```sh

1977
package-lock.json generated

File diff suppressed because it is too large Load Diff

View File

@@ -1,7 +1,7 @@
{ {
"name": "@modelcontextprotocol/servers", "name": "@modelcontextprotocol/servers",
"private": true, "private": true,
"version": "0.5.1", "version": "0.6.2",
"description": "Model Context Protocol servers", "description": "Model Context Protocol servers",
"license": "MIT", "license": "MIT",
"author": "Anthropic, PBC (https://anthropic.com)", "author": "Anthropic, PBC (https://anthropic.com)",
@@ -26,6 +26,8 @@
"@modelcontextprotocol/server-slack": "*", "@modelcontextprotocol/server-slack": "*",
"@modelcontextprotocol/server-brave-search": "*", "@modelcontextprotocol/server-brave-search": "*",
"@modelcontextprotocol/server-memory": "*", "@modelcontextprotocol/server-memory": "*",
"@modelcontextprotocol/server-filesystem": "*" "@modelcontextprotocol/server-filesystem": "*",
"@modelcontextprotocol/server-everart": "*",
"@modelcontextprotocol/server-sequential-thinking": "*"
} }
} }

View File

@@ -0,0 +1,53 @@
# AWS Knowledge Base Retrieval MCP Server
An MCP server implementation for retrieving information from the AWS Knowledge Base using the Bedrock Agent Runtime.
## Features
- **RAG (Retrieval-Augmented Generation)**: Retrieve context from the AWS Knowledge Base based on a query and a Knowledge Base ID.
- **Supports multiple results retrieval**: Option to retrieve a customizable number of results.
## Tools
- **retrieve_from_aws_kb**
- Perform retrieval operations using the AWS Knowledge Base.
- Inputs:
- `query` (string): The search query for retrieval.
- `knowledgeBaseId` (string): The ID of the AWS Knowledge Base.
- `n` (number, optional): Number of results to retrieve (default: 3).
## Configuration
### Setting up AWS Credentials
1. Obtain AWS access key ID, secret access key, and region from the AWS Management Console.
2. Ensure these credentials have appropriate permissions for Bedrock Agent Runtime operations.
### Usage with Claude Desktop
Add this to your `claude_desktop_config.json`:
```json
{
"mcpServers": {
"aws-kb-retrieval": {
"command": "npx",
"args": [
"-y",
"@modelcontextprotocol/server-aws-kb-retrieval"
],
"env": {
"AWS_ACCESS_KEY_ID": "YOUR_ACCESS_KEY_HERE",
"AWS_SECRET_ACCESS_KEY": "YOUR_SECRET_ACCESS_KEY_HERE",
"AWS_REGION": "YOUR_AWS_REGION_HERE"
}
}
}
}
```
## License
This MCP server is licensed under the MIT License. This means you are free to use, modify, and distribute the software, subject to the terms and conditions of the MIT License. For more details, please see the LICENSE file in the project repository.
This README assumes that your server package is named `@modelcontextprotocol/server-aws-kb-retrieval`. Adjust the package name and installation details if they differ in your setup. Also, ensure that your server script is correctly built and that all dependencies are properly managed in your `package.json`.

View File

@@ -0,0 +1,166 @@
#!/usr/bin/env node
import { Server } from "@modelcontextprotocol/sdk/server/index.js";
import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio.js";
import {
CallToolRequestSchema,
ListToolsRequestSchema,
Tool,
} from "@modelcontextprotocol/sdk/types.js";
import {
BedrockAgentRuntimeClient,
RetrieveCommand,
RetrieveCommandInput,
} from "@aws-sdk/client-bedrock-agent-runtime";
// AWS client initialization
const bedrockClient = new BedrockAgentRuntimeClient({
region: process.env.AWS_REGION,
credentials: {
accessKeyId: process.env.AWS_ACCESS_KEY_ID!,
secretAccessKey: process.env.AWS_SECRET_ACCESS_KEY!,
},
});
interface RAGSource {
id: string;
fileName: string;
snippet: string;
score: number;
}
async function retrieveContext(
query: string,
knowledgeBaseId: string,
n: number = 3
): Promise<{
context: string;
isRagWorking: boolean;
ragSources: RAGSource[];
}> {
try {
if (!knowledgeBaseId) {
console.error("knowledgeBaseId is not provided");
return {
context: "",
isRagWorking: false,
ragSources: [],
};
}
const input: RetrieveCommandInput = {
knowledgeBaseId: knowledgeBaseId,
retrievalQuery: { text: query },
retrievalConfiguration: {
vectorSearchConfiguration: { numberOfResults: n },
},
};
const command = new RetrieveCommand(input);
const response = await bedrockClient.send(command);
const rawResults = response?.retrievalResults || [];
const ragSources: RAGSource[] = rawResults
.filter((res) => res?.content?.text)
.map((result, index) => {
const uri = result?.location?.s3Location?.uri || "";
const fileName = uri.split("/").pop() || `Source-${index}.txt`;
return {
id: (result.metadata?.["x-amz-bedrock-kb-chunk-id"] as string) || `chunk-${index}`,
fileName: fileName.replace(/_/g, " ").replace(".txt", ""),
snippet: result.content?.text || "",
score: (result.score as number) || 0,
};
})
.slice(0, 3);
const context = rawResults
.filter((res): res is { content: { text: string } } => res?.content?.text !== undefined)
.map(res => res.content.text)
.join("\n\n");
return {
context,
isRagWorking: true,
ragSources,
};
} catch (error) {
console.error("RAG Error:", error);
return { context: "", isRagWorking: false, ragSources: [] };
}
}
// Define the retrieval tool
const RETRIEVAL_TOOL: Tool = {
name: "retrieve_from_aws_kb",
description: "Performs retrieval from the AWS Knowledge Base using the provided query and Knowledge Base ID.",
inputSchema: {
type: "object",
properties: {
query: { type: "string", description: "The query to perform retrieval on" },
knowledgeBaseId: { type: "string", description: "The ID of the AWS Knowledge Base" },
n: { type: "number", default: 3, description: "Number of results to retrieve" },
},
required: ["query", "knowledgeBaseId"],
},
};
// Server setup
const server = new Server(
{
name: "aws-kb-retrieval-server",
version: "0.2.0",
},
{
capabilities: {
tools: {},
},
},
);
// Request handlers
server.setRequestHandler(ListToolsRequestSchema, async () => ({
tools: [RETRIEVAL_TOOL],
}));
server.setRequestHandler(CallToolRequestSchema, async (request) => {
const { name, arguments: args } = request.params;
if (name === "retrieve_from_aws_kb") {
const { query, knowledgeBaseId, n = 3 } = args as Record<string, any>;
try {
const result = await retrieveContext(query, knowledgeBaseId, n);
if (result.isRagWorking) {
return {
content: [
{ type: "text", text: `Context: ${result.context}` },
{ type: "text", text: `RAG Sources: ${JSON.stringify(result.ragSources)}` },
],
};
} else {
return {
content: [{ type: "text", text: "Retrieval failed or returned no results." }],
};
}
} catch (error) {
return {
content: [{ type: "text", text: `Error occurred: ${error}` }],
};
}
} else {
return {
content: [{ type: "text", text: `Unknown tool: ${name}` }],
isError: true,
};
}
});
// Server startup
async function runServer() {
const transport = new StdioServerTransport();
await server.connect(transport);
console.error("AWS KB Retrieval Server running on stdio");
}
runServer().catch((error) => {
console.error("Fatal error running server:", error);
process.exit(1);
});

View File

@@ -0,0 +1,30 @@
{
"name": "@modelcontextprotocol/server-aws-kb-retrieval",
"version": "0.6.2",
"description": "MCP server for AWS Knowledge Base retrieval using Bedrock Agent Runtime",
"license": "MIT",
"author": "Anthropic, PBC (https://anthropic.com)",
"homepage": "https://modelcontextprotocol.io",
"bugs": "https://github.com/modelcontextprotocol/servers/issues",
"type": "module",
"bin": {
"mcp-server-aws-kb-retrieval": "dist/index.js"
},
"files": [
"dist"
],
"scripts": {
"build": "tsc && shx chmod +x dist/*.js",
"prepare": "npm run build",
"watch": "tsc --watch"
},
"dependencies": {
"@modelcontextprotocol/sdk": "0.5.0",
"@aws-sdk/client-bedrock-agent-runtime": "^3.0.0"
},
"devDependencies": {
"@types/node": "^20.10.0",
"shx": "^0.3.4",
"typescript": "^5.6.2"
}
}

View File

@@ -0,0 +1,17 @@
{
"extends": "../../tsconfig.json",
"compilerOptions": {
"outDir": "./dist",
"rootDir": ".",
"composite": true,
"incremental": true,
"tsBuildInfoFile": "./dist/.tsbuildinfo"
},
"include": [
"./**/*.ts"
],
"exclude": [
"node_modules",
"dist"
]
}

View File

@@ -1,6 +1,6 @@
{ {
"name": "@modelcontextprotocol/server-brave-search", "name": "@modelcontextprotocol/server-brave-search",
"version": "0.5.2", "version": "0.6.2",
"description": "MCP server for Brave Search API integration", "description": "MCP server for Brave Search API integration",
"license": "MIT", "license": "MIT",
"author": "Anthropic, PBC (https://anthropic.com)", "author": "Anthropic, PBC (https://anthropic.com)",
@@ -19,11 +19,11 @@
"watch": "tsc --watch" "watch": "tsc --watch"
}, },
"dependencies": { "dependencies": {
"@modelcontextprotocol/sdk": "0.5.0" "@modelcontextprotocol/sdk": "1.0.1"
}, },
"devDependencies": { "devDependencies": {
"@types/node": "^20.10.0", "@types/node": "^20.10.0",
"shx": "^0.3.4", "shx": "^0.3.4",
"typescript": "^5.6.2" "typescript": "^5.6.2"
} }
} }

73
src/everart/README.md Normal file
View File

@@ -0,0 +1,73 @@
# EverArt MCP Server
Image generation server for Claude Desktop using EverArt's API.
## Install
```bash
npm install
export EVERART_API_KEY=your_key_here
```
## Config
Add to Claude Desktop config:
```json
{
"mcpServers": {
"everart": {
"command": "npx",
"args": ["-y", "@modelcontextprotocol/server-everart"],
"env": {
"EVERART_API_KEY": "your_key_here"
}
}
}
}
```
## Tools
### generate_image
Generates images with multiple model options. Opens result in browser and returns URL.
Parameters:
```typescript
{
prompt: string, // Image description
model?: string, // Model ID (default: "207910310772879360")
image_count?: number // Number of images (default: 1)
}
```
Models:
- 5000: FLUX1.1 (standard)
- 9000: FLUX1.1-ultra
- 6000: SD3.5
- 7000: Recraft-Real
- 8000: Recraft-Vector
All images generated at 1024x1024.
Sample usage:
```javascript
const result = await client.callTool({
name: "generate_image",
arguments: {
prompt: "A cat sitting elegantly",
model: "7000",
image_count: 1
}
});
```
Response format:
```
Image generated successfully!
The image has been opened in your default browser.
Generation details:
- Model: 7000
- Prompt: "A cat sitting elegantly"
- Image URL: https://storage.googleapis.com/...
You can also click the URL above to view the image again.
```

160
src/everart/index.ts Normal file
View File

@@ -0,0 +1,160 @@
#!/usr/bin/env node
import EverArt from "everart";
import { Server } from "@modelcontextprotocol/sdk/server/index.js";
import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio.js";
import {
CallToolRequestSchema,
ListToolsRequestSchema,
ListResourcesRequestSchema,
ReadResourceRequestSchema,
} from "@modelcontextprotocol/sdk/types.js";
import fetch from "node-fetch";
import open from "open";
const server = new Server(
{
name: "example-servers/everart",
version: "0.2.0",
},
{
capabilities: {
tools: {},
resources: {}, // Required for image resources
},
},
);
if (!process.env.EVERART_API_KEY) {
console.error("EVERART_API_KEY environment variable is not set");
process.exit(1);
}
const client = new EverArt.default(process.env.EVERART_API_KEY);
server.setRequestHandler(ListToolsRequestSchema, async () => ({
tools: [
{
name: "generate_image",
description:
"Generate images using EverArt Models and returns a clickable link to view the generated image. " +
"The tool will return a URL that can be clicked to view the image in a browser. " +
"Available models:\n" +
"- 5000:FLUX1.1: Standard quality\n" +
"- 9000:FLUX1.1-ultra: Ultra high quality\n" +
"- 6000:SD3.5: Stable Diffusion 3.5\n" +
"- 7000:Recraft-Real: Photorealistic style\n" +
"- 8000:Recraft-Vector: Vector art style\n" +
"\nThe response will contain a direct link to view the generated image.",
inputSchema: {
type: "object",
properties: {
prompt: {
type: "string",
description: "Text description of desired image",
},
model: {
type: "string",
description:
"Model ID (5000:FLUX1.1, 9000:FLUX1.1-ultra, 6000:SD3.5, 7000:Recraft-Real, 8000:Recraft-Vector)",
default: "5000",
},
image_count: {
type: "number",
description: "Number of images to generate",
default: 1,
},
},
required: ["prompt"],
},
},
],
}));
server.setRequestHandler(ListResourcesRequestSchema, async () => {
return {
resources: [
{
uri: "everart://images",
mimeType: "image/png",
name: "Generated Images",
},
],
};
});
server.setRequestHandler(ReadResourceRequestSchema, async (request) => {
if (request.params.uri === "everart://images") {
return {
contents: [
{
uri: "everart://images",
mimeType: "image/png",
blob: "", // Empty since this is just for listing
},
],
};
}
throw new Error("Resource not found");
});
server.setRequestHandler(CallToolRequestSchema, async (request) => {
if (request.params.name === "generate_image") {
try {
const {
prompt,
model = "207910310772879360",
image_count = 1,
} = request.params.arguments as any;
// Use correct EverArt API method
const generation = await client.v1.generations.create(
model,
prompt,
"txt2img",
{
imageCount: image_count,
height: 1024,
width: 1024,
},
);
// Wait for generation to complete
const completedGen = await client.v1.generations.fetchWithPolling(
generation[0].id,
);
const imgUrl = completedGen.image_url;
if (!imgUrl) throw new Error("No image URL");
// Automatically open the image URL in the default browser
await open(imgUrl);
// Return a formatted message with the clickable link
return {
content: [
{
type: "text",
text: `Image generated successfully!\nThe image has been opened in your default browser.\n\nGeneration details:\n- Model: ${model}\n- Prompt: "${prompt}"\n- Image URL: ${imgUrl}\n\nYou can also click the URL above to view the image again.`,
},
],
};
} catch (error: unknown) {
console.error("Detailed error:", error);
const errorMessage =
error instanceof Error ? error.message : "Unknown error";
return {
content: [{ type: "text", text: `Error: ${errorMessage}` }],
isError: true,
};
}
}
throw new Error(`Unknown tool: ${request.params.name}`);
});
async function runServer() {
const transport = new StdioServerTransport();
await server.connect(transport);
console.error("EverArt MCP Server running on stdio");
}
runServer().catch(console.error);

32
src/everart/package.json Normal file
View File

@@ -0,0 +1,32 @@
{
"name": "@modelcontextprotocol/server-everart",
"version": "0.6.2",
"description": "MCP server for EverArt API integration",
"license": "MIT",
"author": "Anthropic, PBC (https://anthropic.com)",
"homepage": "https://modelcontextprotocol.io",
"bugs": "https://github.com/modelcontextprotocol/servers/issues",
"type": "module",
"bin": {
"mcp-server-everart": "dist/index.js"
},
"files": [
"dist"
],
"scripts": {
"build": "tsc && shx chmod +x dist/*.js",
"prepare": "npm run build",
"watch": "tsc --watch"
},
"dependencies": {
"@modelcontextprotocol/sdk": "0.5.0",
"everart": "^1.0.0",
"node-fetch": "^3.3.2",
"open": "^9.1.0"
},
"devDependencies": {
"@types/node": "^20.11.0",
"shx": "^0.3.4",
"typescript": "^5.3.3"
}
}

10
src/everart/tsconfig.json Normal file
View File

@@ -0,0 +1,10 @@
{
"extends": "../../tsconfig.json",
"compilerOptions": {
"outDir": "./dist",
"rootDir": "."
},
"include": [
"./**/*.ts"
]
}

View File

@@ -1,6 +1,6 @@
{ {
"name": "@modelcontextprotocol/server-everything", "name": "@modelcontextprotocol/server-everything",
"version": "0.5.1", "version": "0.6.2",
"description": "MCP server that exercises all the features of the MCP protocol", "description": "MCP server that exercises all the features of the MCP protocol",
"license": "MIT", "license": "MIT",
"author": "Anthropic, PBC (https://anthropic.com)", "author": "Anthropic, PBC (https://anthropic.com)",
@@ -19,7 +19,7 @@
"watch": "tsc --watch" "watch": "tsc --watch"
}, },
"dependencies": { "dependencies": {
"@modelcontextprotocol/sdk": "0.5.0", "@modelcontextprotocol/sdk": "1.0.1",
"express": "^4.21.1", "express": "^4.21.1",
"zod": "^3.23.8", "zod": "^3.23.8",
"zod-to-json-schema": "^3.23.5" "zod-to-json-schema": "^3.23.5"
@@ -29,4 +29,4 @@
"shx": "^0.3.4", "shx": "^0.3.4",
"typescript": "^5.6.2" "typescript": "^5.6.2"
} }
} }

View File

@@ -1,6 +1,6 @@
[project] [project]
name = "mcp-server-fetch" name = "mcp-server-fetch"
version = "0.6.1" version = "0.6.2"
description = "A Model Context Protocol server providing tools to fetch and convert web content for usage by LLMs" description = "A Model Context Protocol server providing tools to fetch and convert web content for usage by LLMs"
readme = "README.md" readme = "README.md"
requires-python = ">=3.10" requires-python = ">=3.10"

View File

@@ -44,7 +44,7 @@ def extract_content_from_html(html: str) -> str:
return content return content
def get_robots_txt_url(url: AnyUrl | str) -> str: def get_robots_txt_url(url: str) -> str:
"""Get the robots.txt URL for a given website URL. """Get the robots.txt URL for a given website URL.
Args: Args:
@@ -54,7 +54,7 @@ def get_robots_txt_url(url: AnyUrl | str) -> str:
URL of the robots.txt file URL of the robots.txt file
""" """
# Parse the URL into components # Parse the URL into components
parsed = urlparse(str(url)) parsed = urlparse(url)
# Reconstruct the base URL with just scheme, netloc, and /robots.txt path # Reconstruct the base URL with just scheme, netloc, and /robots.txt path
robots_url = urlunparse((parsed.scheme, parsed.netloc, "/robots.txt", "", "", "")) robots_url = urlunparse((parsed.scheme, parsed.netloc, "/robots.txt", "", "", ""))
@@ -62,7 +62,7 @@ def get_robots_txt_url(url: AnyUrl | str) -> str:
return robots_url return robots_url
async def check_may_autonomously_fetch_url(url: AnyUrl | str, user_agent: str) -> None: async def check_may_autonomously_fetch_url(url: str, user_agent: str) -> None:
""" """
Check if the URL can be fetched by the user agent according to the robots.txt file. Check if the URL can be fetched by the user agent according to the robots.txt file.
Raises a McpError if not. Raises a McpError if not.
@@ -74,7 +74,9 @@ async def check_may_autonomously_fetch_url(url: AnyUrl | str, user_agent: str) -
async with AsyncClient() as client: async with AsyncClient() as client:
try: try:
response = await client.get( response = await client.get(
robot_txt_url, headers={"User-Agent": user_agent} robot_txt_url,
follow_redirects=True,
headers={"User-Agent": user_agent},
) )
except HTTPError: except HTTPError:
raise McpError( raise McpError(
@@ -93,7 +95,7 @@ async def check_may_autonomously_fetch_url(url: AnyUrl | str, user_agent: str) -
line for line in robot_txt.splitlines() if not line.strip().startswith("#") line for line in robot_txt.splitlines() if not line.strip().startswith("#")
) )
robot_parser = Protego.parse(processed_robot_txt) robot_parser = Protego.parse(processed_robot_txt)
if not robot_parser.can_fetch(url, user_agent): if not robot_parser.can_fetch(str(url), user_agent):
raise McpError( raise McpError(
INTERNAL_ERROR, INTERNAL_ERROR,
f"The sites robots.txt ({robot_txt_url}), specifies that autonomous fetching of this page is not allowed, " f"The sites robots.txt ({robot_txt_url}), specifies that autonomous fetching of this page is not allowed, "
@@ -106,7 +108,7 @@ async def check_may_autonomously_fetch_url(url: AnyUrl | str, user_agent: str) -
async def fetch_url( async def fetch_url(
url: AnyUrl | str, user_agent: str, force_raw: bool = False url: str, user_agent: str, force_raw: bool = False
) -> Tuple[str, str]: ) -> Tuple[str, str]:
""" """
Fetch the URL and return the content in a form ready for the LLM, as well as a prefix string with status information. Fetch the URL and return the content in a form ready for the LLM, as well as a prefix string with status information.
@@ -116,7 +118,7 @@ async def fetch_url(
async with AsyncClient() as client: async with AsyncClient() as client:
try: try:
response = await client.get( response = await client.get(
str(url), url,
follow_redirects=True, follow_redirects=True,
headers={"User-Agent": user_agent}, headers={"User-Agent": user_agent},
timeout=30, timeout=30,
@@ -221,7 +223,7 @@ Although originally you did not have internet access, and were advised to refuse
except ValueError as e: except ValueError as e:
raise McpError(INVALID_PARAMS, str(e)) raise McpError(INVALID_PARAMS, str(e))
url = args.url url = str(args.url)
if not url: if not url:
raise McpError(INVALID_PARAMS, "URL is required") raise McpError(INVALID_PARAMS, "URL is required")

2
src/fetch/uv.lock generated
View File

@@ -327,7 +327,7 @@ wheels = [
[[package]] [[package]]
name = "mcp-server-fetch" name = "mcp-server-fetch"
version = "0.1.3" version = "0.6.2"
source = { editable = "." } source = { editable = "." }
dependencies = [ dependencies = [
{ name = "markdownify" }, { name = "markdownify" },

View File

@@ -1,6 +1,6 @@
{ {
"name": "@modelcontextprotocol/server-filesystem", "name": "@modelcontextprotocol/server-filesystem",
"version": "0.5.1", "version": "0.6.2",
"description": "MCP server for filesystem access", "description": "MCP server for filesystem access",
"license": "MIT", "license": "MIT",
"author": "Anthropic, PBC (https://anthropic.com)", "author": "Anthropic, PBC (https://anthropic.com)",
@@ -19,7 +19,7 @@
"watch": "tsc --watch" "watch": "tsc --watch"
}, },
"dependencies": { "dependencies": {
"@modelcontextprotocol/sdk": "0.5.0", "@modelcontextprotocol/sdk": "1.0.1",
"glob": "^10.3.10", "glob": "^10.3.10",
"zod-to-json-schema": "^3.23.5" "zod-to-json-schema": "^3.23.5"
}, },
@@ -28,4 +28,4 @@
"shx": "^0.3.4", "shx": "^0.3.4",
"typescript": "^5.3.3" "typescript": "^5.3.3"
} }
} }

View File

@@ -1,6 +1,6 @@
{ {
"name": "@modelcontextprotocol/server-gdrive", "name": "@modelcontextprotocol/server-gdrive",
"version": "0.5.1", "version": "0.6.2",
"description": "MCP server for interacting with Google Drive", "description": "MCP server for interacting with Google Drive",
"license": "MIT", "license": "MIT",
"author": "Anthropic, PBC (https://anthropic.com)", "author": "Anthropic, PBC (https://anthropic.com)",
@@ -20,7 +20,7 @@
}, },
"dependencies": { "dependencies": {
"@google-cloud/local-auth": "^3.0.1", "@google-cloud/local-auth": "^3.0.1",
"@modelcontextprotocol/sdk": "0.5.0", "@modelcontextprotocol/sdk": "1.0.1",
"googleapis": "^144.0.0" "googleapis": "^144.0.0"
}, },
"devDependencies": { "devDependencies": {
@@ -28,4 +28,4 @@
"shx": "^0.3.4", "shx": "^0.3.4",
"typescript": "^5.6.2" "typescript": "^5.6.2"
} }
} }

View File

@@ -53,6 +53,13 @@ Please note that mcp-server-git is currently in early development. The functiona
- `max_count` (number, optional): Maximum number of commits to show (default: 10) - `max_count` (number, optional): Maximum number of commits to show (default: 10)
- Returns: Array of commit entries with hash, author, date, and message - Returns: Array of commit entries with hash, author, date, and message
8. `git_create_branch`
- Creates a new branch
- Inputs:
- `repo_path` (string): Path to Git repository
- `branch_name` (string): Name of the new branch
- `start_point` (string, optional): Starting point for the new branch
- Returns: Confirmation of branch creation
## Installation ## Installation
@@ -156,6 +163,29 @@ cd path/to/servers/src/git
npx @modelcontextprotocol/inspector uv run mcp-server-git npx @modelcontextprotocol/inspector uv run mcp-server-git
``` ```
Running `tail -n 20 -f ~/Library/Logs/Claude/mcp*.log` will show the logs from the server and may
help you debug any issues.
## Development
If you are doing local development, there are two ways to test your changes:
1. Run the MCP inspector to test your changes. See [Debugging](#debugging) for run instructions.
2. Test using the Claude desktop app. Add the following to your `claude_desktop_config.json`:
```json
"git": {
"command": "uv",
"args": [
"--directory",
"/<path to mcp-servers>/mcp-servers/src/git",
"run",
"mcp-server-git"
]
}
```
## License ## License
This MCP server is licensed under the MIT License. This means you are free to use, modify, and distribute the software, subject to the terms and conditions of the MIT License. For more details, please see the LICENSE file in the project repository. This MCP server is licensed under the MIT License. This means you are free to use, modify, and distribute the software, subject to the terms and conditions of the MIT License. For more details, please see the LICENSE file in the project repository.

View File

@@ -1,6 +1,6 @@
[project] [project]
name = "mcp-server-git" name = "mcp-server-git"
version = "0.6.1" version = "0.6.2"
description = "A Model Context Protocol server providing tools to read, search, and manipulate Git repositories programmatically via LLMs" description = "A Model Context Protocol server providing tools to read, search, and manipulate Git repositories programmatically via LLMs"
readme = "README.md" readme = "README.md"
requires-python = ">=3.10" requires-python = ">=3.10"

View File

@@ -39,6 +39,11 @@ class GitLog(BaseModel):
repo_path: str repo_path: str
max_count: int = 10 max_count: int = 10
class GitCreateBranch(BaseModel):
repo_path: str
branch_name: str
base_branch: str | None = None
class GitTools(str, Enum): class GitTools(str, Enum):
STATUS = "git_status" STATUS = "git_status"
DIFF_UNSTAGED = "git_diff_unstaged" DIFF_UNSTAGED = "git_diff_unstaged"
@@ -47,6 +52,7 @@ class GitTools(str, Enum):
ADD = "git_add" ADD = "git_add"
RESET = "git_reset" RESET = "git_reset"
LOG = "git_log" LOG = "git_log"
CREATE_BRANCH = "git_create_branch"
def git_status(repo: git.Repo) -> str: def git_status(repo: git.Repo) -> str:
return repo.git.status() return repo.git.status()
@@ -81,6 +87,15 @@ def git_log(repo: git.Repo, max_count: int = 10) -> list[str]:
) )
return log return log
def git_create_branch(repo: git.Repo, branch_name: str, base_branch: str | None = None) -> str:
if base_branch:
base = repo.refs[base_branch]
else:
base = repo.active_branch
repo.create_head(branch_name, base)
return f"Created branch '{branch_name}' from '{base.name}'"
async def serve(repository: Path | None) -> None: async def serve(repository: Path | None) -> None:
logger = logging.getLogger(__name__) logger = logging.getLogger(__name__)
@@ -132,6 +147,11 @@ async def serve(repository: Path | None) -> None:
description="Shows the commit logs", description="Shows the commit logs",
inputSchema=GitLog.schema(), inputSchema=GitLog.schema(),
), ),
Tool(
name=GitTools.CREATE_BRANCH,
description="Creates a new branch from an optional base branch",
inputSchema=GitCreateBranch.schema(),
),
] ]
async def list_repos() -> Sequence[str]: async def list_repos() -> Sequence[str]:
@@ -218,6 +238,17 @@ async def serve(repository: Path | None) -> None:
text="Commit history:\n" + "\n".join(log) text="Commit history:\n" + "\n".join(log)
)] )]
case GitTools.CREATE_BRANCH:
result = git_create_branch(
repo,
arguments["branch_name"],
arguments.get("base_branch")
)
return [TextContent(
type="text",
text=result
)]
case _: case _:
raise ValueError(f"Unknown tool: {name}") raise ValueError(f"Unknown tool: {name}")

10
src/git/uv.lock generated
View File

@@ -146,7 +146,7 @@ wheels = [
[[package]] [[package]]
name = "mcp" name = "mcp"
version = "0.9.1" version = "1.1.0"
source = { registry = "https://pypi.org/simple" } source = { registry = "https://pypi.org/simple" }
dependencies = [ dependencies = [
{ name = "anyio" }, { name = "anyio" },
@@ -156,14 +156,14 @@ dependencies = [
{ name = "sse-starlette" }, { name = "sse-starlette" },
{ name = "starlette" }, { name = "starlette" },
] ]
sdist = { url = "https://files.pythonhosted.org/packages/e7/1c/932818470ffd49c33509110c835101a8dc4c9cdd06028b9f647fb3dde237/mcp-0.9.1.tar.gz", hash = "sha256:e8509a37c2ab546095788ed170e0fb4d7ce0cf5a3ee56b6449c78af27321a425", size = 78218 } sdist = { url = "https://files.pythonhosted.org/packages/77/f2/067b1fc114e8d3ae4af02fc4f4ed8971a2c4900362d976fabe0f4e9a3418/mcp-1.1.0.tar.gz", hash = "sha256:e3c8d6df93a4de90230ea944dd667730744a3cd91a4cc0ee66a5acd53419e100", size = 83802 }
wheels = [ wheels = [
{ url = "https://files.pythonhosted.org/packages/b3/a0/2ee813d456b57a726d583868417d1ad900fbe12ee3c8cd866e3e804ca486/mcp-0.9.1-py3-none-any.whl", hash = "sha256:7f640fcfb0be486aa510594df309920ae1d375cdca1f8aff21db3a96d837f303", size = 31562 }, { url = "https://files.pythonhosted.org/packages/b9/3e/aef19ac08a6f9a347c086c4e628c2f7329659828cbe92ffd524ec2aac833/mcp-1.1.0-py3-none-any.whl", hash = "sha256:44aa4d2e541f0924d6c344aa7f96b427a6ee1df2fab70b5f9ae2f8777b3f05f2", size = 36576 },
] ]
[[package]] [[package]]
name = "mcp-server-git" name = "mcp-server-git"
version = "0.4.1" version = "0.6.2"
source = { editable = "." } source = { editable = "." }
dependencies = [ dependencies = [
{ name = "click" }, { name = "click" },
@@ -182,7 +182,7 @@ dev = [
requires-dist = [ requires-dist = [
{ name = "click", specifier = ">=8.1.7" }, { name = "click", specifier = ">=8.1.7" },
{ name = "gitpython", specifier = ">=3.1.43" }, { name = "gitpython", specifier = ">=3.1.43" },
{ name = "mcp", specifier = ">=0.6.0" }, { name = "mcp", specifier = ">=1.0.0" },
{ name = "pydantic", specifier = ">=2.0.0" }, { name = "pydantic", specifier = ">=2.0.0" },
] ]

View File

@@ -529,7 +529,7 @@ server.setRequestHandler(CallToolRequestSchema, async (request) => {
case "fork_repository": { case "fork_repository": {
const args = ForkRepositorySchema.parse(request.params.arguments); const args = ForkRepositorySchema.parse(request.params.arguments);
const fork = await forkRepository(args.owner, args.repo, args.organization); const fork = await forkRepository(args.owner, args.repo, args.organization);
return { toolResult: fork }; return { content: [{ type: "text", text: JSON.stringify(fork, null, 2) }] };
} }
case "create_branch": { case "create_branch": {
@@ -562,25 +562,25 @@ server.setRequestHandler(CallToolRequestSchema, async (request) => {
sha sha
}); });
return { toolResult: branch }; return { content: [{ type: "text", text: JSON.stringify(branch, null, 2) }] };
} }
case "search_repositories": { case "search_repositories": {
const args = SearchRepositoriesSchema.parse(request.params.arguments); const args = SearchRepositoriesSchema.parse(request.params.arguments);
const results = await searchRepositories(args.query, args.page, args.perPage); const results = await searchRepositories(args.query, args.page, args.perPage);
return { toolResult: results }; return { content: [{ type: "text", text: JSON.stringify(results, null, 2) }] };
} }
case "create_repository": { case "create_repository": {
const args = CreateRepositorySchema.parse(request.params.arguments); const args = CreateRepositorySchema.parse(request.params.arguments);
const repository = await createRepository(args); const repository = await createRepository(args);
return { toolResult: repository }; return { content: [{ type: "text", text: JSON.stringify(repository, null, 2) }] };
} }
case "get_file_contents": { case "get_file_contents": {
const args = GetFileContentsSchema.parse(request.params.arguments); const args = GetFileContentsSchema.parse(request.params.arguments);
const contents = await getFileContents(args.owner, args.repo, args.path, args.branch); const contents = await getFileContents(args.owner, args.repo, args.path, args.branch);
return { toolResult: contents }; return { content: [{ type: "text", text: JSON.stringify(contents, null, 2) }] };
} }
case "create_or_update_file": { case "create_or_update_file": {
@@ -594,7 +594,7 @@ server.setRequestHandler(CallToolRequestSchema, async (request) => {
args.branch, args.branch,
args.sha args.sha
); );
return { toolResult: result }; return { content: [{ type: "text", text: JSON.stringify(result, null, 2) }] };
} }
case "push_files": { case "push_files": {
@@ -606,21 +606,21 @@ server.setRequestHandler(CallToolRequestSchema, async (request) => {
args.files, args.files,
args.message args.message
); );
return { toolResult: result }; return { content: [{ type: "text", text: JSON.stringify(result, null, 2) }] };
} }
case "create_issue": { case "create_issue": {
const args = CreateIssueSchema.parse(request.params.arguments); const args = CreateIssueSchema.parse(request.params.arguments);
const { owner, repo, ...options } = args; const { owner, repo, ...options } = args;
const issue = await createIssue(owner, repo, options); const issue = await createIssue(owner, repo, options);
return { toolResult: issue }; return { content: [{ type: "text", text: JSON.stringify(issue, null, 2) }] };
} }
case "create_pull_request": { case "create_pull_request": {
const args = CreatePullRequestSchema.parse(request.params.arguments); const args = CreatePullRequestSchema.parse(request.params.arguments);
const { owner, repo, ...options } = args; const { owner, repo, ...options } = args;
const pullRequest = await createPullRequest(owner, repo, options); const pullRequest = await createPullRequest(owner, repo, options);
return { toolResult: pullRequest }; return { content: [{ type: "text", text: JSON.stringify(pullRequest, null, 2) }] };
} }
default: default:

View File

@@ -1,551 +0,0 @@
{
"name": "@modelcontextprotocol/server-github",
"version": "0.2.0",
"lockfileVersion": 3,
"requires": true,
"packages": {
"": {
"name": "@modelcontextprotocol/server-github",
"version": "0.2.0",
"license": "MIT",
"dependencies": {
"@modelcontextprotocol/sdk": "0.6.0",
"@types/node-fetch": "^2.6.12",
"node-fetch": "^3.3.2"
},
"bin": {
"mcp-server-github": "dist/index.js"
},
"devDependencies": {
"shx": "^0.3.4",
"typescript": "^5.6.2"
}
},
"node_modules/@modelcontextprotocol/sdk": {
"version": "0.6.0",
"resolved": "https://registry.npmjs.org/@modelcontextprotocol/sdk/-/sdk-0.6.0.tgz",
"integrity": "sha512-9rsDudGhDtMbvxohPoMMyAUOmEzQsOK+XFchh6gZGqo8sx9sBuZQs+CUttXqa8RZXKDaJRCN2tUtgGof7jRkkw==",
"dependencies": {
"content-type": "^1.0.5",
"raw-body": "^3.0.0",
"zod": "^3.23.8"
}
},
"node_modules/@types/node": {
"version": "22.9.1",
"resolved": "https://registry.npmjs.org/@types/node/-/node-22.9.1.tgz",
"integrity": "sha512-p8Yy/8sw1caA8CdRIQBG5tiLHmxtQKObCijiAa9Ez+d4+PRffM4054xbju0msf+cvhJpnFEeNjxmVT/0ipktrg==",
"dependencies": {
"undici-types": "~6.19.8"
}
},
"node_modules/@types/node-fetch": {
"version": "2.6.12",
"resolved": "https://registry.npmjs.org/@types/node-fetch/-/node-fetch-2.6.12.tgz",
"integrity": "sha512-8nneRWKCg3rMtF69nLQJnOYUcbafYeFSjqkw3jCRLsqkWFlHaoQrr5mXmofFGOx3DKn7UfmBMyov8ySvLRVldA==",
"dependencies": {
"@types/node": "*",
"form-data": "^4.0.0"
}
},
"node_modules/asynckit": {
"version": "0.4.0",
"resolved": "https://registry.npmjs.org/asynckit/-/asynckit-0.4.0.tgz",
"integrity": "sha512-Oei9OH4tRh0YqU3GxhX79dM/mwVgvbZJaSNaRk+bshkj0S5cfHcgYakreBjrHwatXKbz+IoIdYLxrKim2MjW0Q=="
},
"node_modules/balanced-match": {
"version": "1.0.2",
"resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz",
"integrity": "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==",
"dev": true
},
"node_modules/brace-expansion": {
"version": "1.1.11",
"resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz",
"integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==",
"dev": true,
"dependencies": {
"balanced-match": "^1.0.0",
"concat-map": "0.0.1"
}
},
"node_modules/bytes": {
"version": "3.1.2",
"resolved": "https://registry.npmjs.org/bytes/-/bytes-3.1.2.tgz",
"integrity": "sha512-/Nf7TyzTx6S3yRJObOAV7956r8cr2+Oj8AC5dt8wSP3BQAoeX58NoHyCU8P8zGkNXStjTSi6fzO6F0pBdcYbEg==",
"engines": {
"node": ">= 0.8"
}
},
"node_modules/combined-stream": {
"version": "1.0.8",
"resolved": "https://registry.npmjs.org/combined-stream/-/combined-stream-1.0.8.tgz",
"integrity": "sha512-FQN4MRfuJeHf7cBbBMJFXhKSDq+2kAArBlmRBvcvFE5BB1HZKXtSFASDhdlz9zOYwxh8lDdnvmMOe/+5cdoEdg==",
"dependencies": {
"delayed-stream": "~1.0.0"
},
"engines": {
"node": ">= 0.8"
}
},
"node_modules/concat-map": {
"version": "0.0.1",
"resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz",
"integrity": "sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg==",
"dev": true
},
"node_modules/content-type": {
"version": "1.0.5",
"resolved": "https://registry.npmjs.org/content-type/-/content-type-1.0.5.tgz",
"integrity": "sha512-nTjqfcBFEipKdXCv4YDQWCfmcLZKm81ldF0pAopTvyrFGVbcR6P/VAAd5G7N+0tTr8QqiU0tFadD6FK4NtJwOA==",
"engines": {
"node": ">= 0.6"
}
},
"node_modules/data-uri-to-buffer": {
"version": "4.0.1",
"resolved": "https://registry.npmjs.org/data-uri-to-buffer/-/data-uri-to-buffer-4.0.1.tgz",
"integrity": "sha512-0R9ikRb668HB7QDxT1vkpuUBtqc53YyAwMwGeUFKRojY/NWKvdZ+9UYtRfGmhqNbRkTSVpMbmyhXipFFv2cb/A==",
"engines": {
"node": ">= 12"
}
},
"node_modules/delayed-stream": {
"version": "1.0.0",
"resolved": "https://registry.npmjs.org/delayed-stream/-/delayed-stream-1.0.0.tgz",
"integrity": "sha512-ZySD7Nf91aLB0RxL4KGrKHBXl7Eds1DAmEdcoVawXnLD7SDhpNgtuII2aAkg7a7QS41jxPSZ17p4VdGnMHk3MQ==",
"engines": {
"node": ">=0.4.0"
}
},
"node_modules/depd": {
"version": "2.0.0",
"resolved": "https://registry.npmjs.org/depd/-/depd-2.0.0.tgz",
"integrity": "sha512-g7nH6P6dyDioJogAAGprGpCtVImJhpPk/roCzdb3fIh61/s/nPsfR6onyMwkCAR/OlC3yBC0lESvUoQEAssIrw==",
"engines": {
"node": ">= 0.8"
}
},
"node_modules/fetch-blob": {
"version": "3.2.0",
"resolved": "https://registry.npmjs.org/fetch-blob/-/fetch-blob-3.2.0.tgz",
"integrity": "sha512-7yAQpD2UMJzLi1Dqv7qFYnPbaPx7ZfFK6PiIxQ4PfkGPyNyl2Ugx+a/umUonmKqjhM4DnfbMvdX6otXq83soQQ==",
"funding": [
{
"type": "github",
"url": "https://github.com/sponsors/jimmywarting"
},
{
"type": "paypal",
"url": "https://paypal.me/jimmywarting"
}
],
"dependencies": {
"node-domexception": "^1.0.0",
"web-streams-polyfill": "^3.0.3"
},
"engines": {
"node": "^12.20 || >= 14.13"
}
},
"node_modules/form-data": {
"version": "4.0.1",
"resolved": "https://registry.npmjs.org/form-data/-/form-data-4.0.1.tgz",
"integrity": "sha512-tzN8e4TX8+kkxGPK8D5u0FNmjPUjw3lwC9lSLxxoB/+GtsJG91CO8bSWy73APlgAZzZbXEYZJuxjkHH2w+Ezhw==",
"dependencies": {
"asynckit": "^0.4.0",
"combined-stream": "^1.0.8",
"mime-types": "^2.1.12"
},
"engines": {
"node": ">= 6"
}
},
"node_modules/formdata-polyfill": {
"version": "4.0.10",
"resolved": "https://registry.npmjs.org/formdata-polyfill/-/formdata-polyfill-4.0.10.tgz",
"integrity": "sha512-buewHzMvYL29jdeQTVILecSaZKnt/RJWjoZCF5OW60Z67/GmSLBkOFM7qh1PI3zFNtJbaZL5eQu1vLfazOwj4g==",
"dependencies": {
"fetch-blob": "^3.1.2"
},
"engines": {
"node": ">=12.20.0"
}
},
"node_modules/fs.realpath": {
"version": "1.0.0",
"resolved": "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz",
"integrity": "sha512-OO0pH2lK6a0hZnAdau5ItzHPI6pUlvI7jMVnxUQRtw4owF2wk8lOSabtGDCTP4Ggrg2MbGnWO9X8K1t4+fGMDw==",
"dev": true
},
"node_modules/function-bind": {
"version": "1.1.2",
"resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.2.tgz",
"integrity": "sha512-7XHNxH7qX9xG5mIwxkhumTox/MIRNcOgDrxWsMt2pAr23WHp6MrRlN7FBSFpCpr+oVO0F744iUgR82nJMfG2SA==",
"dev": true,
"funding": {
"url": "https://github.com/sponsors/ljharb"
}
},
"node_modules/glob": {
"version": "7.2.3",
"resolved": "https://registry.npmjs.org/glob/-/glob-7.2.3.tgz",
"integrity": "sha512-nFR0zLpU2YCaRxwoCJvL6UvCH2JFyFVIvwTLsIf21AuHlMskA1hhTdk+LlYJtOlYt9v6dvszD2BGRqBL+iQK9Q==",
"deprecated": "Glob versions prior to v9 are no longer supported",
"dev": true,
"dependencies": {
"fs.realpath": "^1.0.0",
"inflight": "^1.0.4",
"inherits": "2",
"minimatch": "^3.1.1",
"once": "^1.3.0",
"path-is-absolute": "^1.0.0"
},
"engines": {
"node": "*"
},
"funding": {
"url": "https://github.com/sponsors/isaacs"
}
},
"node_modules/hasown": {
"version": "2.0.2",
"resolved": "https://registry.npmjs.org/hasown/-/hasown-2.0.2.tgz",
"integrity": "sha512-0hJU9SCPvmMzIBdZFqNPXWa6dqh7WdH0cII9y+CyS8rG3nL48Bclra9HmKhVVUHyPWNH5Y7xDwAB7bfgSjkUMQ==",
"dev": true,
"dependencies": {
"function-bind": "^1.1.2"
},
"engines": {
"node": ">= 0.4"
}
},
"node_modules/http-errors": {
"version": "2.0.0",
"resolved": "https://registry.npmjs.org/http-errors/-/http-errors-2.0.0.tgz",
"integrity": "sha512-FtwrG/euBzaEjYeRqOgly7G0qviiXoJWnvEH2Z1plBdXgbyjv34pHTSb9zoeHMyDy33+DWy5Wt9Wo+TURtOYSQ==",
"dependencies": {
"depd": "2.0.0",
"inherits": "2.0.4",
"setprototypeof": "1.2.0",
"statuses": "2.0.1",
"toidentifier": "1.0.1"
},
"engines": {
"node": ">= 0.8"
}
},
"node_modules/iconv-lite": {
"version": "0.6.3",
"resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.6.3.tgz",
"integrity": "sha512-4fCk79wshMdzMp2rH06qWrJE4iolqLhCUH+OiuIgU++RB0+94NlDL81atO7GX55uUKueo0txHNtvEyI6D7WdMw==",
"dependencies": {
"safer-buffer": ">= 2.1.2 < 3.0.0"
},
"engines": {
"node": ">=0.10.0"
}
},
"node_modules/inflight": {
"version": "1.0.6",
"resolved": "https://registry.npmjs.org/inflight/-/inflight-1.0.6.tgz",
"integrity": "sha512-k92I/b08q4wvFscXCLvqfsHCrjrF7yiXsQuIVvVE7N82W3+aqpzuUdBbfhWcy/FZR3/4IgflMgKLOsvPDrGCJA==",
"deprecated": "This module is not supported, and leaks memory. Do not use it. Check out lru-cache if you want a good and tested way to coalesce async requests by a key value, which is much more comprehensive and powerful.",
"dev": true,
"dependencies": {
"once": "^1.3.0",
"wrappy": "1"
}
},
"node_modules/inherits": {
"version": "2.0.4",
"resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz",
"integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ=="
},
"node_modules/interpret": {
"version": "1.4.0",
"resolved": "https://registry.npmjs.org/interpret/-/interpret-1.4.0.tgz",
"integrity": "sha512-agE4QfB2Lkp9uICn7BAqoscw4SZP9kTE2hxiFI3jBPmXJfdqiahTbUuKGsMoN2GtqL9AxhYioAcVvgsb1HvRbA==",
"dev": true,
"engines": {
"node": ">= 0.10"
}
},
"node_modules/is-core-module": {
"version": "2.15.1",
"resolved": "https://registry.npmjs.org/is-core-module/-/is-core-module-2.15.1.tgz",
"integrity": "sha512-z0vtXSwucUJtANQWldhbtbt7BnL0vxiFjIdDLAatwhDYty2bad6s+rijD6Ri4YuYJubLzIJLUidCh09e1djEVQ==",
"dev": true,
"dependencies": {
"hasown": "^2.0.2"
},
"engines": {
"node": ">= 0.4"
},
"funding": {
"url": "https://github.com/sponsors/ljharb"
}
},
"node_modules/mime-db": {
"version": "1.52.0",
"resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.52.0.tgz",
"integrity": "sha512-sPU4uV7dYlvtWJxwwxHD0PuihVNiE7TyAbQ5SWxDCB9mUYvOgroQOwYQQOKPJ8CIbE+1ETVlOoK1UC2nU3gYvg==",
"engines": {
"node": ">= 0.6"
}
},
"node_modules/mime-types": {
"version": "2.1.35",
"resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.35.tgz",
"integrity": "sha512-ZDY+bPm5zTTF+YpCrAU9nK0UgICYPT0QtT1NZWFv4s++TNkcgVaT0g6+4R2uI4MjQjzysHB1zxuWL50hzaeXiw==",
"dependencies": {
"mime-db": "1.52.0"
},
"engines": {
"node": ">= 0.6"
}
},
"node_modules/minimatch": {
"version": "3.1.2",
"resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz",
"integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==",
"dev": true,
"dependencies": {
"brace-expansion": "^1.1.7"
},
"engines": {
"node": "*"
}
},
"node_modules/minimist": {
"version": "1.2.8",
"resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.8.tgz",
"integrity": "sha512-2yyAR8qBkN3YuheJanUpWC5U3bb5osDywNB8RzDVlDwDHbocAJveqqj1u8+SVD7jkWT4yvsHCpWqqWqAxb0zCA==",
"dev": true,
"funding": {
"url": "https://github.com/sponsors/ljharb"
}
},
"node_modules/node-domexception": {
"version": "1.0.0",
"resolved": "https://registry.npmjs.org/node-domexception/-/node-domexception-1.0.0.tgz",
"integrity": "sha512-/jKZoMpw0F8GRwl4/eLROPA3cfcXtLApP0QzLmUT/HuPCZWyB7IY9ZrMeKw2O/nFIqPQB3PVM9aYm0F312AXDQ==",
"funding": [
{
"type": "github",
"url": "https://github.com/sponsors/jimmywarting"
},
{
"type": "github",
"url": "https://paypal.me/jimmywarting"
}
],
"engines": {
"node": ">=10.5.0"
}
},
"node_modules/node-fetch": {
"version": "3.3.2",
"resolved": "https://registry.npmjs.org/node-fetch/-/node-fetch-3.3.2.tgz",
"integrity": "sha512-dRB78srN/l6gqWulah9SrxeYnxeddIG30+GOqK/9OlLVyLg3HPnr6SqOWTWOXKRwC2eGYCkZ59NNuSgvSrpgOA==",
"dependencies": {
"data-uri-to-buffer": "^4.0.0",
"fetch-blob": "^3.1.4",
"formdata-polyfill": "^4.0.10"
},
"engines": {
"node": "^12.20.0 || ^14.13.1 || >=16.0.0"
},
"funding": {
"type": "opencollective",
"url": "https://opencollective.com/node-fetch"
}
},
"node_modules/once": {
"version": "1.4.0",
"resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz",
"integrity": "sha512-lNaJgI+2Q5URQBkccEKHTQOPaXdUxnZZElQTZY0MFUAuaEqe1E+Nyvgdz/aIyNi6Z9MzO5dv1H8n58/GELp3+w==",
"dev": true,
"dependencies": {
"wrappy": "1"
}
},
"node_modules/path-is-absolute": {
"version": "1.0.1",
"resolved": "https://registry.npmjs.org/path-is-absolute/-/path-is-absolute-1.0.1.tgz",
"integrity": "sha512-AVbw3UJ2e9bq64vSaS9Am0fje1Pa8pbGqTTsmXfaIiMpnr5DlDhfJOuLj9Sf95ZPVDAUerDfEk88MPmPe7UCQg==",
"dev": true,
"engines": {
"node": ">=0.10.0"
}
},
"node_modules/path-parse": {
"version": "1.0.7",
"resolved": "https://registry.npmjs.org/path-parse/-/path-parse-1.0.7.tgz",
"integrity": "sha512-LDJzPVEEEPR+y48z93A0Ed0yXb8pAByGWo/k5YYdYgpY2/2EsOsksJrq7lOHxryrVOn1ejG6oAp8ahvOIQD8sw==",
"dev": true
},
"node_modules/raw-body": {
"version": "3.0.0",
"resolved": "https://registry.npmjs.org/raw-body/-/raw-body-3.0.0.tgz",
"integrity": "sha512-RmkhL8CAyCRPXCE28MMH0z2PNWQBNk2Q09ZdxM9IOOXwxwZbN+qbWaatPkdkWIKL2ZVDImrN/pK5HTRz2PcS4g==",
"dependencies": {
"bytes": "3.1.2",
"http-errors": "2.0.0",
"iconv-lite": "0.6.3",
"unpipe": "1.0.0"
},
"engines": {
"node": ">= 0.8"
}
},
"node_modules/rechoir": {
"version": "0.6.2",
"resolved": "https://registry.npmjs.org/rechoir/-/rechoir-0.6.2.tgz",
"integrity": "sha512-HFM8rkZ+i3zrV+4LQjwQ0W+ez98pApMGM3HUrN04j3CqzPOzl9nmP15Y8YXNm8QHGv/eacOVEjqhmWpkRV0NAw==",
"dev": true,
"dependencies": {
"resolve": "^1.1.6"
},
"engines": {
"node": ">= 0.10"
}
},
"node_modules/resolve": {
"version": "1.22.8",
"resolved": "https://registry.npmjs.org/resolve/-/resolve-1.22.8.tgz",
"integrity": "sha512-oKWePCxqpd6FlLvGV1VU0x7bkPmmCNolxzjMf4NczoDnQcIWrAF+cPtZn5i6n+RfD2d9i0tzpKnG6Yk168yIyw==",
"dev": true,
"dependencies": {
"is-core-module": "^2.13.0",
"path-parse": "^1.0.7",
"supports-preserve-symlinks-flag": "^1.0.0"
},
"bin": {
"resolve": "bin/resolve"
},
"funding": {
"url": "https://github.com/sponsors/ljharb"
}
},
"node_modules/safer-buffer": {
"version": "2.1.2",
"resolved": "https://registry.npmjs.org/safer-buffer/-/safer-buffer-2.1.2.tgz",
"integrity": "sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg=="
},
"node_modules/setprototypeof": {
"version": "1.2.0",
"resolved": "https://registry.npmjs.org/setprototypeof/-/setprototypeof-1.2.0.tgz",
"integrity": "sha512-E5LDX7Wrp85Kil5bhZv46j8jOeboKq5JMmYM3gVGdGH8xFpPWXUMsNrlODCrkoxMEeNi/XZIwuRvY4XNwYMJpw=="
},
"node_modules/shelljs": {
"version": "0.8.5",
"resolved": "https://registry.npmjs.org/shelljs/-/shelljs-0.8.5.tgz",
"integrity": "sha512-TiwcRcrkhHvbrZbnRcFYMLl30Dfov3HKqzp5tO5b4pt6G/SezKcYhmDg15zXVBswHmctSAQKznqNW2LO5tTDow==",
"dev": true,
"dependencies": {
"glob": "^7.0.0",
"interpret": "^1.0.0",
"rechoir": "^0.6.2"
},
"bin": {
"shjs": "bin/shjs"
},
"engines": {
"node": ">=4"
}
},
"node_modules/shx": {
"version": "0.3.4",
"resolved": "https://registry.npmjs.org/shx/-/shx-0.3.4.tgz",
"integrity": "sha512-N6A9MLVqjxZYcVn8hLmtneQWIJtp8IKzMP4eMnx+nqkvXoqinUPCbUFLp2UcWTEIUONhlk0ewxr/jaVGlc+J+g==",
"dev": true,
"dependencies": {
"minimist": "^1.2.3",
"shelljs": "^0.8.5"
},
"bin": {
"shx": "lib/cli.js"
},
"engines": {
"node": ">=6"
}
},
"node_modules/statuses": {
"version": "2.0.1",
"resolved": "https://registry.npmjs.org/statuses/-/statuses-2.0.1.tgz",
"integrity": "sha512-RwNA9Z/7PrK06rYLIzFMlaF+l73iwpzsqRIFgbMLbTcLD6cOao82TaWefPXQvB2fOC4AjuYSEndS7N/mTCbkdQ==",
"engines": {
"node": ">= 0.8"
}
},
"node_modules/supports-preserve-symlinks-flag": {
"version": "1.0.0",
"resolved": "https://registry.npmjs.org/supports-preserve-symlinks-flag/-/supports-preserve-symlinks-flag-1.0.0.tgz",
"integrity": "sha512-ot0WnXS9fgdkgIcePe6RHNk1WA8+muPa6cSjeR3V8K27q9BB1rTE3R1p7Hv0z1ZyAc8s6Vvv8DIyWf681MAt0w==",
"dev": true,
"engines": {
"node": ">= 0.4"
},
"funding": {
"url": "https://github.com/sponsors/ljharb"
}
},
"node_modules/toidentifier": {
"version": "1.0.1",
"resolved": "https://registry.npmjs.org/toidentifier/-/toidentifier-1.0.1.tgz",
"integrity": "sha512-o5sSPKEkg/DIQNmH43V0/uerLrpzVedkUh8tGNvaeXpfpuwjKenlSox/2O/BTlZUtEe+JG7s5YhEz608PlAHRA==",
"engines": {
"node": ">=0.6"
}
},
"node_modules/typescript": {
"version": "5.6.3",
"resolved": "https://registry.npmjs.org/typescript/-/typescript-5.6.3.tgz",
"integrity": "sha512-hjcS1mhfuyi4WW8IWtjP7brDrG2cuDZukyrYrSauoXGNgx0S7zceP07adYkJycEr56BOUTNPzbInooiN3fn1qw==",
"dev": true,
"bin": {
"tsc": "bin/tsc",
"tsserver": "bin/tsserver"
},
"engines": {
"node": ">=14.17"
}
},
"node_modules/undici-types": {
"version": "6.19.8",
"resolved": "https://registry.npmjs.org/undici-types/-/undici-types-6.19.8.tgz",
"integrity": "sha512-ve2KP6f/JnbPBFyobGHuerC9g1FYGn/F8n1LWTwNxCEzd6IfqTwUQcNXgEtmmQ6DlRrC1hrSrBnCZPokRrDHjw=="
},
"node_modules/unpipe": {
"version": "1.0.0",
"resolved": "https://registry.npmjs.org/unpipe/-/unpipe-1.0.0.tgz",
"integrity": "sha512-pjy2bYhSsufwWlKwPc+l3cN7+wuJlK6uz0YdJEOlQDbl6jo/YlPi4mb8agUkVC8BF7V8NuzeyPNqRksA3hztKQ==",
"engines": {
"node": ">= 0.8"
}
},
"node_modules/web-streams-polyfill": {
"version": "3.3.3",
"resolved": "https://registry.npmjs.org/web-streams-polyfill/-/web-streams-polyfill-3.3.3.tgz",
"integrity": "sha512-d2JWLCivmZYTSIoge9MsgFCZrt571BikcWGYkjC1khllbTeDlGqZ2D8vD8E/lJa8WGWbb7Plm8/XJYV7IJHZZw==",
"engines": {
"node": ">= 8"
}
},
"node_modules/wrappy": {
"version": "1.0.2",
"resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz",
"integrity": "sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ==",
"dev": true
},
"node_modules/zod": {
"version": "3.23.8",
"resolved": "https://registry.npmjs.org/zod/-/zod-3.23.8.tgz",
"integrity": "sha512-XBx9AXhXktjUqnepgTiE5flcKIYWi/rme0Eaj+5Y0lftuGBq+jyRu/md4WnuxqgP1ubdpNCsYEYPxrzVHD8d6g==",
"funding": {
"url": "https://github.com/sponsors/colinhacks"
}
}
}
}

View File

@@ -1,6 +1,6 @@
{ {
"name": "@modelcontextprotocol/server-github", "name": "@modelcontextprotocol/server-github",
"version": "0.5.1", "version": "0.6.2",
"description": "MCP server for using the GitHub API", "description": "MCP server for using the GitHub API",
"license": "MIT", "license": "MIT",
"author": "Anthropic, PBC (https://anthropic.com)", "author": "Anthropic, PBC (https://anthropic.com)",
@@ -19,7 +19,7 @@
"watch": "tsc --watch" "watch": "tsc --watch"
}, },
"dependencies": { "dependencies": {
"@modelcontextprotocol/sdk": "0.6.0", "@modelcontextprotocol/sdk": "1.0.1",
"@types/node-fetch": "^2.6.12", "@types/node-fetch": "^2.6.12",
"node-fetch": "^3.3.2", "node-fetch": "^3.3.2",
"zod-to-json-schema": "^3.23.5" "zod-to-json-schema": "^3.23.5"
@@ -28,4 +28,4 @@
"shx": "^0.3.4", "shx": "^0.3.4",
"typescript": "^5.6.2" "typescript": "^5.6.2"
} }
} }

View File

@@ -437,7 +437,7 @@ server.setRequestHandler(CallToolRequestSchema, async (request) => {
case "fork_repository": { case "fork_repository": {
const args = ForkRepositorySchema.parse(request.params.arguments); const args = ForkRepositorySchema.parse(request.params.arguments);
const fork = await forkProject(args.project_id, args.namespace); const fork = await forkProject(args.project_id, args.namespace);
return { toolResult: fork }; return { content: [{ type: "text", text: JSON.stringify(fork, null, 2) }] };
} }
case "create_branch": { case "create_branch": {
@@ -452,25 +452,25 @@ server.setRequestHandler(CallToolRequestSchema, async (request) => {
ref ref
}); });
return { toolResult: branch }; return { content: [{ type: "text", text: JSON.stringify(branch, null, 2) }] };
} }
case "search_repositories": { case "search_repositories": {
const args = SearchRepositoriesSchema.parse(request.params.arguments); const args = SearchRepositoriesSchema.parse(request.params.arguments);
const results = await searchProjects(args.search, args.page, args.per_page); const results = await searchProjects(args.search, args.page, args.per_page);
return { toolResult: results }; return { content: [{ type: "text", text: JSON.stringify(results, null, 2) }] };
} }
case "create_repository": { case "create_repository": {
const args = CreateRepositorySchema.parse(request.params.arguments); const args = CreateRepositorySchema.parse(request.params.arguments);
const repository = await createRepository(args); const repository = await createRepository(args);
return { toolResult: repository }; return { content: [{ type: "text", text: JSON.stringify(repository, null, 2) }] };
} }
case "get_file_contents": { case "get_file_contents": {
const args = GetFileContentsSchema.parse(request.params.arguments); const args = GetFileContentsSchema.parse(request.params.arguments);
const contents = await getFileContents(args.project_id, args.file_path, args.ref); const contents = await getFileContents(args.project_id, args.file_path, args.ref);
return { toolResult: contents }; return { content: [{ type: "text", text: JSON.stringify(contents, null, 2) }] };
} }
case "create_or_update_file": { case "create_or_update_file": {
@@ -483,7 +483,7 @@ server.setRequestHandler(CallToolRequestSchema, async (request) => {
args.branch, args.branch,
args.previous_path args.previous_path
); );
return { toolResult: result }; return { content: [{ type: "text", text: JSON.stringify(result, null, 2) }] };
} }
case "push_files": { case "push_files": {
@@ -494,21 +494,21 @@ server.setRequestHandler(CallToolRequestSchema, async (request) => {
args.branch, args.branch,
args.files.map(f => ({ path: f.file_path, content: f.content })) args.files.map(f => ({ path: f.file_path, content: f.content }))
); );
return { toolResult: result }; return { content: [{ type: "text", text: JSON.stringify(result, null, 2) }] };
} }
case "create_issue": { case "create_issue": {
const args = CreateIssueSchema.parse(request.params.arguments); const args = CreateIssueSchema.parse(request.params.arguments);
const { project_id, ...options } = args; const { project_id, ...options } = args;
const issue = await createIssue(project_id, options); const issue = await createIssue(project_id, options);
return { toolResult: issue }; return { content: [{ type: "text", text: JSON.stringify(issue, null, 2) }] };
} }
case "create_merge_request": { case "create_merge_request": {
const args = CreateMergeRequestSchema.parse(request.params.arguments); const args = CreateMergeRequestSchema.parse(request.params.arguments);
const { project_id, ...options } = args; const { project_id, ...options } = args;
const mergeRequest = await createMergeRequest(project_id, options); const mergeRequest = await createMergeRequest(project_id, options);
return { toolResult: mergeRequest }; return { content: [{ type: "text", text: JSON.stringify(mergeRequest, null, 2) }] };
} }
default: default:

View File

@@ -1,551 +0,0 @@
{
"name": "@modelcontextprotocol/server-gitlab",
"version": "0.5.1",
"lockfileVersion": 1,
"requires": true,
"packages": {
"": {
"name": "@modelcontextprotocol/server-gitlab",
"version": "0.5.1",
"license": "MIT",
"dependencies": {
"@modelcontextprotocol/sdk": "0.6.0",
"@types/node-fetch": "^2.6.12",
"node-fetch": "^3.3.2"
},
"bin": {
"mcp-server-gitlab": "dist/index.js"
},
"devDependencies": {
"shx": "^0.3.4",
"typescript": "^5.6.2"
}
},
"node_modules/@modelcontextprotocol/sdk": {
"version": "0.6.0",
"resolved": "https://registry.npmjs.org/@modelcontextprotocol/sdk/-/sdk-0.6.0.tgz",
"integrity": "sha512-9rsDudGhDtMbvxohPoMMyAUOmEzQsOK+XFchh6gZGqo8sx9sBuZQs+CUttXqa8RZXKDaJRCN2tUtgGof7jRkkw==",
"dependencies": {
"content-type": "^1.0.5",
"raw-body": "^3.0.0",
"zod": "^3.23.8"
}
},
"node_modules/@types/node": {
"version": "22.9.1",
"resolved": "https://registry.npmjs.org/@types/node/-/node-22.9.1.tgz",
"integrity": "sha512-p8Yy/8sw1caA8CdRIQBG5tiLHmxtQKObCijiAa9Ez+d4+PRffM4054xbju0msf+cvhJpnFEeNjxmVT/0ipktrg==",
"dependencies": {
"undici-types": "~6.19.8"
}
},
"node_modules/@types/node-fetch": {
"version": "2.6.12",
"resolved": "https://registry.npmjs.org/@types/node-fetch/-/node-fetch-2.6.12.tgz",
"integrity": "sha512-8nneRWKCg3rMtF69nLQJnOYUcbafYeFSjqkw3jCRLsqkWFlHaoQrr5mXmofFGOx3DKn7UfmBMyov8ySvLRVldA==",
"dependencies": {
"@types/node": "*",
"form-data": "^4.0.0"
}
},
"node_modules/asynckit": {
"version": "0.4.0",
"resolved": "https://registry.npmjs.org/asynckit/-/asynckit-0.4.0.tgz",
"integrity": "sha512-Oei9OH4tRh0YqU3GxhX79dM/mwVgvbZJaSNaRk+bshkj0S5cfHcgYakreBjrHwatXKbz+IoIdYLxrKim2MjW0Q=="
},
"node_modules/balanced-match": {
"version": "1.0.2",
"resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz",
"integrity": "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==",
"dev": true
},
"node_modules/brace-expansion": {
"version": "1.1.11",
"resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz",
"integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==",
"dev": true,
"dependencies": {
"balanced-match": "^1.0.0",
"concat-map": "0.0.1"
}
},
"node_modules/bytes": {
"version": "3.1.2",
"resolved": "https://registry.npmjs.org/bytes/-/bytes-3.1.2.tgz",
"integrity": "sha512-/Nf7TyzTx6S3yRJObOAV7956r8cr2+Oj8AC5dt8wSP3BQAoeX58NoHyCU8P8zGkNXStjTSi6fzO6F0pBdcYbEg==",
"engines": {
"node": ">= 0.8"
}
},
"node_modules/combined-stream": {
"version": "1.0.8",
"resolved": "https://registry.npmjs.org/combined-stream/-/combined-stream-1.0.8.tgz",
"integrity": "sha512-FQN4MRfuJeHf7cBbBMJFXhKSDq+2kAArBlmRBvcvFE5BB1HZKXtSFASDhdlz9zOYwxh8lDdnvmMOe/+5cdoEdg==",
"dependencies": {
"delayed-stream": "~1.0.0"
},
"engines": {
"node": ">= 0.8"
}
},
"node_modules/concat-map": {
"version": "0.0.1",
"resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz",
"integrity": "sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg==",
"dev": true
},
"node_modules/content-type": {
"version": "1.0.5",
"resolved": "https://registry.npmjs.org/content-type/-/content-type-1.0.5.tgz",
"integrity": "sha512-nTjqfcBFEipKdXCv4YDQWCfmcLZKm81ldF0pAopTvyrFGVbcR6P/VAAd5G7N+0tTr8QqiU0tFadD6FK4NtJwOA==",
"engines": {
"node": ">= 0.6"
}
},
"node_modules/data-uri-to-buffer": {
"version": "4.0.1",
"resolved": "https://registry.npmjs.org/data-uri-to-buffer/-/data-uri-to-buffer-4.0.1.tgz",
"integrity": "sha512-0R9ikRb668HB7QDxT1vkpuUBtqc53YyAwMwGeUFKRojY/NWKvdZ+9UYtRfGmhqNbRkTSVpMbmyhXipFFv2cb/A==",
"engines": {
"node": ">= 12"
}
},
"node_modules/delayed-stream": {
"version": "1.0.0",
"resolved": "https://registry.npmjs.org/delayed-stream/-/delayed-stream-1.0.0.tgz",
"integrity": "sha512-ZySD7Nf91aLB0RxL4KGrKHBXl7Eds1DAmEdcoVawXnLD7SDhpNgtuII2aAkg7a7QS41jxPSZ17p4VdGnMHk3MQ==",
"engines": {
"node": ">=0.4.0"
}
},
"node_modules/depd": {
"version": "2.0.0",
"resolved": "https://registry.npmjs.org/depd/-/depd-2.0.0.tgz",
"integrity": "sha512-g7nH6P6dyDioJogAAGprGpCtVImJhpPk/roCzdb3fIh61/s/nPsfR6onyMwkCAR/OlC3yBC0lESvUoQEAssIrw==",
"engines": {
"node": ">= 0.8"
}
},
"node_modules/fetch-blob": {
"version": "3.2.0",
"resolved": "https://registry.npmjs.org/fetch-blob/-/fetch-blob-3.2.0.tgz",
"integrity": "sha512-7yAQpD2UMJzLi1Dqv7qFYnPbaPx7ZfFK6PiIxQ4PfkGPyNyl2Ugx+a/umUonmKqjhM4DnfbMvdX6otXq83soQQ==",
"funding": [
{
"type": "github",
"url": "https://github.com/sponsors/jimmywarting"
},
{
"type": "paypal",
"url": "https://paypal.me/jimmywarting"
}
],
"dependencies": {
"node-domexception": "^1.0.0",
"web-streams-polyfill": "^3.0.3"
},
"engines": {
"node": "^12.20 || >= 14.13"
}
},
"node_modules/form-data": {
"version": "4.0.1",
"resolved": "https://registry.npmjs.org/form-data/-/form-data-4.0.1.tgz",
"integrity": "sha512-tzN8e4TX8+kkxGPK8D5u0FNmjPUjw3lwC9lSLxxoB/+GtsJG91CO8bSWy73APlgAZzZbXEYZJuxjkHH2w+Ezhw==",
"dependencies": {
"asynckit": "^0.4.0",
"combined-stream": "^1.0.8",
"mime-types": "^2.1.12"
},
"engines": {
"node": ">= 6"
}
},
"node_modules/formdata-polyfill": {
"version": "4.0.10",
"resolved": "https://registry.npmjs.org/formdata-polyfill/-/formdata-polyfill-4.0.10.tgz",
"integrity": "sha512-buewHzMvYL29jdeQTVILecSaZKnt/RJWjoZCF5OW60Z67/GmSLBkOFM7qh1PI3zFNtJbaZL5eQu1vLfazOwj4g==",
"dependencies": {
"fetch-blob": "^3.1.2"
},
"engines": {
"node": ">=12.20.0"
}
},
"node_modules/fs.realpath": {
"version": "1.0.0",
"resolved": "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz",
"integrity": "sha512-OO0pH2lK6a0hZnAdau5ItzHPI6pUlvI7jMVnxUQRtw4owF2wk8lOSabtGDCTP4Ggrg2MbGnWO9X8K1t4+fGMDw==",
"dev": true
},
"node_modules/function-bind": {
"version": "1.1.2",
"resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.2.tgz",
"integrity": "sha512-7XHNxH7qX9xG5mIwxkhumTox/MIRNcOgDrxWsMt2pAr23WHp6MrRlN7FBSFpCpr+oVO0F744iUgR82nJMfG2SA==",
"dev": true,
"funding": {
"url": "https://github.com/sponsors/ljharb"
}
},
"node_modules/glob": {
"version": "7.2.3",
"resolved": "https://registry.npmjs.org/glob/-/glob-7.2.3.tgz",
"integrity": "sha512-nFR0zLpU2YCaRxwoCJvL6UvCH2JFyFVIvwTLsIf21AuHlMskA1hhTdk+LlYJtOlYt9v6dvszD2BGRqBL+iQK9Q==",
"deprecated": "Glob versions prior to v9 are no longer supported",
"dev": true,
"dependencies": {
"fs.realpath": "^1.0.0",
"inflight": "^1.0.4",
"inherits": "2",
"minimatch": "^3.1.1",
"once": "^1.3.0",
"path-is-absolute": "^1.0.0"
},
"engines": {
"node": "*"
},
"funding": {
"url": "https://github.com/sponsors/isaacs"
}
},
"node_modules/hasown": {
"version": "2.0.2",
"resolved": "https://registry.npmjs.org/hasown/-/hasown-2.0.2.tgz",
"integrity": "sha512-0hJU9SCPvmMzIBdZFqNPXWa6dqh7WdH0cII9y+CyS8rG3nL48Bclra9HmKhVVUHyPWNH5Y7xDwAB7bfgSjkUMQ==",
"dev": true,
"dependencies": {
"function-bind": "^1.1.2"
},
"engines": {
"node": ">= 0.4"
}
},
"node_modules/http-errors": {
"version": "2.0.0",
"resolved": "https://registry.npmjs.org/http-errors/-/http-errors-2.0.0.tgz",
"integrity": "sha512-FtwrG/euBzaEjYeRqOgly7G0qviiXoJWnvEH2Z1plBdXgbyjv34pHTSb9zoeHMyDy33+DWy5Wt9Wo+TURtOYSQ==",
"dependencies": {
"depd": "2.0.0",
"inherits": "2.0.4",
"setprototypeof": "1.2.0",
"statuses": "2.0.1",
"toidentifier": "1.0.1"
},
"engines": {
"node": ">= 0.8"
}
},
"node_modules/iconv-lite": {
"version": "0.6.3",
"resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.6.3.tgz",
"integrity": "sha512-4fCk79wshMdzMp2rH06qWrJE4iolqLhCUH+OiuIgU++RB0+94NlDL81atO7GX55uUKueo0txHNtvEyI6D7WdMw==",
"dependencies": {
"safer-buffer": ">= 2.1.2 < 3.0.0"
},
"engines": {
"node": ">=0.10.0"
}
},
"node_modules/inflight": {
"version": "1.0.6",
"resolved": "https://registry.npmjs.org/inflight/-/inflight-1.0.6.tgz",
"integrity": "sha512-k92I/b08q4wvFscXCLvqfsHCrjrF7yiXsQuIVvVE7N82W3+aqpzuUdBbfhWcy/FZR3/4IgflMgKLOsvPDrGCJA==",
"deprecated": "This module is not supported, and leaks memory. Do not use it. Check out lru-cache if you want a good and tested way to coalesce async requests by a key value, which is much more comprehensive and powerful.",
"dev": true,
"dependencies": {
"once": "^1.3.0",
"wrappy": "1"
}
},
"node_modules/inherits": {
"version": "2.0.4",
"resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz",
"integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ=="
},
"node_modules/interpret": {
"version": "1.4.0",
"resolved": "https://registry.npmjs.org/interpret/-/interpret-1.4.0.tgz",
"integrity": "sha512-agE4QfB2Lkp9uICn7BAqoscw4SZP9kTE2hxiFI3jBPmXJfdqiahTbUuKGsMoN2GtqL9AxhYioAcVvgsb1HvRbA==",
"dev": true,
"engines": {
"node": ">= 0.10"
}
},
"node_modules/is-core-module": {
"version": "2.15.1",
"resolved": "https://registry.npmjs.org/is-core-module/-/is-core-module-2.15.1.tgz",
"integrity": "sha512-z0vtXSwucUJtANQWldhbtbt7BnL0vxiFjIdDLAatwhDYty2bad6s+rijD6Ri4YuYJubLzIJLUidCh09e1djEVQ==",
"dev": true,
"dependencies": {
"hasown": "^2.0.2"
},
"engines": {
"node": ">= 0.4"
},
"funding": {
"url": "https://github.com/sponsors/ljharb"
}
},
"node_modules/mime-db": {
"version": "1.52.0",
"resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.52.0.tgz",
"integrity": "sha512-sPU4uV7dYlvtWJxwwxHD0PuihVNiE7TyAbQ5SWxDCB9mUYvOgroQOwYQQOKPJ8CIbE+1ETVlOoK1UC2nU3gYvg==",
"engines": {
"node": ">= 0.6"
}
},
"node_modules/mime-types": {
"version": "2.1.35",
"resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.35.tgz",
"integrity": "sha512-ZDY+bPm5zTTF+YpCrAU9nK0UgICYPT0QtT1NZWFv4s++TNkcgVaT0g6+4R2uI4MjQjzysHB1zxuWL50hzaeXiw==",
"dependencies": {
"mime-db": "1.52.0"
},
"engines": {
"node": ">= 0.6"
}
},
"node_modules/minimatch": {
"version": "3.1.2",
"resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz",
"integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==",
"dev": true,
"dependencies": {
"brace-expansion": "^1.1.7"
},
"engines": {
"node": "*"
}
},
"node_modules/minimist": {
"version": "1.2.8",
"resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.8.tgz",
"integrity": "sha512-2yyAR8qBkN3YuheJanUpWC5U3bb5osDywNB8RzDVlDwDHbocAJveqqj1u8+SVD7jkWT4yvsHCpWqqWqAxb0zCA==",
"dev": true,
"funding": {
"url": "https://github.com/sponsors/ljharb"
}
},
"node_modules/node-domexception": {
"version": "1.0.0",
"resolved": "https://registry.npmjs.org/node-domexception/-/node-domexception-1.0.0.tgz",
"integrity": "sha512-/jKZoMpw0F8GRwl4/eLROPA3cfcXtLApP0QzLmUT/HuPCZWyB7IY9ZrMeKw2O/nFIqPQB3PVM9aYm0F312AXDQ==",
"funding": [
{
"type": "github",
"url": "https://github.com/sponsors/jimmywarting"
},
{
"type": "github",
"url": "https://paypal.me/jimmywarting"
}
],
"engines": {
"node": ">=10.5.0"
}
},
"node_modules/node-fetch": {
"version": "3.3.2",
"resolved": "https://registry.npmjs.org/node-fetch/-/node-fetch-3.3.2.tgz",
"integrity": "sha512-dRB78srN/l6gqWulah9SrxeYnxeddIG30+GOqK/9OlLVyLg3HPnr6SqOWTWOXKRwC2eGYCkZ59NNuSgvSrpgOA==",
"dependencies": {
"data-uri-to-buffer": "^4.0.0",
"fetch-blob": "^3.1.4",
"formdata-polyfill": "^4.0.10"
},
"engines": {
"node": "^12.20.0 || ^14.13.1 || >=16.0.0"
},
"funding": {
"type": "opencollective",
"url": "https://opencollective.com/node-fetch"
}
},
"node_modules/once": {
"version": "1.4.0",
"resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz",
"integrity": "sha512-lNaJgI+2Q5URQBkccEKHTQOPaXdUxnZZElQTZY0MFUAuaEqe1E+Nyvgdz/aIyNi6Z9MzO5dv1H8n58/GELp3+w==",
"dev": true,
"dependencies": {
"wrappy": "1"
}
},
"node_modules/path-is-absolute": {
"version": "1.0.1",
"resolved": "https://registry.npmjs.org/path-is-absolute/-/path-is-absolute-1.0.1.tgz",
"integrity": "sha512-AVbw3UJ2e9bq64vSaS9Am0fje1Pa8pbGqTTsmXfaIiMpnr5DlDhfJOuLj9Sf95ZPVDAUerDfEk88MPmPe7UCQg==",
"dev": true,
"engines": {
"node": ">=0.10.0"
}
},
"node_modules/path-parse": {
"version": "1.0.7",
"resolved": "https://registry.npmjs.org/path-parse/-/path-parse-1.0.7.tgz",
"integrity": "sha512-LDJzPVEEEPR+y48z93A0Ed0yXb8pAByGWo/k5YYdYgpY2/2EsOsksJrq7lOHxryrVOn1ejG6oAp8ahvOIQD8sw==",
"dev": true
},
"node_modules/raw-body": {
"version": "3.0.0",
"resolved": "https://registry.npmjs.org/raw-body/-/raw-body-3.0.0.tgz",
"integrity": "sha512-RmkhL8CAyCRPXCE28MMH0z2PNWQBNk2Q09ZdxM9IOOXwxwZbN+qbWaatPkdkWIKL2ZVDImrN/pK5HTRz2PcS4g==",
"dependencies": {
"bytes": "3.1.2",
"http-errors": "2.0.0",
"iconv-lite": "0.6.3",
"unpipe": "1.0.0"
},
"engines": {
"node": ">= 0.8"
}
},
"node_modules/rechoir": {
"version": "0.6.2",
"resolved": "https://registry.npmjs.org/rechoir/-/rechoir-0.6.2.tgz",
"integrity": "sha512-HFM8rkZ+i3zrV+4LQjwQ0W+ez98pApMGM3HUrN04j3CqzPOzl9nmP15Y8YXNm8QHGv/eacOVEjqhmWpkRV0NAw==",
"dev": true,
"dependencies": {
"resolve": "^1.1.6"
},
"engines": {
"node": ">= 0.10"
}
},
"node_modules/resolve": {
"version": "1.22.8",
"resolved": "https://registry.npmjs.org/resolve/-/resolve-1.22.8.tgz",
"integrity": "sha512-oKWePCxqpd6FlLvGV1VU0x7bkPmmCNolxzjMf4NczoDnQcIWrAF+cPtZn5i6n+RfD2d9i0tzpKnG6Yk168yIyw==",
"dev": true,
"dependencies": {
"is-core-module": "^2.13.0",
"path-parse": "^1.0.7",
"supports-preserve-symlinks-flag": "^1.0.0"
},
"bin": {
"resolve": "bin/resolve"
},
"funding": {
"url": "https://github.com/sponsors/ljharb"
}
},
"node_modules/safer-buffer": {
"version": "2.1.2",
"resolved": "https://registry.npmjs.org/safer-buffer/-/safer-buffer-2.1.2.tgz",
"integrity": "sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg=="
},
"node_modules/setprototypeof": {
"version": "1.2.0",
"resolved": "https://registry.npmjs.org/setprototypeof/-/setprototypeof-1.2.0.tgz",
"integrity": "sha512-E5LDX7Wrp85Kil5bhZv46j8jOeboKq5JMmYM3gVGdGH8xFpPWXUMsNrlODCrkoxMEeNi/XZIwuRvY4XNwYMJpw=="
},
"node_modules/shelljs": {
"version": "0.8.5",
"resolved": "https://registry.npmjs.org/shelljs/-/shelljs-0.8.5.tgz",
"integrity": "sha512-TiwcRcrkhHvbrZbnRcFYMLl30Dfov3HKqzp5tO5b4pt6G/SezKcYhmDg15zXVBswHmctSAQKznqNW2LO5tTDow==",
"dev": true,
"dependencies": {
"glob": "^7.0.0",
"interpret": "^1.0.0",
"rechoir": "^0.6.2"
},
"bin": {
"shjs": "bin/shjs"
},
"engines": {
"node": ">=4"
}
},
"node_modules/shx": {
"version": "0.3.4",
"resolved": "https://registry.npmjs.org/shx/-/shx-0.3.4.tgz",
"integrity": "sha512-N6A9MLVqjxZYcVn8hLmtneQWIJtp8IKzMP4eMnx+nqkvXoqinUPCbUFLp2UcWTEIUONhlk0ewxr/jaVGlc+J+g==",
"dev": true,
"dependencies": {
"minimist": "^1.2.3",
"shelljs": "^0.8.5"
},
"bin": {
"shx": "lib/cli.js"
},
"engines": {
"node": ">=6"
}
},
"node_modules/statuses": {
"version": "2.0.1",
"resolved": "https://registry.npmjs.org/statuses/-/statuses-2.0.1.tgz",
"integrity": "sha512-RwNA9Z/7PrK06rYLIzFMlaF+l73iwpzsqRIFgbMLbTcLD6cOao82TaWefPXQvB2fOC4AjuYSEndS7N/mTCbkdQ==",
"engines": {
"node": ">= 0.8"
}
},
"node_modules/supports-preserve-symlinks-flag": {
"version": "1.0.0",
"resolved": "https://registry.npmjs.org/supports-preserve-symlinks-flag/-/supports-preserve-symlinks-flag-1.0.0.tgz",
"integrity": "sha512-ot0WnXS9fgdkgIcePe6RHNk1WA8+muPa6cSjeR3V8K27q9BB1rTE3R1p7Hv0z1ZyAc8s6Vvv8DIyWf681MAt0w==",
"dev": true,
"engines": {
"node": ">= 0.4"
},
"funding": {
"url": "https://github.com/sponsors/ljharb"
}
},
"node_modules/toidentifier": {
"version": "1.0.1",
"resolved": "https://registry.npmjs.org/toidentifier/-/toidentifier-1.0.1.tgz",
"integrity": "sha512-o5sSPKEkg/DIQNmH43V0/uerLrpzVedkUh8tGNvaeXpfpuwjKenlSox/2O/BTlZUtEe+JG7s5YhEz608PlAHRA==",
"engines": {
"node": ">=0.6"
}
},
"node_modules/typescript": {
"version": "5.6.3",
"resolved": "https://registry.npmjs.org/typescript/-/typescript-5.6.3.tgz",
"integrity": "sha512-hjcS1mhfuyi4WW8IWtjP7brDrG2cuDZukyrYrSauoXGNgx0S7zceP07adYkJycEr56BOUTNPzbInooiN3fn1qw==",
"dev": true,
"bin": {
"tsc": "bin/tsc",
"tsserver": "bin/tsserver"
},
"engines": {
"node": ">=14.17"
}
},
"node_modules/undici-types": {
"version": "6.19.8",
"resolved": "https://registry.npmjs.org/undici-types/-/undici-types-6.19.8.tgz",
"integrity": "sha512-ve2KP6f/JnbPBFyobGHuerC9g1FYGn/F8n1LWTwNxCEzd6IfqTwUQcNXgEtmmQ6DlRrC1hrSrBnCZPokRrDHjw=="
},
"node_modules/unpipe": {
"version": "1.0.0",
"resolved": "https://registry.npmjs.org/unpipe/-/unpipe-1.0.0.tgz",
"integrity": "sha512-pjy2bYhSsufwWlKwPc+l3cN7+wuJlK6uz0YdJEOlQDbl6jo/YlPi4mb8agUkVC8BF7V8NuzeyPNqRksA3hztKQ==",
"engines": {
"node": ">= 0.8"
}
},
"node_modules/web-streams-polyfill": {
"version": "3.3.3",
"resolved": "https://registry.npmjs.org/web-streams-polyfill/-/web-streams-polyfill-3.3.3.tgz",
"integrity": "sha512-d2JWLCivmZYTSIoge9MsgFCZrt571BikcWGYkjC1khllbTeDlGqZ2D8vD8E/lJa8WGWbb7Plm8/XJYV7IJHZZw==",
"engines": {
"node": ">= 8"
}
},
"node_modules/wrappy": {
"version": "1.0.2",
"resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz",
"integrity": "sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ==",
"dev": true
},
"node_modules/zod": {
"version": "3.23.8",
"resolved": "https://registry.npmjs.org/zod/-/zod-3.23.8.tgz",
"integrity": "sha512-XBx9AXhXktjUqnepgTiE5flcKIYWi/rme0Eaj+5Y0lftuGBq+jyRu/md4WnuxqgP1ubdpNCsYEYPxrzVHD8d6g==",
"funding": {
"url": "https://github.com/sponsors/colinhacks"
}
}
}
}

View File

@@ -1,6 +1,6 @@
{ {
"name": "@modelcontextprotocol/server-gitlab", "name": "@modelcontextprotocol/server-gitlab",
"version": "0.5.1", "version": "0.6.2",
"description": "MCP server for using the GitLab API", "description": "MCP server for using the GitLab API",
"license": "MIT", "license": "MIT",
"author": "GitLab, PBC (https://gitlab.com)", "author": "GitLab, PBC (https://gitlab.com)",
@@ -19,7 +19,7 @@
"watch": "tsc --watch" "watch": "tsc --watch"
}, },
"dependencies": { "dependencies": {
"@modelcontextprotocol/sdk": "0.6.0", "@modelcontextprotocol/sdk": "1.0.1",
"@types/node-fetch": "^2.6.12", "@types/node-fetch": "^2.6.12",
"node-fetch": "^3.3.2", "node-fetch": "^3.3.2",
"zod-to-json-schema": "^3.23.5" "zod-to-json-schema": "^3.23.5"
@@ -28,4 +28,4 @@
"shx": "^0.3.4", "shx": "^0.3.4",
"typescript": "^5.6.2" "typescript": "^5.6.2"
} }
} }

View File

@@ -141,7 +141,7 @@ function getApiKey(): string {
} }
return apiKey; return apiKey;
} }
const GOOGLE_MAPS_API_KEY = getApiKey(); const GOOGLE_MAPS_API_KEY = getApiKey();
// Tool definitions // Tool definitions
@@ -151,28 +151,28 @@ const GEOCODE_TOOL: Tool = {
inputSchema: { inputSchema: {
type: "object", type: "object",
properties: { properties: {
address: { address: {
type: "string", type: "string",
description: "The address to geocode" description: "The address to geocode"
} }
}, },
required: ["address"] required: ["address"]
} }
}; };
const REVERSE_GEOCODE_TOOL: Tool = { const REVERSE_GEOCODE_TOOL: Tool = {
name: "maps_reverse_geocode", name: "maps_reverse_geocode",
description: "Convert coordinates into an address", description: "Convert coordinates into an address",
inputSchema: { inputSchema: {
type: "object", type: "object",
properties: { properties: {
latitude: { latitude: {
type: "number", type: "number",
description: "Latitude coordinate" description: "Latitude coordinate"
}, },
longitude: { longitude: {
type: "number", type: "number",
description: "Longitude coordinate" description: "Longitude coordinate"
} }
}, },
required: ["latitude", "longitude"] required: ["latitude", "longitude"]
@@ -185,9 +185,9 @@ const SEARCH_PLACES_TOOL: Tool = {
inputSchema: { inputSchema: {
type: "object", type: "object",
properties: { properties: {
query: { query: {
type: "string", type: "string",
description: "Search query" description: "Search query"
}, },
location: { location: {
type: "object", type: "object",
@@ -225,7 +225,7 @@ const DISTANCE_MATRIX_TOOL: Tool = {
name: "maps_distance_matrix", name: "maps_distance_matrix",
description: "Calculate travel distance and time for multiple origins and destinations", description: "Calculate travel distance and time for multiple origins and destinations",
inputSchema: { inputSchema: {
type: "object", type: "object",
properties: { properties: {
origins: { origins: {
type: "array", type: "array",
@@ -233,7 +233,7 @@ const DISTANCE_MATRIX_TOOL: Tool = {
description: "Array of origin addresses or coordinates" description: "Array of origin addresses or coordinates"
}, },
destinations: { destinations: {
type: "array", type: "array",
items: { type: "string" }, items: { type: "string" },
description: "Array of destination addresses or coordinates" description: "Array of destination addresses or coordinates"
}, },
@@ -276,13 +276,13 @@ const DIRECTIONS_TOOL: Tool = {
inputSchema: { inputSchema: {
type: "object", type: "object",
properties: { properties: {
origin: { origin: {
type: "string", type: "string",
description: "Starting point address or coordinates" description: "Starting point address or coordinates"
}, },
destination: { destination: {
type: "string", type: "string",
description: "Ending point address or coordinates" description: "Ending point address or coordinates"
}, },
mode: { mode: {
type: "string", type: "string",
@@ -315,28 +315,24 @@ async function handleGeocode(address: string) {
if (data.status !== "OK") { if (data.status !== "OK") {
return { return {
toolResult: { content: [{
content: [{ type: "text",
type: "text", text: `Geocoding failed: ${data.error_message || data.status}`
text: `Geocoding failed: ${data.error_message || data.status}` }],
}], isError: true
isError: true
}
}; };
} }
return { return {
toolResult: { content: [{
content: [{ type: "text",
type: "text", text: JSON.stringify({
text: JSON.stringify({ location: data.results[0].geometry.location,
location: data.results[0].geometry.location, formatted_address: data.results[0].formatted_address,
formatted_address: data.results[0].formatted_address, place_id: data.results[0].place_id
place_id: data.results[0].place_id }, null, 2)
}, null, 2) }],
}], isError: false
isError: false
}
}; };
} }
@@ -350,28 +346,24 @@ async function handleReverseGeocode(latitude: number, longitude: number) {
if (data.status !== "OK") { if (data.status !== "OK") {
return { return {
toolResult: { content: [{
content: [{ type: "text",
type: "text", text: `Reverse geocoding failed: ${data.error_message || data.status}`
text: `Reverse geocoding failed: ${data.error_message || data.status}` }],
}], isError: true
isError: true
}
}; };
} }
return { return {
toolResult: { content: [{
content: [{ type: "text",
type: "text", text: JSON.stringify({
text: JSON.stringify({ formatted_address: data.results[0].formatted_address,
formatted_address: data.results[0].formatted_address, place_id: data.results[0].place_id,
place_id: data.results[0].place_id, address_components: data.results[0].address_components
address_components: data.results[0].address_components }, null, 2)
}, null, 2) }],
}], isError: false
isError: false
}
}; };
} }
@@ -396,33 +388,29 @@ async function handlePlaceSearch(
if (data.status !== "OK") { if (data.status !== "OK") {
return { return {
toolResult: { content: [{
content: [{ type: "text",
type: "text", text: `Place search failed: ${data.error_message || data.status}`
text: `Place search failed: ${data.error_message || data.status}` }],
}], isError: true
isError: true
}
}; };
} }
return { return {
toolResult: { content: [{
content: [{ type: "text",
type: "text", text: JSON.stringify({
text: JSON.stringify({ places: data.results.map((place) => ({
places: data.results.map((place) => ({ name: place.name,
name: place.name, formatted_address: place.formatted_address,
formatted_address: place.formatted_address, location: place.geometry.location,
location: place.geometry.location, place_id: place.place_id,
place_id: place.place_id, rating: place.rating,
rating: place.rating, types: place.types
types: place.types }))
})) }, null, 2)
}, null, 2) }],
}], isError: false
isError: false
}
}; };
} }
@@ -436,33 +424,29 @@ async function handlePlaceDetails(place_id: string) {
if (data.status !== "OK") { if (data.status !== "OK") {
return { return {
toolResult: { content: [{
content: [{ type: "text",
type: "text", text: `Place details request failed: ${data.error_message || data.status}`
text: `Place details request failed: ${data.error_message || data.status}` }],
}], isError: true
isError: true
}
}; };
} }
return { return {
toolResult: { content: [{
content: [{ type: "text",
type: "text", text: JSON.stringify({
text: JSON.stringify({ name: data.result.name,
name: data.result.name, formatted_address: data.result.formatted_address,
formatted_address: data.result.formatted_address, location: data.result.geometry.location,
location: data.result.geometry.location, formatted_phone_number: data.result.formatted_phone_number,
formatted_phone_number: data.result.formatted_phone_number, website: data.result.website,
website: data.result.website, rating: data.result.rating,
rating: data.result.rating, reviews: data.result.reviews,
reviews: data.result.reviews, opening_hours: data.result.opening_hours
opening_hours: data.result.opening_hours }, null, 2)
}, null, 2) }],
}], isError: false
isError: false
}
}; };
} }
async function handleDistanceMatrix( async function handleDistanceMatrix(
@@ -481,34 +465,30 @@ async function handleDistanceMatrix(
if (data.status !== "OK") { if (data.status !== "OK") {
return { return {
toolResult: { content: [{
content: [{ type: "text",
type: "text", text: `Distance matrix request failed: ${data.error_message || data.status}`
text: `Distance matrix request failed: ${data.error_message || data.status}` }],
}], isError: true
isError: true
}
}; };
} }
return { return {
toolResult: { content: [{
content: [{ type: "text",
type: "text", text: JSON.stringify({
text: JSON.stringify({ origin_addresses: data.origin_addresses,
origin_addresses: data.origin_addresses, destination_addresses: data.destination_addresses,
destination_addresses: data.destination_addresses, results: data.rows.map((row) => ({
results: data.rows.map((row) => ({ elements: row.elements.map((element) => ({
elements: row.elements.map((element) => ({ status: element.status,
status: element.status, duration: element.duration,
duration: element.duration, distance: element.distance
distance: element.distance
}))
})) }))
}, null, 2) }))
}], }, null, 2)
isError: false }],
} isError: false
}; };
} }
@@ -525,30 +505,26 @@ async function handleElevation(locations: Array<{ latitude: number; longitude: n
if (data.status !== "OK") { if (data.status !== "OK") {
return { return {
toolResult: { content: [{
content: [{ type: "text",
type: "text", text: `Elevation request failed: ${data.error_message || data.status}`
text: `Elevation request failed: ${data.error_message || data.status}` }],
}], isError: true
isError: true
}
}; };
} }
return { return {
toolResult: { content: [{
content: [{ type: "text",
type: "text", text: JSON.stringify({
text: JSON.stringify({ results: data.results.map((result) => ({
results: data.results.map((result) => ({ elevation: result.elevation,
elevation: result.elevation, location: result.location,
location: result.location, resolution: result.resolution
resolution: result.resolution }))
})) }, null, 2)
}, null, 2) }],
}], isError: false
isError: false
}
}; };
} }
@@ -568,36 +544,32 @@ async function handleDirections(
if (data.status !== "OK") { if (data.status !== "OK") {
return { return {
toolResult: { content: [{
content: [{ type: "text",
type: "text", text: `Directions request failed: ${data.error_message || data.status}`
text: `Directions request failed: ${data.error_message || data.status}` }],
}], isError: true
isError: true
}
}; };
} }
return { return {
toolResult: { content: [{
content: [{ type: "text",
type: "text", text: JSON.stringify({
text: JSON.stringify({ routes: data.routes.map((route) => ({
routes: data.routes.map((route) => ({ summary: route.summary,
summary: route.summary, distance: route.legs[0].distance,
distance: route.legs[0].distance, duration: route.legs[0].duration,
duration: route.legs[0].duration, steps: route.legs[0].steps.map((step) => ({
steps: route.legs[0].steps.map((step) => ({ instructions: step.html_instructions,
instructions: step.html_instructions, distance: step.distance,
distance: step.distance, duration: step.duration,
duration: step.duration, travel_mode: step.travel_mode
travel_mode: step.travel_mode
}))
})) }))
}, null, 2) }))
}], }, null, 2)
isError: false }],
} isError: false
}; };
} }
@@ -626,7 +598,7 @@ server.setRequestHandler(CallToolRequestSchema, async (request) => {
const { address } = request.params.arguments as { address: string }; const { address } = request.params.arguments as { address: string };
return await handleGeocode(address); return await handleGeocode(address);
} }
case "maps_reverse_geocode": { case "maps_reverse_geocode": {
const { latitude, longitude } = request.params.arguments as { const { latitude, longitude } = request.params.arguments as {
latitude: number; latitude: number;
@@ -634,7 +606,7 @@ server.setRequestHandler(CallToolRequestSchema, async (request) => {
}; };
return await handleReverseGeocode(latitude, longitude); return await handleReverseGeocode(latitude, longitude);
} }
case "maps_search_places": { case "maps_search_places": {
const { query, location, radius } = request.params.arguments as { const { query, location, radius } = request.params.arguments as {
query: string; query: string;
@@ -643,12 +615,12 @@ server.setRequestHandler(CallToolRequestSchema, async (request) => {
}; };
return await handlePlaceSearch(query, location, radius); return await handlePlaceSearch(query, location, radius);
} }
case "maps_place_details": { case "maps_place_details": {
const { place_id } = request.params.arguments as { place_id: string }; const { place_id } = request.params.arguments as { place_id: string };
return await handlePlaceDetails(place_id); return await handlePlaceDetails(place_id);
} }
case "maps_distance_matrix": { case "maps_distance_matrix": {
const { origins, destinations, mode } = request.params.arguments as { const { origins, destinations, mode } = request.params.arguments as {
origins: string[]; origins: string[];
@@ -657,14 +629,14 @@ server.setRequestHandler(CallToolRequestSchema, async (request) => {
}; };
return await handleDistanceMatrix(origins, destinations, mode); return await handleDistanceMatrix(origins, destinations, mode);
} }
case "maps_elevation": { case "maps_elevation": {
const { locations } = request.params.arguments as { const { locations } = request.params.arguments as {
locations: Array<{ latitude: number; longitude: number }>; locations: Array<{ latitude: number; longitude: number }>;
}; };
return await handleElevation(locations); return await handleElevation(locations);
} }
case "maps_directions": { case "maps_directions": {
const { origin, destination, mode } = request.params.arguments as { const { origin, destination, mode } = request.params.arguments as {
origin: string; origin: string;
@@ -673,27 +645,23 @@ server.setRequestHandler(CallToolRequestSchema, async (request) => {
}; };
return await handleDirections(origin, destination, mode); return await handleDirections(origin, destination, mode);
} }
default: default:
return { return {
toolResult: { content: [{
content: [{ type: "text",
type: "text", text: `Unknown tool: ${request.params.name}`
text: `Unknown tool: ${request.params.name}` }],
}], isError: true
isError: true
}
}; };
} }
} catch (error) { } catch (error) {
return { return {
toolResult: { content: [{
content: [{ type: "text",
type: "text", text: `Error: ${error instanceof Error ? error.message : String(error)}`
text: `Error: ${error instanceof Error ? error.message : String(error)}` }],
}], isError: true
isError: true
}
}; };
} }
}); });
@@ -707,4 +675,4 @@ async function runServer() {
runServer().catch((error) => { runServer().catch((error) => {
console.error("Fatal error running server:", error); console.error("Fatal error running server:", error);
process.exit(1); process.exit(1);
}); });

View File

@@ -1,6 +1,6 @@
{ {
"name": "@modelcontextprotocol/server-google-maps", "name": "@modelcontextprotocol/server-google-maps",
"version": "0.5.1", "version": "0.6.2",
"description": "MCP server for using the Google Maps API", "description": "MCP server for using the Google Maps API",
"license": "MIT", "license": "MIT",
"author": "Anthropic, PBC (https://anthropic.com)", "author": "Anthropic, PBC (https://anthropic.com)",
@@ -19,7 +19,7 @@
"watch": "tsc --watch" "watch": "tsc --watch"
}, },
"dependencies": { "dependencies": {
"@modelcontextprotocol/sdk": "0.6.0", "@modelcontextprotocol/sdk": "1.0.1",
"@types/node-fetch": "^2.6.12", "@types/node-fetch": "^2.6.12",
"node-fetch": "^3.3.2" "node-fetch": "^3.3.2"
}, },
@@ -27,4 +27,4 @@
"shx": "^0.3.4", "shx": "^0.3.4",
"typescript": "^5.6.2" "typescript": "^5.6.2"
} }
} }

View File

@@ -377,26 +377,26 @@ server.setRequestHandler(CallToolRequestSchema, async (request) => {
switch (name) { switch (name) {
case "create_entities": case "create_entities":
return { toolResult: await knowledgeGraphManager.createEntities(args.entities as Entity[]) }; return { content: [{ type: "text", text: JSON.stringify(await knowledgeGraphManager.createEntities(args.entities as Entity[]), null, 2) }] };
case "create_relations": case "create_relations":
return { toolResult: await knowledgeGraphManager.createRelations(args.relations as Relation[]) }; return { content: [{ type: "text", text: JSON.stringify(await knowledgeGraphManager.createRelations(args.relations as Relation[]), null, 2) }] };
case "add_observations": case "add_observations":
return { toolResult: await knowledgeGraphManager.addObservations(args.observations as { entityName: string; contents: string[] }[]) }; return { content: [{ type: "text", text: JSON.stringify(await knowledgeGraphManager.addObservations(args.observations as { entityName: string; contents: string[] }[]), null, 2) }] };
case "delete_entities": case "delete_entities":
await knowledgeGraphManager.deleteEntities(args.entityNames as string[]); await knowledgeGraphManager.deleteEntities(args.entityNames as string[]);
return { toolResult: "Entities deleted successfully" }; return { content: [{ type: "text", text: "Entities deleted successfully" }] };
case "delete_observations": case "delete_observations":
await knowledgeGraphManager.deleteObservations(args.deletions as { entityName: string; observations: string[] }[]); await knowledgeGraphManager.deleteObservations(args.deletions as { entityName: string; observations: string[] }[]);
return { toolResult: "Observations deleted successfully" }; return { content: [{ type: "text", text: "Observations deleted successfully" }] };
case "delete_relations": case "delete_relations":
await knowledgeGraphManager.deleteRelations(args.relations as Relation[]); await knowledgeGraphManager.deleteRelations(args.relations as Relation[]);
return { toolResult: "Relations deleted successfully" }; return { content: [{ type: "text", text: "Relations deleted successfully" }] };
case "read_graph": case "read_graph":
return { toolResult: await knowledgeGraphManager.readGraph() }; return { content: [{ type: "text", text: JSON.stringify(await knowledgeGraphManager.readGraph(), null, 2) }] };
case "search_nodes": case "search_nodes":
return { toolResult: await knowledgeGraphManager.searchNodes(args.query as string) }; return { content: [{ type: "text", text: JSON.stringify(await knowledgeGraphManager.searchNodes(args.query as string), null, 2) }] };
case "open_nodes": case "open_nodes":
return { toolResult: await knowledgeGraphManager.openNodes(args.names as string[]) }; return { content: [{ type: "text", text: JSON.stringify(await knowledgeGraphManager.openNodes(args.names as string[]), null, 2) }] };
default: default:
throw new Error(`Unknown tool: ${name}`); throw new Error(`Unknown tool: ${name}`);
} }

View File

@@ -1,6 +1,6 @@
{ {
"name": "@modelcontextprotocol/server-memory", "name": "@modelcontextprotocol/server-memory",
"version": "0.5.1", "version": "0.6.2",
"description": "MCP server for enabling memory for Claude through a knowledge graph", "description": "MCP server for enabling memory for Claude through a knowledge graph",
"license": "MIT", "license": "MIT",
"author": "Anthropic, PBC (https://anthropic.com)", "author": "Anthropic, PBC (https://anthropic.com)",
@@ -19,11 +19,11 @@
"watch": "tsc --watch" "watch": "tsc --watch"
}, },
"dependencies": { "dependencies": {
"@modelcontextprotocol/sdk": "0.5.0" "@modelcontextprotocol/sdk": "1.0.1"
}, },
"devDependencies": { "devDependencies": {
"@types/node": "^22.9.3", "@types/node": "^22.9.3",
"shx": "^0.3.4", "shx": "^0.3.4",
"typescript": "^5.6.2" "typescript": "^5.6.2"
} }
} }

View File

@@ -1,6 +1,6 @@
{ {
"name": "@modelcontextprotocol/server-postgres", "name": "@modelcontextprotocol/server-postgres",
"version": "0.5.1", "version": "0.6.2",
"description": "MCP server for interacting with PostgreSQL databases", "description": "MCP server for interacting with PostgreSQL databases",
"license": "MIT", "license": "MIT",
"author": "Anthropic, PBC (https://anthropic.com)", "author": "Anthropic, PBC (https://anthropic.com)",
@@ -19,7 +19,7 @@
"watch": "tsc --watch" "watch": "tsc --watch"
}, },
"dependencies": { "dependencies": {
"@modelcontextprotocol/sdk": "0.6.0", "@modelcontextprotocol/sdk": "1.0.1",
"pg": "^8.13.0" "pg": "^8.13.0"
}, },
"devDependencies": { "devDependencies": {
@@ -27,4 +27,4 @@
"shx": "^0.3.4", "shx": "^0.3.4",
"typescript": "^5.6.2" "typescript": "^5.6.2"
} }
} }

View File

@@ -133,20 +133,18 @@ declare global {
} }
} }
async function handleToolCall(name: string, args: any): Promise<{ toolResult: CallToolResult }> { async function handleToolCall(name: string, args: any): Promise<CallToolResult> {
const page = await ensureBrowser(); const page = await ensureBrowser();
switch (name) { switch (name) {
case "puppeteer_navigate": case "puppeteer_navigate":
await page.goto(args.url); await page.goto(args.url);
return { return {
toolResult: { content: [{
content: [{ type: "text",
type: "text", text: `Navigated to ${args.url}`,
text: `Navigated to ${args.url}`, }],
}], isError: false,
isError: false,
},
}; };
case "puppeteer_screenshot": { case "puppeteer_screenshot": {
@@ -160,13 +158,11 @@ async function handleToolCall(name: string, args: any): Promise<{ toolResult: Ca
if (!screenshot) { if (!screenshot) {
return { return {
toolResult: { content: [{
content: [{ type: "text",
type: "text", text: args.selector ? `Element not found: ${args.selector}` : "Screenshot failed",
text: args.selector ? `Element not found: ${args.selector}` : "Screenshot failed", }],
}], isError: true,
isError: true,
},
}; };
} }
@@ -176,20 +172,18 @@ async function handleToolCall(name: string, args: any): Promise<{ toolResult: Ca
}); });
return { return {
toolResult: { content: [
content: [ {
{ type: "text",
type: "text", text: `Screenshot '${args.name}' taken at ${width}x${height}`,
text: `Screenshot '${args.name}' taken at ${width}x${height}`, } as TextContent,
} as TextContent, {
{ type: "image",
type: "image", data: screenshot,
data: screenshot, mimeType: "image/png",
mimeType: "image/png", } as ImageContent,
} as ImageContent, ],
], isError: false,
isError: false,
},
}; };
} }
@@ -197,23 +191,19 @@ async function handleToolCall(name: string, args: any): Promise<{ toolResult: Ca
try { try {
await page.click(args.selector); await page.click(args.selector);
return { return {
toolResult: { content: [{
content: [{ type: "text",
type: "text", text: `Clicked: ${args.selector}`,
text: `Clicked: ${args.selector}`, }],
}], isError: false,
isError: false,
},
}; };
} catch (error) { } catch (error) {
return { return {
toolResult: { content: [{
content: [{ type: "text",
type: "text", text: `Failed to click ${args.selector}: ${(error as Error).message}`,
text: `Failed to click ${args.selector}: ${(error as Error).message}`, }],
}], isError: true,
isError: true,
},
}; };
} }
@@ -222,23 +212,19 @@ async function handleToolCall(name: string, args: any): Promise<{ toolResult: Ca
await page.waitForSelector(args.selector); await page.waitForSelector(args.selector);
await page.type(args.selector, args.value); await page.type(args.selector, args.value);
return { return {
toolResult: { content: [{
content: [{ type: "text",
type: "text", text: `Filled ${args.selector} with: ${args.value}`,
text: `Filled ${args.selector} with: ${args.value}`, }],
}], isError: false,
isError: false,
},
}; };
} catch (error) { } catch (error) {
return { return {
toolResult: { content: [{
content: [{ type: "text",
type: "text", text: `Failed to fill ${args.selector}: ${(error as Error).message}`,
text: `Failed to fill ${args.selector}: ${(error as Error).message}`, }],
}], isError: true,
isError: true,
},
}; };
} }
@@ -247,23 +233,19 @@ async function handleToolCall(name: string, args: any): Promise<{ toolResult: Ca
await page.waitForSelector(args.selector); await page.waitForSelector(args.selector);
await page.select(args.selector, args.value); await page.select(args.selector, args.value);
return { return {
toolResult: { content: [{
content: [{ type: "text",
type: "text", text: `Selected ${args.selector} with: ${args.value}`,
text: `Selected ${args.selector} with: ${args.value}`, }],
}], isError: false,
isError: false,
},
}; };
} catch (error) { } catch (error) {
return { return {
toolResult: { content: [{
content: [{ type: "text",
type: "text", text: `Failed to select ${args.selector}: ${(error as Error).message}`,
text: `Failed to select ${args.selector}: ${(error as Error).message}`, }],
}], isError: true,
isError: true,
},
}; };
} }
@@ -272,23 +254,19 @@ async function handleToolCall(name: string, args: any): Promise<{ toolResult: Ca
await page.waitForSelector(args.selector); await page.waitForSelector(args.selector);
await page.hover(args.selector); await page.hover(args.selector);
return { return {
toolResult: { content: [{
content: [{ type: "text",
type: "text", text: `Hovered ${args.selector}`,
text: `Hovered ${args.selector}`, }],
}], isError: false,
isError: false,
},
}; };
} catch (error) { } catch (error) {
return { return {
toolResult: { content: [{
content: [{ type: "text",
type: "text", text: `Failed to hover ${args.selector}: ${(error as Error).message}`,
text: `Failed to hover ${args.selector}: ${(error as Error).message}`, }],
}], isError: true,
isError: true,
},
}; };
} }
@@ -318,37 +296,31 @@ async function handleToolCall(name: string, args: any): Promise<{ toolResult: Ca
}); });
return { return {
toolResult: { content: [
content: [ {
{ type: "text",
type: "text", text: `Execution result:\n${JSON.stringify(result, null, 2)}\n\nConsole output:\n${logs.join('\n')}`,
text: `Execution result:\n${JSON.stringify(result, null, 2)}\n\nConsole output:\n${logs.join('\n')}`, },
}, ],
], isError: false,
isError: false,
},
}; };
} catch (error) { } catch (error) {
return { return {
toolResult: { content: [{
content: [{ type: "text",
type: "text", text: `Script execution failed: ${(error as Error).message}`,
text: `Script execution failed: ${(error as Error).message}`, }],
}], isError: true,
isError: true,
},
}; };
} }
default: default:
return { return {
toolResult: { content: [{
content: [{ type: "text",
type: "text", text: `Unknown tool: ${name}`,
text: `Unknown tool: ${name}`, }],
}], isError: true,
isError: true,
},
}; };
} }
} }

View File

@@ -1,6 +1,6 @@
{ {
"name": "@modelcontextprotocol/server-puppeteer", "name": "@modelcontextprotocol/server-puppeteer",
"version": "0.5.1", "version": "0.6.2",
"description": "MCP server for browser automation using Puppeteer", "description": "MCP server for browser automation using Puppeteer",
"license": "MIT", "license": "MIT",
"author": "Anthropic, PBC (https://anthropic.com)", "author": "Anthropic, PBC (https://anthropic.com)",
@@ -19,11 +19,11 @@
"watch": "tsc --watch" "watch": "tsc --watch"
}, },
"dependencies": { "dependencies": {
"@modelcontextprotocol/sdk": "0.5.0", "@modelcontextprotocol/sdk": "1.0.1",
"puppeteer": "^23.4.0" "puppeteer": "^23.4.0"
}, },
"devDependencies": { "devDependencies": {
"shx": "^0.3.4", "shx": "^0.3.4",
"typescript": "^5.6.2" "typescript": "^5.6.2"
} }
} }

View File

@@ -1,6 +1,6 @@
[project] [project]
name = "mcp-server-sentry" name = "mcp-server-sentry"
version = "0.6.1" version = "0.6.2"
description = "MCP server for retrieving issues from sentry.io" description = "MCP server for retrieving issues from sentry.io"
readme = "README.md" readme = "README.md"
requires-python = ">=3.10" requires-python = ">=3.10"

View File

@@ -0,0 +1,4 @@
from mcp_server_sentry.server import main
if __name__ == "__main__":
main()

2
src/sentry/uv.lock generated
View File

@@ -147,7 +147,7 @@ wheels = [
[[package]] [[package]]
name = "mcp-server-sentry" name = "mcp-server-sentry"
version = "0.6.0" version = "0.6.2"
source = { editable = "." } source = { editable = "." }
dependencies = [ dependencies = [
{ name = "mcp" }, { name = "mcp" },

View File

@@ -0,0 +1,63 @@
# Sequential Thinking MCP Server
An MCP server implementation that provides a tool for dynamic and reflective problem-solving through a structured thinking process.
## Features
- Break down complex problems into manageable steps
- Revise and refine thoughts as understanding deepens
- Branch into alternative paths of reasoning
- Adjust the total number of thoughts dynamically
- Generate and verify solution hypotheses
## Tool
### sequential_thinking
Facilitates a detailed, step-by-step thinking process for problem-solving and analysis.
**Inputs:**
- `thought` (string): The current thinking step
- `nextThoughtNeeded` (boolean): Whether another thought step is needed
- `thoughtNumber` (integer): Current thought number
- `totalThoughts` (integer): Estimated total thoughts needed
- `isRevision` (boolean, optional): Whether this revises previous thinking
- `revisesThought` (integer, optional): Which thought is being reconsidered
- `branchFromThought` (integer, optional): Branching point thought number
- `branchId` (string, optional): Branch identifier
- `needsMoreThoughts` (boolean, optional): If more thoughts are needed
## Usage
The Sequential Thinking tool is designed for:
- Breaking down complex problems into steps
- Planning and design with room for revision
- Analysis that might need course correction
- Problems where the full scope might not be clear initially
- Tasks that need to maintain context over multiple steps
- Situations where irrelevant information needs to be filtered out
## Configuration
### Usage with Claude Desktop
Add this to your `claude_desktop_config.json`:
```json
{
"mcpServers": {
"sequential-thinking": {
"command": "npx",
"args": [
"-y",
"@modelcontextprotocol/server-sequential-thinking"
]
}
}
}
```
## License
This MCP server is licensed under the MIT License. This means you are free to use, modify, and distribute the software, subject to the terms and conditions of the MIT License. For more details, please see the LICENSE file in the project repository.

View File

@@ -0,0 +1,278 @@
#!/usr/bin/env node
import { Server } from "@modelcontextprotocol/sdk/server/index.js";
import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio.js";
import {
CallToolRequestSchema,
ListToolsRequestSchema,
Tool,
} from "@modelcontextprotocol/sdk/types.js";
// Fixed chalk import for ESM
import chalk from 'chalk';
interface ThoughtData {
thought: string;
thoughtNumber: number;
totalThoughts: number;
isRevision?: boolean;
revisesThought?: number;
branchFromThought?: number;
branchId?: string;
needsMoreThoughts?: boolean;
nextThoughtNeeded: boolean;
}
class SequentialThinkingServer {
private thoughtHistory: ThoughtData[] = [];
private branches: Record<string, ThoughtData[]> = {};
private validateThoughtData(input: unknown): ThoughtData {
const data = input as Record<string, unknown>;
if (!data.thought || typeof data.thought !== 'string') {
throw new Error('Invalid thought: must be a string');
}
if (!data.thoughtNumber || typeof data.thoughtNumber !== 'number') {
throw new Error('Invalid thoughtNumber: must be a number');
}
if (!data.totalThoughts || typeof data.totalThoughts !== 'number') {
throw new Error('Invalid totalThoughts: must be a number');
}
if (typeof data.nextThoughtNeeded !== 'boolean') {
throw new Error('Invalid nextThoughtNeeded: must be a boolean');
}
return {
thought: data.thought,
thoughtNumber: data.thoughtNumber,
totalThoughts: data.totalThoughts,
nextThoughtNeeded: data.nextThoughtNeeded,
isRevision: data.isRevision as boolean | undefined,
revisesThought: data.revisesThought as number | undefined,
branchFromThought: data.branchFromThought as number | undefined,
branchId: data.branchId as string | undefined,
needsMoreThoughts: data.needsMoreThoughts as boolean | undefined,
};
}
private formatThought(thoughtData: ThoughtData): string {
const { thoughtNumber, totalThoughts, thought, isRevision, revisesThought, branchFromThought, branchId } = thoughtData;
let prefix = '';
let context = '';
if (isRevision) {
prefix = chalk.yellow('🔄 Revision');
context = ` (revising thought ${revisesThought})`;
} else if (branchFromThought) {
prefix = chalk.green('🌿 Branch');
context = ` (from thought ${branchFromThought}, ID: ${branchId})`;
} else {
prefix = chalk.blue('💭 Thought');
context = '';
}
const header = `${prefix} ${thoughtNumber}/${totalThoughts}${context}`;
const border = '─'.repeat(Math.max(header.length, thought.length) + 4);
return `
${border}
${header}
${border}
${thought.padEnd(border.length - 2)}
${border}`;
}
public processThought(input: unknown): { content: Array<{ type: string; text: string }>; isError?: boolean } {
try {
const validatedInput = this.validateThoughtData(input);
if (validatedInput.thoughtNumber > validatedInput.totalThoughts) {
validatedInput.totalThoughts = validatedInput.thoughtNumber;
}
this.thoughtHistory.push(validatedInput);
if (validatedInput.branchFromThought && validatedInput.branchId) {
if (!this.branches[validatedInput.branchId]) {
this.branches[validatedInput.branchId] = [];
}
this.branches[validatedInput.branchId].push(validatedInput);
}
const formattedThought = this.formatThought(validatedInput);
console.error(formattedThought);
return {
content: [{
type: "text",
text: JSON.stringify({
thoughtNumber: validatedInput.thoughtNumber,
totalThoughts: validatedInput.totalThoughts,
nextThoughtNeeded: validatedInput.nextThoughtNeeded,
branches: Object.keys(this.branches),
thoughtHistoryLength: this.thoughtHistory.length
}, null, 2)
}]
};
} catch (error) {
return {
content: [{
type: "text",
text: JSON.stringify({
error: error instanceof Error ? error.message : String(error),
status: 'failed'
}, null, 2)
}],
isError: true
};
}
}
}
const SEQUENTIAL_THINKING_TOOL: Tool = {
name: "sequentialthinking",
description: `A detailed tool for dynamic and reflective problem-solving through thoughts.
This tool helps analyze problems through a flexible thinking process that can adapt and evolve.
Each thought can build on, question, or revise previous insights as understanding deepens.
When to use this tool:
- Breaking down complex problems into steps
- Planning and design with room for revision
- Analysis that might need course correction
- Problems where the full scope might not be clear initially
- Problems that require a multi-step solution
- Tasks that need to maintain context over multiple steps
- Situations where irrelevant information needs to be filtered out
Key features:
- You can adjust total_thoughts up or down as you progress
- You can question or revise previous thoughts
- You can add more thoughts even after reaching what seemed like the end
- You can express uncertainty and explore alternative approaches
- Not every thought needs to build linearly - you can branch or backtrack
- Generates a solution hypothesis
- Verifies the hypothesis based on the Chain of Thought steps
- Repeats the process until satisfied
- Provides a correct answer
Parameters explained:
- thought: Your current thinking step, which can include:
* Regular analytical steps
* Revisions of previous thoughts
* Questions about previous decisions
* Realizations about needing more analysis
* Changes in approach
* Hypothesis generation
* Hypothesis verification
- next_thought_needed: True if you need more thinking, even if at what seemed like the end
- thought_number: Current number in sequence (can go beyond initial total if needed)
- total_thoughts: Current estimate of thoughts needed (can be adjusted up/down)
- is_revision: A boolean indicating if this thought revises previous thinking
- revises_thought: If is_revision is true, which thought number is being reconsidered
- branch_from_thought: If branching, which thought number is the branching point
- branch_id: Identifier for the current branch (if any)
- needs_more_thoughts: If reaching end but realizing more thoughts needed
You should:
1. Start with an initial estimate of needed thoughts, but be ready to adjust
2. Feel free to question or revise previous thoughts
3. Don't hesitate to add more thoughts if needed, even at the "end"
4. Express uncertainty when present
5. Mark thoughts that revise previous thinking or branch into new paths
6. Ignore information that is irrelevant to the current step
7. Generate a solution hypothesis when appropriate
8. Verify the hypothesis based on the Chain of Thought steps
9. Repeat the process until satisfied with the solution
10. Provide a single, ideally correct answer as the final output
11. Only set next_thought_needed to false when truly done and a satisfactory answer is reached`,
inputSchema: {
type: "object",
properties: {
thought: {
type: "string",
description: "Your current thinking step"
},
nextThoughtNeeded: {
type: "boolean",
description: "Whether another thought step is needed"
},
thoughtNumber: {
type: "integer",
description: "Current thought number",
minimum: 1
},
totalThoughts: {
type: "integer",
description: "Estimated total thoughts needed",
minimum: 1
},
isRevision: {
type: "boolean",
description: "Whether this revises previous thinking"
},
revisesThought: {
type: "integer",
description: "Which thought is being reconsidered",
minimum: 1
},
branchFromThought: {
type: "integer",
description: "Branching point thought number",
minimum: 1
},
branchId: {
type: "string",
description: "Branch identifier"
},
needsMoreThoughts: {
type: "boolean",
description: "If more thoughts are needed"
}
},
required: ["thought", "nextThoughtNeeded", "thoughtNumber", "totalThoughts"]
}
};
const server = new Server(
{
name: "sequential-thinking-server",
version: "0.2.0",
},
{
capabilities: {
tools: {},
},
}
);
const thinkingServer = new SequentialThinkingServer();
server.setRequestHandler(ListToolsRequestSchema, async () => ({
tools: [SEQUENTIAL_THINKING_TOOL],
}));
server.setRequestHandler(CallToolRequestSchema, async (request) => {
if (request.params.name === "sequentialthinking") {
return thinkingServer.processThought(request.params.arguments);
}
return {
content: [{
type: "text",
text: `Unknown tool: ${request.params.name}`
}],
isError: true
};
});
async function runServer() {
const transport = new StdioServerTransport();
await server.connect(transport);
console.error("Sequential Thinking MCP Server running on stdio");
}
runServer().catch((error) => {
console.error("Fatal error running server:", error);
process.exit(1);
});

View File

@@ -0,0 +1,32 @@
{
"name": "@modelcontextprotocol/server-sequential-thinking",
"version": "0.6.2",
"description": "MCP server for sequential thinking and problem solving",
"license": "MIT",
"author": "Anthropic, PBC (https://anthropic.com)",
"homepage": "https://modelcontextprotocol.io",
"bugs": "https://github.com/modelcontextprotocol/servers/issues",
"type": "module",
"bin": {
"mcp-server-sequential-thinking": "dist/index.js"
},
"files": [
"dist"
],
"scripts": {
"build": "tsc && shx chmod +x dist/*.js",
"prepare": "npm run build",
"watch": "tsc --watch"
},
"dependencies": {
"@modelcontextprotocol/sdk": "0.5.0",
"chalk": "^5.3.0",
"yargs": "^17.7.2"
},
"devDependencies": {
"@types/node": "^20.11.0",
"@types/yargs": "^17.0.32",
"shx": "^0.3.4",
"typescript": "^5.3.3"
}
}

View File

@@ -0,0 +1,10 @@
{
"extends": "../../tsconfig.json",
"compilerOptions": {
"outDir": "./dist",
"rootDir": ".",
"moduleResolution": "NodeNext",
"module": "NodeNext"
},
"include": ["./**/*.ts"]
}

View File

@@ -1,6 +1,6 @@
{ {
"name": "@modelcontextprotocol/server-slack", "name": "@modelcontextprotocol/server-slack",
"version": "0.5.1", "version": "0.6.2",
"description": "MCP server for interacting with Slack", "description": "MCP server for interacting with Slack",
"license": "MIT", "license": "MIT",
"author": "Anthropic, PBC (https://anthropic.com)", "author": "Anthropic, PBC (https://anthropic.com)",
@@ -19,11 +19,11 @@
"watch": "tsc --watch" "watch": "tsc --watch"
}, },
"dependencies": { "dependencies": {
"@modelcontextprotocol/sdk": "0.6.0" "@modelcontextprotocol/sdk": "1.0.1"
}, },
"devDependencies": { "devDependencies": {
"@types/node": "^22.9.3", "@types/node": "^22.9.3",
"shx": "^0.3.4", "shx": "^0.3.4",
"typescript": "^5.6.2" "typescript": "^5.6.2"
} }
} }

View File

@@ -1,6 +1,6 @@
[project] [project]
name = "mcp-server-sqlite" name = "mcp-server-sqlite"
version = "0.6.1" version = "0.6.2"
description = "A simple SQLite MCP server" description = "A simple SQLite MCP server"
readme = "README.md" readme = "README.md"
requires-python = ">=3.10" requires-python = ">=3.10"

2
src/sqlite/uv.lock generated
View File

@@ -138,7 +138,7 @@ wheels = [
[[package]] [[package]]
name = "mcp-server-sqlite" name = "mcp-server-sqlite"
version = "0.6.0" version = "0.6.2"
source = { editable = "." } source = { editable = "." }
dependencies = [ dependencies = [
{ name = "mcp" }, { name = "mcp" },

View File

@@ -1,6 +1,6 @@
[project] [project]
name = "mcp-server-time" name = "mcp-server-time"
version = "0.6.1" version = "0.6.2"
description = "A Model Context Protocol server providing tools for time queries and timezone conversions for LLMs" description = "A Model Context Protocol server providing tools for time queries and timezone conversions for LLMs"
readme = "README.md" readme = "README.md"
requires-python = ">=3.10" requires-python = ">=3.10"

2
src/time/uv.lock generated
View File

@@ -159,7 +159,7 @@ wheels = [
[[package]] [[package]]
name = "mcp-server-time" name = "mcp-server-time"
version = "0.6.0" version = "0.6.2"
source = { editable = "." } source = { editable = "." }
dependencies = [ dependencies = [
{ name = "mcp" }, { name = "mcp" },