Big News: Socket raises $60M Series C at a $1B valuation to secure software supply chains for AI-driven development.Announcement
Sign In

@picahq/pica-mcp

Package Overview
Dependencies
Maintainers
4
Versions
9
Alerts
File Explorer

Advanced tools

Socket logo

Install Socket

Detect and block malicious and high-risk dependencies

Install

@picahq/pica-mcp - npm Package Compare versions

Comparing version
1.0.2
to
1.1.0
+556
-14
build/index.js
#!/usr/bin/env node
import { Server } from "@modelcontextprotocol/sdk/server/index.js";
import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio.js";
import { CallToolRequestSchema, ListResourcesRequestSchema, ListToolsRequestSchema, ReadResourceRequestSchema, } from "@modelcontextprotocol/sdk/types.js";
import { CallToolRequestSchema, ListResourcesRequestSchema, ListToolsRequestSchema, ReadResourceRequestSchema, ListPromptsRequestSchema, GetPromptRequestSchema, CreateMessageRequestSchema, } from "@modelcontextprotocol/sdk/types.js";
import axios from "axios";
import FormData from 'form-data';
// Helper functions for generating prompt context
function formatConnectionsInfo(connections) {
if (connections.length === 0) {
return "No active connections found. User needs to connect to platforms first.";
}
const groupedByPlatform = connections.reduce((acc, conn) => {
if (!acc[conn.platform]) {
acc[conn.platform] = [];
}
acc[conn.platform].push(conn.key);
return acc;
}, {});
return Object.entries(groupedByPlatform)
.map(([platform, keys]) => `- ${platform}: ${keys.join(', ')}`)
.join('\n');
}
function formatAvailablePlatformsInfo(connectionDefinitions) {
if (connectionDefinitions.length === 0) {
return "No available platform information found.";
}
const platforms = connectionDefinitions
.filter(def => def.active && !def.deprecated)
.map(def => `- ${def.platform}: ${def.description}`)
.join('\n');
return platforms || "No active platforms available.";
}
class PicaClient {

@@ -33,2 +59,3 @@ secret;

catch (error) {
console.error("Failed to initialize connections:", error);
this.connections = [];

@@ -69,5 +96,8 @@ }

async getAvailableActions(platform) {
if (!platform) {
throw new Error("Platform name is required");
}
try {
const headers = this.generateHeaders();
const url = `${this.baseUrl}/v1/knowledge?supported=true&connectionPlatform=${platform}&limit=1000`;
const url = `${this.baseUrl}/v1/knowledge?supported=true&connectionPlatform=${encodeURIComponent(platform)}&limit=1000`;
const response = await axios.get(url, { headers });

@@ -78,2 +108,5 @@ return response.data?.rows || [];

console.error("Error fetching available actions:", error);
if (axios.isAxiosError(error)) {
throw new Error(`Failed to fetch available actions: ${error.response?.status} ${error.response?.statusText}`);
}
throw new Error("Failed to fetch available actions");

@@ -83,5 +116,8 @@ }

async getActionKnowledge(actionId) {
if (!actionId) {
throw new Error("Action ID is required");
}
try {
const headers = this.generateHeaders();
const url = `${this.baseUrl}/v1/knowledge?_id=${actionId}`;
const url = `${this.baseUrl}/v1/knowledge?_id=${encodeURIComponent(actionId)}`;
const response = await axios.get(url, { headers });

@@ -95,2 +131,5 @@ if (!response.data.rows || response.data.rows.length === 0) {

console.error("Error fetching action knowledge:", error);
if (axios.isAxiosError(error)) {
throw new Error(`Failed to fetch action knowledge: ${error.response?.status} ${error.response?.statusText}`);
}
throw new Error("Failed to fetch action knowledge");

@@ -100,8 +139,11 @@ }

replacePathVariables(path, variables) {
if (!path)
return path;
return path.replace(/\{\{([^}]+)\}\}/g, (match, variable) => {
const value = variables[variable];
if (!value) {
throw new Error(`Missing value for path variable: ${variable}`);
const trimmedVariable = variable.trim();
const value = variables[trimmedVariable];
if (value === undefined || value === null || value === '') {
throw new Error(`Missing value for path variable: ${trimmedVariable}`);
}
return value.toString();
return encodeURIComponent(value.toString());
});

@@ -176,2 +218,59 @@ }

}
async generateRequestConfig(actionId, connectionKey, method, path, data, pathVariables, queryParams, headers, isFormData, isFormUrlEncoded) {
const newHeaders = {
...this.generateHeaders(),
'x-pica-connection-key': connectionKey,
'x-pica-action-id': actionId,
...(isFormData ? { 'Content-Type': 'multipart/form-data' } : {}),
...(isFormUrlEncoded ? { 'Content-Type': 'application/x-www-form-urlencoded' } : {}),
...headers
};
// Handle path variables
let resolvedPath = path;
if (pathVariables) {
resolvedPath = this.replacePathVariables(path, pathVariables);
}
const url = `${this.baseUrl}/v1/passthrough${resolvedPath.startsWith('/') ? resolvedPath : '/' + resolvedPath}`;
const requestConfig = {
url,
method,
headers: newHeaders,
params: queryParams
};
if (method?.toLowerCase() !== 'get') {
if (isFormData) {
const formData = new FormData();
if (data && typeof data === 'object' && !Array.isArray(data)) {
Object.entries(data).forEach(([key, value]) => {
if (typeof value === 'object') {
formData.append(key, JSON.stringify(value));
}
else {
formData.append(key, value);
}
});
}
requestConfig.data = formData;
Object.assign(requestConfig.headers, formData.getHeaders());
}
else if (isFormUrlEncoded) {
const params = new URLSearchParams();
if (data && typeof data === 'object' && !Array.isArray(data)) {
Object.entries(data).forEach(([key, value]) => {
if (typeof value === 'object') {
params.append(key, JSON.stringify(value));
}
else {
params.append(key, String(value));
}
});
}
requestConfig.data = params;
}
else {
requestConfig.data = data;
}
}
return requestConfig;
}
}

@@ -186,17 +285,64 @@ const server = new Server({

prompts: {},
sampling: {},
},
});
// Validate required environment variables
const PICA_SECRET = process.env.PICA_SECRET;
const picaClient = new PicaClient(PICA_SECRET);
if (!PICA_SECRET) {
console.error("PICA_SECRET environment variable is required");
process.exit(1);
}
const PICA_BASE_URL = process.env.PICA_BASE_URL || "https://api.picaos.com";
const picaClient = new PicaClient(PICA_SECRET, PICA_BASE_URL);
let picaInitialized = false;
let initializationPromise = null;
const initializePica = async () => {
if (!picaInitialized) {
await picaClient.initialize();
picaInitialized = true;
if (picaInitialized) {
return;
}
if (initializationPromise) {
return initializationPromise;
}
initializationPromise = (async () => {
try {
await picaClient.initialize();
picaInitialized = true;
console.error("Pica client initialized successfully");
}
catch (error) {
console.error("Failed to initialize Pica client:", error);
// Reset so we can try again next time
initializationPromise = null;
throw error;
}
})();
return initializationPromise;
};
server.setRequestHandler(ListResourcesRequestSchema, async () => {
await initializePica();
const resources = [];
// Add connections as resources
const connections = picaClient.getConnections();
for (const connection of connections) {
if (connection.active) {
resources.push({
uri: `pica-connection://${connection.platform}/${connection.key}`,
name: `${connection.platform} Connection (${connection.key})`,
description: `Active connection to ${connection.platform}`,
mimeType: "application/json"
});
}
}
// Add unique platforms as resources
const platforms = [...new Set(connections.map(c => c.platform))];
for (const platform of platforms) {
resources.push({
uri: `pica-platform://${platform}`,
name: `${platform} Actions`,
description: `Available actions for ${platform}`,
mimeType: "application/json"
});
}
return {
resources: []
resources
};

@@ -243,2 +389,24 @@ });

}
else if (scheme === 'pica-action:') {
const actionId = url.hostname;
try {
const action = await picaClient.getActionKnowledge(actionId);
return {
contents: [{
uri: request.params.uri,
mimeType: "application/json",
text: JSON.stringify({
id: action._id,
title: action.title,
knowledge: action.knowledge,
path: action.path,
tags: action.tags || []
}, null, 2)
}]
};
}
catch (error) {
throw new Error(`Failed to get action details: ${error.message}`);
}
}
throw new Error(`Unsupported resource URI scheme: ${scheme}`);

@@ -335,2 +503,63 @@ });

}
},
{
name: "generate_action_config_knowledge",
description: "Generate request configuration for an action using knowledge-based path handling, this is to be used when the user is asking you to write code.",
inputSchema: {
type: "object",
properties: {
platform: {
type: "string",
description: "Platform name"
},
action: {
type: "object",
properties: {
_id: {
type: "string",
description: "Action ID"
},
path: {
type: "string",
description: "Action path template with variables"
}
},
required: ["_id", "path"],
description: "Action object with ID and path"
},
method: {
type: "string",
description: "HTTP method (GET, POST, PUT, DELETE, etc.)"
},
connectionKey: {
type: "string",
description: "Key of the connection to use"
},
data: {
type: "object",
description: "Request data (for POST, PUT, etc.)"
},
pathVariables: {
type: "object",
description: "Variables to replace in the path"
},
queryParams: {
type: "object",
description: "Query parameters"
},
headers: {
type: "object",
description: "Additional headers"
},
isFormData: {
type: "boolean",
description: "Whether to send data as multipart/form-data"
},
isFormUrlEncoded: {
type: "boolean",
description: "Whether to send data as application/x-www-form-urlencoded"
}
},
required: ["platform", "action", "method", "connectionKey"]
}
}

