Skip to content

5.12-b Write tools, non-destructive (phase 2) #7709

Description

@andypalmi

Parent: #7681 (5.12 Team data and packages)
Tool file: new forge/ee/lib/mcp/tools/teamData.js

readOnlyHint: false, destructiveHint: false. One tool per endpoint; these siblings do not share a single action concept, so they are not consolidated.

Tool Endpoint Scope Annotation
platform_create_database_table POST /teams/:teamId/databases/:databaseId/tables team:database:create write
platform_create_library_entry POST /storage/library/:libraryId/* library:entry:create write
platform_update_git_token PUT /teams/:teamId/git/tokens/:tokenId team:git:tokens:edit write

Design notes:

  • Plan-gated (enabled per team type/plan, not per user role): tables, npm, gitIntegration, shared-library. If the team's plan does not include the feature the route returns a 404 (Not Found - not available on team), independent of the PAT's permissions. The tool should surface this as a clear "feature not enabled for this team" message rather than passing through a bare "not found", which an agent would misread as a missing resource.
  • update_git_token edits an existing token record; it does not mint or return a new credential (the minting POST is excluded, see 5.12-d).

Scopes to allow-list + access-tag (#7445):
team:database:create (write), library:entry:create (write), team:git:tokens:edit (write).

Tool definitions (description + zod inputSchema):

platform_create_database_table: {
  description: 'Creates a new table in a database. Both name and columns are required to create the table.',
  inputSchema: z.object({
    teamId: z.string().describe('team hashid'),
    databaseId: z.string().describe('database hashid'),
    name: z.string().describe('name for the new table'),
    columns: z.array(z.object({
      name: z.string().describe('column name'),
      type: z.string().describe('column data type (free-form string; the API declares no enum)'),
      nullable: z.boolean().optional().describe('whether the column allows NULL'),
      default: z.string().nullable().optional().describe('default value, or null for none'),
      generated: z.boolean().optional().describe('whether the column value is generated'),
      maxLength: z.number().nullable().optional().describe('maximum length, or null for unbounded')
    })).describe('column definitions for the new table')
  })
},
platform_create_library_entry: {
  description: 'Creates an entry in the team shared library. type is required and a missing type is rejected with a 400 error. When body is an object it is JSON-stringified before storage.',
  inputSchema: z.object({
    libraryId: z.string().describe('shared-library hashid (the team hashid)'),
    path: z.string().describe('Library entry path'),
    type: z.string().describe('entry type (e.g. flows, functions)'),
    body: z.any().describe('entry contents'),
    meta: z.record(z.any()).optional().describe('arbitrary metadata stored with the entry')
  })
},
platform_update_git_token: {
  description: 'Updates an existing git token. name is the only editable field: the update only changes the token name and never mints or returns a credential.',
  inputSchema: z.object({
    teamId: z.string().describe('team hashid'),
    tokenId: z.string().describe('git token hashid'),
    name: z.string().describe('new name for the git token')
  })
}

Tests:

  • Read-only PAT rejected for every tool here.
  • Feature-disabled team returns the descriptive gate error.

Metadata

Metadata

Assignees

No one assigned

    Labels

    storyA user-oriented description of a feature

    Type

    No type

    Fields

    No fields configured for issues without a type.

    Projects

    Status
    No status

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions