SpainMCP
Clientes

Scoping de Tokens

Define con precisión qué conexiones y operaciones están disponibles para cada token, ya sea por usuario, workspace o cualquier criterio personalizado.

Vista previa — El Scoping de Tokens está en preview. La superficie de la API puede cambiar. Únete a nuestro Discord para soporte y feedback.

Los tokens de servicio hacen posible que SpainMCP se integre de forma segura en navegadores, aplicaciones móviles y agentes de IA, todo ello sin necesidad de exponer tu API key. Cada token incorpora restricciones que determinan exactamente qué namespaces, recursos, operaciones y metadata son accesibles.

Si necesitas información sobre la configuración general, visita SpainMCP Connect.

Restringir un Token a un Usuario Concreto

En aplicaciones multiusuario, lo habitual es que cada token solo tenga visibilidad sobre las conexiones de su propietario. El mecanismo es sencillo: al crear una conexión, asígnale metadata (por ejemplo, { userId: "user-123" }). Después, genera un token con esa misma restricción de metadata. De esta forma, el token únicamente podrá interactuar con las conexiones cuya metadata sea coincidente.

spainmcp auth token --policy '[{
  "namespaces": "my-app",
  "resources": "connections",
  "operations": ["read", "execute"],
  "metadata": { "userId": "user-123" },
  "ttl": "1h"
}]'
const { token } = await spainmcp.tokens.create({
  policy: [
    {
      namespaces: 'my-app',
      resources: 'connections',
      operations: ['read', 'execute'],
      metadata: { userId: 'user-123' },
      ttl: '1h',
    },
  ],
})
curl -X POST "https://api.spainmcp.com/v1/auth/token" \
  -H "Authorization: Bearer $SPAINMCP_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{"policy":[{"namespaces":"my-app","resources":"connections","operations":["read","execute"],"metadata":{"userId":"user-123"},"ttl":"1h"}]}'

Con este token es posible listar y ejecutar herramientas en las conexiones de my-app que tengan metadata.userId igual a user-123, y nada fuera de ese alcance. Cualquier intento de acceder a la conexión de otro usuario resultara en una peticion rechazada.

Tambien es posible filtrar por varios campos de metadata simultaneamente. Dentro de un mismo objeto de metadata, los campos se combinan con logica AND, de modo que el siguiente token solo coincide con conexiones donde userId y tier se cumplan a la vez:

spainmcp auth token --policy '[{
  "namespaces": "my-app",
  "resources": "connections",
  "operations": ["read", "execute"],
  "metadata": { "userId": "user-123", "tier": "pro" },
  "ttl": "1h"
}]'
const { token } = await spainmcp.tokens.create({
  policy: [
    {
      namespaces: 'my-app',
      resources: 'connections',
      operations: ['read', 'execute'],
      metadata: { userId: 'user-123', tier: 'pro' },
      ttl: '1h',
    },
  ],
})
curl -X POST "https://api.spainmcp.com/v1/auth/token" \
  -H "Authorization: Bearer $SPAINMCP_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{"policy":[{"namespaces":"my-app","resources":"connections","operations":["read","execute"],"metadata":{"userId":"user-123","tier":"pro"},"ttl":"1h"}]}'

Acceso Jerárquico (Workspace / Organización)

En aplicaciones reales es frecuente que existan varios niveles de acceso. Un usuario típico necesitaría ver:

  • Las conexiones que le pertenecen
  • Las conexiones compartidas dentro de su workspace
  • Las conexiones globales definidas por un administrador

Para lograrlo, incluye varias restricciones en el array policy. Cada restricción funciona como un permiso independiente: el token obtiene acceso a todo lo que encaje con al menos una de ellas.