@@ -465,2 +694,81 @@ ]

}
case "generate_action_config_knowledge": {
const { platform, action, method, connectionKey, data, pathVariables, queryParams, headers, isFormData, isFormUrlEncoded } = request.params.arguments;
try {
// Check if connection exists
const connections = picaClient.getConnections();
if (!connections.some(conn => conn.key === connectionKey)) {
throw new Error(`Connection not found. Please add a ${platform} connection first.`);
}
// Handle path variables from action.path
const templateVariables = action.path.match(/\{\{([^}]+)\}\}/g);
let resolvedPath = action.path;
let finalPathVariables = pathVariables || {};
let finalData = data;
if (templateVariables) {
const requiredVariables = templateVariables.map((v) => v.replace(/\{\{|\}\}/g, ''));
const combinedVariables = {
...(Array.isArray(data) ? {} : (data || {})),
...(pathVariables || {})
};
const missingVariables = requiredVariables.filter((v) => !combinedVariables[v]);
if (missingVariables.length > 0) {
throw new Error(`Missing required path variables: ${missingVariables.join(', ')}. ` +
`Please provide values for these variables.`);
}
// Clean up data object and prepare path variables
if (!Array.isArray(data) && data) {
finalData = { ...data };
requiredVariables.forEach((v) => {
if (finalData && finalData[v] && (!pathVariables || !pathVariables[v])) {
finalPathVariables[v] = finalData[v];
delete finalData[v];
}
});
}
resolvedPath = picaClient.replacePathVariables(action.path, finalPathVariables);
}
const requestConfig = await picaClient.generateRequestConfig(action._id, connectionKey, method, resolvedPath, finalData, finalPathVariables, queryParams, headers, isFormData, isFormUrlEncoded);
// Generate TypeScript code example
const tsCode = `
import axios from 'axios';
const requestConfig = ${JSON.stringify(requestConfig, null, 2)};
// Make the request
try {
const response = await axios(requestConfig);
console.log('Response:', response.data);
} catch (error) {
console.error('Error:', error.response?.data || error.message);
}
IMPORTANT: For the Pica secret always use the environment variable PICA_SECRET.
`;
return {
content: [{
type: "text",
text: JSON.stringify({
success: true,
title: "Request config returned",
message: "Request config returned without execution. Use the TypeScript code below to make the HTTP request.",
requestConfig,
typeScriptCode: tsCode
}, null, 2)
}]
};
}
catch (error) {
return {
content: [{
type: "text",
text: JSON.stringify({
success: false,
title: "Failed to create request config",
message: error.message
}, null, 2)
}]
};
}
}
default:

