agentsclimarketplace

Mcp server

Skill RevealUIStudio/revskills/skills/mcp-server

Model Context Protocol server development patterns. Use when building custom MCP servers, exposing tools and resources, handling JSON-RPC, implementing credential isolation, or integrating with Claude Desktop, Cursor, or AI agents. Covers @modelcontextprotocol/sdk, StdioServerTransport, tool schemas, and multi-tenant credential patterns.From its SKILL.md

Install
npx -y skills add RevealUIStudio/revskills --skill mcp-server

Assembled from the repository path, not quoted from the project. Check it against their README if it does not work.

One thing to look at

  • 2 stars2 stars. Stars are a popularity signal and not a quality one, but at this level it is likely that nobody has read this closely except its author, and you would be relying on your own review.

What its file declares

Copied from the file, not written here

The file declares its own license as MIT. That is the author’s claim about this one file, and it is not the same thing as the license GitHub reports for the repository, which is listed with the other numbers below.

SKILL.md

5.4 KB, as published. Nobody here has run it

MCP Server Development

Server Scaffolding

import { Server } from '@modelcontextprotocol/sdk/server/index.js';
import { StdioServerTransport } from '@modelcontextprotocol/sdk/server/stdio.js';
import {
  type CallToolRequest,
  CallToolRequestSchema,
  ListToolsRequestSchema,
  type Tool,
} from '@modelcontextprotocol/sdk/types.js';

const server = new Server(
  { name: 'my-server', version: '0.1.0' },
  { capabilities: { tools: {} } },
);

Tool Definition

Tools use JSON Schema for input validation:

const TOOLS: Tool[] = [
  {
    name: 'my_tool',
    description: 'What this tool does and when to use it.',
    inputSchema: {
      type: 'object',
      properties: {
        query: { type: 'string', description: 'Search query' },
        limit: { type: 'number', description: 'Max results (default: 10)', default: 10 },
        filters: {
          type: 'object',
          description: 'Optional filters',
          properties: {
            status: { type: 'string', enum: ['active', 'archived'] },
          },
        },
      },
      required: ['query'],
    },
  },
];

server.setRequestHandler(ListToolsRequestSchema, async () => ({ tools: TOOLS }));

Tool Dispatch

server.setRequestHandler(CallToolRequestSchema, async (request: CallToolRequest) => {
  const startTime = Date.now();
  const toolName = request.params.name;

  try {
    let data: unknown;

    switch (toolName) {
      case 'my_tool': {
        const { query, limit = 10 } = request.params.arguments as {
          query: string;
          limit?: number;
        };
        data = await myApiCall(query, limit);
        break;
      }

      default:
        return {
          content: [{ type: 'text', text: `Error: Unknown tool: ${toolName}` }],
          isError: true,
        };
    }

    return {
      content: [{
        type: 'text',
        text: JSON.stringify({
          data,
          _meta: {
            durationMs: Date.now() - startTime,
            server: 'my-server',
            tool: toolName,
            timestamp: new Date().toISOString(),
          },
        }, null, 2),
      }],
    };
  } catch (err) {
    return {
      content: [{
        type: 'text',
        text: `Error: ${err instanceof Error ? err.message : String(err)}`,
      }],
      isError: true,
    };
  }
});

Server Startup

async function main() {
  const transport = new StdioServerTransport();
  await server.connect(transport);
}

main().catch((err) => {
  console.error('MCP server error:', err);
  process.exit(1);
});

Credential Isolation

For multi-tenant servers, use a credential override pattern:

let _credentialOverrides: Record<string, string> = {};

export function setCredentials(creds: Record<string, string>): void {
  _credentialOverrides = creds;
}

// In tool handler:
const apiKey = _credentialOverrides.API_KEY ?? process.env.API_KEY;
if (!apiKey) {
  return { content: [{ type: 'text', text: 'Error: API_KEY not set' }], isError: true };
}

The hypervisor calls setCredentials() with tenant-scoped credentials before each invocation.

HTTP API Helper Pattern

function authHeaders(token: string): Record<string, string> {
  return {
    Authorization: `Bearer ${token}`,
    'Content-Type': 'application/json',
    'User-Agent': 'MyServer-MCP/0.1.0',
  };
}

async function apiPost(path: string, body: Record<string, unknown>): Promise<unknown> {
  const { apiUrl, token } = getConfig();
  const res = await fetch(`${apiUrl}${path}`, {
    method: 'POST',
    headers: authHeaders(token),
    body: JSON.stringify(body),
  });
  const data = await res.json();
  if (!res.ok) throw new Error(data.error ?? `API error ${res.status}`);
  return data;
}

Hypervisor Registration

hypervisor.registerServer({
  name: 'my-server',
  command: 'node',
  args: ['dist/servers/my-server.js'],
  env: { API_KEY: 'resolved-at-spawn' },
  requiredTier: 'pro',
});

Claude Desktop Configuration

{
  "mcpServers": {
    "my-server": {
      "command": "node",
      "args": ["/path/to/dist/servers/my-server.js"],
      "env": {
        "API_KEY": "your-api-key"
      }
    }
  }
}

Response Format

Always return content array with type: 'text':

// Success
return {
  content: [{ type: 'text', text: JSON.stringify(result, null, 2) }],
};

// Error
return {
  content: [{ type: 'text', text: `Error: ${message}` }],
  isError: true,
};

Best Practices

  • Validate all inputs before API calls
  • Include _meta with duration, server name, tool name, timestamp
  • Use descriptive tool names with a namespace prefix (e.g., stripe_, memory_)
  • Keep tool descriptions actionable: what it does, when to use it
  • Set required only for truly required fields; use defaults for optional
  • Handle timeouts gracefully (AbortController with 10-30s limits)
  • Log errors server-side but return clean error messages to clients

Keep looking

Skills are one crate of 627,801. Ordering is by how many stacks a row turns up in, so the top of any crate is what has actually been picked rather than what has the most stars.