spainmcp auth token --policy '[
  {
    "namespaces": "my-app",
    "resources": "connections",
    "operations": ["read", "execute"],
    "metadata": { "userId": "user-123" },
    "ttl": "1h"
  },
  {
    "namespaces": "my-app",
    "resources": "connections",
    "operations": ["read", "execute"],
    "metadata": { "workspaceId": "ws-acme" },
    "ttl": "1h"
  },
  {
    "namespaces": "my-app",
    "resources": "connections",
    "operations": ["read", "execute"],
    "metadata": { "scope": "global" },
    "ttl": "1h"
  }
]'
const { token } = await spainmcp.tokens.create({
  policy: [
    { namespaces: 'my-app', resources: 'connections', operations: ['read', 'execute'], metadata: { userId: 'user-123' }, ttl: '1h' },
    { namespaces: 'my-app', resources: 'connections', operations: ['read', 'execute'], metadata: { workspaceId: 'ws-acme' }, ttl: '1h' },
    { namespaces: 'my-app', resources: 'connections', operations: ['read', 'execute'], metadata: { scope: 'global' }, ttl: '1h' },
  ],
})
curl -X POST "https://api.spainmcp.com/v1/auth/token" \
  -H "Authorization: Bearer $SPAINMCP_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{"policy":[{"namespaces":"my-app","resources":"connections","operations":["read","execute"],"metadata":{"userId":"user-123"},"ttl":"1h"},{"namespaces":"my-app","resources":"connections","operations":["read","execute"],"metadata":{"workspaceId":"ws-acme"},"ttl":"1h"},{"namespaces":"my-app","resources":"connections","operations":["read","execute"],"metadata":{"scope":"global"},"ttl":"1h"}]}'

Quien posea este token podrá ver las conexiones que coincidan con cualquiera de los tres permisos definidos, sin necesidad de gestionar tokens separados para cada nivel de acceso.

Para que esto funcione, etiqueta tus conexiones con la metadata correcta al crearlas:

  • Conexiones de usuario: metadata: { userId: 'user-123' }
  • Conexiones de workspace: metadata: { workspaceId: 'ws-acme' }
  • Conexiones globales: metadata: { scope: 'global' }

Reducir el Alcance de un Token

Es posible derivar un token con permisos mas limitados a partir de un token de servicio existente. El token resultante solo puede tener un alcance igual o inferior al del token original; nunca puede exceder los permisos del padre.

Este patron resulta especialmente util cuando tu backend dispone de un token amplio y necesita emitir tokens mas acotados para cada peticion individual. Por ejemplo, partiendo del token multi-nivel descrito en la seccion anterior:

# Estrechar el token amplio a las conexiones de un solo usuario
SPAINMCP_API_KEY=$BROAD_SERVICE_TOKEN spainmcp auth token \
  --policy '[{
    "resources": "connections",
    "operations": "read",
    "metadata": { "userId": "user-123" },
    "ttl": "20m"
  }]'
const spainmcpWithBroadToken = new SpainMCP({ apiKey: broadToken })

const { token: userToken } = await spainmcpWithBroadToken.tokens.create({
  policy: [
    {
      resources: 'connections',
      operations: 'read',
      metadata: { userId: 'user-123' },
      ttl: '20m',
    },
  ],
})
curl -X POST "https://api.spainmcp.com/v1/auth/token" \
  -H "Authorization: Bearer $BROAD_SERVICE_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{"policy":[{"resources":"connections","operations":"read","metadata":{"userId":"user-123"},"ttl":"20m"}]}'

Caso de uso habitual: Tu backend genera un token amplio durante el arranque (por ejemplo, con acceso a todas las conexiones de un namespace). En cada peticion entrante, reduce ese token al usuario o contexto concreto antes de enviarlo al codigo del lado del cliente.

Control de Operaciones por Recurso

Permite definir con granularidad que acciones puede realizar un token sobre cada tipo de recurso.

RecursoOperacionesDescripción
connectionsreadListar y obtener conexiones
connectionswriteCrear y eliminar conexiones
connectionsexecuteLlamar herramientas MCP a través de una conexión
serversread, writeMetadata y configuración del servidor
namespacesread, writeGestión de namespaces

Token de Solo Lectura (Dashboard)

spainmcp auth token --policy '[{
  "namespaces": "my-app",
  "resources": "connections",
  "operations": "read",
  "ttl": "1h"
}]'
const { token } = await spainmcp.tokens.create({
  policy: [{ namespaces: 'my-app', resources: 'connections', operations: 'read', ttl: '1h' }],
})
curl -X POST "https://api.spainmcp.com/v1/auth/token" \
  -H "Authorization: Bearer $SPAINMCP_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{"policy":[{"namespaces":"my-app","resources":"connections","operations":"read","ttl":"1h"}]}'

Token de Solo Ejecución (Agente)

spainmcp auth token --policy '[{
  "namespaces": "my-app",
  "resources": "connections",
  "operations": "execute",
  "metadata": { "userId": "user-123" },
  "ttl": "30m"
}]'
const { token } = await spainmcp.tokens.create({
  policy: [{ namespaces: 'my-app', resources: 'connections', operations: 'execute', metadata: { userId: 'user-123' }, ttl: '30m' }],
})
curl -X POST "https://api.spainmcp.com/v1/auth/token" \
  -H "Authorization: Bearer $SPAINMCP_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{"policy":[{"namespaces":"my-app","resources":"connections","operations":"execute","metadata":{"userId":"user-123"},"ttl":"30m"}]}'