@@ -470,6 +778,240 @@ throw new Error("Unknown tool");

});
server.setRequestHandler(ListPromptsRequestSchema, async () => {
return {
prompts: [
{
name: "create-api-integration",
description: "Generate code for integrating with a specific API endpoint",
arguments: [
{
name: "platform",
description: "The platform to integrate with (e.g., slack, github)",
required: true
},
{
name: "action",
description: "The specific action to perform",
required: true
},
{
name: "language",
description: "Programming language for the integration (typescript, python, javascript)",
required: false
}
]
},
{
name: "list-platform-actions",
description: "Get a formatted list of available actions for a platform",
arguments: [
{
name: "platform",
description: "The platform to list actions for",
required: true
}
]
},
{
name: "knowledge-agent-system",
description: "System prompt with Pica Knowledge Agent capabilities for enhanced API guidance",
arguments: [
{
name: "includeEnvironmentVariables",
description: "Whether to include environment variable access in the prompt",
required: false
}
]
},
{
name: "default-system",
description: "Basic system prompt with Pica Intelligence Tools",
arguments: []
}
]
};
});
server.setRequestHandler(GetPromptRequestSchema, async (request) => {
await initializePica();
const { name, arguments: args } = request.params;
switch (name) {
case "create-api-integration": {
const platform = args?.platform;
const action = args?.action;
const language = args?.language || "typescript";
if (!platform || !action) {
throw new Error("Platform and action arguments are required");
}
return {
messages: [
{
role: "user",
content: {
type: "text",
text: `Create a ${language} integration for the ${platform} API to ${action}. Include proper error handling, type definitions (if applicable), and example usage.`
}
}
]
};
}
case "list-platform-actions": {
const platform = args?.platform;
if (!platform) {
throw new Error("Platform argument is required");
}
return {
messages: [
{
role: "user",
content: {
type: "text",
text: `List all available actions for the ${platform} platform. Format the output as a categorized list with descriptions for each action.`
}
}
]
};
}
case "knowledge-agent-system": {
const includeEnvironmentVariables = args?.includeEnvironmentVariables || false;
const connections = picaClient.getConnections().filter(conn => conn.active);
const connectionDefinitions = picaClient.getConnectionDefinitions();
const connectionsInfo = formatConnectionsInfo(connections);
const availablePlatformsInfo = formatAvailablePlatformsInfo(connectionDefinitions);
const envPrompt = includeEnvironmentVariables ? `
ENVIRONMENT VARIABLES:
You can access environment variables when needed for configuration or API keys.` : '';
const systemPrompt = `You have access to Pica's Intelligence Tools with Knowledge Agent capabilities that can help you connect to various APIs and services.
ACTIVE CONNECTIONS:
${connectionsInfo}
AVAILABLE PLATFORMS:
${availablePlatformsInfo}${envPrompt}
You can:
1. Get available actions for any platform using getAvailableActions
2. Get detailed knowledge about specific actions using getActionKnowledge
3. Generate request configurations (without executing) using execute
As a Knowledge Agent, you have enhanced understanding of API documentation and can provide detailed guidance on using various platforms and their APIs.
When using the execute tool, you will receive a TypeScript code block showing how to make the HTTP request using the Pica Passthrough API.
Always check what connections are available before attempting to use them.`;
return {
messages: [
{
role: "system",
content: {
type: "text",
text: systemPrompt
}
}
]
};
}
case "default-system": {
const connections = picaClient.getConnections().filter(conn => conn.active);
const connectionDefinitions = picaClient.getConnectionDefinitions();
const connectionsInfo = formatConnectionsInfo(connections);
const availablePlatformsInfo = formatAvailablePlatformsInfo(connectionDefinitions);
const systemPrompt = `You have access to Pica's Intelligence Tools that can help you connect to various APIs and services.
ACTIVE CONNECTIONS:
${connectionsInfo}
AVAILABLE PLATFORMS:
${availablePlatformsInfo}
You can:
1. Get available actions for any platform using getAvailableActions
2. Get detailed knowledge about specific actions using getActionKnowledge
3. Generate request configurations (without executing) using execute
When using the execute tool, you will receive a TypeScript code block showing how to make the HTTP request using the Pica Passthrough API.
Always check what connections are available before attempting to use them.`;
return {
messages: [
{
role: "system",
content: {
type: "text",
text: systemPrompt
}
}
]
};
}
default:
throw new Error(`Unknown prompt: ${name}`);
}
});
server.setRequestHandler(CreateMessageRequestSchema, async (request) => {
const { messages, modelPreferences } = request.params;
// Extract context from the conversation
const lastMessage = messages[messages.length - 1];
if (!lastMessage || lastMessage.role !== 'user') {
throw new Error("Expected user message");
}
let content = '';
if (typeof lastMessage.content === 'string') {
content = lastMessage.content;
}
else if (typeof lastMessage.content === 'object' && 'text' in lastMessage.content) {
content = lastMessage.content.text || '';
}
// Analyze the request and generate appropriate response
if (content.includes('generate') && content.includes('code')) {
// Extract platform and action from context
const platformMatch = content.match(/(?:for|using)\s+(\w+)/i);
const actionMatch = content.match(/(?:to|for)\s+(.+?)(?:\.|$)/i);
if (platformMatch && actionMatch) {
const platform = platformMatch[1];
const action = actionMatch[1];
return {
model: modelPreferences?.hints?.find(h => h.name === 'model')?.value || 'claude-3',
role: 'assistant',
content: {
type: 'text',
text: `I'll help you generate code for ${platform} to ${action}. First, let me check what actions are available for this platform...`
}
};
}
}
// Default response
return {
model: modelPreferences?.hints?.find(h => h.name === 'model')?.value || 'claude-3',
role: 'assistant',
content: {
type: 'text',
text: "I can help you with Pica integrations. You can ask me to list connections, get available actions for a platform, or generate integration code."
}
};
});
async function main() {
const transport = new StdioServerTransport();
await server.connect(transport);
try {
const transport = new StdioServerTransport();
await server.connect(transport);
console.error("Pica MCP server running on stdio");
// Log debug info if requested
if (process.env.DEBUG === 'true') {
console.error("Debug mode enabled");
console.error(`PICA_BASE_URL: ${PICA_BASE_URL}`);
}
}
catch (error) {
console.error("Failed to start server:", error);
process.exit(1);
}
}
// Handle graceful shutdown
process.on('SIGINT', async () => {
console.error("Shutting down server...");
process.exit(0);
});
process.on('SIGTERM', async () => {
console.error("Shutting down server...");
process.exit(0);
});
main().catch((error) => {

@@ -476,0 +1018,0 @@ console.error("Server error:", error);

+15
-6
{
"name": "@picahq/pica-mcp",
"version": "1.0.2",
"version": "1.1.0",
"description": "A Model Context Protocol Server for Pica",

@@ -16,12 +16,21 @@ "type": "module",

"watch": "tsc --watch",
"inspector": "npx @modelcontextprotocol/inspector build/index.js"
"inspector": "npx @modelcontextprotocol/inspector build/index.js",
"http": "npm run build && node build/index.js",
"http:dev": "npm run build && nodemon build/index.js"
},
"dependencies": {
"@modelcontextprotocol/sdk": "0.6.0",
"@modelcontextprotocol/sdk": "^1.12.1",
"@vercel/mcp-adapter": "^0.9.1",
"axios": "^1.8.3",
"form-data": "^4.0.2"
"cors": "^2.8.5",
"express": "^5.1.0",
"form-data": "^4.0.2",
"zod": "^3.23.0"
},
"devDependencies": {
"@types/node": "^20.11.24",
"typescript": "^5.3.3"
"@types/cors": "^2.8.19",
"@types/express": "^5.0.3",
"@types/node": "^22.0.0",
"nodemon": "^3.1.10",
"typescript": "^5.6.0"
},

@@ -28,0 +37,0 @@ "author": {

+234
-124
# Pica MCP Server
[![smithery badge](https://smithery.ai/badge/@picahq/pica)](https://smithery.ai/server/@picahq/pica)
A Model Context Protocol (MCP) server that integrates with the Pica API platform, enabling seamless interaction with various third-party services through a standardized interface.
![Pica MCP Banner](https://assets.picaos.com/github/mcp.jpeg)
## Features
A [Model Context Protocol](https://modelcontextprotocol.io) Server for [Pica](https://picaos.com), built in TypeScript.
### 🔧 Tools
- **list_user_connections_and_available_connectors** - List all available connectors and active connections
- **get_available_actions** - Get available actions for a specific platform
- **get_action_knowledge** - Get detailed information about a specific action
- **execute_action** - Execute API actions with full parameter support
- **generate_action_config_knowledge** - Generate request configurations for code generation
**Setup Video:** https://youtu.be/JJ62NUEkKAs
### 📚 Resources
- **pica-platform://{platform}** - Browse available actions for a platform
- **pica-connection://{platform}/{key}** - View connection details
- **pica-action://{actionId}** - Get detailed action information
**Demo Video:** https://youtu.be/0jeasO20PyM
### 💬 Prompts
- **create-api-integration** - Generate code for API integrations
- **list-platform-actions** - Get formatted lists of platform actions
## What is MCP?
### 🤖 Sampling
The server supports the MCP sampling capability for generating contextual responses based on conversation history.
[Model Context Protocol (MCP)](https://modelcontextprotocol.io) is a system that lets AI apps, like [Claude Desktop](https://claude.ai/download), connect to external tools and data sources. It gives a clear and safe way for AI assistants to work with local services and APIs while keeping the user in control.
## Architecture
## What is Pica?
```mermaid
graph TB
Client["MCP Client<br/>(Claude, VS Code, etc.)"]
Server["Pica MCP Server"]
Transport["StdioServerTransport"]
PicaAPI["Pica API"]
Client <-->|"JSON-RPC<br/>over stdio"| Transport
Transport <--> Server
Server -->|"HTTP/REST"| PicaAPI
```
[Pica](https://picaos.com) is a powerful agentic tooling platform that enables connections to 70+ third-party services and applications. This MCP server allows Claude Desktop and anything using the [Model Context Protocol](https://modelcontextprotocol.io) to securely interact with all these connections through natural language requests.
## Installation
With Pica MCP Server, you can:
```bash
npm install @picahq/pica-mcp
```
- **Access Multiple Data Sources**: Query databases, fetch files, and retrieve information across services
- **Automate Workflows**: Trigger actions and automate tasks across your connected platforms
- **Enhance LLM Capabilities**: Give Claude Desktop powerful real-world capabilities through API access
## Deployment Options
### Supported Connections
### Deploy to Vercel
Pica supports [70+ connections](https://app.picaos.com/tools) (with more added regularly) across categories like:
You can deploy this MCP server to Vercel for remote access:
#### Communication & Collaboration
- Gmail, Outlook Mail, Slack, Teams, SendGrid
- Notion, Google Drive, Dropbox, OneDrive
1. Install dependencies including Vercel adapter:
```bash
npm install @vercel/mcp-adapter zod
```
#### Data & Analytics
- PostgreSQL, BigQuery, Supabase
- Google Sheets, Airtable
2. Deploy to Vercel:
```bash
vercel
```
#### Business & CRM
- Salesforce, HubSpot, Pipedrive, Zoho
- Zendesk, Freshdesk, Intercom
3. Configure your MCP client to use the remote server:
- **For Cursor**: `https://your-project.vercel.app/api/mcp`
- **For Claude/Cline**: Use `npx mcp-remote https://your-project.vercel.app/api/mcp`
#### AI & ML Services
- OpenAI, Anthropic, Gemini, ElevenLabs
See [DEPLOYMENT.md](./DEPLOYMENT.md) for detailed Vercel deployment instructions.
#### E-commerce & Financial
- Shopify, BigCommerce, Square, Stripe
- QuickBooks, Xero, NetSuite
## Configuration
## Installation 🛠️
Set the following environment variables:
### Using npx
```bash
# Required
export PICA_SECRET="your-pica-secret-key"
You can use this package directly with npx:
# Optional
export PICA_BASE_URL="https://api.picaos.com" # Default
export DEBUG="true" # Enable debug logging
```
## Usage
### As a Standalone Server
```bash
# Using npx
npx @picahq/pica-mcp
# Or if installed globally
pica-mcp
```
Or install it globally:
### With MCP Inspector
```bash
npm install -g @picahq/pica-mcp
npm run inspector
```
### Installing via Smithery
### In Claude Desktop
To install pica for Claude Desktop automatically via [Smithery](https://smithery.ai/server/@picahq/pica):
Add to your Claude configuration file:
```bash
npx -y @smithery/cli install @picahq/pica --client claude
```json
{
"mcpServers": {
"pica": {
"command": "npx",
"args": ["@picahq/pica-mcp"],
"env": {
"PICA_SECRET": "your-pica-secret-key"
}
}
}
}
```
### Environment Setup
## Examples
This server requires a [Pica API key](https://app.picaos.com/settings/api-keys). Set the environment variable:
### List Available Connections
```bash
export PICA_SECRET=your_pica_secret_key
```typescript
// Using the list_user_connections_and_available_connectors tool
const result = await client.callTool({
name: "list_user_connections_and_available_connectors"
});
```
### Using Docker
### Get Platform Actions
Build the Docker Image:
```typescript
// Using the get_available_actions tool
const actions = await client.callTool({
name: "get_available_actions",
arguments: {
platform: "slack"
}
});
```
```bash
docker build -t pica-mcp-server .
### Execute an Action
```typescript
// Using the execute_action tool
const result = await client.callTool({
name: "execute_action",
arguments: {
actionId: "action-id",
connectionKey: "connection-key",
method: "POST",
path: "/api/messages",
data: {
channel: "#general",
text: "Hello from MCP!"
}
}
});
```
Run the Docker Container:
### Generate Integration Code
```bash
docker run -e PICA_SECRET=your_pica_secret_key pica-mcp-server
```typescript
// Using the generate_action_config_knowledge tool
const config = await client.callTool({
name: "generate_action_config_knowledge",
arguments: {
platform: "slack",
action: {
_id: "send-message",
path: "/api/messages"
},
method: "POST",
connectionKey: "slack-connection-key",
data: {
channel: "#general",
text: "Hello!"
}
}
});
```
### Manual Installation
## Development
Install dependencies:
### Building
```bash
npm install
npm run build
```
Build the server:
### Watching for Changes
```bash
npm run build
npm run watch
```
For development with auto-rebuild:
### Running with Debug Mode
```bash
npm run watch
DEBUG=true npm run build && node build/index.js
```
### Using Claude Desktop
## API Reference
### Tools
To use with [Claude Desktop](https://claude.ai/download), add the server config:
#### list_user_connections_and_available_connectors
Lists all connections in the user's Pica account and available connectors.
On MacOS: `~/Library/Application\ Support/Claude/claude_desktop_config.json`
**Parameters:** None
On Windows: `%APPDATA%/Claude/claude_desktop_config.json`
**Returns:**
- `connections`: Array of active connections
- `availablePicaConnectors`: Array of available connectors
#### Docker
#### get_available_actions
Get available actions for a specific platform.
To use the Docker container with Claude Desktop, update your `claude_desktop_config.json` with:
**Parameters:**
- `platform` (string, required): Platform name
```json
{
"mcpServers": {
"pica-mcp-server": {
"command": "docker",
"args": [
"run",
"--rm",
"-i",
"-e", "PICA_SECRET=YOUR_PICA_SECRET_KEY",
"pica-mcp-server"
]
}
}
}
```
**Returns:**
- `actions`: Array of available actions with id, title, and tags
#### Manual
#### get_action_knowledge
Get detailed information about a specific action.
```json
{
"mcpServers": {
"pica-mcp-server": {
"command": "node",
"args": [
"/path/to/pica-mcp-server/build/index.js"
],
"env": {
"PICA_SECRET": "YOUR_PICA_SECRET_KEY"
}
}
}
}
```
**Parameters:**
- `actionId` (string, required): Action ID
### Debugging
**Returns:**
- `action`: Detailed action information including knowledge base
Since MCP servers communicate over stdio, debugging can be challenging. We recommend using the [MCP Inspector](https://github.com/modelcontextprotocol/inspector), which is available as a package script:
#### execute_action
Execute a specific action through the Pica API.
```bash
npm run inspector
```
**Parameters:**
- `actionId` (string, required): Action ID
- `connectionKey` (string, required): Connection key
- `method` (string, required): HTTP method
- `path` (string, required): API path
- `data` (object, optional): Request body
- `pathVariables` (object, optional): Path variables
- `queryParams` (object, optional): Query parameters
- `headers` (object, optional): Additional headers
- `isFormData` (boolean, optional): Send as multipart/form-data
- `isFormUrlEncoded` (boolean, optional): Send as URL-encoded
The Inspector will provide a URL to access debugging tools in your browser.
**Returns:**
- `result`: API response data
- `requestConfig`: Request configuration details
## Example Usage ✨
#### generate_action_config_knowledge
Generate request configuration for code generation.
Once you've added the server config and connected some platforms in the [Pica dashboard](https://app.picaos.com/connections), restart Claude Desktop and try out some examples:
**Parameters:**
- `platform` (string, required): Platform name
- `action` (object, required): Action object with _id and path
- `method` (string, required): HTTP method
- `connectionKey` (string, required): Connection key
- `data` (object, optional): Request body
- `pathVariables` (object, optional): Path variables
- `queryParams` (object, optional): Query parameters
- `headers` (object, optional): Additional headers
- `isFormData` (boolean, optional): Send as multipart/form-data
- `isFormUrlEncoded` (boolean, optional): Send as URL-encoded
### Communication & Productivity
- Send an email using Gmail to a colleague with a meeting summary
- Create a calendar event in Google Calendar for next Tuesday at 2pm
- Send a message in Slack to the #marketing channel with the latest campaign metrics
- Find documents in Google Drive related to Q3 planning
**Returns:**
- `requestConfig`: Complete request configuration
- `typeScriptCode`: Example TypeScript code
### Data Access & Analysis
- List the top 10 customers from my PostgreSQL database
- Create a new sheet in Google Sheets with sales data
- Query Salesforce for opportunities closing this month
- Update a Notion database with project statuses
### Resources
### Business Operations
- Create a support ticket in Zendesk from customer feedback
- Process a refund for a customer order in Stripe
- Add a new lead to HubSpot from a website inquiry
- Generate an invoice in QuickBooks for a client project
Resources can be read using the MCP resource protocol:
### AI & Content
- Generate an image with DALL-E based on product specifications
- Transcribe a meeting recording with ElevenLabs
- Research market trends using Tavily or SerpApi
- Analyze customer sentiment from support tickets
- `pica-platform://{platform}` - List of actions for a platform
- `pica-connection://{platform}/{key}` - Connection details
- `pica-action://{actionId}` - Detailed action information
Got any cool examples? [Open a PR](https://github.com/picahq/awesome-pica) and share them!
### Prompts
#### create-api-integration
Generate code for API integrations.
**Arguments:**
- `platform` (string, required): Target platform
- `action` (string, required): Action to perform
- `language` (string, optional): Programming language (default: "typescript")
#### list-platform-actions
Get a formatted list of available actions.
**Arguments:**
- `platform` (string, required): Target platform
## Error Handling
The server implements comprehensive error handling:
- Connection validation before action execution
- Path variable validation and substitution
- Graceful handling of API failures
- Detailed error messages for debugging
## Security
- API keys are passed via environment variables
- Connections are validated before use
- All requests include proper authentication headers
## License
This project is licensed under the GPL-3.0 license. See the [LICENSE](LICENSE) file for details.
GPL-3.0
## Support
For support, please contact support@picaos.com or visit https://picaos.com