Skip to content
Download for Mac

Custom MCP Servers

The Model Context Protocol (MCP) defines a standard interface for connecting external tools to AI applications. QARK discovers and invokes tools from any MCP-compliant server. Wrap your databases, APIs, scripts, and internal services as MCP tools, and your agents gain capabilities tailored to your workflow.

For connecting pre-built MCP servers (GitHub, Slack, Filesystem, etc.), see MCP Integration. This page covers building your own.


An MCP server is a process or endpoint that:

  1. Advertises tools — Declares a manifest of available tools, each with a name, description, and typed input schema.
  2. Receives invocations — Accepts structured tool calls with validated parameters.
  3. Returns results — Sends back structured output that QARK passes to the model.

Two transport types:

TransportCommunicationLifecycleUse Case
stdiostdin/stdout JSON-RPCQARK spawns and manages the processLocal tools, scripts, databases
HTTPHTTP requestsServer runs independentlyRemote APIs, shared team services

A stdio server runs as a local subprocess. QARK spawns it using a login shell (e.g., bash -l -c or zsh -l -c), which means your shell profile is loaded — nvm, pyenv, rbenv, conda, and PATH customizations all work automatically.

FieldDescriptionExample
CommandExecutable pathnode, python3, npx
ArgsArguments array["server.js", "--readonly"]
Environment variablesKey-value pairs injected into the process{ "DATABASE_URL": "postgres://..." }

The server process only sees variables explicitly configured — it does not inherit your full shell environment beyond what the login shell profile provides.

Each tool needs three components:

{
"name": "query_database",
"description": "Execute a read-only SQL query against the application database. Returns results as JSON array of row objects. Maximum 1000 rows. Do not use for mutations — write operations are blocked.",
"input_schema": {
"type": "object",
"properties": {
"sql": {
"type": "string",
"description": "The SQL SELECT query to execute"
},
"params": {
"type": "array",
"items": { "type": "string" },
"description": "Parameterized values to bind to $1, $2, etc."
}
},
"required": ["sql"]
}
}

Write the description for an LLM audience — the model reads it to decide when and how to call the tool. Be specific about what the tool does, what it returns, and any constraints.

Server: Node.js process connecting to PostgreSQL

{
"command": "node",
"args": ["/path/to/db-server/index.js"],
"env_vars": {
"DATABASE_URL": "postgresql://user:pass@localhost:5432/mydb",
"MAX_ROWS": "1000"
}
}

The server reads JSON-RPC requests from stdin, executes queries, and writes JSON-RPC responses to stdout. Diagnostic output goes to stderr (stdout is reserved for protocol messages).

Wrap any Python script as an MCP tool:

{
"command": "python3",
"args": ["/path/to/mcp_server.py"],
"env_vars": {
"API_KEY": "sk-...",
"ENVIRONMENT": "production"
}
}

An HTTP server runs independently — on your local network, a cloud VM, or a hosted service. QARK connects over HTTP.

FieldDescriptionExample
URLServer endpointhttps://tools.internal.company.com/mcp
HeadersAuth and custom headers{ "Authorization": "Bearer sk-...", "X-Team": "engineering" }

Headers are stored with AES-256 encryption on disk.

  • Bearer tokenAuthorization: Bearer <token> header. Most common.
  • API key — Custom header like X-API-Key: <key>.
  • Mutual TLS — For high-security environments with client certificates.

An HTTP server wrapping your internal project management API:

{
"url": "https://tools.internal.company.com/mcp",
"headers": {
"Authorization": "Bearer sk-proj-abc123",
"X-Team": "engineering"
}
}

Tools exposed:

[
{
"name": "list_tickets",
"description": "List open tickets for a project. Returns ticket ID, title, assignee, and status.",
"input_schema": {
"type": "object",
"properties": {
"project_id": {
"type": "string",
"description": "Project identifier (e.g., 'BACKEND', 'MOBILE')"
},
"status": {
"type": "string",
"enum": ["open", "in_progress", "review", "done"],
"description": "Filter by status. Omit for all."
}
},
"required": ["project_id"]
}
},
{
"name": "get_ticket_details",
"description": "Full details for a specific ticket including description, comments, and linked pull requests.",
"input_schema": {
"type": "object",
"properties": {
"ticket_id": {
"type": "string",
"description": "Ticket identifier (e.g., 'BACKEND-1234')"
}
},
"required": ["ticket_id"]
}
}
]

Two methods to add MCP servers:

  1. Open Settings → Tools & MCP → MCP Servers
  2. Click Add Server
  3. Select transport type (stdio or HTTP)
  4. Fill in configuration fields
  5. Save and connect

Paste or import a JSON configuration. QARK accepts the Claude Desktop / Cursor mcpServers wrapper format:

{
"mcpServers": {
"my-database": {
"command": "node",
"args": ["server.js"],
"env": {
"DATABASE_URL": "postgres://..."
}
}
}
}

And flat format:

{
"my-database": {
"command": "node",
"args": ["server.js"],
"env": {
"DATABASE_URL": "postgres://..."
}
}
}

This makes it straightforward to reuse MCP server configurations from other tools.


  • Auto-connect on launch — Enabled servers connect automatically in the background when QARK starts. Connection happens asynchronously and does not block app startup.
  • Connection statesdisconnectedconnectingconnected (or error).
  • Tool discovery — On connection, QARK queries the server’s tool manifest and lists discovered tools with names, descriptions, and input schemas.
  • Graceful shutdown — On app exit or manual disconnect, QARK sends cancellation tokens and waits for the server process to terminate cleanly.
  • Reconnect — If a server disconnects unexpectedly, reconnect manually from Settings or restart the app.

After connecting, check that your tools appear in the @mention popover as mcp:{server_name}:{tool_name}. Start a conversation, type @, and look for your server’s tools in the MCP section.

  1. Ask a question that should trigger your tool
  2. Expand the tool call block in the conversation
  3. Verify: correct tool invoked, correct parameters, expected response
SymptomCauseFix
Server stays connectingCommand path wrong or executable missingVerify command exists and is executable. Run manually in terminal.
ENOENT on connectRuntime not installedInstall Node.js, Python, etc. and verify it is in PATH.
HTTP connection refusedServer not running or URL incorrectCheck URL, verify server process, check firewall rules.
Auth error (401/403)Invalid or expired credentialsUpdate headers in MCP settings.
Tool returns errorServer-side exceptionCheck server stderr/logs for stack trace.
Parameters malformedModel sent unexpected inputImprove input_schema with stricter types, enums, and descriptions.
Missing env varsServer does not inherit shell envAdd all required variables explicitly in the server configuration.
nvm/pyenv command not foundLogin shell not loading profileQARK uses login shell — verify your profile sets up the tool correctly.