Token Multi-Recurso

Con un solo token puedes otorgar acceso a varios tipos de recursos. Basta con incluir varias restricciones en el array policy:

spainmcp auth token --policy '[
  {
    "namespaces": "my-app",
    "resources": "connections",
    "operations": ["read", "execute"],
    "metadata": { "userId": "user-123" },
    "ttl": "1h"
  },
  {
    "namespaces": "my-app",
    "resources": "servers",
    "operations": "read",
    "ttl": "1h"
  }
]'
const { token } = await spainmcp.tokens.create({
  policy: [
    { namespaces: 'my-app', resources: 'connections', operations: ['read', 'execute'], metadata: { userId: 'user-123' }, ttl: '1h' },
    { namespaces: 'my-app', resources: 'servers', operations: 'read', ttl: '1h' },
  ],
})
curl -X POST "https://api.spainmcp.com/v1/auth/token" \
  -H "Authorization: Bearer $SPAINMCP_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{"policy":[{"namespaces":"my-app","resources":"connections","operations":["read","execute"],"metadata":{"userId":"user-123"},"ttl":"1h"},{"namespaces":"my-app","resources":"servers","operations":"read","ttl":"1h"}]}'

Filtrado de Peticiones MCP (Experimental)

Inestable — La coincidencia de peticiones MCP es experimental. La forma del campo rpcReqMatch puede cambiar en versiones futuras.

De forma predeterminada, un token con permiso connections:execute puede invocar cualquier herramienta disponible en una conexion. Mediante el campo rpcReqMatch, es posible acotar exactamente que llamadas JSON-RPC puede realizar el token, proporcionando control a nivel de cada peticion individual.

Las reglas de filtrado analizan el cuerpo JSON-RPC de la peticion. Las claves se expresan como dot-paths (por ejemplo, params.name apunta al nombre de la herramienta en una llamada tools/call). Los valores son patrones regex. Cuando una restriccion contiene multiples entradas, todas deben cumplirse (logica AND).

Permitir Solo Herramientas Específicas

const { token } = await spainmcp.tokens.create({
  policy: [
    {
      namespaces: 'my-app',
      resources: 'connections',
      operations: 'execute',
      metadata: { userId: 'user-123' },
      rpcReqMatch: { 'params.name': '^(search|get_page)$' },
      ttl: '1h',
    },
  ],
})

// Este token solo puede llamar las herramientas "search" y "get_page" — nada más
curl -X POST "https://api.spainmcp.com/v1/auth/token" \
  -H "Authorization: Bearer $SPAINMCP_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{"policy":[{"namespaces":"my-app","resources":"connections","operations":"execute","metadata":{"userId":"user-123"},"rpcReqMatch":{"params.name":"^(search|get_page)$"},"ttl":"1h"}]}'

Permisos Combinados: Lectura Libre + Ejecución Selectiva

Si necesitas un token que pueda listar conexiones sin restricciones pero que solo ejecute herramientas concretas, hay que definir dos restricciones separadas: una para el acceso de lectura general y otra para la ejecucion limitada:

const { token } = await spainmcp.tokens.create({
  policy: [
    // Permiso 1: listar conexiones (sin restricción rpcReqMatch)
    {
      namespaces: 'my-app',
      resources: 'connections',
      operations: 'read',
      metadata: { userId: 'user-123' },
      ttl: '1h',
    },
    // Permiso 2: ejecutar solo la herramienta "search"
    {
      namespaces: 'my-app',
      resources: 'connections',
      operations: 'execute',
      metadata: { userId: 'user-123' },
      rpcReqMatch: { 'params.name': '^search$' },
      ttl: '1h',
    },
  ],
})
curl -X POST "https://api.spainmcp.com/v1/auth/token" \
  -H "Authorization: Bearer $SPAINMCP_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{"policy":[{"namespaces":"my-app","resources":"connections","operations":"read","metadata":{"userId":"user-123"},"ttl":"1h"},{"namespaces":"my-app","resources":"connections","operations":"execute","metadata":{"userId":"user-123"},"rpcReqMatch":{"params.name":"^search$"},"ttl":"1h"}]}'

Patrones de Coincidencia

Los valores de filtrado son patrones regex. Utiliza anclas (^...$) cuando necesites coincidencia exacta:

PatrónValores de ejemploSignificado
"^search$""search"Coincidencia exacta
"^(search|get_page)$""search", "get_page"Uno de varios valores
"^create_""create_issue", "create_user"Coincidencia por prefijo
".*"cualquier cosaCoincide todo

Dentro de una misma restriccion, las entradas de coincidencia se combinan con logica AND. Si defines varias claves en rpcReqMatch, la peticion debe satisfacer todas simultaneamente:

rpcReqMatch: {
  'params.name': '^create_issue$',
  'params.arguments.repo': '^my-org/my-repo$',
}
// Solo permite tools/call donde name es "create_issue" Y repo es "my-org/my-repo"

Los paths separados por puntos coinciden en el cuerpo de la petición JSON-RPC. Para una petición tools/call como {"method":"tools/call","params":{"name":"search","arguments":{"query":"test"}}}, el path params.name coincide con "search" y params.arguments.query coincide con "test".

Referencia de Restricciones

El array policy esta compuesto por restricciones, donde cada una representa un permiso autocontenido que especifica a que tiene acceso el token.

interface Constraint {
  namespaces?: string | string[]
  resources?: 'connections' | 'servers' | 'namespaces' | 'skills'
    | ('connections' | 'servers' | 'namespaces' | 'skills')[]
  operations?: 'read' | 'write' | 'execute'
    | ('read' | 'write' | 'execute')[]
  metadata?: Record<string, string>
    | Record<string, string>[]
  rpcReqMatch?: Record<string, string>  // experimental — patrones regex para coincidencia de peticiones MCP
  ttl?: string | number  // p.ej., "1h", "30m", "20s", 3600
}

Cada restriccion se rige por dos principios fundamentales:

  • Agregar un campo reduce el alcance (AND). Cada campo introduce una condicion adicional. A mas campos, mas restrictivo sera el permiso.
  • Agregar elementos a una lista amplia el alcance (OR). Cada elemento de la lista representa una alternativa valida. A mas elementos, mas permisivo resulta.
// Añadir campos estrecha el permiso
{ resources: 'connections' }
// → cualquier operación en connections

{ resources: 'connections', operations: 'read' }
// → solo leer connections

{ resources: 'connections', operations: 'read', metadata: { userId: 'user-123' } }
// → solo leer las connections de user-123

// Añadir a una lista amplía el permiso
{ operations: ['read', 'write'] }
// → read OR write

{ metadata: [{ userId: 'user-123' }, { workspaceId: 'ws-acme' }] }
// → userId=user-123 OR workspaceId=ws-acme

Si incluyes varias restricciones dentro del array policy, cada una actua como un permiso separado. El token obtendra acceso a todo aquello que encaje con al menos una de las restricciones.

# Dos permisos: leer connections de alice O leer/escribir servers
spainmcp auth token --policy '[
  {
    "resources": "connections",
    "operations": "read",
    "metadata": { "owner": "alice" }
  },
  {
    "resources": "servers",
    "operations": ["read", "write"]
  }
]'
const { token } = await spainmcp.tokens.create({
  policy: [
    { resources: 'connections', operations: 'read', metadata: { owner: 'alice' } },
    { resources: 'servers', operations: ['read', 'write'] },
  ],
})
curl -X POST "https://api.spainmcp.com/v1/auth/token" \
  -H "Authorization: Bearer $SPAINMCP_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{"policy":[{"resources":"connections","operations":"read","metadata":{"owner":"alice"}},{"resources":"servers","operations":["read","write"]}]}'

La metadata dentro de un único objeto es AND: { owner: 'alice', env: 'prod' } significa que owner es alice y env es prod. Usa una lista para OR: [{ owner: 'alice' }, { env: 'prod' }] significa que owner es alice o env es prod.

Recomendaciones de Seguridad

  • Define siempre un TTL. Los tokens caducan tras el tiempo especificado (maximo 24 horas). Cuanto mas corto, mejor: genera tokens nuevos en cada sesion.
  • Aplica el principio de minimo privilegio. Un token destinado a invocar herramientas solo requiere connections:execute, no connections:write.
  • Emplea metadata para aislar el acceso por fila. No dependas exclusivamente de los IDs de conexion: las restricciones basadas en metadata se evaluan en el servidor.
  • Reduce el alcance antes de compartir con entornos no confiables. Si vas a enviar un token a un navegador, agente o sandbox, limítalo al usuario y las operaciones estrictamente necesarias.
  • Los tokens no generan permisos de la nada. Solo las API keys o tokens preexistentes pueden crear nuevos tokens, y un token hijo jamas puede superar los permisos de su padre.
¿Te ha sido útil esta página?

En esta página